AltBeacon / android-beacon-library

Allows Android apps to interact with BLE beacons
Apache License 2.0
2.84k stars 836 forks source link

Backgroun and foreground together. Not starting after boot #784

Closed YuraAAA closed 5 years ago

YuraAAA commented 5 years ago

Expected behavior

Bind to consumer in foreground and work with RegionBootstrap in background

Actual behavior

Background scan doesn't start

Steps to reproduce this behavior

I want to combine background and foreground beacon detection.

Class for foreground scan

class BeaconForegroundService(private val application: Application) : BeaconConsumer {

    private var beaconManager: BeaconManager? = null

    companion object {
        private const val REGION_UID = "region_uid"
    }

    override fun getApplicationContext(): Context {
        return application.applicationContext
    }

    override fun unbindService(p0: ServiceConnection) {
        application.unbindService(p0)
    }

    override fun bindService(p0: Intent, p1: ServiceConnection, p2: Int): Boolean {
        return application.bindService(p0, p1, p2)
    }

    override fun onBeaconServiceConnect() {

        beaconManager!!.beaconParsers.clear()
        beaconManager!!.beaconParsers.add(AltBeaconParser())
        beaconManager!!.beaconParsers.add(BeaconParser().setBeaconLayout(BeaconParser.URI_BEACON_LAYOUT))
        beaconManager!!.beaconParsers.add(BeaconParser().setBeaconLayout(BeaconParser.EDDYSTONE_TLM_LAYOUT))
        beaconManager!!.beaconParsers.add(BeaconParser().setBeaconLayout(BeaconParser.EDDYSTONE_UID_LAYOUT))
        beaconManager!!.beaconParsers.add(BeaconParser().setBeaconLayout(BeaconParser.EDDYSTONE_URL_LAYOUT))
        beaconManager!!.beaconParsers.add(BeaconParser().setBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24,d:25-25"))
        beaconManager!!.backgroundMode = false

        beaconManager!!.addMonitorNotifier(object : MonitorNotifier {
            override fun didDetermineStateForRegion(p0: Int, p1: Region?) {
                Timber.d("FGBeacon: didDetermineStateForRegion INSIDE = ${p0 == MonitorNotifier.INSIDE}")
            }

            override fun didEnterRegion(p0: Region?) {
                Timber.d("FGBeacon: didEnterRegion")
            }

            override fun didExitRegion(p0: Region?) {
                Timber.d("FGBeacon: didExitRegion")
            }
        })
        beaconManager!!.addRangeNotifier { mutableCollection: MutableCollection<Beacon>, region: Region ->
            Timber.d("FGBeacon $mutableCollection")
        }
        beaconManager!!.startMonitoringBeaconsInRegion(Region(REGION_UID, null, null, null))
        beaconManager!!.startRangingBeaconsInRegion(Region(REGION_UID, null, null, null))
    }

    fun startScan() {
        beaconManager = BeaconManager.getInstanceForApplication(application)
        beaconManager!!.bind(this)
    }

    fun stopScan() {
        beaconManager?.unbind(this)
    }
}

And in instance of android.app.Application:


class MyApplication : Application(), BootstrapNotifier {

// Fields
private var beaconManager: BeaconManager? = null
private var backgroundPowerSaver: BackgroundPowerSaver ?= null
private var regionBootstrap : RegionBootstrap ?= null
private var foregroundService: BeaconForegroundService ?= null
val REGION_UID = "region_uid"

//Method for start background scan here

fun startScan() {
        beaconManager = BeaconManager.getInstanceForApplication(this)
        beaconManager!!.beaconParsers.clear()
        beaconManager!!.beaconParsers.add(AltBeaconParser())
        beaconManager!!.beaconParsers.add(BeaconParser().setBeaconLayout(BeaconParser.URI_BEACON_LAYOUT))
        beaconManager!!.beaconParsers.add(BeaconParser().setBeaconLayout(BeaconParser.EDDYSTONE_TLM_LAYOUT))
        beaconManager!!.beaconParsers.add(BeaconParser().setBeaconLayout(BeaconParser.EDDYSTONE_UID_LAYOUT))
        beaconManager!!.beaconParsers.add(BeaconParser().setBeaconLayout(BeaconParser.EDDYSTONE_URL_LAYOUT))
        beaconManager!!.beaconParsers.add(BeaconParser().setBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24,d:25-25"))

        val notificationBuilder = Notification.Builder(this)
        notificationBuilder.setSmallIcon(R.drawable.ic_launcher_foreground)
        notificationBuilder.setContentTitle("Scanning for beacons")
        val intent = Intent(this, MainActivity::class.java)
        val pendingIntent = PendingIntent.getActivity(this, MainActivity.BEACON_REQUEST_CODE, intent, PendingIntent.FLAG_UPDATE_CURRENT)
        notificationBuilder.setContentIntent(pendingIntent)

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channel = NotificationChannel("MyChannelId", "NotyName", NotificationManager.IMPORTANCE_DEFAULT)
            channel.description = "NotyDesc"
            val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
            notificationManager.createNotificationChannel(channel)
            notificationBuilder.setChannelId(channel.id)
        }

        val region = Region(REGION_UID, null, null, null)

        beaconManager!!.enableForegroundServiceScanning(notificationBuilder.build(), 456)
        beaconManager!!.setEnableScheduledScanJobs(false)
        beaconManager!!.backgroundBetweenScanPeriod = 0
        beaconManager!!.backgroundScanPeriod = TimeUnit.SECONDS.toMillis(5)
        beaconManager!!.backgroundMode = true

        regionBootstrap  = RegionBootstrap(this, region)
        backgroundPowerSaver = BackgroundPowerSaver(this)

        beaconManager!!.addRangeNotifier { mutableCollection: MutableCollection<Beacon>, r: Region ->
            Timber.d("PBeacon $mutableCollection")
        }
    }

//Disable background scan if application start in foreground
fun disableMonitoring() {
        regionBootstrap?.disable()
        regionBootstrap = null
        beaconManager?.removeAllRangeNotifiers()
    }

  override fun didDetermineStateForRegion(p0: Int, p1: Region?) {
        Timber.d("PBeacon: StateForRegion INSIDE = ${p0 == MonitorNotifier.INSIDE}")
    }

//Start ranging if we inside region
    override fun didEnterRegion(p0: Region?) {
        Timber.d("PBeacon: I see a beacon first time")
        beaconManager!!.startRangingBeaconsInRegion(Region(REGION_UID, null, null, null))

    }

//Stop ranging if we move out from region
    override fun didExitRegion(p0: Region?) {
        Timber.d("PBeacon : I no longer see a beacon.")
        beaconManager!!.stopRangingBeaconsInRegion(Region(REGION_UID, null, null, null))
    }

Switch modes in onCreate inside my app class

registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacks {

            //Stop background scan and start foreground
            override fun onActivityStarted(activity: Activity?) {
                disableMonitoring() 

                foregroundService = BeaconForegroundService(this@MyApplication)
                foregroundService!!.startScan()
            }

              //Stop foreground scan and start background
              override fun onActivityStopped(activity: Activity?) {
                foregroundService?.stopScan()
                foregroundService = null

                startScan()
            }

        })

Mobile device model and OS version

OnePlus 6 (A6000) Android 9.0 OxygenOS 9.0.2

Android Beacon Library version

2+ (2.15.2)

Logs

Logs when application starting in foreground (looks fine)

D/BeaconParser: Parsing beacon layout: m:2-3=beac,i:4-19,i:20-21,i:22-23,p:24-24,d:25-25
D/BeaconParser: Parsing beacon layout: m:2-3=beac,i:4-19,i:20-21,i:22-23,p:24-24,d:25-25
D/BeaconParser: Parsing beacon layout: s:0-1=fed8,m:2-2=00,p:3-3:-41,i:4-21v
D/BeaconParser: Parsing beacon layout: x,s:0-1=feaa,m:2-2=20,d:3-3,d:4-5,d:6-7,d:8-11,d:12-15
D/BeaconParser: Parsing beacon layout: s:0-1=feaa,m:2-2=00,p:3-3:-41,i:4-13,i:14-19
D/BeaconParser: Parsing beacon layout: s:0-1=feaa,m:2-2=10,p:3-3:-41,i:4-21v
D/BeaconParser: Parsing beacon layout: m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24,d:25-25
....
BeaconForegroundService$onBeaconServiceConnect: [id1: b5b182c7-eab1-4988-aa99-b5c1517008d9 id2: 1 id3: 57197]

Close app (background mode?):

Processing pdu type FF: 0201061aff4c000215b5b182c7eab14988aa99b5c1517008d90001df6dc50d0961626561636f6e5f36444446000000000000000000000000000000000000 with startIndex: 5, endIndex: 29
D/BeaconParser: This is not a matching Beacon advertisement. Was expecting aa fe at offset 5 and 20 at offset 7.  The bytes I see are: 0201061aff4c000215b5b182c7eab14988aa99b5c1517008d90001df6dc50d0961626561636f6e5f36444446000000000000000000000000000000000000
 D/BeaconParser: Ignoring pdu type 01
...
 D/BeaconParser: Processing pdu type FF: 0201061aff4c000215b5b182c7eab14988aa99b5c1517008d90001df6dc50d0961626561636f6e5f36444446000000000000000000000000000000000000 with startIndex: 5, endIndex: 29
D/BeaconParser: This is a recognized beacon advertisement -- 02 15 seen
D/BeaconParser: Bytes are: 0201061aff4c000215b5b182c7eab14988aa99b5c1517008d90001df6dc50d0961626561636f6e5f36444446000000000000000000000000000000000000
D/ScanHelper: Beacon packet detected for: id1: b5b182c7-eab1-4988-aa99-b5c1517008d9 id2: 1 id3: 57197 with rssi -46
D/RangeState: adding id1: b5b182c7-eab1-4988-aa99-b5c1517008d9 id2: 1 id3: 57197 to existing range for: org.altbeacon.beacon.service.RangedBeacon@332c859

After reboot:

I/BeaconManager: BeaconManager started up on pid 7407 named 'com.myapp' for application package 'com.myapp'.  isMainProcess=true
D/BeaconParser: Parsing beacon layout: m:2-3=beac,i:4-19,i:20-21,i:22-23,p:24-24,d:25-25

And thats all. No detections...

So, my question:

  1. Is it bug of library/device or i doing something wrong?
  2. Can we use background scan without notification?
  3. Whan we start application again (to foreground) notification refreshed. How can i avoid this?

Thanks

davidgyoung commented 5 years ago

@YuraAAA, this question is really out of scope for this forum since it is about debugging a custom app. This forum is reserved for feature requests and reproducible bugs with the library itself.

If you repost your question on StackOverflow.com, I am happy to look, but please try to make it as comcise as possible.

In general, for background detection to work, you must trigger Region bootstrap in the onCreate method of your custon Application class. Please verify you do that and show clearly how that is done.

YuraAAA commented 5 years ago

@YuraAAA, this question is really out of scope for this forum since it is about debugging a custom app. This forum is reserved for feature requests and reproducible bugs with the library itself.

If you repost your question on StackOverflow.com, I am happy to look, but please try to make it as comcise as possible.

In general, for background detection to work, you must trigger Region bootstrap in the onCreate method of your custon Application class. Please verify you do that and show clearly how that is done.

Sure, sorry for this issue) Can you please look at my question? stackoverflow