Doze mode locks scan?
See original GitHub issueExpected behavior
Scanner works when device is locked or how we can to check is scanner locked by OS?
Actual behavior
Periodically scanner stops
Steps to reproduce this behavior
Run scanner with foreground service and lock device. Sometimes didRangeBeaconsInRegion not called.
Mobile device model and OS version
Samsung Galaxy S6 edge+ (Android 7.0)
Android Beacon Library version
2.15.2
I’m not sure that this question should be a issue. Briefly:
When method addRangeNotifier invoked, i iterate by beacon collections (in method didRangeBeaconsInRegion argument) and add it into List<> if not exsits, or update last visible time parameter (modifiedAt = System.currentTimeMillis()) if beacon was already in list.
Every 10 seconds my background thread iterates through this collection (List<>) and checks modifiedAt field. If we saw beacon more than 1 minute ago i remove it from collection. So i guess that we left the zone.
But. If device in idle state, periodically we do not receive events.
It’s mean (Situation1) :
- User enters in zone (new beacon, not exists in our cache, in our List<>)
- User locks screen and does not leave the zone.
- For a while we get an events, all is good, great.
- After a while didRangeBeaconsInRegion stop calling.
- Sooner or later didRangeBeaconsInRegion invokes again
I guess it’s doze mode, but im not sure because see something strange (method for adding beacon or update it modifiedAt field):
fun addBeacon(beacon: AppBeacon) {
if (isInDozeMode(TheApplication.getInstance())) {
Crashlytics.logException(InconsistencyStateException("addBeacon invoke but doze mode active"))
}
//next logic
fun isInDozeMode(context: Context) : Boolean {
val powerManager = context.getSystemService(Context.POWER_SERVICE) as PowerManager
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && powerManager.isDeviceIdleMode
}
And in reports i see this exception. I mean we obtain callback from library but isInDozeMode returns true.
For avoiding [Situation1] i added condition inside looper thread (thread that clean up expired objects).
if (isInDozeMode()) {
//Ignore check modifiedAt parameter.
} else {
//Check modifiedAt. If >1minute remove it
}
Unfortunately this condition does not work perfectly.
So, my question. Can we check is scanner not available now (blocked by OS)? Thanks.
Attachment: scanner setup in Application instance class
private const val REGION_UID = "my.packagename.here"
private val region : Region
get() {
return Region(REGION_UID, null, null, null)
}
const val FOREGROUND_BETWEEN_SCAN_DELAY: Long = 1000L
const val BACKGROUND_BETWEEN_SCAN_DELAY: Long = 1000L
const val FOREGROUND_SCAN_PERIOD: Long = 2000
const val BACKGROUND_SCAN_PERIOD: Long = 5100
private fun setupBeaconScanner() {
LogManager.setLogger(BeaconLogger())
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 = NotificationCompat.Builder(this)
notificationBuilder.setSmallIcon(R.drawable.ic_details_action)
notificationBuilder.setLargeIcon(BitmapFactory.decodeResource(resources, R.drawable.ic_details_action))
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 channelId = createNotificationChannel(SCANNER_CHANEL_ID, SCANNER_CHANEL_NAME, SCANNER_IMPORTANCE)
notificationBuilder.setChannelId(channelId)
notificationBuilder.setBadgeIconType(BADGE_ICON_SMALL)
}
val notification = notificationBuilder.build()
beaconManager!!.enableForegroundServiceScanning(notification, 456)
beaconManager!!.addRangeNotifier { p0, p1 ->
p0?.run {
forEach {
val beacon = AppBeacon.fromLibraryBeacon(it)
if (beacon != null) {
AppBeaconManager.addBeacon(beacon
}
}
}
}
beaconManager!!.addMonitorNotifier(this)
beaconManager!!.setEnableScheduledScanJobs(false)
beaconManager!!.backgroundBetweenScanPeriod = BACKGROUND_BETWEEN_SCAN_DELAY
beaconManager!!.foregroundBetweenScanPeriod = FOREGROUND_BETWEEN_SCAN_DELAY
beaconManager!!.backgroundScanPeriod = BACKGROUND_SCAN_PERIOD
beaconManager!!.foregroundScanPeriod = FOREGROUND_SCAN_PERIOD
regionBootstrap = RegionBootstrap(this, region)
// Power saver temporary excluded but it did not fix the situation.
// backgroundPowerSaver = BackgroundPowerSaver(this)
}
Issue Analytics
- State:
- Created 5 years ago
- Comments:22 (10 by maintainers)
Top GitHub Comments
Yes, so long as ranging is active, didRangeBeconsInRegion is called with a zero length collection of beacons when none are in range.
If you are ranging, then a call to didRangeBeaconsInRegion indicates the time the last scan cycle completed. If you see these stop, then the scan cycles have stopped for some reason.
I suspect you can test on your OnePlus despite custom behavior that kills the app in the background. You can either whitelist your app to in the OnePlus settings so it can run forever, or you can simply use an ADB command to force entering doze mode immediately:
$ adb shell dumpsys deviceidle force-idle