diff --git a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/SettingsValues.java b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/SettingsValues.java
index d51d7848c..75ca2f7e8 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/SettingsValues.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/SettingsValues.java
@@ -50,6 +50,8 @@ public final class SettingsValues extends SignalStoreValues {
public static final String PREFER_SYSTEM_EMOJI = "settings.use.system.emoji";
public static final String ENTER_KEY_SENDS = "settings.enter.key.sends";
public static final String BACKUPS_ENABLED = "settings.backups.enabled";
+ public static final String BACKUPS_SCHEDULE_HOUR = "settings.backups.schedule.hour";
+ public static final String BACKUPS_SCHEDULE_MINUTE = "settings.backups.schedule.minute";
public static final String SMS_DELIVERY_REPORTS_ENABLED = "settings.sms.delivery.reports.enabled";
public static final String WIFI_CALLING_COMPATIBILITY_MODE_ENABLED = "settings.wifi.calling.compatibility.mode.enabled";
public static final String MESSAGE_NOTIFICATIONS_ENABLED = "settings.message.notifications.enabled";
@@ -263,6 +265,19 @@ public final class SettingsValues extends SignalStoreValues {
putBoolean(BACKUPS_ENABLED, backupEnabled);
}
+ public int getBackupHour() {
+ return getInteger(BACKUPS_SCHEDULE_HOUR, 2);
+ }
+
+ public int getBackupMinute() {
+ return getInteger(BACKUPS_SCHEDULE_MINUTE, 0);
+ }
+
+ public void setBackupSchedule(int hour, int minute) {
+ putInteger(BACKUPS_SCHEDULE_HOUR, hour);
+ putInteger(BACKUPS_SCHEDULE_MINUTE, minute);
+ }
+
public boolean isSmsDeliveryReportsEnabled() {
return getBoolean(SMS_DELIVERY_REPORTS_ENABLED, TextSecurePreferences.isSmsDeliveryReportsEnabled(ApplicationDependencies.getApplication()));
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/preferences/BackupsPreferenceFragment.java b/app/src/main/java/org/thoughtcrime/securesms/preferences/BackupsPreferenceFragment.java
index 03bc49575..55528e040 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/preferences/BackupsPreferenceFragment.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/preferences/BackupsPreferenceFragment.java
@@ -2,11 +2,14 @@ package org.thoughtcrime.securesms.preferences;
import android.Manifest;
import android.app.Activity;
+import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
+import android.text.format.DateFormat;
import android.text.method.LinkMovementMethod;
+import android.util.TimeUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -19,6 +22,9 @@ import androidx.annotation.RequiresApi;
import androidx.core.text.HtmlCompat;
import androidx.fragment.app.Fragment;
+import com.google.android.material.timepicker.MaterialTimePicker;
+import com.google.android.material.timepicker.TimeFormat;
+
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
@@ -32,10 +38,14 @@ import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.jobs.LocalBackupJob;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.permissions.Permissions;
+import org.thoughtcrime.securesms.service.LocalBackupListener;
import org.thoughtcrime.securesms.util.BackupUtil;
+import org.thoughtcrime.securesms.util.JavaTimeExtensionsKt;
import org.thoughtcrime.securesms.util.StorageUtil;
+import org.thoughtcrime.securesms.util.TextSecurePreferences;
import java.text.NumberFormat;
+import java.time.LocalTime;
import java.util.Locale;
import java.util.Objects;
@@ -48,6 +58,8 @@ public class BackupsPreferenceFragment extends Fragment {
private View create;
private View folder;
private View verify;
+ private View timer;
+ private TextView timeLabel;
private TextView toggle;
private TextView info;
private TextView summary;
@@ -67,6 +79,8 @@ public class BackupsPreferenceFragment extends Fragment {
create = view.findViewById(R.id.fragment_backup_create);
folder = view.findViewById(R.id.fragment_backup_folder);
verify = view.findViewById(R.id.fragment_backup_verify);
+ timer = view.findViewById(R.id.fragment_backup_time);
+ timeLabel = view.findViewById(R.id.fragment_backup_time_value);
toggle = view.findViewById(R.id.fragment_backup_toggle);
info = view.findViewById(R.id.fragment_backup_info);
summary = view.findViewById(R.id.fragment_backup_create_summary);
@@ -77,6 +91,7 @@ public class BackupsPreferenceFragment extends Fragment {
toggle.setOnClickListener(unused -> onToggleClicked());
create.setOnClickListener(unused -> onCreateClicked());
verify.setOnClickListener(unused -> BackupDialog.showVerifyBackupPassphraseDialog(requireContext()));
+ timer.setOnClickListener(unused -> pickTime());
formatter.setMinimumFractionDigits(1);
formatter.setMaximumFractionDigits(1);
@@ -243,6 +258,25 @@ public class BackupsPreferenceFragment extends Fragment {
LocalBackupJob.enqueue(true);
}
+ private void pickTime() {
+ int timeFormat = DateFormat.is24HourFormat(requireContext()) ? TimeFormat.CLOCK_24H : TimeFormat.CLOCK_12H;
+ final MaterialTimePicker timePickerFragment = new MaterialTimePicker.Builder()
+ .setTimeFormat(timeFormat)
+ .setHour(SignalStore.settings().getBackupHour())
+ .setMinute(SignalStore.settings().getBackupMinute())
+ .setTitleText("Set Backup Time")
+ .build();
+ timePickerFragment.addOnPositiveButtonClickListener(v -> {
+ int hour = timePickerFragment.getHour();
+ int minute = timePickerFragment.getMinute();
+ SignalStore.settings().setBackupSchedule(hour, minute);
+ updateTimeLabel();
+ TextSecurePreferences.setNextBackupTime(requireContext(), 0);
+ LocalBackupListener.schedule(requireContext());
+ });
+ timePickerFragment.show(getChildFragmentManager(), "TIME_PICKER");
+ }
+
private void onCreateClickedLegacy() {
Permissions.with(this)
.request(Manifest.permission.WRITE_EXTERNAL_STORAGE)
@@ -255,10 +289,19 @@ public class BackupsPreferenceFragment extends Fragment {
.execute();
}
+ private void updateTimeLabel() {
+ final int backupHour = SignalStore.settings().getBackupHour();
+ final int backupMinute = SignalStore.settings().getBackupMinute();
+ LocalTime time = LocalTime.of(backupHour, backupMinute);
+ timeLabel.setText(JavaTimeExtensionsKt.formatHours(time, requireContext()));
+ }
+
private void setBackupsEnabled() {
toggle.setText(R.string.BackupsPreferenceFragment__turn_off);
create.setVisibility(View.VISIBLE);
verify.setVisibility(View.VISIBLE);
+ timer.setVisibility(View.VISIBLE);
+ updateTimeLabel();
setBackupFolderName();
}
@@ -267,6 +310,7 @@ public class BackupsPreferenceFragment extends Fragment {
create.setVisibility(View.GONE);
folder.setVisibility(View.GONE);
verify.setVisibility(View.GONE);
+ timer.setVisibility(View.GONE);
ApplicationDependencies.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 a8d68c254..23c23e466 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/service/LocalBackupListener.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/service/LocalBackupListener.java
@@ -50,7 +50,9 @@ public class LocalBackupListener extends PersistentAlarmManagerListener {
nextTime = System.currentTimeMillis() + INTERVAL;
} else {
LocalDateTime now = LocalDateTime.now();
- LocalDateTime next = now.withHour(2).withMinute(0).withSecond(0);
+ int hour = SignalStore.settings().getBackupHour();
+ int minute = SignalStore.settings().getBackupMinute();
+ LocalDateTime next = now.withHour(hour).withMinute(minute).withSecond(0);
if (now.getHour() >= 2) {
next = next.plusDays(1);
}
diff --git a/app/src/main/res/layout/fragment_backups.xml b/app/src/main/res/layout/fragment_backups.xml
index ef935a257..d3a076875 100644
--- a/app/src/main/res/layout/fragment_backups.xml
+++ b/app/src/main/res/layout/fragment_backups.xml
@@ -117,6 +117,37 @@
android:textColor="@color/signal_text_secondary" />
+
+
+
+
+
+
+
+
Create backup
Last backup: %1$s
Backup folder
+
+ Backup time
Verify backup passphrase
Test your backup passphrase and verify that it matches
Turn on