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);
}
}
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:This causes the second monitored region to replace the first one in the code below:
To fix this, change the region setup to:
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 yourBeaconApplication
class. You can then move your code into thedidEnterRegion
anddidExitRegion
methods of theBeaconApplication
class from yourBeaconMonitoringService
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.