Only schedule one job per constraint set.
This commit is contained in:
parent
893749fcab
commit
b077c9b4f3
4 changed files with 42 additions and 28 deletions
|
@ -3,6 +3,7 @@ package org.thoughtcrime.securesms.jobmanager;
|
|||
import android.app.job.JobInfo;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
|
||||
public interface Constraint {
|
||||
|
@ -14,6 +15,15 @@ public interface Constraint {
|
|||
@RequiresApi(26)
|
||||
void applyToJobInfo(@NonNull JobInfo.Builder jobInfoBuilder);
|
||||
|
||||
/**
|
||||
* If you do something in {@link #applyToJobInfo} you should return something here.
|
||||
* <p>
|
||||
* It is sorted and concatenated with other constraints key parts to form a unique job id.
|
||||
*/
|
||||
default @Nullable String getJobSchedulerKeyPart() {
|
||||
return null;
|
||||
}
|
||||
|
||||
interface Factory<T extends Constraint> {
|
||||
T create();
|
||||
}
|
||||
|
|
|
@ -6,26 +6,23 @@ import android.app.job.JobParameters;
|
|||
import android.app.job.JobScheduler;
|
||||
import android.app.job.JobService;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.RequiresApi;
|
||||
|
||||
import com.annimon.stream.Collectors;
|
||||
import com.annimon.stream.Stream;
|
||||
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
@RequiresApi(26)
|
||||
public class JobSchedulerScheduler implements Scheduler {
|
||||
public final class JobSchedulerScheduler implements Scheduler {
|
||||
|
||||
private static final String TAG = JobSchedulerScheduler.class.getSimpleName();
|
||||
|
||||
private static final String PREF_NAME = "JobSchedulerScheduler_prefs";
|
||||
private static final String PREF_NEXT_ID = "pref_next_id";
|
||||
|
||||
private static final int MAX_ID = 20;
|
||||
private static final String TAG = Log.tag(JobSchedulerScheduler.class);
|
||||
|
||||
private final Application application;
|
||||
|
||||
|
@ -37,14 +34,23 @@ public class JobSchedulerScheduler implements Scheduler {
|
|||
@Override
|
||||
public void schedule(long delay, @NonNull List<Constraint> constraints) {
|
||||
JobScheduler jobScheduler = application.getSystemService(JobScheduler.class);
|
||||
int currentId = getCurrentId();
|
||||
|
||||
if (constraints.isEmpty() && jobScheduler.getPendingJob(currentId) != null) {
|
||||
Log.d(TAG, "Skipping JobScheduler enqueue because we have no constraints and there's already one pending.");
|
||||
String constraintNames = constraints.isEmpty() ? ""
|
||||
: Stream.of(constraints)
|
||||
.map(Constraint::getJobSchedulerKeyPart)
|
||||
.withoutNulls()
|
||||
.sorted()
|
||||
.collect(Collectors.joining("-"));
|
||||
|
||||
int jobId = constraintNames.hashCode();
|
||||
|
||||
if (jobScheduler.getPendingJob(jobId) != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
JobInfo.Builder jobInfoBuilder = new JobInfo.Builder(getAndUpdateNextId(), new ComponentName(application, SystemService.class))
|
||||
Log.i(TAG, String.format(Locale.US, "JobScheduler enqueue of %s (%d)", constraintNames, jobId));
|
||||
|
||||
JobInfo.Builder jobInfoBuilder = new JobInfo.Builder(jobId, new ComponentName(application, SystemService.class))
|
||||
.setMinimumLatency(delay)
|
||||
.setPersisted(true);
|
||||
|
||||
|
@ -55,21 +61,6 @@ public class JobSchedulerScheduler implements Scheduler {
|
|||
jobScheduler.schedule(jobInfoBuilder.build());
|
||||
}
|
||||
|
||||
private int getCurrentId() {
|
||||
SharedPreferences prefs = application.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
|
||||
return prefs.getInt(PREF_NEXT_ID, 0);
|
||||
}
|
||||
|
||||
private int getAndUpdateNextId() {
|
||||
SharedPreferences prefs = application.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
|
||||
int returnedId = prefs.getInt(PREF_NEXT_ID, 0);
|
||||
int nextId = returnedId + 1 > MAX_ID ? 0 : returnedId + 1;
|
||||
|
||||
prefs.edit().putInt(PREF_NEXT_ID, nextId).apply();
|
||||
|
||||
return returnedId;
|
||||
}
|
||||
|
||||
@RequiresApi(api = 26)
|
||||
public static class SystemService extends JobService {
|
||||
|
||||
|
@ -77,6 +68,8 @@ public class JobSchedulerScheduler implements Scheduler {
|
|||
public boolean onStartJob(JobParameters params) {
|
||||
JobManager jobManager = ApplicationDependencies.getJobManager();
|
||||
|
||||
Log.i(TAG, "Waking due to job: " + params.getJobId());
|
||||
|
||||
jobManager.addOnEmptyQueueListener(new JobManager.EmptyQueueListener() {
|
||||
@Override
|
||||
public void onQueueEmpty() {
|
||||
|
|
|
@ -33,6 +33,11 @@ public class ChargingConstraint implements Constraint {
|
|||
jobInfoBuilder.setRequiresCharging(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getJobSchedulerKeyPart() {
|
||||
return "CHARGING";
|
||||
}
|
||||
|
||||
public static final class Factory implements Constraint.Factory<ChargingConstraint> {
|
||||
|
||||
@Override
|
||||
|
|
|
@ -7,6 +7,7 @@ import android.net.ConnectivityManager;
|
|||
import android.net.NetworkInfo;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
|
||||
import org.thoughtcrime.securesms.jobmanager.Constraint;
|
||||
|
@ -37,6 +38,11 @@ public class NetworkConstraint implements Constraint {
|
|||
jobInfoBuilder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getJobSchedulerKeyPart() {
|
||||
return "NETWORK";
|
||||
}
|
||||
|
||||
public static boolean isMet(@NonNull Context context) {
|
||||
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||
NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
|
||||
|
|
Loading…
Add table
Reference in a new issue