This method should be called when the user presses the buttons to set a new backup schedule with the given parameters. */
+ private void applyNewBackupScheduleSetting(BackupFrequencyV1 frequency, int hour, int minute) {
+ Log.i(TAG, "Setting backup schedule: " + frequency.name() + " at" + hour + "h" + minute + "m");
+ SignalStore.settings().setBackupSchedule(frequency, hour, minute);
+ if (frequency == BackupFrequencyV1.NEVER) {
+ LocalBackupListener.unschedule(requireContext());
+ } else {
+ // Schedule the next backup using the newly set frequency, but relative to the time of the
+ // last backup. This should only kick off a new backup to be created immediately if the
+ // last backup was long enough ago (or doesn't exist at all).
+ long lastBackupTime = 0;
+ try {
+ lastBackupTime = Optional.ofNullable(BackupUtil.getLatestBackup())
+ .map(BackupUtil.BackupInfo::getTimestamp)
+ .orElse(0L);
+ } catch (NoExternalStorageException ignored) {}
+ TextSecurePreferences.setNextBackupTime(requireContext(), lastBackupTime + frequency.getDays() * 24 * 60 * 60 * 1000L);
+ LocalBackupListener.schedule(requireContext());
+ }
+ }
+
private void onCreateClickedLegacy() {
Permissions.with(this)
.request(Manifest.permission.WRITE_EXTERNAL_STORAGE)
@@ -304,6 +346,10 @@ private void updateTimeLabel() {
timeLabel.setText(JavaTimeExtensionsKt.formatHours(time, requireContext()));
}
+ private void updateDateLabel() {
+ frequencyLabel.setText(getResources().getString(SignalStore.settings().getBackupFrequency().getResourceId()));
+ }
+
private void updateToggle() {
boolean userUnregistered = TextSecurePreferences.isUnauthorizedReceived(AppDependencies.getApplication()) || !SignalStore.account().isRegistered();
boolean clientDeprecated = SignalStore.misc().isClientDeprecated();
@@ -317,8 +363,10 @@ private void setBackupsEnabled() {
create.setVisibility(View.VISIBLE);
verify.setVisibility(View.VISIBLE);
timer.setVisibility(View.VISIBLE);
+ frequencyView.setVisibility(View.VISIBLE);
updateToggle();
updateTimeLabel();
+ updateDateLabel();
setBackupFolderName();
}
@@ -328,6 +376,7 @@ private void setBackupsDisabled() {
folder.setVisibility(View.GONE);
verify.setVisibility(View.GONE);
timer.setVisibility(View.GONE);
+ frequencyView.setVisibility(View.GONE);
updateToggle();
AppDependencies.getJobManager().cancelAllInQueue(LocalBackupJob.QUEUE);
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/LocalBackupListener.java b/app/src/main/java/org/thoughtcrime/securesms/service/LocalBackupListener.java
index f7888530fbd..cbec6839ae6 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/service/LocalBackupListener.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/service/LocalBackupListener.java
@@ -7,6 +7,7 @@
import org.thoughtcrime.securesms.jobs.LocalBackupJob;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
+import org.thoughtcrime.securesms.preferences.BackupFrequencyV1;
import org.thoughtcrime.securesms.util.JavaTimeExtensionsKt;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
@@ -30,7 +31,7 @@ protected long getNextScheduledExecutionTime(Context context) {
@Override
protected long onAlarm(Context context, long scheduledTime) {
- if (SignalStore.settings().isBackupEnabled()) {
+ if (SignalStore.settings().isBackupEnabled() && SignalStore.settings().getBackupFrequency() != BackupFrequencyV1.NEVER) {
LocalBackupJob.enqueue(false);
}
@@ -38,17 +39,31 @@ protected long onAlarm(Context context, long scheduledTime) {
}
public static void schedule(Context context) {
- if (SignalStore.settings().isBackupEnabled()) {
+ if (SignalStore.settings().isBackupEnabled() && SignalStore.settings().getBackupFrequency() != BackupFrequencyV1.NEVER) {
new LocalBackupListener().onReceive(context, getScheduleIntent());
}
}
+ /** Cancels any future backup scheduled with AlarmManager and attempts to cancel any ongoing backup job. */
+ public static void unschedule(Context context) {
+ new LocalBackupListener().cancel(context);
+ LocalBackupJob.cancelRunningJobs();
+ }
+
public static long setNextBackupTimeToIntervalFromNow(@NonNull Context context) {
- LocalDateTime now = LocalDateTime.now();
- int hour = SignalStore.settings().getBackupHour();
- int minute = SignalStore.settings().getBackupMinute();
- LocalDateTime next = MessageBackupListener.getNextDailyBackupTimeFromNowWithJitter(now, hour, minute, BACKUP_JITTER_WINDOW_SECONDS, new Random());
+ BackupFrequencyV1 freq = SignalStore.settings().getBackupFrequency();
+
+ if (freq == BackupFrequencyV1.NEVER) {
+ TextSecurePreferences.setNextBackupTime(context, -1);
+ return -1;
+ }
+
+ LocalDateTime now = LocalDateTime.now();
+ int hour = SignalStore.settings().getBackupHour();
+ int minute = SignalStore.settings().getBackupMinute();
+ LocalDateTime next = MessageBackupListener.getNextDailyBackupTimeFromNowWithJitter(now, hour, minute, BACKUP_JITTER_WINDOW_SECONDS, new Random());
+ next = next.plusDays(freq.getDays());
long nextTime = JavaTimeExtensionsKt.toMillis(next);
TextSecurePreferences.setNextBackupTime(context, nextTime);
diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/PersistentAlarmManagerListener.java b/app/src/main/java/org/thoughtcrime/securesms/service/PersistentAlarmManagerListener.java
index c430089a382..09993cbbd02 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/service/PersistentAlarmManagerListener.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/service/PersistentAlarmManagerListener.java
@@ -28,6 +28,15 @@ public abstract class PersistentAlarmManagerListener extends BroadcastReceiver {
protected abstract long onAlarm(Context context, long scheduledTime);
+ public void cancel(Context context) {
+ AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+ Intent alarmIntent = new Intent(context, getClass());
+ PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, alarmIntent, PendingIntentFlags.immutable());
+
+ info("Cancelling alarm");
+ alarmManager.cancel(pendingIntent);
+ }
+
@Override
public void onReceive(Context context, Intent intent) {
info(String.format("onReceive(%s)", intent.getAction()));
@@ -47,6 +56,7 @@ public void onReceive(Context context, Intent intent) {
return;
}
+ // If we've already scheduled this alarm, cancel it so we can schedule it again with the new time.
alarmManager.cancel(pendingIntent);
if (shouldScheduleExact()) {
diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/TextSecurePreferences.java b/app/src/main/java/org/thoughtcrime/securesms/util/TextSecurePreferences.java
index be120e23fe2..c8893ebdb5a 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/util/TextSecurePreferences.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/util/TextSecurePreferences.java
@@ -107,7 +107,7 @@ public class TextSecurePreferences {
public static final String BACKUP_ENABLED = "pref_backup_enabled";
private static final String BACKUP_PASSPHRASE = "pref_backup_passphrase";
private static final String ENCRYPTED_BACKUP_PASSPHRASE = "pref_encrypted_backup_passphrase";
- private static final String BACKUP_TIME = "pref_backup_next_time";
+ private static final String BACKUP_TIME = "pref_backup_next_time"; // milliseconds since 1970
@Deprecated
public static final String REGISTRATION_LOCK_PREF_V1 = "pref_registration_lock";
diff --git a/app/src/main/res/layout/fragment_backups.xml b/app/src/main/res/layout/fragment_backups.xml
index 62f2ca53e2c..63f8786912c 100644
--- a/app/src/main/res/layout/fragment_backups.xml
+++ b/app/src/main/res/layout/fragment_backups.xml
@@ -158,6 +158,36 @@
tools:text="3:00" />
+