No monitoring and no change of scan period in a service using altbeacon android library

813 views Asked by At

I'm an android-beginner and are testing out some Estimote-Beacons on Android. My project worked with the Estimote library but now I want to try the more open altbeacon-library, but I have several problems.

The function of my app should be like this: When the app is started, the BeaconApplication should start the BeaconsMonitoringService. Two regions should be monitored. If a region is entered, the service should sent an intent using the broadcast manager. With the information of the intent a checkbox should be checked/unchecked in main-activity. The Service is also started when the app was killed or the bluetooth state has changed.

The Problems are:

  • No region is detected
  • The scan periods are not set

All debug-logs are shown, except "Entered" and "Left" from onBeaconServiceConnect. Any help would be appreciated. Hopefully it's just a dumb/newbie error and it works generally. :)

Here ist my code of the BeaconApplication:

package de.mcd.presencealtbeacon;

import android.app.Application;
import android.content.Intent;

import org.altbeacon.beacon.BeaconManager;

public class BeaconApplication extends Application {

    private BeaconManager beaconManager = null;

    @Override
    public void onCreate() {
        super.onCreate();
        beaconManager = BeaconManager.getInstanceForApplication(this);
        startService(new Intent(getApplicationContext(), BeaconsMonitoringService.class));
    }

    public BeaconManager getBeaconManager() {
        if (beaconManager == null) {
            beaconManager = BeaconManager.getInstanceForApplication(this);
        }
        return beaconManager;
    }
}

Here is the code of the BeaconsMonitoringService:

package de.mcd.presencealtbeacon;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;

import org.altbeacon.beacon.BeaconConsumer;
import org.altbeacon.beacon.BeaconManager;
import org.altbeacon.beacon.Identifier;
import org.altbeacon.beacon.MonitorNotifier;
import org.altbeacon.beacon.Region;
import org.altbeacon.beacon.BeaconParser;


public class BeaconsMonitoringService  extends Service implements BeaconConsumer {
    private static final String UUID = "1234567-1234-1234-1234-123456789012";
    private static final Region Room = new Region("mcd", Identifier.parse(UUID), Identifier.fromInt(1), null);
    private static final Region Kitchen = new Region("mcd", Identifier.parse(UUID), Identifier.fromInt(2), null);
    private static final String TAG = "BEACON";
    private BeaconManager beaconManager;


    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
        Log.d(TAG, "Beacons monitoring service started");
    }

    @Override
    public void onDestroy() {
        Log.d(TAG, "Beacons monitoring service destroyed");
    }

    public void onBeaconServiceConnect(){

        beaconManager.setMonitorNotifier(new MonitorNotifier() {
            @Override
            public void didEnterRegion(Region region) {
                Log.d(TAG, "Entered");
                if (region.getId2() == Identifier.fromInt(1)) {
                    postNotification("Room", "Entered");
                    intent("1-1");
                } else {
                    postNotification("Kitchen", "Entered");
                    intent("2-1");

                }
            }

            @Override
            public void didExitRegion(Region region) {
                Log.d(TAG, "Left");
                if (region.getId2() == Identifier.fromInt(1)) {
                    postNotification("Room", "Left");
                    intent("1-2");
                } else {
                    postNotification("Kitchen", "Left");
                    intent("2-2");
                }

            }

            @Override
            public void didDetermineStateForRegion(int state, Region region) {
                Log.d(TAG, "Don't know what it's useful for" + state);
            }
        });

        try {
            Log.d(TAG, "Service ready");
            beaconManager.startMonitoringBeaconsInRegion(Room);
            beaconManager.startMonitoringBeaconsInRegion(Kitchen);
        } catch (RemoteException e) {
            Log.e(TAG, "Cannot start ranging", e);
        }
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d(TAG, "onStart Start");
        BeaconApplication app = (BeaconApplication)getApplication();
        beaconManager = app.getBeaconManager();

        beaconManager.setBackgroundScanPeriod(1100l);
        beaconManager.setBackgroundBetweenScanPeriod(10000l);

        beaconManager.getBeaconParsers ().add ( new BeaconParser ().setBeaconLayout (
                "m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24" ) );
        beaconManager.bind(this);

        Log.d(TAG, "onStart End");

        Notification noti = new Notification.Builder(this)
                .setContentTitle("Started")
                .setContentText("Here we go")
                .setSmallIcon(R.mipmap.ic_launcher)
                .build();

        NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        mNotificationManager.cancel(2);
        mNotificationManager.notify(1, noti);


        return START_STICKY;
    }


    private void postNotification(String room, String action) {
        Intent notificationIntent = new Intent(BeaconsMonitoringService.this, MyActivity.class);
        notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP
                | Intent.FLAG_ACTIVITY_SINGLE_TOP);
        PendingIntent intent = PendingIntent.getActivity(BeaconsMonitoringService.this, 0,
                notificationIntent, 0);

        Notification noti = new Notification.Builder(BeaconsMonitoringService.this)
                .setContentTitle(room)
                .setContentText(action)
                .setSmallIcon(R.mipmap.ic_launcher)
                .setContentIntent(intent)
                .build();


        NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        mNotificationManager.cancel(2);
        mNotificationManager.notify(1, noti);
    }


    private void intent (String code){
        Intent intent = new Intent("statechanged");
        intent.putExtra("info", code);
        LocalBroadcastManager.getInstance(BeaconsMonitoringService.this).sendBroadcast(intent);
    }
}
1

There are 1 answers

2
davidgyoung On BEST ANSWER

One issue is that the first parameter of the Region constructor is a unique string to identify the Region to the library. Each region must have a unique string, otherwise it will replace another region with the same identifier when you start ranging or monitoring. The code below uses the same identifier for two regions:

private static final Region Room = new Region("mcd", Identifier.parse(UUID), Identifier.fromInt(1), null);
private static final Region Kitchen = new Region("mcd", Identifier.parse(UUID), Identifier.fromInt(2), null);

This causes the second monitored region to replace the first one in the code below:

beaconManager.startMonitoringBeaconsInRegion(Room);
beaconManager.startMonitoringBeaconsInRegion(Kitchen);

To fix this, change the region setup to:

private static final Region Room = new Region("mcd1", Identifier.parse(UUID), Identifier.fromInt(1), null);
private static final Region Kitchen = new Region("mcd2", Identifier.parse(UUID), Identifier.fromInt(2), null);

On a more fundamental level, building a background service that starts up automatically in the background is a pretty advanced task to tackle for a self-described beginner. There are probably many other issues that aren't obvious looking at the code. The Android Beacon Library is already designed to start up automatically in the background and scan for beacons with scan intervals that change appropriately as the app changes from the foreground to the background.

You can see a simple example of this in the Application class in the reference app here.

I would recommend that instead of using your BeaconMoinitoringService you copy the code from the reference app's Application class into your BeaconApplication class. You can then move your code into the didEnterRegion and didExitRegion methods of the BeaconApplication class from your BeaconMonitoringService class.

If you'd prefer approach with a custom service, I'm sure it is possible, but it is probably a bit of an uphill climb.