AltBeacon / android-beacon-library

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

Handle Foreground Service Start Failures in Android 12 #1090

Closed davidgyoung closed 2 years ago

davidgyoung commented 2 years ago

Apps using this library on Android 12 can crash if they configure the library's foreground service for scanning as reported in https://github.com/AltBeacon/android-beacon-library/issues/1082. This happens because Android 12 restricts when foreground services can be started to when:

The app is in the foreground The app has received BOOT_COMPLETED A number of other qualifying events (motion, Firebase messages, Bluetooth connect, etc.) not tracked by the library. While it is possible to code around the above, the restrictions make it difficult to use the library. These following changes are designed to make using the library with a foreground service on Android 12 easier.

The library will detect if starting its foreground service fails, catching the exception and preventing a crash. If the foreground service can't be started, the library will fall back to using the default ScanJob scanning strategy. This will keep beacon detections working, albeit in a degraded fashion. If the library detects the app has come to the foreground after the above failure has happened, it will start the foreground service at that time. A new public API method on BeaconManager indicates if a failure to start the foreground service has happened: foregroundServiceStartFailed() A new public API method on BeaconManager allows the app to retry starting the foreground service (useful for the case that a qualifying event other than the automatically handled foreground change is known to have happened): retryForegroundServiceScanning() For this change I performed the following tests with the Kotlin reference app:

Modifying app to use a forreground service but long background between scan periods Launching app with no beacons around Killing foreground service from adb while app is in a between scan cycle. Turning on a beacon to re-launch the app in the background. I see this: 2022-06-03 11:47:45.897 5802-5802/org.altbeacon.beaconreference I/BeaconManager: Attempting to starting foreground beacon scanning service. 2022-06-03 11:47:45.905 5802-5802/org.altbeacon.beaconreference W/BeaconManager: Foreground service blocked by ServiceStartNotAllowedException. Falling back to job scheduler The above confirms fallback to ScanJobs works.

Now test failover when the app. comes to the foreground:

Tapp app launcher to bring to foreground 06-03 11:52:38.440 5802 5802 I BeaconManager: unbinding all consumers for strategy failover 06-03 11:52:38.440 5802 5802 D BeaconManager: Unbinding 06-03 11:52:38.440 5802 5802 D BeaconManager: Not unbinding from scanning service as we are using scan jobs. 06-03 11:52:38.440 5802 5802 D BeaconManager: Before unbind, consumer count is 1 06-03 11:52:38.440 5802 5802 D BeaconManager: After unbind, consumer count is 0 06-03 11:52:38.440 5802 5802 I BeaconManager: Cancelling scheduled jobs after unbind of last consumer. 06-03 11:52:38.440 5802 5802 I ScanJob : Using immediateScanJobId from manifest: 208352939 06-03 11:52:38.442 5802 5802 I ScanJob : Using periodicScanJobId from manifest: 208352940 06-03 11:52:38.442 5802 5802 I BeaconManager: binding all consumers for strategy failover 06-03 11:52:38.443 5802 5802 D BeaconManager: Need to rebind for switch to foreground service 06-03 11:52:38.443 5802 5802 D BeaconManager: Binding to service 06-03 11:52:38.443 5802 5802 I BeaconManager: Attempting to starting foreground beacon scanning service. 06-03 11:52:38.444 5802 5802 I BeaconManager: successfully started foreground beacon scanning service. 06-03 11:52:38.446 5802 5802 D BeaconManager: consumer count is now: 1 06-03 11:52:38.446 5802 5802 I BeaconManager: Done with failover Verify foreground service is started and beacons are being scanned.

Note: This PR replaces #1082 with a smaller set of changes.