From 20f7b450841d38013f9b37da021bc3817d955ed9 Mon Sep 17 00:00:00 2001 From: Brad Armstrong Date: Thu, 12 Oct 2017 19:07:06 -0500 Subject: [PATCH] When the library is in foreground mode, and the job expires, immediately schedule the next job. This should give virtually constant scanning when in the foreground, matching behavior of using the BeaconService before Android O. --- .../org/altbeacon/beacon/service/ScanJob.java | 35 +++++++++++++------ .../beacon/service/ScanJobScheduler.java | 16 ++++++--- 2 files changed, 37 insertions(+), 14 deletions(-) diff --git a/src/main/java/org/altbeacon/beacon/service/ScanJob.java b/src/main/java/org/altbeacon/beacon/service/ScanJob.java index f97770bc8..fcd01e4fb 100644 --- a/src/main/java/org/altbeacon/beacon/service/ScanJob.java +++ b/src/main/java/org/altbeacon/beacon/service/ScanJob.java @@ -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; @@ -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(); @@ -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); @@ -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()); } @@ -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; @@ -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; } diff --git a/src/main/java/org/altbeacon/beacon/service/ScanJobScheduler.java b/src/main/java/org/altbeacon/beacon/service/ScanJobScheduler.java index 43ed2699b..136a44278 100644 --- a/src/main/java/org/altbeacon/beacon/service/ScanJobScheduler.java +++ b/src/main/java/org/altbeacon/beacon/service/ScanJobScheduler.java @@ -113,6 +113,11 @@ public void scheduleAfterBackgroundWakeup(Context context, List 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); @@ -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) @@ -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)) @@ -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); }