AltBeacon / android-beacon-library

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

foreground Scanning Stopped after 4 minutes - background mode automatically started #1086

Closed mspapant closed 2 years ago

mspapant commented 2 years ago

Expected behavior

The beacon scanning it's supposed to work in foreground, since a foreground service has been started (foreground scanning mode)

Actual behavior

The scanning works foreground for a couple of minutes, but then is automatically switched to background mode. I see lot of log entries:

2022-05-16 22:41:13.508 23376-23974/mspapant D/BeaconParser: This is not a matching Beacon advertisement. (Was expecting 02 15.  The bytes I see are: 02011a0aff4c00100503182690f7000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
2022-05-16 22:41:13.508 23376-23974/mspapant D/BeaconParser: Ignoring pdu type 01
2022-05-16 22:41:13.508 23376-23974/mspapant D/BeaconParser: Processing pdu type FF: 02011a0aff4c00100503182690f7000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

But after 3.5 minutes scanning changed to background mode and i can see the follow logs:

2022-05-16 22:41:36.136 23376-23376/mspapant D/CycledLeScanner: Waiting to stop scan cycle for another 95 milliseconds
2022-05-16 22:41:36.140 23376-23376/mspapant D/CycledLeScanner: Set a wakeup alarm to go off in 300000 ms: PendingIntent{59e0fb1: android.os.BinderProxy@facc96}
2022-05-16 22:41:36.236 23376-23376/mspapant D/CycledLeScanner: Done with scan cycle
2022-05-16 22:41:36.236 23376-23376/mspapant D/ScanHelper: Beacon simulator not enabled
2022-05-16 22:41:36.237 23376-23376/mspapant D/ScanHelper: Calling ranging callback
2022-05-16 22:41:36.239 23376-23376/mspapant D/RunningAverageRssiFilter: Running average mRssi based on 43 measurements: -47.75757575757576
2022-05-16 22:41:36.239 23376-23376/mspapant D/RangedBeacon: calculated new runningAverageRssi: -47.75757575757576
2022-05-16 22:41:36.240 23376-23376/mspapant D/Callback: attempting callback via local broadcast intent: org.altbeacon.beacon.range_notification
2022-05-16 22:41:36.240 23376-23376/mspapant D/CycledLeScanner: Not stopping scanning.  Device capable of multiple indistinct detections per scan.
2022-05-16 22:41:36.240 23376-23376/mspapant D/CycledLeScanner: starting a new scan cycle
2022-05-16 22:41:36.240 23376-23376/mspapant D/CycledLeScanner: We are already scanning and have been for 213869 millis
2022-05-16 22:41:36.241 23376-23376/mspapant D/CycledLeScanner: Waiting to stop scan cycle for another 1100 milliseconds
2022-05-16 22:41:36.245 23376-23376/mspapant D/CycledLeScanner: Set a wakeup alarm to go off in 300000 ms: PendingIntent{59e0fb1: android.os.BinderProxy@facc96}
2022-05-16 22:41:36.245 23376-23376/mspapant D/CycledLeScanner: Scan started

Steps to reproduce this behavior

This is the code that initiate the scanning:

public class MyApplication extends MultiDexApplication implements BootstrapNotifier, BeaconConsumer {

    public static final String CHANNEL_ID = "1";
    public static final String CHANNEL_NOTIFICATION_ID = "2";

    private static BeaconManager beaconManager;
    private static LinkedList<Region> regions = new LinkedList<>();
    private static RegionBootstrap regionBootstrap;

    private Region region = new Region("wildcard", null, null, null);

    @Override
    public void onCreate() {
        super.onCreate();
        beaconManager = org.altbeacon.beacon.BeaconManager.getInstanceForApplication(this);
        beaconManager.setDebug(true);

        final Notification.Builder builder = new Notification.Builder(this);
        builder.setSmallIcon(R.drawable.ic_logo);
        builder.setContentTitle(getString(R.string.foreground_notification_title));
        builder.setContentText(getString(R.string.foreground_notification_text));
        final RouteActivity_.IntentBuilder_ intentBuilder = RouteActivity_.intent(this).flags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
        final Intent intent = intentBuilder.get();

        PendingIntent pendingIntent = PendingIntent.getActivity(
                this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT
        );
        builder.setContentIntent(pendingIntent);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(CHANNEL_ID,
                    getString(R.string.app_name) + " Scanning Channel", NotificationManager.IMPORTANCE_DEFAULT);
            channel.setDescription("Listening for beacons");
            NotificationManager notificationManager = (NotificationManager) getSystemService(
                    Context.NOTIFICATION_SERVICE);
            if (notificationManager != null) {
                notificationManager.createNotificationChannel(channel);
                builder.setChannelId(channel.getId());
            }
        }
        beaconManager.enableForegroundServiceScanning(builder.build(), 456);
        beaconManager.setForegroundScanPeriod(1000L);
        beaconManager.setForegroundBetweenScanPeriod(2000L);

        beaconManager.setEnableScheduledScanJobs(false);
        beaconManager.setBackgroundBetweenScanPeriod(0);
        beaconManager.setBackgroundScanPeriod(1100);
        BeaconManager.setRegionExitPeriod(10000000);

        try {
            beaconManager.stopRangingBeaconsInRegion(region);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public void startListening() {
        regionBootstrap = new RegionBootstrap(this, region);
        beaconManager.bind(this);
    }

    @Override
    public void didEnterRegion(Region region) {
        Log.i("My App", "didEnterRegion");
    }

    @Override
    public void didExitRegion(Region region) {
        Log.i("My App", "didExitRegion");
    }

    @Override
    public void didDetermineStateForRegion(int state, Region region) {
        Log.i("My App", "didDetermineStateForRegion");
    }

    public void stopListening() {
        if (regionBootstrap != null) {
            regionBootstrap.disable();
            regionBootstrap = null;
        }
        beaconManager.unbind(this);
        try {
            beaconManager.stopRangingBeaconsInRegion(region);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void onBeaconServiceConnect() {
        RangeNotifier rangeNotifier = (beacons, region) -> {
            if (beacons.size() > 0) {
                BeaconServiceHandler.getInstance().onEnterRegion(beacons.iterator().next(), BoikomApplication.this);
            }
        };
        try {
            beaconManager.startRangingBeaconsInRegion(region);
            beaconManager.addRangeNotifier(rangeNotifier);
        } catch (RemoteException e) {
        }
    }
}

When user opens the bluetooth i call:

startListening()

Mobile device model and OS version

Android 12 - MIUI 13

Android Beacon Library version

2.17.1

IMPORTANT: This forum is reserved for feature requests or reproducible bugs with the library itself. If you need help with using the library with your project, please open a new question on StackOverflow.com.

davidgyoung commented 2 years ago

The custom code shown in this issue is very different from the official Java reference app for this library, so helping debug a custom app is out of scope for this forum. If you can make a reproducible test case with minimal modifications to that reference app, we can re-open this issue.

Three important points:

  1. The second log snippet does not indicate that the library's "scanning changed to background mode".

  2. The MIUI operating system is a heavily modified version of Android with undocumented limits on background processing. You may be seeing a proprietary limitation on background scanning. Read more here

  3. The sample code shown uses several deprecated methods including RegionBoostrap and direct calls to bind and unbind. Using these deprecated methods add lots of complexity and subtle timing issues and are a common source of bugs. This is why they are deprecated. I would highly recommend refactoring to use these to use the new autobind APIs. Read here for more info.

Deprecated methods continue to exist in the library for backward compatibility only. While you are welcome to continue using them if needed, it will be increasingly hard to get help from others for using them as time goes on.