Skip to content

Commit

Permalink
got alarms working to wake up from sleep
Browse files Browse the repository at this point in the history
  • Loading branch information
davidgyoung committed Nov 24, 2014
1 parent a75ebb6 commit bb89a08
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 44 deletions.
18 changes: 13 additions & 5 deletions src/main/java/org/altbeacon/beacon/BeaconManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,13 @@ public boolean isBound(BeaconConsumer consumer) {
}
}

/**
* Tells you if the any beacon consumer is bound to the service
* @return
*/
public boolean isAnyConsumerBound() {
return consumers.size() > 0 && (serviceMessenger != null);
}
/**
* This method notifies the beacon service that the application is either moving to background
* mode or foreground mode. When in background mode, BluetoothLE scans to look for beacons are
Expand Down Expand Up @@ -375,7 +382,7 @@ public void setMonitorNotifier(MonitorNotifier notifier) {
* @see BeaconManager#setRangeNotifier(RangeNotifier)
* @see BeaconManager#stopRangingBeaconsInRegion(Region region)
* @see RangeNotifier
* @see Region
* @see Region
* @param region
*/
@TargetApi(18)
Expand All @@ -388,7 +395,7 @@ public void startRangingBeaconsInRegion(Region region) throws RemoteException {
throw new RemoteException("The BeaconManager is not bound to the service. Call beaconManager.bind(BeaconConsumer consumer) and wait for a callback to onBeaconServiceConnect()");
}
Message msg = Message.obtain(null, BeaconService.MSG_START_RANGING, 0, 0);
StartRMData obj = new StartRMData(region, callbackPackageName(), this.getScanPeriod(), this.getBetweenScanPeriod() );
StartRMData obj = new StartRMData(region, callbackPackageName(), this.getScanPeriod(), this.getBetweenScanPeriod(), this.mBackgroundMode );
msg.obj = obj;
serviceMessenger.send(msg);
synchronized (rangedRegions) {
Expand All @@ -415,7 +422,7 @@ public void stopRangingBeaconsInRegion(Region region) throws RemoteException {
throw new RemoteException("The BeaconManager is not bound to the service. Call beaconManager.bind(BeaconConsumer consumer) and wait for a callback to onBeaconServiceConnect()");
}
Message msg = Message.obtain(null, BeaconService.MSG_STOP_RANGING, 0, 0);
StartRMData obj = new StartRMData(region, callbackPackageName(),this.getScanPeriod(), this.getBetweenScanPeriod() );
StartRMData obj = new StartRMData(region, callbackPackageName(),this.getScanPeriod(), this.getBetweenScanPeriod(), this.mBackgroundMode );
msg.obj = obj;
serviceMessenger.send(msg);
synchronized (rangedRegions) {
Expand Down Expand Up @@ -449,7 +456,7 @@ public void startMonitoringBeaconsInRegion(Region region) throws RemoteException
throw new RemoteException("The BeaconManager is not bound to the service. Call beaconManager.bind(BeaconConsumer consumer) and wait for a callback to onBeaconServiceConnect()");
}
Message msg = Message.obtain(null, BeaconService.MSG_START_MONITORING, 0, 0);
StartRMData obj = new StartRMData(region, callbackPackageName(),this.getScanPeriod(), this.getBetweenScanPeriod() );
StartRMData obj = new StartRMData(region, callbackPackageName(),this.getScanPeriod(), this.getBetweenScanPeriod(), this.mBackgroundMode );
msg.obj = obj;
serviceMessenger.send(msg);
synchronized (monitoredRegions) {
Expand Down Expand Up @@ -477,7 +484,7 @@ public void stopMonitoringBeaconsInRegion(Region region) throws RemoteException
throw new RemoteException("The BeaconManager is not bound to the service. Call beaconManager.bind(BeaconConsumer consumer) and wait for a callback to onBeaconServiceConnect()");
}
Message msg = Message.obtain(null, BeaconService.MSG_STOP_MONITORING, 0, 0);
StartRMData obj = new StartRMData(region, callbackPackageName(),this.getScanPeriod(), this.getBetweenScanPeriod() );
StartRMData obj = new StartRMData(region, callbackPackageName(),this.getScanPeriod(), this.getBetweenScanPeriod(), this.mBackgroundMode );
msg.obj = obj;
serviceMessenger.send(msg);
synchronized (monitoredRegions) {
Expand Down Expand Up @@ -688,4 +695,5 @@ public static void setAndroidLScanningDisabled(boolean disabled) {
sAndroidLScanningDisabled = disabled;
}


}
20 changes: 7 additions & 13 deletions src/main/java/org/altbeacon/beacon/service/BeaconService.java
Original file line number Diff line number Diff line change
Expand Up @@ -144,27 +144,26 @@ public void handleMessage(Message msg) {
case MSG_START_RANGING:
Log.i(TAG, "start ranging received");
service.startRangingBeaconsInRegion(startRMData.getRegionData(), new org.altbeacon.beacon.service.Callback(startRMData.getCallbackPackageName()));
service.setScanPeriods(startRMData.getScanPeriod(), startRMData.getBetweenScanPeriod());
service.setScanPeriods(startRMData.getScanPeriod(), startRMData.getBetweenScanPeriod(), startRMData.getBackgroundFlag());
break;
case MSG_STOP_RANGING:
Log.i(TAG, "stop ranging received");
service.stopRangingBeaconsInRegion(startRMData.getRegionData());
service.setScanPeriods(startRMData.getScanPeriod(), startRMData.getBetweenScanPeriod());
service.setScanPeriods(startRMData.getScanPeriod(), startRMData.getBetweenScanPeriod(), startRMData.getBackgroundFlag());
break;
case MSG_START_MONITORING:
Log.i(TAG, "start monitoring received");
service.startMonitoringBeaconsInRegion(startRMData.getRegionData(), new org.altbeacon.beacon.service.Callback(startRMData.getCallbackPackageName()));
service.setScanPeriods(startRMData.getScanPeriod(), startRMData.getBetweenScanPeriod());
service.setScanPeriods(startRMData.getScanPeriod(), startRMData.getBetweenScanPeriod(), startRMData.getBackgroundFlag());
break;
case MSG_STOP_MONITORING:
Log.i(TAG, "stop monitoring received");
service.stopMonitoringBeaconsInRegion(startRMData.getRegionData());
service.setScanPeriods(startRMData.getScanPeriod(), startRMData.getBetweenScanPeriod());
service.setScanPeriods(startRMData.getScanPeriod(), startRMData.getBetweenScanPeriod(), startRMData.getBackgroundFlag());
break;
case MSG_SET_SCAN_PERIODS:
Log.i(TAG, "set scan intervals received");
service.setScanPeriods(startRMData.getScanPeriod(), startRMData.getBetweenScanPeriod());
service.setBackgroundFlag(startRMData.getBackgroundFlag());
service.setScanPeriods(startRMData.getScanPeriod(), startRMData.getBetweenScanPeriod(), startRMData.getBackgroundFlag());
break;
default:
super.handleMessage(msg);
Expand Down Expand Up @@ -293,13 +292,8 @@ public void stopMonitoringBeaconsInRegion(Region region) {
}
}

public void setBackgroundFlag(boolean flag) {
mBackgroundFlag = flag;
mCycledScanner.setBackgroundFlag(flag);
}

public void setScanPeriods(long scanPeriod, long betweenScanPeriod) {
mCycledScanner.setScanPeriods(scanPeriod, betweenScanPeriod);
public void setScanPeriods(long scanPeriod, long betweenScanPeriod, boolean backgroundFlag) {
mCycledScanner.setScanPeriods(scanPeriod, betweenScanPeriod, backgroundFlag);
}

private CycledLeScanCallback mCycledLeScanCallback = new CycledLeScanCallback() {
Expand Down
67 changes: 50 additions & 17 deletions src/main/java/org/altbeacon/beacon/service/CycledLeScanner.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import android.util.Log;

import org.altbeacon.beacon.BeaconManager;
import org.altbeacon.beacon.startup.StartupBroadcastReceiver;
import org.altbeacon.bluetooth.BluetoothCrashResolver;

import java.util.ArrayList;
Expand Down Expand Up @@ -76,22 +77,27 @@ public CycledLeScanner(Context context, long scanPeriod, long betweenScanPeriod,
}

/**
* Tells the cycler whether it is in operating in background mode.
* This is used only on Android 5.0 scanning implementations to go to
* LOW_POWER_MODE vs. LOW_LATENCY_MODE
* @param flag
* Tells the cycler the scan rate and whether it is in operating in background mode.
* Background mode flag is used only with the Android 5.0 scanning implementations to switch
* between LOW_POWER_MODE vs. LOW_LATENCY_MODE
* @param backgroundFlag
*/
public void setBackgroundFlag(boolean flag) {
if (mBackgroundFlag != flag) {
public void setScanPeriods(long scanPeriod, long betweenScanPeriod, boolean backgroundFlag) {
Log.d(TAG, "Set scan periods called with "+scanPeriod+", "+betweenScanPeriod+" Background mode must have changed.");
if (mBackgroundFlag != backgroundFlag) {
mRestartNeeded = true;
}
mBackgroundFlag = flag;
}

public void setScanPeriods(long scanPeriod, long betweenScanPeriod) {
Log.d(TAG, "Set scan periods called with "+scanPeriod+", "+betweenScanPeriod+" Background mode must have changed.");
mBackgroundFlag = backgroundFlag;
mScanPeriod = scanPeriod;
mBetweenScanPeriod = betweenScanPeriod;
if (mBackgroundFlag == true) {
BeaconManager.logDebug(TAG, "We are in the background. Setting wakeup alarm");
setWakeUpAlarm();
}
else {
BeaconManager.logDebug(TAG, "We are not in the background. Cancelling wakeup alarm");
cancelWakeUpAlarm();
}
long now = new Date().getTime();
if (mNextScanCycleStartTime > now) {
// We are waiting to start scanning. We may need to adjust the next start time
Expand Down Expand Up @@ -159,6 +165,9 @@ private boolean deferScanIfNeeded() {
// Don't actually wait until the next scan time -- only wait up to 1 second. this
// allows us to start scanning sooner if a consumer enters the foreground and expects
// results more quickly
if (mBackgroundFlag) {
setWakeUpAlarm();
}
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
Expand Down Expand Up @@ -274,6 +283,9 @@ private void scheduleScanCycleStop() {
long millisecondsUntilStop = mScanCycleStopTime - (new Date().getTime());
if (millisecondsUntilStop > 0) {
BeaconManager.logDebug(TAG, "Waiting to stop scan cycle for another " + millisecondsUntilStop + " milliseconds");
if (mBackgroundFlag) {
setWakeUpAlarm();
}
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
Expand Down Expand Up @@ -334,6 +346,7 @@ private void finishScanCycle() {
else {
BeaconManager.logDebug(TAG, "Scanning disabled. No ranging or monitoring regions are active.");
mScanCyclerStarted = false;
cancelWakeUpAlarm();
}
}
}
Expand Down Expand Up @@ -406,16 +419,36 @@ private BluetoothAdapter getBluetoothAdapter() {
return mBluetoothAdapter;
}

// In case we go into deep sleep, we will set up a wakeup alarm when in the background to kick

private PendingIntent mWakeUpOperation = null;
// In case we go into deep sleep, we will set up a wakeup alarm when in the background to kickofƒ
// off the scan cycle again
private void setPeriodicWakeUpAlarm() {
@TargetApi(3)
private void setWakeUpAlarm() {
// wake up time will be the maximum of 5 minutes, the scan period, the between scan period
mill
long milliseconds = 1000l*60*5; /* five minutes */
if (milliseconds < mBetweenScanPeriod) {
milliseconds = mBetweenScanPeriod;
}
if (milliseconds < mScanPeriod) {
milliseconds = mScanPeriod;
}
AlarmManager alarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent();
intent.setClassName(mContext, BeaconService.class.getName());
PendingIntent operation = PendingIntent.getBroadcast(mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, milliseconds, operation);
intent.setClassName(mContext, StartupBroadcastReceiver.class.getName());
intent.putExtra("wakeup", true);
cancelWakeUpAlarm();
mWakeUpOperation = PendingIntent.getBroadcast(mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, System.currentTimeMillis()+milliseconds, mWakeUpOperation);
BeaconManager.logDebug(TAG, "Set a wakeup alarm to go off in "+milliseconds+" ms: "+mWakeUpOperation);
}

@TargetApi(3)
private void cancelWakeUpAlarm() {
Log.d(TAG, "cancel wakeup alarm: "+mWakeUpOperation);
if (mWakeUpOperation != null) {
AlarmManager alarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
alarmManager.cancel(mWakeUpOperation);
}
}
}
4 changes: 3 additions & 1 deletion src/main/java/org/altbeacon/beacon/service/StartRMData.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,15 @@ public StartRMData(Region region, String callbackPackageName) {
public StartRMData(long scanPeriod, long betweenScanPeriod, boolean backgroundFlag) {
this.scanPeriod = scanPeriod;
this.betweenScanPeriod = betweenScanPeriod;
this.backgroundFlag = backgroundFlag;
}

public StartRMData(Region region, String callbackPackageName, long scanPeriod, long betweenScanPeriod) {
public StartRMData(Region region, String callbackPackageName, long scanPeriod, long betweenScanPeriod, boolean backgroundFlag) {
this.scanPeriod = scanPeriod;
this.betweenScanPeriod = betweenScanPeriod;
this.region = region;
this.callbackPackageName = callbackPackageName;
this.backgroundFlag = backgroundFlag;
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ public RegionBootstrap(BootstrapNotifier application, Region region) {
throw new NullPointerException("The BootstrapNotifier instance is returning null from its getApplicationContext() method. Have you implemented this method?");
}
beaconManager = BeaconManager.getInstanceForApplication(application.getApplicationContext());

this.application = application;
regions = new ArrayList<Region>();
regions.add(region);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
public class StartupBroadcastReceiver extends BroadcastReceiver
{
private static final String TAG = "StartupBroadcastReceiver";
private Context context;

@Override
public void onReceive(Context context, Intent intent) {
Expand All @@ -24,11 +23,14 @@ public void onReceive(Context context, Intent intent) {
return;
}
BeaconManager beaconManager = BeaconManager.getInstanceForApplication(context.getApplicationContext());

Intent startServiceIntent = new Intent(context, BeaconService.class);
context.startService(startServiceIntent);
startServiceIntent = new Intent(context, BeaconIntentProcessor.class);
context.startService(startServiceIntent);

if (beaconManager.isAnyConsumerBound()) {
if (intent.getBooleanExtra("wakeup", false)) {
BeaconManager.logDebug(TAG, "got wake up intent");
}
else {
BeaconManager.logDebug(TAG, "Already started. Ignoring intent: "+intent+" of type: "+intent.getStringExtra("wakeup"));
}
return;
}
}
}

0 comments on commit bb89a08

Please sign in to comment.