Search code examples
androidibeacon-androidaltbeaconbeacon

BootstrapNotifier callbacks in loop


I've a problem with the beacon detection.

Sometimes the app is in loop through the BootstrapNotifier callbacks (didDetermineStateForRegion(int arg0, Region arg1), didEnterRegion(Region arg0) and didExitRegion(Region arg0)).

Sometimes occurs when I start the app, other times is when the app is in background... I haven't found any pattern, so by this reason I've no idea of where can be the problem.

The loop is like this (there's only a piece of the log):

D/MyApplication: Got a didDetermineStateForRegion call: 2f234454-cf6d-4a0f-adf2-f4911ba9ffa6
D/MyApplication: Got a didEnterRegion call: 2f234454-cf6d-4a0f-adf2-f4911ba9ffa6
D/MyApplication: Got a didDetermineStateForRegion call: 2f234454-cf6d-4a0f-adf2-f4911ba9ffa6
D/MyApplication: Got a didExitRegion call: null
D/MyApplication: Got a didDetermineStateForRegion call: 2f234454-cf6d-4a0f-adf2-f4911ba9ffa6
D/MyApplication: Got a didEnterRegion call: 2f234454-cf6d-4a0f-adf2-f4911ba9ffa6
D/MyApplication: Got a didDetermineStateForRegion call: 2f234454-cf6d-4a0f-adf2-f4911ba9ffa6
D/MyApplication: Got a didExitRegion call: null
D/MyApplication: Got a didDetermineStateForRegion call: 2f234454-cf6d-4a0f-adf2-f4911ba9ffa6
D/MyApplication: Got a didEnterRegion call: 2f234454-cf6d-4a0f-adf2-f4911ba9ffa6
D/MyApplication: Got a didDetermineStateForRegion call: 2f234454-cf6d-4a0f-adf2-f4911ba9ffa6
D/MyApplication: Got a didExitRegion call: null
D/MyApplication: Got a didDetermineStateForRegion call: 2f234454-cf6d-4a0f-adf2-f4911ba9ffa6
D/MyApplication: Got a didEnterRegion call: 2f234454-cf6d-4a0f-adf2-f4911ba9ffa6
D/MyApplication: Got a didDetermineStateForRegion call: 2f234454-cf6d-4a0f-adf2-f4911ba9ffa6
D/MyApplication: Got a didExitRegion call: null
D/MyApplication: Got a didDetermineStateForRegion call: 2f234454-cf6d-4a0f-adf2-f4911ba9ffa6
D/MyApplication: Got a didEnterRegion call: 2f234454-cf6d-4a0f-adf2-f4911ba9ffa6
D/MyApplication: Got a didDetermineStateForRegion call: 2f234454-cf6d-4a0f-adf2-f4911ba9ffa6
D/MyApplication: Got a didExitRegion call: null
D/MyApplication: Got a didDetermineStateForRegion call: 2f234454-cf6d-4a0f-adf2-f4911ba9ffa6
D/MyApplication: Got a didEnterRegion call: 2f234454-cf6d-4a0f-adf2-f4911ba9ffa6

Why it occurs? The app detects the region, but doesn't start the beacon scan inmediately. After a minute more or less with this loop the scans normally begins (but not always).

To test the app, I'm using this beacon software simulator as a transmitter (https://github.com/WebBluetoothCG/ble-test-peripheral-android)

-------------- UPDATED ------------

My code:

public class BeaconApplication extends Application implements BootstrapNotifier, BeaconConsumer {

    private String TAG = "MyApplication";
    private BeaconManager beaconManager;
    private Region region;


    @Override
    public void onCreate() {
        super.onCreate();
        startBeaconScan();
    }

    public void startBeaconScan() {

        Log.d(TAG, "App started up");

        beaconManager = BeaconManager.getInstanceForApplication(this);
        beaconManager.getBeaconParsers().add(new BeaconParser().
        setBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24,d:25-25"));  //iBeacon layout

        beaconManager.setRegionStatePeristenceEnabled(false);
        beaconManager.bind(this);

        region = new Region("myMonitoringUniqueId", Identifier.parse("2f234454-cf6d-4a0f-adf2-f4911ba9ffa6"), null, null);
        new RegionBootstrap(this, region);
    }

    @Override
    public void didDetermineStateForRegion(int arg0, Region arg1) {
        beaconManager.addRangeNotifier(new RangeNotifier() {
            @Override
            public void didRangeBeaconsInRegion(Collection<Beacon> beacons, Region region) {
               //CODE FOR BEACON DETECTION    
            }
        });

        try {
            beaconManager.startRangingBeaconsInRegion(region);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
        Log.d(TAG, "Got a didDetermineStateForRegion call: " + arg1.getId1());
    }

    @Override
    public void didEnterRegion(Region arg0) {
        Log.d(TAG, "Got a didEnterRegion call: " + arg0.getId1());
    }

    @Override
    public void didExitRegion(Region arg0) {
        Log.d(TAG, "Got a didExitRegion call: " + arg0.getBluetoothAddress());
    }

    @Override
    public void onBeaconServiceConnect() {
        try {
            beaconManager.setBackgroundBetweenScanPeriod(500);
            beaconManager.setBackgroundScanPeriod(500);
            beaconManager.setForegroundBetweenScanPeriod(500);
            beaconManager.setForegroundScanPeriod(500);
            beaconManager.updateScanPeriods();
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }
}

I have tried with "beaconManager.startRangingBeaconsInRegion(region);" inside of "onBeaconServiceConnect()" callback, but seems that it does not produce any difference.


Solution

  • Two things may be causing this:

    • Setting such short scan periods can be problematic unless you are positive that the beacon you are testing with is transmitting at 10Hz or more. This is because 500ms is not much time to detect a packet, and the radio is off for some time when you cycle between scanning on and off. I would make the scan period longer (at least 1100ms) to see if the problem goes away.

    • A bug was introduced in library version 2.10 which can cause region exits in the background. I doubt it would solve the problem with such short scan periods. Try targeting library version 2.9, or you can use the instructions to try 2.11-beta1.

    Some other tips:

    • There is no reason to call bind() when using RegionBootstrap, and it can cause problems with background mode switching if you do. You can put your customized scan period code next to where you set your BeaconParser, and then simply take out the call to updateScanPeriods() as it is only needed if you change scan periods after scanning starts.

    • Background scanning periods are not used unless you activate the BackgroundPowerSaver class or programmatically change the background mode of the beaconManager. Unless you do one of these things, foreground scan periods will always be used.