kopia lustrzana https://github.com/ryukoposting/Signal-Android
Notify about accidentally disabled backups.
rodzic
d1478c5ce0
commit
b5d6cb2a8d
|
@ -18,10 +18,10 @@ import org.thoughtcrime.securesms.notifications.NotificationChannels;
|
|||
import java.io.IOException;
|
||||
|
||||
public enum BackupFileIOError {
|
||||
ACCESS_ERROR(R.string.LocalBackupJobApi29_backups_disabled, R.string.LocalBackupJobApi29_your_backup_directory_has_been_deleted_or_moved),
|
||||
ACCESS_ERROR(R.string.LocalBackupJobApi29_backup_failed, R.string.LocalBackupJobApi29_your_backup_directory_has_been_deleted_or_moved),
|
||||
FILE_TOO_LARGE(R.string.LocalBackupJobApi29_backup_failed, R.string.LocalBackupJobApi29_your_backup_file_is_too_large),
|
||||
NOT_ENOUGH_SPACE(R.string.LocalBackupJobApi29_backup_failed, R.string.LocalBackupJobApi29_there_is_not_enough_space),
|
||||
UNKNOWN(R.string.LocalBackupJobApi29_backup_failed, R.string.LocalBackupJobApi29_backup_failed_for_an_unknown_reason);
|
||||
UNKNOWN(R.string.LocalBackupJobApi29_backup_failed, R.string.LocalBackupJobApi29_tap_to_manage_backups);
|
||||
|
||||
private static final short BACKUP_FAILED_ID = 31321;
|
||||
|
||||
|
@ -42,8 +42,8 @@ public enum BackupFileIOError {
|
|||
|
||||
intent.putExtra(ApplicationPreferencesActivity.LAUNCH_TO_BACKUPS_FRAGMENT, true);
|
||||
|
||||
PendingIntent pendingIntent = PendingIntent.getActivity(context, -1, intent, 0);
|
||||
Notification backupFailedNotification = new NotificationCompat.Builder(context, NotificationChannels.BACKUPS)
|
||||
PendingIntent pendingIntent = PendingIntent.getActivity(context, -1, intent, 0);
|
||||
Notification backupFailedNotification = new NotificationCompat.Builder(context, NotificationChannels.FAILURES)
|
||||
.setSmallIcon(R.drawable.ic_signal_backup)
|
||||
.setContentTitle(context.getString(titleId))
|
||||
.setContentText(context.getString(messageId))
|
||||
|
|
|
@ -28,6 +28,7 @@ import org.thoughtcrime.securesms.jobmanager.migrations.SendReadReceiptsJobMigra
|
|||
import org.thoughtcrime.securesms.migrations.AttributesMigrationJob;
|
||||
import org.thoughtcrime.securesms.migrations.AvatarIdRemovalMigrationJob;
|
||||
import org.thoughtcrime.securesms.migrations.AvatarMigrationJob;
|
||||
import org.thoughtcrime.securesms.migrations.BackupNotificationMigrationJob;
|
||||
import org.thoughtcrime.securesms.migrations.CachedAttachmentsMigrationJob;
|
||||
import org.thoughtcrime.securesms.migrations.DatabaseMigrationJob;
|
||||
import org.thoughtcrime.securesms.migrations.DirectoryRefreshMigrationJob;
|
||||
|
@ -135,6 +136,7 @@ public final class JobManagerFactories {
|
|||
put(AttributesMigrationJob.KEY, new AttributesMigrationJob.Factory());
|
||||
put(AvatarIdRemovalMigrationJob.KEY, new AvatarIdRemovalMigrationJob.Factory());
|
||||
put(AvatarMigrationJob.KEY, new AvatarMigrationJob.Factory());
|
||||
put(BackupNotificationMigrationJob.KEY, new BackupNotificationMigrationJob.Factory());
|
||||
put(CachedAttachmentsMigrationJob.KEY, new CachedAttachmentsMigrationJob.Factory());
|
||||
put(DatabaseMigrationJob.KEY, new DatabaseMigrationJob.Factory());
|
||||
put(DirectoryRefreshMigrationJob.KEY, new DirectoryRefreshMigrationJob.Factory());
|
||||
|
|
|
@ -2,7 +2,6 @@ package org.thoughtcrime.securesms.jobs;
|
|||
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
|
@ -94,7 +93,7 @@ public final class LocalBackupJob extends BaseJob {
|
|||
notification.setIndeterminateProgress();
|
||||
|
||||
String backupPassword = BackupPassphrase.get(context);
|
||||
File backupDirectory = StorageUtil.getBackupDirectory();
|
||||
File backupDirectory = StorageUtil.getOrCreateBackupDirectory();
|
||||
String timestamp = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss", Locale.US).format(new Date());
|
||||
String fileName = String.format("signal-%s.backup", timestamp);
|
||||
File backupFile = new File(backupDirectory, fileName);
|
||||
|
|
|
@ -89,7 +89,6 @@ public final class LocalBackupJobApi29 extends BaseJob {
|
|||
String fileName = String.format("signal-%s.backup", timestamp);
|
||||
|
||||
if (backupDirectory == null || !backupDirectory.canWrite()) {
|
||||
BackupUtil.disableBackups(context);
|
||||
BackupFileIOError.ACCESS_ERROR.postNotification(context);
|
||||
throw new IOException("Cannot write to backup directory location.");
|
||||
}
|
||||
|
|
|
@ -39,31 +39,32 @@ public class ApplicationMigrations {
|
|||
|
||||
private static final int LEGACY_CANONICAL_VERSION = 455;
|
||||
|
||||
public static final int CURRENT_VERSION = 22;
|
||||
public static final int CURRENT_VERSION = 23;
|
||||
|
||||
private static final class Version {
|
||||
static final int LEGACY = 1;
|
||||
static final int RECIPIENT_ID = 2;
|
||||
static final int RECIPIENT_SEARCH = 3;
|
||||
static final int RECIPIENT_CLEANUP = 4;
|
||||
static final int AVATAR_MIGRATION = 5;
|
||||
static final int UUIDS = 6;
|
||||
static final int CACHED_ATTACHMENTS = 7;
|
||||
static final int STICKERS_LAUNCH = 8;
|
||||
static final int LEGACY = 1;
|
||||
static final int RECIPIENT_ID = 2;
|
||||
static final int RECIPIENT_SEARCH = 3;
|
||||
static final int RECIPIENT_CLEANUP = 4;
|
||||
static final int AVATAR_MIGRATION = 5;
|
||||
static final int UUIDS = 6;
|
||||
static final int CACHED_ATTACHMENTS = 7;
|
||||
static final int STICKERS_LAUNCH = 8;
|
||||
//static final int TEST_ARGON2 = 9;
|
||||
static final int SWOON_STICKERS = 10;
|
||||
static final int STORAGE_SERVICE = 11;
|
||||
static final int SWOON_STICKERS = 10;
|
||||
static final int STORAGE_SERVICE = 11;
|
||||
//static final int STORAGE_KEY_ROTATE = 12;
|
||||
static final int REMOVE_AVATAR_ID = 13;
|
||||
static final int STORAGE_CAPABILITY = 14;
|
||||
static final int PIN_REMINDER = 15;
|
||||
static final int VERSIONED_PROFILE = 16;
|
||||
static final int PIN_OPT_OUT = 17;
|
||||
static final int TRIM_SETTINGS = 18;
|
||||
static final int THUMBNAIL_CLEANUP = 19;
|
||||
static final int GV2 = 20;
|
||||
static final int GV2_2 = 21;
|
||||
static final int CDS = 22;
|
||||
static final int REMOVE_AVATAR_ID = 13;
|
||||
static final int STORAGE_CAPABILITY = 14;
|
||||
static final int PIN_REMINDER = 15;
|
||||
static final int VERSIONED_PROFILE = 16;
|
||||
static final int PIN_OPT_OUT = 17;
|
||||
static final int TRIM_SETTINGS = 18;
|
||||
static final int THUMBNAIL_CLEANUP = 19;
|
||||
static final int GV2 = 20;
|
||||
static final int GV2_2 = 21;
|
||||
static final int CDS = 22;
|
||||
static final int BACKUP_NOTIFICATION = 23;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -267,6 +268,10 @@ public class ApplicationMigrations {
|
|||
jobs.put(Version.CDS, new DirectoryRefreshMigrationJob());
|
||||
}
|
||||
|
||||
if (lastSeenVersion < Version.BACKUP_NOTIFICATION) {
|
||||
jobs.put(Version.BACKUP_NOTIFICATION, new BackupNotificationMigrationJob());
|
||||
}
|
||||
|
||||
return jobs;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
package org.thoughtcrime.securesms.migrations;
|
||||
|
||||
import android.os.Build;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.thoughtcrime.securesms.backup.BackupFileIOError;
|
||||
import org.thoughtcrime.securesms.jobmanager.Data;
|
||||
import org.thoughtcrime.securesms.jobmanager.Job;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
import org.thoughtcrime.securesms.util.BackupUtil;
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Handles showing a notification if we think backups were unintentionally disabled.
|
||||
*/
|
||||
public final class BackupNotificationMigrationJob extends MigrationJob {
|
||||
|
||||
private static final String TAG = Log.tag(BackupNotificationMigrationJob.class);
|
||||
|
||||
public static final String KEY = "BackupNotificationMigrationJob";
|
||||
|
||||
BackupNotificationMigrationJob() {
|
||||
this(new Parameters.Builder().build());
|
||||
}
|
||||
|
||||
private BackupNotificationMigrationJob(@NonNull Parameters parameters) {
|
||||
super(parameters);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUiBlocking() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull String getFactoryKey() {
|
||||
return KEY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void performMigration() {
|
||||
if (Build.VERSION.SDK_INT >= 29 && !TextSecurePreferences.isBackupEnabled(context) && BackupUtil.hasBackupFiles(context)) {
|
||||
Log.w(TAG, "Stranded backup! Notifying.");
|
||||
BackupFileIOError.UNKNOWN.postNotification(context);
|
||||
} else {
|
||||
Log.w(TAG, String.format(Locale.US, "Does not meet criteria. API: %d, BackupsEnabled: %s, HasFiles: %s",
|
||||
Build.VERSION.SDK_INT,
|
||||
TextSecurePreferences.isBackupEnabled(context),
|
||||
BackupUtil.hasBackupFiles(context)));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean shouldRetry(@NonNull Exception e) {
|
||||
return e instanceof IOException;
|
||||
}
|
||||
|
||||
public static class Factory implements Job.Factory<BackupNotificationMigrationJob> {
|
||||
@Override
|
||||
public @NonNull BackupNotificationMigrationJob create(@NonNull Parameters parameters, @NonNull Data data) {
|
||||
return new BackupNotificationMigrationJob(parameters);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -18,7 +18,6 @@ import androidx.annotation.Nullable;
|
|||
import androidx.annotation.RequiresApi;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.core.text.HtmlCompat;
|
||||
import androidx.documentfile.provider.DocumentFile;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
|
@ -165,7 +164,7 @@ public class BackupsPreferenceFragment extends Fragment {
|
|||
} else if (StorageUtil.canWriteInSignalStorageDir()) {
|
||||
try {
|
||||
folder.setVisibility(View.VISIBLE);
|
||||
folderName.setText(StorageUtil.getBackupDirectory().getPath());
|
||||
folderName.setText(StorageUtil.getOrCreateBackupDirectory().getPath());
|
||||
} catch (NoExternalStorageException e) {
|
||||
Log.w(TAG, "Could not display folder name.", e);
|
||||
}
|
||||
|
|
|
@ -15,7 +15,6 @@ import androidx.documentfile.provider.DocumentFile;
|
|||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.backup.BackupPassphrase;
|
||||
import org.thoughtcrime.securesms.database.NoExternalStorageException;
|
||||
import org.thoughtcrime.securesms.database.documents.Document;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.logging.Log;
|
||||
|
@ -181,7 +180,7 @@ public class BackupUtil {
|
|||
}
|
||||
|
||||
private static List<BackupInfo> getAllBackupsNewestFirstLegacy() throws NoExternalStorageException {
|
||||
File backupDirectory = StorageUtil.getBackupDirectory();
|
||||
File backupDirectory = StorageUtil.getOrCreateBackupDirectory();
|
||||
File[] files = backupDirectory.listFiles();
|
||||
List<BackupInfo> backups = new ArrayList<>(files.length);
|
||||
|
||||
|
@ -213,6 +212,20 @@ public class BackupUtil {
|
|||
return result;
|
||||
}
|
||||
|
||||
public static boolean hasBackupFiles(@NonNull Context context) {
|
||||
if (Permissions.hasAll(context, Manifest.permission.READ_EXTERNAL_STORAGE)) {
|
||||
try {
|
||||
File directory = StorageUtil.getBackupDirectory();
|
||||
return directory.exists() && directory.isDirectory() && directory.listFiles().length > 0;
|
||||
} catch (NoExternalStorageException e) {
|
||||
Log.w(TAG, "Failed to read storage!", e);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static long getBackupTimestamp(@NonNull String backupName) {
|
||||
String[] prefixSuffix = backupName.split("[.]");
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ import org.thoughtcrime.securesms.database.NoExternalStorageException;
|
|||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.permissions.Permissions;
|
||||
import org.whispersystems.libsignal.util.guava.Optional;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
@ -28,20 +29,14 @@ public class StorageUtil {
|
|||
|
||||
private static final String PRODUCTION_PACKAGE_ID = "org.thoughtcrime.securesms";
|
||||
|
||||
public static File getBackupDirectory() throws NoExternalStorageException {
|
||||
public static File getOrCreateBackupDirectory() throws NoExternalStorageException {
|
||||
File storage = Environment.getExternalStorageDirectory();
|
||||
|
||||
if (!storage.canWrite()) {
|
||||
throw new NoExternalStorageException();
|
||||
}
|
||||
|
||||
File signal = new File(storage, "Signal");
|
||||
File backups = new File(signal, "Backups");
|
||||
|
||||
//noinspection ConstantConditions
|
||||
if (BuildConfig.APPLICATION_ID.startsWith(PRODUCTION_PACKAGE_ID + ".")) {
|
||||
backups = new File(backups, BuildConfig.APPLICATION_ID.substring(PRODUCTION_PACKAGE_ID.length() + 1));
|
||||
}
|
||||
File backups = getBackupDirectory();
|
||||
|
||||
if (!backups.exists()) {
|
||||
if (!backups.mkdirs()) {
|
||||
|
@ -52,6 +47,19 @@ public class StorageUtil {
|
|||
return backups;
|
||||
}
|
||||
|
||||
public static File getBackupDirectory() throws NoExternalStorageException {
|
||||
File storage = Environment.getExternalStorageDirectory();
|
||||
File signal = new File(storage, "Signal");
|
||||
File backups = new File(signal, "Backups");
|
||||
|
||||
//noinspection ConstantConditions
|
||||
if (BuildConfig.APPLICATION_ID.startsWith(PRODUCTION_PACKAGE_ID + ".")) {
|
||||
backups = new File(backups, BuildConfig.APPLICATION_ID.substring(PRODUCTION_PACKAGE_ID.length() + 1));
|
||||
}
|
||||
|
||||
return backups;
|
||||
}
|
||||
|
||||
@RequiresApi(24)
|
||||
public static @NonNull String getDisplayPath(@NonNull Context context, @NonNull Uri uri) {
|
||||
String lastPathSegment = Objects.requireNonNull(uri.getLastPathSegment());
|
||||
|
|
|
@ -2625,12 +2625,11 @@
|
|||
<string name="ChatsPreferenceFragment_last_backup_s">Last backup: %s</string>
|
||||
<string name="ChatsPreferenceFragment_in_progress">In progress</string>
|
||||
<string name="LocalBackupJob_creating_backup">Creating backup…</string>
|
||||
<string name="LocalBackupJobApi29_backups_disabled">Backups disabled.</string>
|
||||
<string name="LocalBackupJobApi29_backup_failed">Backup failed.</string>
|
||||
<string name="LocalBackupJobApi29_backup_failed">Backup failed</string>
|
||||
<string name="LocalBackupJobApi29_your_backup_directory_has_been_deleted_or_moved">Your backup directory has been deleted or moved.</string>
|
||||
<string name="LocalBackupJobApi29_your_backup_file_is_too_large">Your backup file is too large to store on this volume.</string>
|
||||
<string name="LocalBackupJobApi29_there_is_not_enough_space">There is not enough space to store your backup.</string>
|
||||
<string name="LocalBackupJobApi29_backup_failed_for_an_unknown_reason">Backup failed for an unknown reason.</string>
|
||||
<string name="LocalBackupJobApi29_tap_to_manage_backups">Tap to manage backups.</string>
|
||||
<string name="ProgressPreference_d_messages_so_far">%d messages so far</string>
|
||||
<string name="RegistrationActivity_please_enter_the_verification_code_sent_to_s">Please enter the verification code sent to %s.</string>
|
||||
<string name="RegistrationActivity_wrong_number">Wrong number</string>
|
||||
|
|
Ładowanie…
Reference in New Issue