0
votes

I'm trying to monitor beacons on background and foreground mode, by only assigning the first ID and then getting full UUID of the beacons detected.

Using the method didEnterRegion, the second ID of the region was null so what I did was to start ranging beacons when I enter to one region to detect which is that second ID.

public class BeaconListener extends Application implements BootstrapNotifier {
private static final String TAG = "BEACON TEST";
private RegionBootstrap regionBootstrap;
private MonitoringActivity monitoringActivity = null;
private Region mRegion;
private BeaconManager beaconManager;
private String UUID;
public void onCreate() {
    super.onCreate();
    beaconManager = BeaconManager.getInstanceForApplication(this);
    beaconManager.getBeaconParsers().add(new BeaconParser().
            setBeaconLayout("s:0-1=feaa,m:2-2=00,p:3-3:-41,i:4-13,i:14-19"));
    beaconManager.setBackgroundScanPeriod(1100);
    beaconManager.setBackgroundBetweenScanPeriod(0);
    beaconManager.setAndroidLScanningDisabled(true);

    beaconManager.setBackgroundMode(true);

    mRegion = new Region("Beacon", Identifier.parse("0xffffffffffffffffffff"), null, null);

    regionBootstrap = new RegionBootstrap(this, mRegion);

}

@Override
public void didEnterRegion(Region arg0) {
    // In this example, this class sends a notification to the user whenever a Beacon
    // matching a Region (defined above) are first seen.

    try {
        beaconManager.startRangingBeaconsInRegion(mRegion);
        beaconManager.setRangeNotifier(new RangeNotifier() {
            @Override
            public void didRangeBeaconsInRegion(Collection<Beacon> beacons, Region arg0) {
                try {
                    for (Beacon beacon : beacons) {
                          beaconManager.stopRangingBeaconsInRegion(mRegion);
                          sendNotification();
                    }
                } catch (Exception e) {
                    Log.i(TAG, e.getMessage());
                }
            }
        });

        beaconManager.startRangingBeaconsInRegion(mRegion);
        beaconManager.setBackgroundScanPeriod(1100);
        beaconManager.setBackgroundBetweenScanPeriod(0);
        beaconManager.setAndroidLScanningDisabled(true);
    } catch (RemoteException e) {    }
}

This works fine, and I can get the full UUID of the beacon/s that are detected but, when I kill the app or I put it on background mode, it takes some minutes (about 5) to restart the monitoring service. Is there any way to restart the service immediately after going to background or killing the app? When I connect the device to the charger it restarts the service and quickly finds the beacons again.

PS: when I talk about first ID and second ID I asume that UUID = ID1 + ID2

2

2 Answers

0
votes

You are correct that it takes up to five minutes to restart scanning after a user kills an app using the Android Beacon Library. There is no way to configure this interval, but it can be changed in code if appropriate for your use case.

Understand that when you kill an app with the task switcher, the OS will stop all processes associated with the app, including background services like the one the library uses to scan for beacons. The library restarts this scanning service using two different techniques:

  1. By listening for power connect/disconnect events.

  2. By using an AlarmManager to restart if five minutes have passed since the last time it was active.

The second method is used both for cases where an app was killed with the task switcher and by the operating system due to a low memory condition. In the latter case, it would be inappropriate to restart immediately because a foreground app may need to evict other apps to use all system memory for some time. The Google Maps app often causes this when panning and zooming.

The five minute interval was chosen simply because it is a reasonable time interval to expect a low memory condition to clear.

While the five minute default is not configurable in the library, since it is open source, you can compile a modified version to set this to a shorter interval if you wish. The code to change is here. Understand, however, that this may negatively impact memory-hungry foreground apps.

0
votes

No delay at all to detect the beacon(s) in foreground, background, kill states.

Write code in only Application class, no need background service for monitoring beacons.

I have done this way:

/**
 * Created by Hiren Patel on 3/25/2017.
 */
public class MyApplication extends Application implements BootstrapNotifier {

    private BeaconManager iBeaconManager;
    private RegionBootstrap regionBootstrap;


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

        stopBeaconMonitoring();
        startBeaconMonitoring();

    }

    public void stopBeaconMonitoring() {
        Log.i("Application", "stopBeaconMonitoring");
        if (iBeaconManager != null) {
            iBeaconManager.removeAllMonitorNotifiers();
            iBeaconManager.removeAllRangeNotifiers();
            iBeaconManager = null;
        }
    }

    private void startBeaconMonitoring() {

        iBeaconManager = BeaconManager.getInstanceForApplication(this);
        iBeaconManager.getBeaconParsers().add(new BeaconParser().setBeaconLayout("m:0-3=4c000215,i:4-19,i:20-21,i:22-23,p:24-24"));
        iBeaconManager.setBackgroundBetweenScanPeriod(5000l);
        iBeaconManager.setBackgroundScanPeriod(1000l);
        iBeaconManager.setDebug(true);

        //Start the Services that will keep checking for beacons in the background, even if the application is closed (swiped away from the app-switcher).
        Intent startServiceIntent = new Intent(this.getApplicationContext(), BeaconService.class);
        this.getApplicationContext().startService(startServiceIntent);
        startServiceIntent = new Intent(this.getApplicationContext(), BeaconIntentProcessor.class);
        this.getApplicationContext().startService(startServiceIntent);

        List<BeaconEntity> beaconEntityList = YourBeaconListHere;
        if (beaconEntityList != null) {
            for (BeaconEntity beaconEntity : beaconEntityList) {
                Region region = new Region(beaconEntity.Name, Identifier.parse(beaconEntity.UUID), Identifier.parse(String.valueOf(beaconEntity.Major)), Identifier.parse(String.valueOf(beaconEntity.Minor)));
                regionBootstrap = new RegionBootstrap(this, region);
                Log.i("Beacons List", beaconEntity.Name + "-" + beaconEntity.UUID + "-" + String.valueOf(beaconEntity.Major) + "-" + String.valueOf(beaconEntity.Minor));
            }
        }else{
            Log.i("Beacons List", "null");
        }
    }

    @Override
    public void didEnterRegion(Region region) {
        // You entered in Region(beacon range)
        Log.i("Application", "didEnterRegion called");
    }

    @Override
    public void didExitRegion(Region region) {
        // You exited from Region(beacon range)
        Log.i("Application", "didExitRegion called");
    }

    @Override
    public void didDetermineStateForRegion(int i, Region region) {
        // Region state changed, just ignore it
        Log.i("Application", "didDetermineStateForRegion called");
    }
}

Enjoy beaconing .