Skip to content

Commit

Permalink
Merge pull request #645 from AltBeacon/configurable-scan-job-id
Browse files Browse the repository at this point in the history
Configurable scan job ids
  • Loading branch information
davidgyoung authored Feb 23, 2018
2 parents 027f56b + d81ab6d commit 733c351
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 9 deletions.
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
### Development

Bug Fixes:
Enhancements:
- Allow configuring job ids (#645, David G. Young)

Bug Fixes:
- Allow scans with screen off on Android 8.1 (#637, David G. Young)

### 2.12.4 / 2017-12-16
Expand Down
6 changes: 5 additions & 1 deletion src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,11 @@
/>

<service android:name=".service.ScanJob"
android:permission="android.permission.BIND_JOB_SERVICE" />
android:permission="android.permission.BIND_JOB_SERVICE" >
<meta-data android:name="immmediateScanJobId" android:value="208352939" />
<meta-data android:name="periodicScanJobId" android:value="208352940" />
</service>

</application>

</manifest>
101 changes: 97 additions & 4 deletions src/main/java/org/altbeacon/beacon/service/ScanJob.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
import android.app.job.JobService;
import android.bluetooth.le.ScanRecord;
import android.bluetooth.le.ScanResult;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageItemInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Handler;

Expand Down Expand Up @@ -35,13 +39,13 @@
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public class ScanJob extends JobService {
private static final String TAG = ScanJob.class.getSimpleName();
public static final int PERIODIC_SCAN_JOB_ID = 1;
/*
Periodic scan jobs are used in general, but they cannot be started immediately. So we have
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 IMMEDIATE_SCAN_JOB_ID = 2;
private static int sOverrideImmediateScanJobId = -1;
private static int sOverridePeriodicScanJobId = -1;

private ScanState mScanState;
private Handler mStopHandler = new Handler();
Expand All @@ -51,7 +55,7 @@ public class ScanJob extends JobService {
@Override
public boolean onStartJob(final JobParameters jobParameters) {
initialzeScanHelper();
if (jobParameters.getJobId() == IMMEDIATE_SCAN_JOB_ID) {
if (jobParameters.getJobId() == getImmediateScanJobId(this)) {
LogManager.i(TAG, "Running immediate scan job: instance is "+this);
}
else {
Expand Down Expand Up @@ -143,7 +147,7 @@ private void startPassiveScanIfNeeded() {

@Override
public boolean onStopJob(JobParameters params) {
if (params.getJobId() == PERIODIC_SCAN_JOB_ID) {
if (params.getJobId() == getPeriodicScanJobId(this)) {
LogManager.i(TAG, "onStopJob called for periodic scan " + this);
}
else {
Expand Down Expand Up @@ -220,4 +224,93 @@ private boolean startScanning() {
Beacon.setDistanceCalculator(defaultDistanceCalculator);
return restartScanning();
}

/**
* Allows configuration of the job id for the Android Job Scheduler. If not configured, this
* will default to the value in the AndroidManifest.xml
*
* WARNING: If using this library in a multi-process application, this method may not work.
* This is considered a private API and may be removed at any time.
*
* the preferred way of setting this is in the AndroidManifest.xml as so:
* <code>
* <service android:name="org.altbeacon.beacon.service.ScanJob">
* </service>
* </code>
*
* @param id identifier to give the job
*/
@SuppressWarnings("unused")
public static void setOverrideImmediateScanJobId(int id) {
sOverrideImmediateScanJobId = id;
}

/**
* Allows configuration of the job id for the Android Job Scheduler. If not configured, this
* will default to the value in the AndroidManifest.xml
*
* WARNING: If using this library in a multi-process application, this method may not work.
* This is considered a private API and may be removed at any time.
*
* the preferred way of setting this is in the AndroidManifest.xml as so:
* <code>
* <service android:name="org.altbeacon.beacon.service.ScanJob">
* <meta-data android:name="immmediateScanJobId" android:value="1001" tools:replace="android:value"/>
* <meta-data android:name="periodicScanJobId" android:value="1002" tools:replace="android:value"/>
* </service>
* </code>
*
* @param id identifier to give the job
*/
@SuppressWarnings("unused")
public static void setOverridePeriodicScanJobId(int id) {
sOverridePeriodicScanJobId = id;
}

/**
* Returns the job id to be used to schedule this job. This may be set in the
* AndroidManifest.xml or in single process applications by using #setOverrideJobId
* @param context the application context
* @return the job id
*/
public static int getImmediateScanJobId(Context context) {
if (sOverrideImmediateScanJobId >= 0) {
LogManager.i(TAG, "Using ImmediateScanJobId from static override: "+
sOverrideImmediateScanJobId);
return sOverrideImmediateScanJobId;
}
return getJobIdFromManifest(context, "immediateScanJobId");
}

/**
* Returns the job id to be used to schedule this job. This may be set in the
* AndroidManifest.xml or in single process applications by using #setOverrideJobId
* @param context the application context
* @return the job id
*/
public static int getPeriodicScanJobId(Context context) {
if (sOverrideImmediateScanJobId >= 0) {
LogManager.i(TAG, "Using PeriodicScanJobId from static override: "+
sOverridePeriodicScanJobId);
return sOverridePeriodicScanJobId;
}
return getJobIdFromManifest(context, "periodicScanJobId");
}

private static int getJobIdFromManifest(Context context, String name) {
PackageItemInfo info = null;
try {
info = context.getPackageManager().getServiceInfo(new ComponentName(context,
ScanJob.class), PackageManager.GET_META_DATA);
} catch (PackageManager.NameNotFoundException e) { /* do nothing here */ }
if (info != null && info.metaData != null && info.metaData.get(name) != null) {
int jobId = info.metaData.getInt(name);
LogManager.i(TAG, "Using "+name+" from manifest: "+jobId);
return jobId;
}
else {
throw new RuntimeException("Cannot get job id from manifest. " +
"Make sure that the "+name+" is configured in the manifest for the ScanJob.");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -153,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.IMMEDIATE_SCAN_JOB_ID, new ComponentName(context, ScanJob.class))
JobInfo immediateJob = new JobInfo.Builder(ScanJob.getImmediateScanJobId(context), new ComponentName(context, ScanJob.class))
.setPersisted(true) // This makes it restart after reboot
.setExtras(new PersistableBundle())
.setMinimumLatency(millisToNextJobStart)
Expand All @@ -168,10 +168,10 @@ private void schedule(Context context, ScanState scanState, boolean backgroundWa
}
else {
LogManager.d(TAG, "Not scheduling an immediate scan because we are in background mode. Cancelling existing immediate scan.");
jobScheduler.cancel(ScanJob.IMMEDIATE_SCAN_JOB_ID);
jobScheduler.cancel(ScanJob.getImmediateScanJobId(context));
}

JobInfo.Builder periodicJobBuilder = new JobInfo.Builder(ScanJob.PERIODIC_SCAN_JOB_ID, new ComponentName(context, ScanJob.class))
JobInfo.Builder periodicJobBuilder = new JobInfo.Builder(ScanJob.getPeriodicScanJobId(context), new ComponentName(context, ScanJob.class))
.setPersisted(true) // This makes it restart after reboot
.setExtras(new PersistableBundle());

Expand Down

0 comments on commit 733c351

Please sign in to comment.