mirror of
https://github.com/beemdevelopment/Aegis.git
synced 2025-05-14 22:12:55 +00:00
Store and display backup error messages more clearly
This commit is contained in:
parent
4427498d5e
commit
8ae8130b71
10 changed files with 242 additions and 34 deletions
|
@ -29,7 +29,7 @@ public class AegisBackupAgent extends BackupAgent {
|
||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
super.onCreate();
|
super.onCreate();
|
||||||
|
|
||||||
// cannot use injection with Dagger Hilt here, because the app is launched in a restricted mode on restore
|
// Cannot use injection with Dagger Hilt here, because the app is launched in a restricted mode on restore
|
||||||
_prefs = new Preferences(this);
|
_prefs = new Preferences(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ public class AegisBackupAgent extends BackupAgent {
|
||||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ? data.getQuota() : -1));
|
Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ? data.getQuota() : -1));
|
||||||
|
|
||||||
boolean isD2D = Build.VERSION.SDK_INT >= Build.VERSION_CODES.P
|
boolean isD2D = Build.VERSION.SDK_INT >= Build.VERSION_CODES.P
|
||||||
&& (data.getTransportFlags() & FLAG_DEVICE_TO_DEVICE_TRANSFER) == FLAG_DEVICE_TO_DEVICE_TRANSFER;
|
&& (data.getTransportFlags() & FLAG_DEVICE_TO_DEVICE_TRANSFER) == FLAG_DEVICE_TO_DEVICE_TRANSFER;
|
||||||
|
|
||||||
if (isD2D) {
|
if (isD2D) {
|
||||||
Log.i(TAG, "onFullBackup(): allowing D2D transfer");
|
Log.i(TAG, "onFullBackup(): allowing D2D transfer");
|
||||||
|
@ -49,31 +49,39 @@ public class AegisBackupAgent extends BackupAgent {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// first copy the vault to the files/backup directory
|
// We perform a catch of any Exception here to make sure we also
|
||||||
|
// report any runtime exceptions, in addition to the expected IOExceptions.
|
||||||
|
try {
|
||||||
|
fullBackup(data);
|
||||||
|
_prefs.setAndroidBackupResult(new Preferences.BackupResult(null));
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e(TAG, String.format("onFullBackup() failed: %s", e));
|
||||||
|
_prefs.setAndroidBackupResult(new Preferences.BackupResult(e));
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.i(TAG, "onFullBackup() finished");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fullBackup(FullBackupDataOutput data) throws IOException {
|
||||||
|
// First copy the vault to the files/backup directory
|
||||||
|
createBackupDir();
|
||||||
File vaultBackupFile = getVaultBackupFile();
|
File vaultBackupFile = getVaultBackupFile();
|
||||||
try (OutputStream outputStream = new FileOutputStream(vaultBackupFile)) {
|
try (OutputStream outputStream = new FileOutputStream(vaultBackupFile)) {
|
||||||
createBackupDir();
|
|
||||||
|
|
||||||
VaultFile vaultFile = VaultRepository.readVaultFile(this);
|
VaultFile vaultFile = VaultRepository.readVaultFile(this);
|
||||||
byte[] bytes = vaultFile.exportable().toBytes();
|
byte[] bytes = vaultFile.exportable().toBytes();
|
||||||
outputStream.write(bytes);
|
outputStream.write(bytes);
|
||||||
} catch (VaultRepositoryException | IOException e) {
|
} catch (VaultRepositoryException | IOException e) {
|
||||||
Log.e(TAG, String.format("onFullBackup() failed: %s", e));
|
|
||||||
deleteBackupDir();
|
deleteBackupDir();
|
||||||
throw new IOException(e);
|
throw new IOException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
// then call the original implementation so that fullBackupContent specified in AndroidManifest is read
|
// Then call the original implementation so that fullBackupContent specified in AndroidManifest is read
|
||||||
try {
|
try {
|
||||||
super.onFullBackup(data);
|
super.onFullBackup(data);
|
||||||
} catch (IOException e) {
|
|
||||||
Log.e(TAG, String.format("onFullBackup() failed: %s", e));
|
|
||||||
throw e;
|
|
||||||
} finally {
|
} finally {
|
||||||
deleteBackupDir();
|
deleteBackupDir();
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.i(TAG, "onFullBackup() finished");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -114,14 +122,16 @@ public class AegisBackupAgent extends BackupAgent {
|
||||||
|
|
||||||
private void createBackupDir() throws IOException {
|
private void createBackupDir() throws IOException {
|
||||||
File dir = getVaultBackupFile().getParentFile();
|
File dir = getVaultBackupFile().getParentFile();
|
||||||
if (!dir.exists() && !dir.mkdir()) {
|
if (dir == null || (!dir.exists() && !dir.mkdir())) {
|
||||||
throw new IOException(String.format("Unable to create backup directory: %s", dir.toString()));
|
throw new IOException(String.format("Unable to create backup directory: %s", dir));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void deleteBackupDir() {
|
private void deleteBackupDir() {
|
||||||
File dir = getVaultBackupFile().getParentFile();
|
File dir = getVaultBackupFile().getParentFile();
|
||||||
IOUtils.clearDirectory(dir, true);
|
if (dir != null) {
|
||||||
|
IOUtils.clearDirectory(dir, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private File getVaultBackupFile() {
|
private File getVaultBackupFile() {
|
||||||
|
|
|
@ -7,10 +7,15 @@ import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import com.beemdevelopment.aegis.util.JsonUtils;
|
||||||
|
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import java.text.DateFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
@ -259,6 +264,7 @@ public class Preferences {
|
||||||
|
|
||||||
public void setIsAndroidBackupsEnabled(boolean enabled) {
|
public void setIsAndroidBackupsEnabled(boolean enabled) {
|
||||||
_prefs.edit().putBoolean("pref_android_backups", enabled).apply();
|
_prefs.edit().putBoolean("pref_android_backups", enabled).apply();
|
||||||
|
setAndroidBackupResult(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isBackupsEnabled() {
|
public boolean isBackupsEnabled() {
|
||||||
|
@ -267,6 +273,7 @@ public class Preferences {
|
||||||
|
|
||||||
public void setIsBackupsEnabled(boolean enabled) {
|
public void setIsBackupsEnabled(boolean enabled) {
|
||||||
_prefs.edit().putBoolean("pref_backups", enabled).apply();
|
_prefs.edit().putBoolean("pref_backups", enabled).apply();
|
||||||
|
setBuiltInBackupResult(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Uri getBackupsLocation() {
|
public Uri getBackupsLocation() {
|
||||||
|
@ -298,12 +305,64 @@ public class Preferences {
|
||||||
_prefs.edit().putInt("pref_backups_versions", versions).apply();
|
_prefs.edit().putInt("pref_backups_versions", versions).apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setBackupsError(Exception e) {
|
public void setAndroidBackupResult(@Nullable BackupResult res) {
|
||||||
_prefs.edit().putString("pref_backups_error", e == null ? null : e.toString()).apply();
|
setBackupResult(false, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getBackupsError() {
|
public void setBuiltInBackupResult(@Nullable BackupResult res) {
|
||||||
return _prefs.getString("pref_backups_error", null);
|
setBackupResult(true, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public BackupResult getAndroidBackupResult() {
|
||||||
|
return getBackupResult(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public BackupResult getBuiltInBackupResult() {
|
||||||
|
return getBackupResult(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public Preferences.BackupResult getErroredBackupResult() {
|
||||||
|
Preferences.BackupResult res = getBuiltInBackupResult();
|
||||||
|
if (res != null && !res.isSuccessful()) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
res = getAndroidBackupResult();
|
||||||
|
if (res != null && !res.isSuccessful()) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setBackupResult(boolean isBuiltInBackup, @Nullable BackupResult res) {
|
||||||
|
String json = null;
|
||||||
|
if (res != null) {
|
||||||
|
res.setIsBuiltIn(isBuiltInBackup);
|
||||||
|
json = res.toJson();
|
||||||
|
}
|
||||||
|
_prefs.edit().putString(getBackupResultKey(isBuiltInBackup), json).apply();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private BackupResult getBackupResult(boolean isBuiltInBackup) {
|
||||||
|
String json = _prefs.getString(getBackupResultKey(isBuiltInBackup), null);
|
||||||
|
if (json == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
BackupResult res = BackupResult.fromJson(json);
|
||||||
|
res.setIsBuiltIn(isBuiltInBackup);
|
||||||
|
return res;
|
||||||
|
} catch (JSONException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getBackupResultKey(boolean isBuiltInBackup) {
|
||||||
|
return isBuiltInBackup ? "pref_backups_result_builtin": "pref_backups_result_android";
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setIsBackupReminderNeeded(boolean needed) {
|
public void setIsBackupReminderNeeded(boolean needed) {
|
||||||
|
@ -382,4 +441,63 @@ public class Preferences {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class BackupResult {
|
||||||
|
private final Date _time;
|
||||||
|
private boolean _isBuiltIn;
|
||||||
|
private final String _error;
|
||||||
|
|
||||||
|
public BackupResult(@Nullable Exception e) {
|
||||||
|
this(new Date(), e == null ? null : e.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private BackupResult(Date time, @Nullable String error) {
|
||||||
|
_time = time;
|
||||||
|
_error = error;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public String getError() {
|
||||||
|
return _error;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSuccessful() {
|
||||||
|
return _error == null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getTime() {
|
||||||
|
return _time;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getHumanReadableTime() {
|
||||||
|
return DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT).format(_time);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isBuiltIn() {
|
||||||
|
return _isBuiltIn;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setIsBuiltIn(boolean isBuiltIn) {
|
||||||
|
_isBuiltIn = isBuiltIn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toJson() {
|
||||||
|
JSONObject obj = new JSONObject();
|
||||||
|
|
||||||
|
try {
|
||||||
|
obj.put("time", _time.getTime());
|
||||||
|
obj.put("error", _error == null ? JSONObject.NULL : _error);
|
||||||
|
} catch (JSONException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BackupResult fromJson(String json) throws JSONException {
|
||||||
|
JSONObject obj = new JSONObject(json);
|
||||||
|
long time = obj.getLong("time");
|
||||||
|
String error = JsonUtils.optString(obj, "error");
|
||||||
|
return new BackupResult(new Date(time), error);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,6 @@ import com.beemdevelopment.aegis.helpers.FabScrollHelper;
|
||||||
import com.beemdevelopment.aegis.helpers.PermissionHelper;
|
import com.beemdevelopment.aegis.helpers.PermissionHelper;
|
||||||
import com.beemdevelopment.aegis.otp.GoogleAuthInfo;
|
import com.beemdevelopment.aegis.otp.GoogleAuthInfo;
|
||||||
import com.beemdevelopment.aegis.otp.GoogleAuthInfoException;
|
import com.beemdevelopment.aegis.otp.GoogleAuthInfoException;
|
||||||
import com.beemdevelopment.aegis.otp.OtpInfo;
|
|
||||||
import com.beemdevelopment.aegis.otp.OtpInfoException;
|
import com.beemdevelopment.aegis.otp.OtpInfoException;
|
||||||
import com.beemdevelopment.aegis.ui.dialogs.Dialogs;
|
import com.beemdevelopment.aegis.ui.dialogs.Dialogs;
|
||||||
import com.beemdevelopment.aegis.ui.fragments.preferences.BackupsPreferencesFragment;
|
import com.beemdevelopment.aegis.ui.fragments.preferences.BackupsPreferencesFragment;
|
||||||
|
@ -781,15 +780,13 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateErrorBar() {
|
private void updateErrorBar() {
|
||||||
String backupError = null;
|
Preferences.BackupResult backupRes = _prefs.getErroredBackupResult();
|
||||||
if (_prefs.isBackupsEnabled()) {
|
if (backupRes != null) {
|
||||||
backupError = _prefs.getBackupsError();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (backupError != null) {
|
|
||||||
_textErrorBar.setText(R.string.backup_error_bar_message);
|
_textErrorBar.setText(R.string.backup_error_bar_message);
|
||||||
_btnErrorBar.setOnClickListener(view -> {
|
_btnErrorBar.setOnClickListener(view -> {
|
||||||
startPreferencesActivity(BackupsPreferencesFragment.class, "pref_backups");
|
Dialogs.showBackupErrorDialog(this, backupRes, (dialog, which) -> {
|
||||||
|
startPreferencesActivity(BackupsPreferencesFragment.class, "pref_backups");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
_btnErrorBar.setVisibility(View.VISIBLE);
|
_btnErrorBar.setVisibility(View.VISIBLE);
|
||||||
} else if (_prefs.isBackupsReminderNeeded()) {
|
} else if (_prefs.isBackupsReminderNeeded()) {
|
||||||
|
|
|
@ -36,6 +36,7 @@ import com.beemdevelopment.aegis.R;
|
||||||
import com.beemdevelopment.aegis.helpers.EditTextHelper;
|
import com.beemdevelopment.aegis.helpers.EditTextHelper;
|
||||||
import com.beemdevelopment.aegis.helpers.PasswordStrengthHelper;
|
import com.beemdevelopment.aegis.helpers.PasswordStrengthHelper;
|
||||||
import com.beemdevelopment.aegis.importers.DatabaseImporter;
|
import com.beemdevelopment.aegis.importers.DatabaseImporter;
|
||||||
|
import com.beemdevelopment.aegis.ui.fragments.preferences.BackupsPreferencesFragment;
|
||||||
import com.beemdevelopment.aegis.ui.tasks.KeyDerivationTask;
|
import com.beemdevelopment.aegis.ui.tasks.KeyDerivationTask;
|
||||||
import com.beemdevelopment.aegis.vault.VaultEntry;
|
import com.beemdevelopment.aegis.vault.VaultEntry;
|
||||||
import com.beemdevelopment.aegis.vault.slots.PasswordSlot;
|
import com.beemdevelopment.aegis.vault.slots.PasswordSlot;
|
||||||
|
@ -403,6 +404,12 @@ public class Dialogs {
|
||||||
Dialogs.showSecureDialog(dialog);
|
Dialogs.showSecureDialog(dialog);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void showBackupErrorDialog(Context context, Preferences.BackupResult backupRes, DialogInterface.OnClickListener listener) {
|
||||||
|
String system = context.getString(backupRes.isBuiltIn() ? R.string.backup_system_builtin : R.string.backup_system_android);
|
||||||
|
String message = context.getString(R.string.backup_error_dialog_details, system, backupRes.getHumanReadableTime());
|
||||||
|
Dialogs.showErrorDialog(context, message, backupRes.getError(), listener);
|
||||||
|
}
|
||||||
|
|
||||||
public static void showMultiMessageDialog(
|
public static void showMultiMessageDialog(
|
||||||
Context context, @StringRes int title, String message, List<CharSequence> messages, DialogInterface.OnClickListener listener) {
|
Context context, @StringRes int title, String message, List<CharSequence> messages, DialogInterface.OnClickListener listener) {
|
||||||
Dialogs.showSecureDialog(new AlertDialog.Builder(context)
|
Dialogs.showSecureDialog(new AlertDialog.Builder(context)
|
||||||
|
|
|
@ -2,10 +2,16 @@ package com.beemdevelopment.aegis.ui.fragments.preferences;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.graphics.Typeface;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.text.Spannable;
|
||||||
|
import android.text.SpannableString;
|
||||||
|
import android.text.style.ForegroundColorSpan;
|
||||||
|
import android.text.style.StyleSpan;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import androidx.preference.Preference;
|
import androidx.preference.Preference;
|
||||||
import androidx.preference.SwitchPreferenceCompat;
|
import androidx.preference.SwitchPreferenceCompat;
|
||||||
|
|
||||||
|
@ -21,6 +27,9 @@ public class BackupsPreferencesFragment extends PreferencesFragment {
|
||||||
private Preference _backupsTriggerPreference;
|
private Preference _backupsTriggerPreference;
|
||||||
private Preference _backupsVersionsPreference;
|
private Preference _backupsVersionsPreference;
|
||||||
|
|
||||||
|
private Preference _builtinBackupStatusPreference;
|
||||||
|
private Preference _androidBackupStatusPreference;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onResume() {
|
public void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
|
@ -32,6 +41,23 @@ public class BackupsPreferencesFragment extends PreferencesFragment {
|
||||||
super.onCreatePreferences(savedInstanceState, rootKey);
|
super.onCreatePreferences(savedInstanceState, rootKey);
|
||||||
addPreferencesFromResource(R.xml.preferences_backups);
|
addPreferencesFromResource(R.xml.preferences_backups);
|
||||||
|
|
||||||
|
_builtinBackupStatusPreference = requirePreference("pref_status_backup_builtin");
|
||||||
|
_builtinBackupStatusPreference.setOnPreferenceClickListener(preference -> {
|
||||||
|
Preferences.BackupResult backupRes = _prefs.getBuiltInBackupResult();
|
||||||
|
if (backupRes != null && !backupRes.isSuccessful()) {
|
||||||
|
Dialogs.showBackupErrorDialog(requireContext(), backupRes, null);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
_androidBackupStatusPreference = requirePreference("pref_status_backup_android");
|
||||||
|
_androidBackupStatusPreference.setOnPreferenceClickListener(preference -> {
|
||||||
|
Preferences.BackupResult backupRes = _prefs.getAndroidBackupResult();
|
||||||
|
if (backupRes != null && !backupRes.isSuccessful()) {
|
||||||
|
Dialogs.showBackupErrorDialog(requireContext(), backupRes, null);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
_backupsPreference = requirePreference("pref_backups");
|
_backupsPreference = requirePreference("pref_backups");
|
||||||
_backupsPreference.setOnPreferenceChangeListener((preference, newValue) -> {
|
_backupsPreference.setOnPreferenceChangeListener((preference, newValue) -> {
|
||||||
if ((boolean) newValue) {
|
if ((boolean) newValue) {
|
||||||
|
@ -48,7 +74,9 @@ public class BackupsPreferencesFragment extends PreferencesFragment {
|
||||||
_androidBackupsPreference.setOnPreferenceChangeListener((preference, newValue) -> {
|
_androidBackupsPreference.setOnPreferenceChangeListener((preference, newValue) -> {
|
||||||
_prefs.setIsAndroidBackupsEnabled((boolean) newValue);
|
_prefs.setIsAndroidBackupsEnabled((boolean) newValue);
|
||||||
updateBackupPreference();
|
updateBackupPreference();
|
||||||
_vaultManager.scheduleAndroidBackup();
|
if ((boolean) newValue) {
|
||||||
|
_vaultManager.scheduleAndroidBackup();
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -66,6 +94,7 @@ public class BackupsPreferencesFragment extends PreferencesFragment {
|
||||||
_backupsTriggerPreference.setOnPreferenceClickListener(preference -> {
|
_backupsTriggerPreference.setOnPreferenceClickListener(preference -> {
|
||||||
if (_prefs.isBackupsEnabled()) {
|
if (_prefs.isBackupsEnabled()) {
|
||||||
scheduleBackup();
|
scheduleBackup();
|
||||||
|
_builtinBackupStatusPreference.setVisible(false);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
@ -100,7 +129,6 @@ public class BackupsPreferencesFragment extends PreferencesFragment {
|
||||||
|
|
||||||
_prefs.setBackupsLocation(uri);
|
_prefs.setBackupsLocation(uri);
|
||||||
_prefs.setIsBackupsEnabled(true);
|
_prefs.setIsBackupsEnabled(true);
|
||||||
_prefs.setBackupsError(null);
|
|
||||||
_backupsLocationPreference.setSummary(String.format("%s: %s", getString(R.string.pref_backups_location_summary), Uri.decode(uri.toString())));
|
_backupsLocationPreference.setSummary(String.format("%s: %s", getString(R.string.pref_backups_location_summary), Uri.decode(uri.toString())));
|
||||||
updateBackupPreference();
|
updateBackupPreference();
|
||||||
scheduleBackup();
|
scheduleBackup();
|
||||||
|
@ -117,6 +145,38 @@ public class BackupsPreferencesFragment extends PreferencesFragment {
|
||||||
_backupsLocationPreference.setVisible(backupEnabled);
|
_backupsLocationPreference.setVisible(backupEnabled);
|
||||||
_backupsTriggerPreference.setVisible(backupEnabled);
|
_backupsTriggerPreference.setVisible(backupEnabled);
|
||||||
_backupsVersionsPreference.setVisible(backupEnabled);
|
_backupsVersionsPreference.setVisible(backupEnabled);
|
||||||
|
if (backupEnabled) {
|
||||||
|
Preferences.BackupResult backupRes = _prefs.getBuiltInBackupResult();
|
||||||
|
_builtinBackupStatusPreference.setSummary(getBackupStatusMessage(backupRes));
|
||||||
|
_builtinBackupStatusPreference.setSelectable(backupRes != null && !backupRes.isSuccessful());
|
||||||
|
}
|
||||||
|
if (androidBackupEnabled) {
|
||||||
|
Preferences.BackupResult backupRes = _prefs.getAndroidBackupResult();
|
||||||
|
_androidBackupStatusPreference.setSummary(getBackupStatusMessage(backupRes));
|
||||||
|
_androidBackupStatusPreference.setSelectable(backupRes != null && !backupRes.isSuccessful());
|
||||||
|
}
|
||||||
|
_builtinBackupStatusPreference.setVisible(backupEnabled);
|
||||||
|
_androidBackupStatusPreference.setVisible(androidBackupEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
private CharSequence getBackupStatusMessage(@Nullable Preferences.BackupResult res) {
|
||||||
|
String message;
|
||||||
|
int color = R.color.warning_color;
|
||||||
|
if (res == null) {
|
||||||
|
message = getString(R.string.backup_status_none);
|
||||||
|
} else if (res.isSuccessful()) {
|
||||||
|
color = R.color.success_color;
|
||||||
|
message = getString(R.string.backup_status_success, res.getHumanReadableTime());
|
||||||
|
} else {
|
||||||
|
message = getString(R.string.backup_status_failed, res.getHumanReadableTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
Spannable spannable = new SpannableString(message);
|
||||||
|
spannable.setSpan(new ForegroundColorSpan(getResources().getColor(color)), 0, message.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||||
|
if (color == R.color.warning_color) {
|
||||||
|
spannable.setSpan(new StyleSpan(Typeface.BOLD), 0, message.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||||
|
}
|
||||||
|
return spannable;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void selectBackupsLocation() {
|
private void selectBackupsLocation() {
|
||||||
|
|
|
@ -52,10 +52,10 @@ public class VaultBackupManager {
|
||||||
_executor.execute(() -> {
|
_executor.execute(() -> {
|
||||||
try {
|
try {
|
||||||
createBackup(tempFile, dirUri, versionsToKeep);
|
createBackup(tempFile, dirUri, versionsToKeep);
|
||||||
_prefs.setBackupsError(null);
|
_prefs.setBuiltInBackupResult(new Preferences.BackupResult(null));
|
||||||
} catch (VaultRepositoryException e) {
|
} catch (VaultRepositoryException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
_prefs.setBackupsError(e);
|
_prefs.setBuiltInBackupResult(new Preferences.BackupResult(e));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -126,7 +126,7 @@ public class VaultFile {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new VaultFile(getContent(), new VaultFile.Header(
|
return new VaultFile(_content, new VaultFile.Header(
|
||||||
getHeader().getSlots().exportable(),
|
getHeader().getSlots().exportable(),
|
||||||
getHeader().getParams()
|
getHeader().getParams()
|
||||||
));
|
));
|
||||||
|
|
|
@ -196,9 +196,8 @@ public class VaultManager {
|
||||||
backedUp = true;
|
backedUp = true;
|
||||||
try {
|
try {
|
||||||
scheduleBackup();
|
scheduleBackup();
|
||||||
_prefs.setBackupsError(null);
|
|
||||||
} catch (VaultRepositoryException e) {
|
} catch (VaultRepositoryException e) {
|
||||||
_prefs.setBackupsError(e);
|
_prefs.setBuiltInBackupResult(new Preferences.BackupResult(e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -205,6 +205,9 @@
|
||||||
<string name="disable_encryption_error">An error occurred while disabling encryption</string>
|
<string name="disable_encryption_error">An error occurred while disabling encryption</string>
|
||||||
<string name="backup_successful">The backup was scheduled successfully</string>
|
<string name="backup_successful">The backup was scheduled successfully</string>
|
||||||
<string name="backup_error">An error occurred while trying to create a backup</string>
|
<string name="backup_error">An error occurred while trying to create a backup</string>
|
||||||
|
<string name="backup_status_success">Most recent backup successful: %s</string>
|
||||||
|
<string name="backup_status_failed">Most recent backup failed: %s</string>
|
||||||
|
<string name="backup_status_none">No backups have been made yet</string>
|
||||||
<string name="documentsui_error">DocumentsUI appears to be missing from your device. This is an important system component necessary for the selection and creation of documents. If you used a tool to "debloat" your device, you may have accidentally deleted it and will have to reinstall it.</string>
|
<string name="documentsui_error">DocumentsUI appears to be missing from your device. This is an important system component necessary for the selection and creation of documents. If you used a tool to "debloat" your device, you may have accidentally deleted it and will have to reinstall it.</string>
|
||||||
<string name="icon_pack_import_error">An error occurred while trying to import an icon pack</string>
|
<string name="icon_pack_import_error">An error occurred while trying to import an icon pack</string>
|
||||||
<string name="icon_pack_import_exists_error">The icon pack you\'re trying to import already exists. Do you want to overwrite it?</string>
|
<string name="icon_pack_import_exists_error">The icon pack you\'re trying to import already exists. Do you want to overwrite it?</string>
|
||||||
|
@ -351,6 +354,9 @@
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="google_qr_export_unexpected">Expected QR code #%d, but scanned #%d instead</string>
|
<string name="google_qr_export_unexpected">Expected QR code #%d, but scanned #%d instead</string>
|
||||||
<string name="backup_error_bar_message"><b>Vault backup failed recently</b></string>
|
<string name="backup_error_bar_message"><b>Vault backup failed recently</b></string>
|
||||||
|
<string name="backup_error_dialog_details">A recent vault backup attempt using %s failed because an error occurred. The backup was attempted at: %s. Please check your backup settings to make sure backups can complete successfully.</string>
|
||||||
|
<string name="backup_system_builtin">Aegis\' built-in automatic backups</string>
|
||||||
|
<string name="backup_system_android">Android\'s cloud backup system</string>
|
||||||
<string name="backup_reminder_bar_message"><b>Recent vault changes are not backed up</b></string>
|
<string name="backup_reminder_bar_message"><b>Recent vault changes are not backed up</b></string>
|
||||||
<string name="backup_plaintext_export_warning"><b>The vault was recently exported in plain text</b></string>
|
<string name="backup_plaintext_export_warning"><b>The vault was recently exported in plain text</b></string>
|
||||||
<string name="pref_show_plaintext_warning_hint">Don\'t show this warning again</string>
|
<string name="pref_show_plaintext_warning_hint">Don\'t show this warning again</string>
|
||||||
|
|
|
@ -25,6 +25,11 @@
|
||||||
android:key="pref_backups_versions"
|
android:key="pref_backups_versions"
|
||||||
android:title="@string/pref_backups_versions_title"
|
android:title="@string/pref_backups_versions_title"
|
||||||
app:iconSpaceReserved="false"/>
|
app:iconSpaceReserved="false"/>
|
||||||
|
<Preference
|
||||||
|
android:key="pref_status_backup_builtin"
|
||||||
|
android:persistent="false"
|
||||||
|
android:selectable="false"
|
||||||
|
app:iconSpaceReserved="false"/>
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
<PreferenceCategory
|
<PreferenceCategory
|
||||||
android:title="@string/pref_cat_backups_android"
|
android:title="@string/pref_cat_backups_android"
|
||||||
|
@ -36,6 +41,12 @@
|
||||||
android:summary="@string/pref_android_backups_summary"
|
android:summary="@string/pref_android_backups_summary"
|
||||||
app:iconSpaceReserved="false"/>
|
app:iconSpaceReserved="false"/>
|
||||||
<Preference
|
<Preference
|
||||||
|
android:key="pref_status_backup_android"
|
||||||
|
android:persistent="false"
|
||||||
|
android:selectable="false"
|
||||||
|
app:iconSpaceReserved="false"/>
|
||||||
|
<Preference
|
||||||
|
android:persistent="false"
|
||||||
android:selectable="false"
|
android:selectable="false"
|
||||||
android:summary="@string/pref_android_backups_hint"
|
android:summary="@string/pref_android_backups_hint"
|
||||||
app:iconSpaceReserved="false"/>
|
app:iconSpaceReserved="false"/>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue