Skip to content

Commit

Permalink
Merge pull request #607 from hashbrown/reschedule-job-in-foreground
Browse files Browse the repository at this point in the history
Continuous Scanning While in Foreground on Android 8
  • Loading branch information
davidgyoung authored Oct 17, 2017
2 parents 7ae5dd1 + 20f7b45 commit 6c3c9e0
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 14 deletions.
35 changes: 25 additions & 10 deletions src/main/java/org/altbeacon/beacon/service/ScanJob.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,9 @@
import android.bluetooth.le.ScanResult;
import android.os.Build;
import android.os.Handler;
import android.support.annotation.NonNull;

import org.altbeacon.beacon.Beacon;
import org.altbeacon.beacon.BeaconManager;
import org.altbeacon.beacon.BeaconLocalBroadcastProcessor;
import org.altbeacon.beacon.BuildConfig;
import org.altbeacon.beacon.Region;
import org.altbeacon.beacon.distance.ModelSpecificDistanceCalculator;
Expand Down Expand Up @@ -43,7 +41,7 @@ public class ScanJob extends JobService {
a second immediate scan job to kick off when scanning gets started or settings changed.
Once the periodic one gets run, the immediate is cancelled.
*/
public static final int IMMMEDIATE_SCAN_JOB_ID = 2;
public static final int IMMEDIATE_SCAN_JOB_ID = 2;

private ScanState mScanState;
private Handler mStopHandler = new Handler();
Expand All @@ -53,8 +51,8 @@ public class ScanJob extends JobService {
@Override
public boolean onStartJob(final JobParameters jobParameters) {
mScanHelper = new ScanHelper(this);
if (jobParameters.getJobId() == IMMMEDIATE_SCAN_JOB_ID) {
LogManager.i(TAG, "Running immdiate scan job: instance is "+this);
if (jobParameters.getJobId() == IMMEDIATE_SCAN_JOB_ID) {
LogManager.i(TAG, "Running immediate scan job: instance is "+this);
}
else {
LogManager.i(TAG, "Running periodic scan job: instance is "+this);
Expand Down Expand Up @@ -85,13 +83,19 @@ public boolean onStartJob(final JobParameters jobParameters) {
mStopHandler.postDelayed(new Runnable() {
@Override
public void run() {
LogManager.i(TAG, "Scan job runtime expired");
LogManager.i(TAG, "Scan job runtime expired: " + ScanJob.this);
stopScanning();
mScanState.save();
ScanJob.this.jobFinished(jobParameters , false);

startPassiveScanIfNeeded();
// need to execute this after the current block or Android stops this job prematurely
mStopHandler.post(new Runnable() {
@Override
public void run() {
scheduleNextScan();
}
});

ScanJob.this.jobFinished(jobParameters , false);
}
}, mScanState.getScanJobRuntimeMillis());
}
Expand All @@ -102,6 +106,16 @@ public void run() {
return true;
}

private void scheduleNextScan(){
if(!mScanState.getBackgroundMode()){
// immediately reschedule scan if running in foreground
LogManager.d(TAG, "In foreground mode, schedule next scan");
ScanJobScheduler.getInstance().forceScheduleNextScan(ScanJob.this);
} else {
startPassiveScanIfNeeded();
}
}

private void startPassiveScanIfNeeded() {
LogManager.d(TAG, "Checking to see if we need to start a passive scan");
boolean insideAnyRegion = false;
Expand Down Expand Up @@ -130,15 +144,16 @@ private void startPassiveScanIfNeeded() {
@Override
public boolean onStopJob(JobParameters params) {
if (params.getJobId() == PERIODIC_SCAN_JOB_ID) {
LogManager.i(TAG, "onStopJob called for periodic scan");
LogManager.i(TAG, "onStopJob called for periodic scan " + this);
}
else {
LogManager.i(TAG, "onStopJob called for immediate scan");
LogManager.i(TAG, "onStopJob called for immediate scan " + this);
}
// Cancel the stop timer. The OS is stopping prematurely
mStopHandler.removeCallbacksAndMessages(null);
stopScanning();
startPassiveScanIfNeeded();

return false;
}

Expand Down
16 changes: 12 additions & 4 deletions src/main/java/org/altbeacon/beacon/service/ScanJobScheduler.java
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,11 @@ public void scheduleAfterBackgroundWakeup(Context context, List<ScanResult> scan
schedule(context, scanState, true);
}

public void forceScheduleNextScan(Context context) {
ScanState scanState = ScanState.restore(context);
schedule(context, scanState, false);
}

private void schedule(Context context, ScanState scanState, boolean backgroundWakeup) {
ensureNotificationProcessorSetup(context);

Expand Down Expand Up @@ -148,7 +153,7 @@ private void schedule(Context context, ScanState scanState, boolean backgroundWa
// If the next time we want to scan is less than 50ms from the periodic scan cycle, then]
// we schedule it for that specific time.
LogManager.d(TAG, "Scheduling immediate ScanJob to run in "+millisToNextJobStart+" millis");
JobInfo immediateJob = new JobInfo.Builder(ScanJob.IMMMEDIATE_SCAN_JOB_ID, new ComponentName(context, ScanJob.class))
JobInfo immediateJob = new JobInfo.Builder(ScanJob.IMMEDIATE_SCAN_JOB_ID, new ComponentName(context, ScanJob.class))
.setPersisted(true) // This makes it restart after reboot
.setExtras(new PersistableBundle())
.setMinimumLatency(millisToNextJobStart)
Expand All @@ -157,11 +162,13 @@ private void schedule(Context context, ScanState scanState, boolean backgroundWa
if (error < 0) {
LogManager.e(TAG, "Failed to schedule scan job. Beacons will not be detected. Error: "+error);
}
} else {
LogManager.d(TAG, "Not scheduling immediate scan, assuming periodic is about to run");
}
}
else {
LogManager.d(TAG, "Not scheduling an immediate scan because we are in background mode. Cancelling existing immediate scan.");
jobScheduler.cancel(ScanJob.IMMMEDIATE_SCAN_JOB_ID);
jobScheduler.cancel(ScanJob.IMMEDIATE_SCAN_JOB_ID);
}

JobInfo.Builder periodicJobBuilder = new JobInfo.Builder(ScanJob.PERIODIC_SCAN_JOB_ID, new ComponentName(context, ScanJob.class))
Expand Down Expand Up @@ -227,8 +234,9 @@ private void schedule(Context context, ScanState scanState, boolean backgroundWa
06-08 07:44:22.431 6455-6455/org.altbeacon.beaconreference I/ScanJob: Running periodic scan job: instance is org.altbeacon.beacon.service.ScanJob@4d2e9e6
*/

LogManager.d(TAG, "Scheduling ScanJob to run every "+scanState.getScanJobIntervalMillis()+" millis");
int error = jobScheduler.schedule(periodicJobBuilder.build());
final JobInfo jobInfo = periodicJobBuilder.build();
LogManager.d(TAG, "Scheduling ScanJob " + jobInfo + " to run every "+scanState.getScanJobIntervalMillis()+" millis");
int error = jobScheduler.schedule(jobInfo);
if (error < 0) {
LogManager.e(TAG, "Failed to schedule scan job. Beacons will not be detected. Error: "+error);
}
Expand Down

0 comments on commit 6c3c9e0

Please sign in to comment.