mirror of
https://github.com/beemdevelopment/Aegis.git
synced 2025-04-23 23:39:14 +00:00
Improve backup error handling and frequency
This patch improves our backup functionality in a number of ways: - Only backup the vault when important changes are made, not when the order of entries is changed, for instance. - Don't bubble up backup errors when saving the vault. - Instead, show an error bar in the main view if the most recent backup attempt failed. <img src="https://alexbakker.me/u/kbhhj2hcgx.png" width="300" /> Clicking on the error bar will take the user to the backup settings.
This commit is contained in:
parent
ae5502b650
commit
08ab8237e7
11 changed files with 116 additions and 28 deletions
|
@ -160,6 +160,14 @@ public class Preferences {
|
|||
_prefs.edit().putInt("pref_backups_versions", versions).apply();
|
||||
}
|
||||
|
||||
public void setBackupsError(Exception e) {
|
||||
_prefs.edit().putString("pref_backups_error", e == null ? null : e.toString()).apply();
|
||||
}
|
||||
|
||||
public String getBackupsError() {
|
||||
return _prefs.getString("pref_backups_error", null);
|
||||
}
|
||||
|
||||
public boolean isTimeSyncWarningEnabled() {
|
||||
return _prefs.getBoolean("pref_warn_time_sync", true);
|
||||
}
|
||||
|
|
|
@ -122,9 +122,9 @@ public abstract class AegisActivity extends AppCompatActivity implements AegisAp
|
|||
this.getResources().updateConfiguration(config, this.getResources().getDisplayMetrics());
|
||||
}
|
||||
|
||||
protected boolean saveVault() {
|
||||
protected boolean saveVault(boolean backup) {
|
||||
try {
|
||||
getApp().getVaultManager().save();
|
||||
getApp().getVaultManager().save(backup);
|
||||
return true;
|
||||
} catch (VaultManagerException e) {
|
||||
Toast.makeText(this, getString(R.string.saving_error), Toast.LENGTH_LONG).show();
|
||||
|
|
|
@ -36,7 +36,6 @@ import com.beemdevelopment.aegis.helpers.UiThreadExecutor;
|
|||
import com.beemdevelopment.aegis.ui.tasks.PasswordSlotDecryptTask;
|
||||
import com.beemdevelopment.aegis.vault.VaultFile;
|
||||
import com.beemdevelopment.aegis.vault.VaultFileCredentials;
|
||||
import com.beemdevelopment.aegis.vault.VaultManager;
|
||||
import com.beemdevelopment.aegis.vault.VaultManagerException;
|
||||
import com.beemdevelopment.aegis.vault.slots.BiometricSlot;
|
||||
import com.beemdevelopment.aegis.vault.slots.PasswordSlot;
|
||||
|
@ -273,10 +272,9 @@ public class AuthActivity extends AegisActivity {
|
|||
} else {
|
||||
try {
|
||||
AegisApplication app = getApp();
|
||||
VaultManager vault = app.initVaultManager(app.loadVaultFile(), creds);
|
||||
app.initVaultManager(app.loadVaultFile(), creds);
|
||||
if (isSlotRepaired) {
|
||||
vault.setCredentials(creds);
|
||||
saveVault();
|
||||
saveVault(true);
|
||||
}
|
||||
} catch (VaultManagerException e) {
|
||||
e.printStackTrace();
|
||||
|
|
|
@ -467,7 +467,7 @@ public class EditEntryActivity extends AegisActivity {
|
|||
intent.putExtra("entryUUID", entry.getUUID());
|
||||
intent.putExtra("delete", delete);
|
||||
|
||||
if (saveVault()) {
|
||||
if (saveVault(true)) {
|
||||
setResult(RESULT_OK, intent);
|
||||
finish();
|
||||
}
|
||||
|
|
|
@ -16,6 +16,8 @@ import android.view.MenuInflater;
|
|||
import android.view.MenuItem;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.SubMenu;
|
||||
import android.view.View;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.appcompat.view.ActionMode;
|
||||
|
@ -81,6 +83,7 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
|
|||
private SearchView _searchView;
|
||||
private FloatingActionsMenu _fabMenu;
|
||||
private EntryListView _entryListView;
|
||||
private LinearLayout _btnBackupError;
|
||||
|
||||
private FabScrollHelper _fabScrollHelper;
|
||||
|
||||
|
@ -125,6 +128,11 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
|
|||
startScanActivity();
|
||||
});
|
||||
|
||||
_btnBackupError = findViewById(R.id.btn_backup_error);
|
||||
_btnBackupError.setOnClickListener(view -> {
|
||||
startPreferencesActivity("pref_backups");
|
||||
});
|
||||
|
||||
_fabScrollHelper = new FabScrollHelper(_fabMenu);
|
||||
_selectedEntries = new ArrayList<>();
|
||||
}
|
||||
|
@ -264,7 +272,7 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
|
|||
}
|
||||
}
|
||||
|
||||
saveVault();
|
||||
saveVault(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -400,6 +408,12 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
|
|||
startActivityForResult(Intent.createChooser(chooserIntent, getString(R.string.select_picture)), CODE_SCAN_IMAGE);
|
||||
}
|
||||
|
||||
private void startPreferencesActivity(String preference) {
|
||||
Intent intent = new Intent(this, PreferencesActivity.class);
|
||||
intent.putExtra("pref", preference);
|
||||
startActivityForResult(intent, CODE_PREFERENCES);
|
||||
}
|
||||
|
||||
private void doShortcutActions() {
|
||||
Intent intent = getIntent();
|
||||
String action = intent.getStringExtra("action");
|
||||
|
@ -489,6 +503,7 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
|
|||
handleDeeplink();
|
||||
updateLockIcon();
|
||||
doShortcutActions();
|
||||
updateBackupErrorBar();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -517,7 +532,7 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
|
|||
_entryListView.removeEntry(oldEntry);
|
||||
}
|
||||
|
||||
saveVault();
|
||||
saveVault(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -567,8 +582,7 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
|
|||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.action_settings: {
|
||||
Intent intent = new Intent(this, PreferencesActivity.class);
|
||||
startActivityForResult(intent, CODE_PREFERENCES);
|
||||
startPreferencesActivity(null);
|
||||
return true;
|
||||
}
|
||||
case R.id.action_about: {
|
||||
|
@ -647,6 +661,15 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
|
|||
}
|
||||
}
|
||||
|
||||
private void updateBackupErrorBar() {
|
||||
String error = null;
|
||||
if (_app.getPreferences().isBackupsEnabled()) {
|
||||
error = _app.getPreferences().getBackupsError();
|
||||
}
|
||||
|
||||
_btnBackupError.setVisibility(error == null ? View.GONE : View.VISIBLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEntryClick(VaultEntry entry) {
|
||||
if (_actionMode != null) {
|
||||
|
@ -694,12 +717,12 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
|
|||
|
||||
@Override
|
||||
public void onEntryDrop(VaultEntry entry) {
|
||||
saveVault();
|
||||
saveVault(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEntryChange(VaultEntry entry) {
|
||||
saveVault();
|
||||
saveVault(true);
|
||||
}
|
||||
|
||||
public void onEntryCopy(VaultEntry entry) {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package com.beemdevelopment.aegis.ui;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.MenuItem;
|
||||
|
||||
|
@ -24,6 +25,18 @@ public class PreferencesActivity extends AegisActivity {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
|
||||
Intent intent = getIntent();
|
||||
String preference = intent.getStringExtra("pref");
|
||||
if (preference != null) {
|
||||
_fragment.scrollToPreference(preference);
|
||||
intent.removeExtra("pref");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
|
||||
// pass permission request results to the fragment
|
||||
|
|
|
@ -434,8 +434,8 @@ public class PreferencesFragment extends PreferenceFragmentCompat {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(Bundle savedInstanceState) {
|
||||
super.onActivityCreated(savedInstanceState);
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
updateEncryptionPreferences();
|
||||
updateBackupPreference();
|
||||
}
|
||||
|
@ -749,13 +749,14 @@ public class PreferencesFragment extends PreferenceFragmentCompat {
|
|||
|
||||
_prefs.setBackupsLocation(uri);
|
||||
_prefs.setIsBackupsEnabled(true);
|
||||
_prefs.setBackupsError(null);
|
||||
_backupsLocationPreference.setSummary(String.format("%s: %s", getString(R.string.pref_backups_location_summary), Uri.decode(uri.toString())));
|
||||
updateBackupPreference();
|
||||
}
|
||||
|
||||
private boolean saveVault() {
|
||||
try {
|
||||
_vault.save();
|
||||
_vault.save(true);
|
||||
} catch (VaultManagerException e) {
|
||||
e.printStackTrace();
|
||||
Dialogs.showErrorDialog(getContext(), R.string.saving_error, e);
|
||||
|
|
|
@ -96,7 +96,7 @@ public class VaultManager {
|
|||
}
|
||||
}
|
||||
|
||||
public void save() throws VaultManagerException {
|
||||
public void save(boolean backup) throws VaultManagerException {
|
||||
try {
|
||||
JSONObject obj = _vault.toJson();
|
||||
|
||||
|
@ -108,13 +108,18 @@ public class VaultManager {
|
|||
}
|
||||
|
||||
save(_context, file);
|
||||
|
||||
if (_prefs.isBackupsEnabled()) {
|
||||
backup();
|
||||
}
|
||||
} catch (VaultFileException e) {
|
||||
throw new VaultManagerException(e);
|
||||
}
|
||||
|
||||
if (backup && _prefs.isBackupsEnabled()) {
|
||||
try {
|
||||
backup();
|
||||
_prefs.setBackupsError(null);
|
||||
} catch (VaultManagerException e) {
|
||||
_prefs.setBackupsError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void export(OutputStream stream, boolean encrypt) throws VaultManagerException {
|
||||
|
@ -190,11 +195,11 @@ public class VaultManager {
|
|||
|
||||
public void enableEncryption(VaultFileCredentials creds) throws VaultManagerException {
|
||||
_creds = creds;
|
||||
save();
|
||||
save(true);
|
||||
}
|
||||
|
||||
public void disableEncryption() throws VaultManagerException {
|
||||
_creds = null;
|
||||
save();
|
||||
save(true);
|
||||
}
|
||||
}
|
||||
|
|
8
app/src/main/res/drawable/ic_alert_black_24dp.xml
Normal file
8
app/src/main/res/drawable/ic_alert_black_24dp.xml
Normal file
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24dp"
|
||||
android:width="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path android:fillColor="#000" android:pathData="M13,14H11V10H13M13,18H11V16H13M1,21H23L12,2L1,21Z" />
|
||||
</vector>
|
|
@ -8,12 +8,43 @@
|
|||
android:fitsSystemWindows="true"
|
||||
tools:context="com.beemdevelopment.aegis.ui.MainActivity">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
<LinearLayout
|
||||
android:id="@+id/btn_backup_error"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:visibility="gone"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:paddingHorizontal="10dp"
|
||||
android:paddingVertical="10dp"
|
||||
android:background="@color/colorAccent"
|
||||
android:foreground="?android:selectableItemBackground"
|
||||
android:gravity="center">
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:tint="@color/icon_primary_inverted"
|
||||
android:src="@drawable/ic_alert_black_24dp" />
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/backup_error_bar_message"
|
||||
android:textColor="@color/primary_text_inverted"
|
||||
android:layout_marginStart="5dp" />
|
||||
</LinearLayout>
|
||||
|
||||
<fragment
|
||||
android:name="com.beemdevelopment.aegis.ui.views.EntryListView"
|
||||
android:id="@+id/key_profiles"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_width="match_parent"
|
||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"/>
|
||||
</LinearLayout>
|
||||
|
||||
<!-- note: the fab should always be the last element to be sure it's displayed on top -->
|
||||
<com.getbase.floatingactionbutton.FloatingActionsMenu
|
||||
|
|
|
@ -248,6 +248,7 @@
|
|||
<string name="google_qr_export_unrelated">Unrelated QR code found. Try restarting the scanner.</string>
|
||||
<string name="google_qr_export_scanned">Scanned %d/%d QR codes</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="custom_notices_format_style" translatable="false" >
|
||||
body {
|
||||
|
|
Loading…
Add table
Reference in a new issue