Merge pull request #111 from andOTP/google-backups
Allow auto backups to Google sync
This commit is contained in:
commit
cbec5458da
8 changed files with 126 additions and 11 deletions
|
@ -6,7 +6,9 @@
|
|||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
|
||||
<application
|
||||
android:allowBackup="false"
|
||||
android:allowBackup="true"
|
||||
android:backupAgent=".Utilities.BackupAgent"
|
||||
android:fullBackupOnly="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:supportsRtl="true"
|
||||
|
|
|
@ -22,18 +22,26 @@
|
|||
|
||||
package org.shadowice.flocke.andotp.Activities;
|
||||
|
||||
import android.app.KeyguardManager;
|
||||
import android.app.backup.BackupManager;
|
||||
import android.app.backup.RestoreObserver;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.preference.CheckBoxPreference;
|
||||
import android.preference.ListPreference;
|
||||
import android.preference.Preference;
|
||||
import android.preference.PreferenceCategory;
|
||||
import android.preference.PreferenceFragment;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.design.widget.Snackbar;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.ViewStub;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.openintents.openpgp.util.OpenPgpAppPreference;
|
||||
|
@ -114,10 +122,24 @@ public class SettingsActivity extends BaseActivity
|
|||
}
|
||||
|
||||
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
|
||||
BackupManager backupManager = new BackupManager(this);
|
||||
backupManager.dataChanged();
|
||||
|
||||
if (key.equals(getString(R.string.settings_key_theme)) ||
|
||||
key.equals(getString(R.string.settings_key_locale)) ||
|
||||
key.equals(getString(R.string.settings_key_special_features))) {
|
||||
recreate();
|
||||
}else if(key.equals(getString(R.string.settings_key_encryption))) {
|
||||
if(settings.getEncryption() != EncryptionType.PASSWORD) {
|
||||
boolean wasSyncEnabled = settings.getAndroidBackupServiceEnabled();
|
||||
settings.setAndroidBackupServiceEnabled(false);
|
||||
|
||||
if(wasSyncEnabled) {
|
||||
UIHelper.showGenericDialog(this,
|
||||
R.string.settings_dialog_title_android_sync,
|
||||
R.string.settings_dialog_msg_android_sync_disabled_encryption);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -207,7 +229,8 @@ public class SettingsActivity extends BaseActivity
|
|||
}
|
||||
}
|
||||
|
||||
public static class SettingsFragment extends PreferenceFragment {
|
||||
public static class SettingsFragment extends PreferenceFragment
|
||||
implements SharedPreferences.OnSharedPreferenceChangeListener{
|
||||
PreferenceCategory catSecurity;
|
||||
|
||||
Settings settings;
|
||||
|
@ -216,6 +239,13 @@ public class SettingsActivity extends BaseActivity
|
|||
OpenPgpAppPreference pgpProvider;
|
||||
OpenPgpKeyPreference pgpKey;
|
||||
|
||||
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
|
||||
CheckBoxPreference useAndroidSync = (CheckBoxPreference) findPreference(getString(R.string.settings_key_enable_android_backup_service));
|
||||
useAndroidSync.setEnabled(settings.getEncryption() == EncryptionType.PASSWORD);
|
||||
if(!useAndroidSync.isEnabled())
|
||||
useAndroidSync.setChecked(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
@ -223,6 +253,7 @@ public class SettingsActivity extends BaseActivity
|
|||
settings = new Settings(getActivity());
|
||||
|
||||
final SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getActivity().getBaseContext());
|
||||
sharedPref.registerOnSharedPreferenceChangeListener(this);
|
||||
addPreferencesFromResource(R.xml.preferences);
|
||||
|
||||
CredentialsPreference credentialsPreference = (CredentialsPreference) findPreference(getString(R.string.settings_key_auth));
|
||||
|
@ -251,9 +282,9 @@ public class SettingsActivity extends BaseActivity
|
|||
} else {
|
||||
if (settings.getAuthCredentials().isEmpty()) {
|
||||
UIHelper.showGenericDialog(getActivity(), R.string.settings_dialog_title_error, R.string.settings_dialog_msg_encryption_invalid_without_credentials);
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
((SettingsActivity) getActivity()).tryEncryptionChangeWithAuth(encryptionType);
|
||||
} else if (encryptionType == EncryptionType.KEYSTORE) {
|
||||
|
@ -278,6 +309,8 @@ public class SettingsActivity extends BaseActivity
|
|||
});
|
||||
pgpKey.setDefaultUserId("Alice <alice@example.com>");
|
||||
|
||||
CheckBoxPreference useAndroidSync = (CheckBoxPreference) findPreference(getString(R.string.settings_key_enable_android_backup_service));
|
||||
useAndroidSync.setEnabled(settings.getEncryption() == EncryptionType.PASSWORD);
|
||||
|
||||
if (sharedPref.contains(getString(R.string.settings_key_special_features)) &&
|
||||
sharedPref.getBoolean(getString(R.string.settings_key_special_features), false)) {
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
package org.shadowice.flocke.andotp.Utilities;
|
||||
|
||||
import android.app.backup.BackupAgentHelper;
|
||||
import android.app.backup.BackupDataInput;
|
||||
import android.app.backup.BackupDataOutput;
|
||||
import android.app.backup.FileBackupHelper;
|
||||
import android.app.backup.SharedPreferencesBackupHelper;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class BackupAgent extends BackupAgentHelper {
|
||||
static final String PREFS_BACKUP_KEY = "prefs";
|
||||
static final String FILES_BACKUP_KEY = "files";
|
||||
|
||||
// PreferenceManager.getDefaultSharedPreferencesName is only available in API > 24, this is its implementation
|
||||
String getDefaultSharedPreferencesName() {
|
||||
return getPackageName() + "_preferences";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data, ParcelFileDescriptor newState) throws IOException {
|
||||
Settings settings = new Settings(this);
|
||||
|
||||
if(settings.getAndroidBackupServiceEnabled()) {
|
||||
synchronized (DatabaseHelper.DatabaseFileLock) {
|
||||
super.onBackup(oldState, data, newState);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState) throws IOException {
|
||||
synchronized (DatabaseHelper.DatabaseFileLock) {
|
||||
super.onRestore(data, appVersionCode, newState);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
String prefs = getDefaultSharedPreferencesName();
|
||||
|
||||
SharedPreferencesBackupHelper sharedPreferencesBackupHelper = new SharedPreferencesBackupHelper(this, prefs);
|
||||
addHelper(PREFS_BACKUP_KEY, sharedPreferencesBackupHelper);
|
||||
|
||||
FileBackupHelper fileBackupHelper = new FileBackupHelper(this, Constants.FILENAME_DATABASE, Constants.FILENAME_DATABASE_BACKUP);
|
||||
addHelper(FILES_BACKUP_KEY, fileBackupHelper);
|
||||
}
|
||||
}
|
|
@ -23,6 +23,7 @@
|
|||
|
||||
package org.shadowice.flocke.andotp.Utilities;
|
||||
|
||||
import android.app.backup.BackupManager;
|
||||
import android.content.Context;
|
||||
import android.widget.Toast;
|
||||
|
||||
|
@ -42,6 +43,8 @@ import javax.crypto.SecretKey;
|
|||
|
||||
public class DatabaseHelper {
|
||||
|
||||
static final Object DatabaseFileLock = new Object();
|
||||
|
||||
public static void wipeDatabase(Context context) {
|
||||
File db = new File(context.getFilesDir() + "/" + Constants.FILENAME_DATABASE);
|
||||
File dbBackup = new File(context.getFilesDir() + "/" + Constants.FILENAME_DATABASE_BACKUP);
|
||||
|
@ -102,15 +105,19 @@ public class DatabaseHelper {
|
|||
String jsonString = entriesToString(entries);
|
||||
|
||||
try {
|
||||
byte[] data = EncryptionHelper.encrypt(encryptionKey, jsonString.getBytes());
|
||||
|
||||
FileHelper.writeBytesToFile(new File(context.getFilesDir() + "/" + Constants.FILENAME_DATABASE), data);
|
||||
synchronized (DatabaseHelper.DatabaseFileLock) {
|
||||
byte[] data = EncryptionHelper.encrypt(encryptionKey, jsonString.getBytes());
|
||||
|
||||
FileHelper.writeBytesToFile(new File(context.getFilesDir() + "/" + Constants.FILENAME_DATABASE), data);
|
||||
}
|
||||
} catch (Exception error) {
|
||||
error.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
|
||||
BackupManager backupManager = new BackupManager(context);
|
||||
backupManager.dataChanged();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -119,10 +126,12 @@ public class DatabaseHelper {
|
|||
|
||||
if (encryptionKey != null) {
|
||||
try {
|
||||
byte[] data = FileHelper.readFileToBytes(new File(context.getFilesDir() + "/" + Constants.FILENAME_DATABASE));
|
||||
data = EncryptionHelper.decrypt(encryptionKey, data);
|
||||
synchronized (DatabaseHelper.DatabaseFileLock) {
|
||||
byte[] data = FileHelper.readFileToBytes(new File(context.getFilesDir() + "/" + Constants.FILENAME_DATABASE));
|
||||
data = EncryptionHelper.decrypt(encryptionKey, data);
|
||||
|
||||
entries = stringToEntries(new String(data));
|
||||
entries = stringToEntries(new String(data));
|
||||
}
|
||||
} catch (Exception error) {
|
||||
error.printStackTrace();
|
||||
}
|
||||
|
|
|
@ -469,6 +469,14 @@ public class Settings {
|
|||
setBoolean(R.string.settings_key_last_used_dialog_shown, value);
|
||||
}
|
||||
|
||||
public boolean getAndroidBackupServiceEnabled() {
|
||||
return getBoolean(R.string.settings_key_enable_android_backup_service, false);
|
||||
}
|
||||
|
||||
public void setAndroidBackupServiceEnabled(boolean value) {
|
||||
setBoolean(R.string.settings_key_enable_android_backup_service, value);
|
||||
}
|
||||
|
||||
public boolean getIsAppendingDateTimeToBackups() {
|
||||
return getBoolean(R.string.settings_key_backup_append_date_time, false);
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
<string name="settings_key_tags_toggles" translatable="false">pref_tags_toggles</string>
|
||||
|
||||
<string name="settings_key_enable_screenshot" translatable="false">pref_enable_screenshot</string>
|
||||
<string name="settings_key_enable_android_backup_service" translatable="false">pref_enable_android_backup_service</string>
|
||||
<string name="settings_key_clear_keystore" translatable="false">pref_clear_keystore</string>
|
||||
|
||||
<string name="settings_key_last_used_dialog_shown" translatable="false">pref_last_used_dialog_shown</string>
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
|
||||
<string name="settings_title_special_features">Enable special features</string>
|
||||
<string name="settings_title_enable_screenshot">Enable screenshots</string>
|
||||
<string name="settings_title_enable_android_backup_service">Enable android sync</string>
|
||||
<string name="settings_title_clear_keystore">Clear KeyStore</string>
|
||||
|
||||
<!-- Descriptions -->
|
||||
|
@ -64,6 +65,8 @@
|
|||
<string name="settings_desc_special_features">Uncheck to disable the special features again</string>
|
||||
<string name="settings_desc_enable_screenshot">Allow to take screenshots of the main screen
|
||||
(disabled by default for security reasons)</string>
|
||||
<string name="settings_desc_enable_android_backup_service">Enables andOTP to use android\'s
|
||||
built in backup service to bacup keys and preferences</string>
|
||||
<string name="settings_desc_clear_keystore">Delete the encryption key from the KeyStore</string>
|
||||
|
||||
<!-- Toasts -->
|
||||
|
@ -91,6 +94,7 @@
|
|||
|
||||
<string name="settings_dialog_title_error">Error</string>
|
||||
<string name="settings_dialog_title_clear_keystore">Clear the KeyStore?</string>
|
||||
<string name="settings_dialog_title_android_sync">Android sync</string>
|
||||
|
||||
<string name="settings_dialog_msg_auth_invalid_with_encryption">You can only use Password or PIN as
|
||||
long as the database encryption is set to \"Password / PIN\"!</string>
|
||||
|
@ -110,6 +114,9 @@
|
|||
your accounts. Make sure you have a backup!\n\n<b>Are you really sure you want to clear the
|
||||
KeyStore?</b></string>
|
||||
|
||||
<string name="settings_dialog_msg_android_sync_disabled_encryption">Android sync can not be used with keystore
|
||||
encryption, <b>you should perform a manual backup!</b></string>
|
||||
|
||||
<!-- List entries -->
|
||||
<string-array name="settings_entries_auth">
|
||||
<item>None</item>
|
||||
|
@ -165,4 +172,4 @@
|
|||
|
||||
<string name="settings_label_short_password">The password needs to be at least %1$d characters long!</string>
|
||||
<string name="settings_label_short_pin">The PIN needs to be at least %1$d digits long!</string>
|
||||
</resources>
|
||||
</resources>
|
||||
|
|
|
@ -104,6 +104,12 @@
|
|||
<PreferenceCategory
|
||||
android:title="@string/settings_category_title_backup">
|
||||
|
||||
<CheckBoxPreference
|
||||
android:key="@string/settings_key_enable_android_backup_service"
|
||||
android:title="@string/settings_title_enable_android_backup_service"
|
||||
android:summary="@string/settings_desc_enable_android_backup_service"
|
||||
android:defaultValue="false" />
|
||||
|
||||
<CheckBoxPreference
|
||||
android:key="@string/settings_key_backup_append_date_time"
|
||||
android:title="@string/settings_title_backup_append_date"
|
||||
|
|
Loading…
Reference in a new issue