Add a charging constraint to the backup job.

This commit is contained in:
Greyson Parrelli 2020-09-15 13:21:14 -04:00
parent 7108fc81a9
commit 19cc43c442
7 changed files with 128 additions and 11 deletions

View file

@ -0,0 +1,43 @@
package org.thoughtcrime.securesms.jobmanager.impl;
import android.app.job.JobInfo;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import org.thoughtcrime.securesms.jobmanager.Constraint;
/**
* Job constraint for determining whether or not the device is actively charging.
*/
public class ChargingConstraint implements Constraint {
public static final String KEY = "ChargingConstraint";
private ChargingConstraint() {
}
@Override
public boolean isMet() {
return ChargingConstraintObserver.isCharging();
}
@Override
public @NonNull String getFactoryKey() {
return KEY;
}
@RequiresApi(26)
@Override
public void applyToJobInfo(@NonNull JobInfo.Builder jobInfoBuilder) {
jobInfoBuilder.setRequiresCharging(true);
}
public static final class Factory implements Constraint.Factory<ChargingConstraint> {
@Override
public ChargingConstraint create() {
return new ChargingConstraint();
}
}
}

View file

@ -0,0 +1,62 @@
package org.thoughtcrime.securesms.jobmanager.impl;
import android.app.Application;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.BatteryManager;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import org.thoughtcrime.securesms.jobmanager.ConstraintObserver;
/**
* Observes the charging state of the device and notifies the JobManager system when appropriate.
*/
public class ChargingConstraintObserver implements ConstraintObserver {
private static final String REASON = ChargingConstraintObserver.class.getSimpleName();
private static final int STATUS_BATTERY = 0;
private final Application application;
private static volatile boolean charging;
public ChargingConstraintObserver(@NonNull Application application) {
this.application = application;
}
@Override
public void register(@NonNull Notifier notifier) {
Intent intent = application.registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
boolean wasCharging = charging;
charging = isCharging(intent);
if (charging && !wasCharging) {
notifier.onConstraintMet(REASON);
}
}
}, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
charging = isCharging(intent);
}
public static boolean isCharging() {
return charging;
}
private static boolean isCharging(@Nullable Intent intent) {
if (intent == null) {
return false;
}
int status = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, STATUS_BATTERY);
return status != STATUS_BATTERY;
}
}

View file

@ -10,6 +10,8 @@ import org.thoughtcrime.securesms.jobmanager.ConstraintObserver;
import org.thoughtcrime.securesms.jobmanager.Job;
import org.thoughtcrime.securesms.jobmanager.JobMigration;
import org.thoughtcrime.securesms.jobmanager.impl.CellServiceConstraintObserver;
import org.thoughtcrime.securesms.jobmanager.impl.ChargingConstraint;
import org.thoughtcrime.securesms.jobmanager.impl.ChargingConstraintObserver;
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraint;
import org.thoughtcrime.securesms.jobmanager.impl.NetworkConstraintObserver;
import org.thoughtcrime.securesms.jobmanager.impl.NetworkOrCellServiceConstraint;
@ -158,6 +160,7 @@ public final class JobManagerFactories {
public static Map<String, Constraint.Factory> getConstraintFactories(@NonNull Application application) {
return new HashMap<String, Constraint.Factory>() {{
put(ChargingConstraint.KEY, new ChargingConstraint.Factory());
put(NetworkConstraint.KEY, new NetworkConstraint.Factory(application));
put(NetworkOrCellServiceConstraint.KEY, new NetworkOrCellServiceConstraint.Factory(application));
put(NetworkOrCellServiceConstraint.LEGACY_KEY, new NetworkOrCellServiceConstraint.Factory(application));
@ -168,6 +171,7 @@ public final class JobManagerFactories {
public static List<ConstraintObserver> getConstraintObservers(@NonNull Application application) {
return Arrays.asList(CellServiceConstraintObserver.getInstance(application),
new ChargingConstraintObserver(application),
new NetworkConstraintObserver(application),
new SqlCipherMigrationConstraintObserver(),
new WebsocketDrainedConstraintObserver());

View file

@ -13,6 +13,7 @@ import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.NoExternalStorageException;
import org.thoughtcrime.securesms.jobmanager.Data;
import org.thoughtcrime.securesms.jobmanager.Job;
import org.thoughtcrime.securesms.jobmanager.impl.ChargingConstraint;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.notifications.NotificationChannels;
import org.thoughtcrime.securesms.permissions.Permissions;
@ -36,12 +37,21 @@ public final class LocalBackupJob extends BaseJob {
public static final String TEMP_BACKUP_FILE_PREFIX = ".backup";
public static final String TEMP_BACKUP_FILE_SUFFIX = ".tmp";
public LocalBackupJob() {
this(new Job.Parameters.Builder()
.setQueue("__LOCAL_BACKUP__")
.setMaxInstances(1)
.setMaxAttempts(3)
.build());
public LocalBackupJob(boolean forceNow) {
this(buildParameters(forceNow));
}
private static @NonNull Job.Parameters buildParameters(boolean forceNow) {
Job.Parameters.Builder builder = new Job.Parameters.Builder()
.setQueue("__LOCAL_BACKUP__")
.setMaxInstances(1)
.setMaxAttempts(3);
if (!forceNow) {
builder.addConstraint(ChargingConstraint.KEY);
}
return builder.build();
}
private LocalBackupJob(@NonNull Job.Parameters parameters) {

View file

@ -153,7 +153,7 @@ public class ChatsPreferenceFragment extends ListSummaryPreferenceFragment {
.ifNecessary()
.onAllGranted(() -> {
Log.i(TAG, "Queing backup...");
ApplicationDependencies.getJobManager().add(new LocalBackupJob());
ApplicationDependencies.getJobManager().add(new LocalBackupJob(true));
})
.withPermanentDenialDialog(getString(R.string.ChatsPreferenceFragment_signal_requires_external_storage_permission_in_order_to_create_backups))
.execute();

View file

@ -24,7 +24,7 @@ public class LocalBackupListener extends PersistentAlarmManagerListener {
@Override
protected long onAlarm(Context context, long scheduledTime) {
if (TextSecurePreferences.isBackupEnabled(context)) {
ApplicationDependencies.getJobManager().add(new LocalBackupJob());
ApplicationDependencies.getJobManager().add(new LocalBackupJob(false));
}
return setNextBackupTimeToIntervalFromNow(context);

View file

@ -5,14 +5,12 @@ import android.app.ActivityManager;
import android.app.AlarmManager;
import android.app.NotificationManager;
import android.app.job.JobScheduler;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.hardware.display.DisplayManager;
import android.location.LocationManager;
import android.media.AudioManager;
import android.net.ConnectivityManager;
import android.os.Build;
import android.os.PowerManager;
import android.os.Vibrator;
import androidx.annotation.NonNull;
@ -80,7 +78,7 @@ public class ServiceUtil {
return (JobScheduler) context.getSystemService(JobScheduler.class);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP_MR1)
@RequiresApi(22)
public static @Nullable SubscriptionManager getSubscriptionManager(@NonNull Context context) {
return (SubscriptionManager) context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
}