rudimentary support for JobScheduler to run updates

The new JobScheduler API can opportunitistically run a job based on whether
there is good internet, connected to power, etc.  This is very useful for
running updates.  Ideally, updates would always happen in the background
while on unmetered internet and connected to power.

#588
This commit is contained in:
Hans-Christoph Steiner 2018-04-18 22:34:13 +02:00
parent e36d7719b3
commit 9e0de9ac69
3 changed files with 79 additions and 15 deletions

View File

@ -258,6 +258,10 @@
</receiver>
<service android:name=".UpdateService"/>
<service
android:name=".UpdateJobService"
android:exported="false"
android:permission="android.permission.BIND_JOB_SERVICE"/>
<service
android:name=".net.DownloaderService"
android:exported="false"/>

View File

@ -0,0 +1,43 @@
package org.fdroid.fdroid;
import android.annotation.TargetApi;
import android.app.job.JobParameters;
import android.app.job.JobService;
import android.content.Intent;
/**
* Interface between the new {@link android.app.job.JobScheduler} API and
* our old {@link UpdateService}, which is based on {@link android.app.IntentService}.
* This does not do things the way it should, e.g. stopping the job on
* {@link #onStopJob(JobParameters)} and properly reporting
* {@link #jobFinished(JobParameters, boolean)}, but this at least provides
* the nice early triggering when there is good power/wifi available.
*
* @see <a href="https://developer.android.com/about/versions/android-5.0.html#Power">Project Volta: Scheduling jobs</a>
*/
@TargetApi(21)
public class UpdateJobService extends JobService {
@Override
public boolean onStartJob(final JobParameters params) {
new Thread() {
@Override
public void run() {
// faking the actually run time
try {
startService(new Intent(UpdateJobService.this, UpdateService.class));
Thread.sleep(2000);
} catch (InterruptedException e) {
// ignored
} finally {
jobFinished(params, false);
}
}
}.start();
return true;
}
@Override
public boolean onStopJob(JobParameters params) {
return false;
}
}

View File

@ -22,7 +22,10 @@ import android.app.AlarmManager;
import android.app.IntentService;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.job.JobInfo;
import android.app.job.JobScheduler;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@ -118,27 +121,41 @@ public class UpdateService extends IntentService {
}
/**
* Schedule or cancel this service to update the app index, according to the
* current preferences. Should be called a) at boot, b) if the preference
* is changed, or c) on startup, in case we get upgraded.
* Schedule this service to update the app index while canceling any previously
* scheduled updates, according to the current preferences. Should be called
* a) at boot, b) if the preference is changed, or c) on startup, in case we get
* upgraded. It works differently on {@code android-21} and newer, versus older,
* due to the {@link JobScheduler} API handling it very nicely for us.
*
* @see <a href="https://developer.android.com/about/versions/android-5.0.html#Power">Project Volta: Scheduling jobs</a>
*/
public static void schedule(Context ctx) {
public static void schedule(Context context) {
int interval = Preferences.get().getUpdateInterval();
Intent intent = new Intent(ctx, UpdateService.class);
PendingIntent pending = PendingIntent.getService(ctx, 0, intent, 0);
if (Build.VERSION.SDK_INT < 21) {
Intent intent = new Intent(context, UpdateService.class);
PendingIntent pending = PendingIntent.getService(context, 0, intent, 0);
AlarmManager alarm = (AlarmManager) ctx
.getSystemService(Context.ALARM_SERVICE);
alarm.cancel(pending);
if (interval > 0) {
alarm.setInexactRepeating(AlarmManager.ELAPSED_REALTIME,
SystemClock.elapsedRealtime() + 5000, interval, pending);
Utils.debugLog(TAG, "Update scheduler alarm set");
AlarmManager alarm = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarm.cancel(pending);
if (interval > 0) {
alarm.setInexactRepeating(AlarmManager.ELAPSED_REALTIME,
SystemClock.elapsedRealtime() + 5000, interval, pending);
Utils.debugLog(TAG, "Update scheduler alarm set");
} else {
Utils.debugLog(TAG, "Update scheduler alarm not set");
}
} else {
Utils.debugLog(TAG, "Update scheduler alarm not set");
Utils.debugLog(TAG, "Using android-21 JobScheduler for updates");
JobScheduler jobScheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
jobScheduler.cancelAll();
ComponentName componentName = new ComponentName(context, UpdateJobService.class);
JobInfo task = new JobInfo.Builder(0xfedcba, componentName)
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED)
.setOverrideDeadline(interval)
.build();
jobScheduler.schedule(task);
}
}
/**