Refactor backup activity to better work with background tasks
This commit is contained in:
parent
e1ced76b55
commit
feeeba7294
7 changed files with 417 additions and 408 deletions
|
@ -36,11 +36,16 @@ import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewStub;
|
import android.view.ViewStub;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.AdapterView;
|
||||||
import android.widget.Switch;
|
import android.widget.Button;
|
||||||
|
import android.widget.CheckBox;
|
||||||
|
import android.widget.ProgressBar;
|
||||||
|
import android.widget.Spinner;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import com.google.android.material.switchmaterial.SwitchMaterial;
|
||||||
|
|
||||||
import org.openintents.openpgp.OpenPgpError;
|
import org.openintents.openpgp.OpenPgpError;
|
||||||
import org.openintents.openpgp.OpenPgpSignatureResult;
|
import org.openintents.openpgp.OpenPgpSignatureResult;
|
||||||
import org.openintents.openpgp.util.OpenPgpApi;
|
import org.openintents.openpgp.util.OpenPgpApi;
|
||||||
|
@ -48,6 +53,7 @@ import org.openintents.openpgp.util.OpenPgpServiceConnection;
|
||||||
import org.shadowice.flocke.andotp.Database.Entry;
|
import org.shadowice.flocke.andotp.Database.Entry;
|
||||||
import org.shadowice.flocke.andotp.Dialogs.PasswordEntryDialog;
|
import org.shadowice.flocke.andotp.Dialogs.PasswordEntryDialog;
|
||||||
import org.shadowice.flocke.andotp.R;
|
import org.shadowice.flocke.andotp.R;
|
||||||
|
import org.shadowice.flocke.andotp.Tasks.BackupTask;
|
||||||
import org.shadowice.flocke.andotp.Utilities.BackupHelper;
|
import org.shadowice.flocke.andotp.Utilities.BackupHelper;
|
||||||
import org.shadowice.flocke.andotp.Utilities.Constants;
|
import org.shadowice.flocke.andotp.Utilities.Constants;
|
||||||
import org.shadowice.flocke.andotp.Utilities.DatabaseHelper;
|
import org.shadowice.flocke.andotp.Utilities.DatabaseHelper;
|
||||||
|
@ -67,9 +73,11 @@ import java.util.concurrent.Executors;
|
||||||
|
|
||||||
import javax.crypto.SecretKey;
|
import javax.crypto.SecretKey;
|
||||||
|
|
||||||
public class BackupActivity extends BaseActivity {
|
public class BackupActivity extends BaseActivity
|
||||||
|
implements BackupTask.BackupCallback {
|
||||||
private final static String TAG = BackupActivity.class.getSimpleName();
|
private final static String TAG = BackupActivity.class.getSimpleName();
|
||||||
|
|
||||||
|
private Constants.BackupType backupType = Constants.BackupType.ENCRYPTED;
|
||||||
private SecretKey encryptionKey = null;
|
private SecretKey encryptionKey = null;
|
||||||
|
|
||||||
private OpenPgpServiceConnection pgpServiceConnection;
|
private OpenPgpServiceConnection pgpServiceConnection;
|
||||||
|
@ -78,7 +86,14 @@ public class BackupActivity extends BaseActivity {
|
||||||
private Uri encryptTargetFile;
|
private Uri encryptTargetFile;
|
||||||
private Uri decryptSourceFile;
|
private Uri decryptSourceFile;
|
||||||
|
|
||||||
private Switch replace;
|
private Button btnBackup;
|
||||||
|
private Button btnRestore;
|
||||||
|
private TextView txtBackupLabel;
|
||||||
|
private TextView txtBackupWarning;
|
||||||
|
private SwitchMaterial swReplace;
|
||||||
|
private CheckBox chkOldFormat;
|
||||||
|
private ProgressBar progressBackup;
|
||||||
|
private ProgressBar progressRestore;
|
||||||
|
|
||||||
private boolean reload = false;
|
private boolean reload = false;
|
||||||
|
|
||||||
|
@ -100,96 +115,119 @@ public class BackupActivity extends BaseActivity {
|
||||||
byte[] keyMaterial = callingIntent.getByteArrayExtra(Constants.EXTRA_BACKUP_ENCRYPTION_KEY);
|
byte[] keyMaterial = callingIntent.getByteArrayExtra(Constants.EXTRA_BACKUP_ENCRYPTION_KEY);
|
||||||
encryptionKey = EncryptionHelper.generateSymmetricKey(keyMaterial);
|
encryptionKey = EncryptionHelper.generateSymmetricKey(keyMaterial);
|
||||||
|
|
||||||
// Plain-text
|
Spinner spBackupType = v.findViewById(R.id.backupType);
|
||||||
|
btnBackup = v.findViewById(R.id.buttonBackup);
|
||||||
|
btnRestore = v.findViewById(R.id.buttonRestore);
|
||||||
|
txtBackupLabel = v.findViewById(R.id.backupLabel);
|
||||||
|
txtBackupWarning = v.findViewById(R.id.backupErrorLabel);
|
||||||
|
swReplace = v.findViewById(R.id.backup_replace);
|
||||||
|
chkOldFormat = v.findViewById(R.id.restoreOldCrypt);
|
||||||
|
progressBackup = v.findViewById(R.id.progressBarBackup);
|
||||||
|
progressRestore = v.findViewById(R.id.progressBarRestore);
|
||||||
|
|
||||||
LinearLayout backupPlain = v.findViewById(R.id.button_backup_plain);
|
setupBackupType(settings.getDefaultBackupType());
|
||||||
LinearLayout restorePlain = v.findViewById(R.id.button_restore_plain);
|
spBackupType.setSelection(backupType.ordinal());
|
||||||
|
|
||||||
backupPlain.setOnClickListener(new View.OnClickListener() {
|
spBackupType.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View view) {
|
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
|
||||||
backupPlainWithWarning();
|
Constants.BackupType type = Constants.BackupType.values()[i];
|
||||||
|
setupBackupType(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onNothingSelected(AdapterView<?> adapterView) { }
|
||||||
});
|
});
|
||||||
|
|
||||||
restorePlain.setOnClickListener(new View.OnClickListener() {
|
btnBackup.setOnClickListener(view -> {
|
||||||
@Override
|
switch (backupType) {
|
||||||
public void onClick(View view) {
|
case PLAIN_TEXT:
|
||||||
showOpenFileSelector(Constants.INTENT_BACKUP_OPEN_DOCUMENT_PLAIN);
|
backupPlainWithWarning();
|
||||||
}
|
break;
|
||||||
});
|
case ENCRYPTED:
|
||||||
|
showSaveFileSelector(Constants.BACKUP_MIMETYPE_CRYPT, Constants.BackupType.ENCRYPTED, Constants.INTENT_BACKUP_SAVE_DOCUMENT_CRYPT);
|
||||||
// Password
|
break;
|
||||||
|
case OPEN_PGP:
|
||||||
TextView cryptSetup = v.findViewById(R.id.msg_crypt_setup);
|
|
||||||
LinearLayout backupCrypt = v.findViewById(R.id.button_backup_crypt);
|
|
||||||
LinearLayout restoreCrypt = v.findViewById(R.id.button_restore_crypt);
|
|
||||||
LinearLayout restoreCryptOld = v.findViewById(R.id.button_restore_crypt_old);
|
|
||||||
|
|
||||||
if (settings.getBackupPasswordEnc().isEmpty()) {
|
|
||||||
cryptSetup.setVisibility(View.VISIBLE);
|
|
||||||
} else {
|
|
||||||
cryptSetup.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
backupCrypt.setOnClickListener(new View.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View view) {
|
|
||||||
showSaveFileSelector(Constants.BACKUP_MIMETYPE_CRYPT, Constants.BackupType.ENCRYPTED, Constants.INTENT_BACKUP_SAVE_DOCUMENT_CRYPT);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
restoreCrypt.setOnClickListener(new View.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View view) {
|
|
||||||
showOpenFileSelector(Constants.INTENT_BACKUP_OPEN_DOCUMENT_CRYPT);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
restoreCryptOld.setOnClickListener(new View.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View view) {
|
|
||||||
showOpenFileSelector(Constants.INTENT_BACKUP_OPEN_DOCUMENT_CRYPT_OLD);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// OpenPGP
|
|
||||||
|
|
||||||
String PGPProvider = settings.getOpenPGPProvider();
|
|
||||||
pgpEncryptionUserIDs = settings.getOpenPGPEncryptionUserIDs();
|
|
||||||
|
|
||||||
TextView setupPGP = v.findViewById(R.id.msg_openpgp_setup);
|
|
||||||
LinearLayout backupPGP = v.findViewById(R.id.button_backup_openpgp);
|
|
||||||
LinearLayout restorePGP = v.findViewById(R.id.button_restore_openpgp);
|
|
||||||
|
|
||||||
if (TextUtils.isEmpty(PGPProvider)) {
|
|
||||||
setupPGP.setVisibility(View.VISIBLE);
|
|
||||||
backupPGP.setVisibility(View.GONE);
|
|
||||||
restorePGP.setVisibility(View.GONE);
|
|
||||||
} else if (TextUtils.isEmpty(pgpEncryptionUserIDs)){
|
|
||||||
setupPGP.setVisibility(View.VISIBLE);
|
|
||||||
setupPGP.setText(R.string.backup_desc_openpgp_keyid);
|
|
||||||
backupPGP.setVisibility(View.GONE);
|
|
||||||
} else {
|
|
||||||
pgpServiceConnection = new OpenPgpServiceConnection(BackupActivity.this.getApplicationContext(), PGPProvider);
|
|
||||||
pgpServiceConnection.bindToService();
|
|
||||||
|
|
||||||
backupPGP.setOnClickListener(new View.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View view) {
|
|
||||||
showSaveFileSelector(Constants.BACKUP_MIMETYPE_PGP, Constants.BackupType.OPEN_PGP, Constants.INTENT_BACKUP_SAVE_DOCUMENT_PGP);
|
showSaveFileSelector(Constants.BACKUP_MIMETYPE_PGP, Constants.BackupType.OPEN_PGP, Constants.INTENT_BACKUP_SAVE_DOCUMENT_PGP);
|
||||||
}
|
break;
|
||||||
});
|
}
|
||||||
|
});
|
||||||
|
|
||||||
restorePGP.setOnClickListener(new View.OnClickListener() {
|
btnRestore.setOnClickListener(view -> {
|
||||||
@Override
|
switch (backupType) {
|
||||||
public void onClick(View view) {
|
case PLAIN_TEXT:
|
||||||
|
showOpenFileSelector(Constants.INTENT_BACKUP_OPEN_DOCUMENT_PLAIN);
|
||||||
|
break;
|
||||||
|
case ENCRYPTED:
|
||||||
|
if (chkOldFormat.isChecked())
|
||||||
|
showOpenFileSelector(Constants.INTENT_BACKUP_OPEN_DOCUMENT_CRYPT_OLD);
|
||||||
|
else
|
||||||
|
showOpenFileSelector(Constants.INTENT_BACKUP_OPEN_DOCUMENT_CRYPT);
|
||||||
|
break;
|
||||||
|
case OPEN_PGP:
|
||||||
showOpenFileSelector(Constants.INTENT_BACKUP_OPEN_DOCUMENT_PGP);
|
showOpenFileSelector(Constants.INTENT_BACKUP_OPEN_DOCUMENT_PGP);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setupBackupType(Constants.BackupType type) {
|
||||||
|
switch (type) {
|
||||||
|
case PLAIN_TEXT:
|
||||||
|
txtBackupLabel.setText(R.string.backup_label_warning_plain);
|
||||||
|
|
||||||
|
chkOldFormat.setVisibility(View.GONE);
|
||||||
|
txtBackupWarning.setVisibility(View.GONE);
|
||||||
|
|
||||||
|
btnBackup.setEnabled(true);
|
||||||
|
btnRestore.setEnabled(true);
|
||||||
|
|
||||||
|
break;
|
||||||
|
case ENCRYPTED:
|
||||||
|
txtBackupLabel.setText(R.string.backup_label_crypt);
|
||||||
|
|
||||||
|
chkOldFormat.setVisibility(View.VISIBLE);
|
||||||
|
txtBackupWarning.setVisibility(View.GONE);
|
||||||
|
|
||||||
|
btnBackup.setEnabled(true);
|
||||||
|
btnRestore.setEnabled(true);
|
||||||
|
|
||||||
|
break;
|
||||||
|
case OPEN_PGP:
|
||||||
|
txtBackupLabel.setText(R.string.backup_label_pgp);
|
||||||
|
|
||||||
|
chkOldFormat.setVisibility(View.GONE);
|
||||||
|
|
||||||
|
String PGPProvider = settings.getOpenPGPProvider();
|
||||||
|
pgpEncryptionUserIDs = settings.getOpenPGPEncryptionUserIDs();
|
||||||
|
|
||||||
|
if (TextUtils.isEmpty(PGPProvider)) {
|
||||||
|
txtBackupWarning.setText(R.string.backup_desc_openpgp_provider);
|
||||||
|
txtBackupWarning.setVisibility(View.VISIBLE);
|
||||||
|
|
||||||
|
btnBackup.setEnabled(false);
|
||||||
|
btnRestore.setEnabled(false);
|
||||||
|
} else if (TextUtils.isEmpty(pgpEncryptionUserIDs)){
|
||||||
|
txtBackupWarning.setText(R.string.backup_desc_openpgp_keyid);
|
||||||
|
txtBackupWarning.setVisibility(View.VISIBLE);
|
||||||
|
|
||||||
|
btnBackup.setEnabled(false);
|
||||||
|
btnRestore.setEnabled(false);
|
||||||
|
} else {
|
||||||
|
txtBackupWarning.setVisibility(View.GONE);
|
||||||
|
|
||||||
|
btnBackup.setEnabled(true);
|
||||||
|
btnRestore.setEnabled(true);
|
||||||
|
|
||||||
|
pgpServiceConnection = new OpenPgpServiceConnection(BackupActivity.this.getApplicationContext(), PGPProvider);
|
||||||
|
pgpServiceConnection.bindToService();
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
replace = v.findViewById(R.id.backup_replace);
|
backupType = type;
|
||||||
|
settings.setDefaultBackupType(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
// End with a result
|
// End with a result
|
||||||
|
@ -221,6 +259,38 @@ public class BackupActivity extends BaseActivity {
|
||||||
pgpServiceConnection.unbindFromService();
|
pgpServiceConnection.unbindFromService();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBackupFinished() {
|
||||||
|
hideProgress();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBackupFailed() {
|
||||||
|
hideProgress();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showProgress(boolean restore) {
|
||||||
|
btnBackup.setEnabled(false);
|
||||||
|
btnRestore.setEnabled(false);
|
||||||
|
chkOldFormat.setEnabled(false);
|
||||||
|
swReplace.setEnabled(false);
|
||||||
|
|
||||||
|
if (restore)
|
||||||
|
progressRestore.setVisibility(View.VISIBLE);
|
||||||
|
else
|
||||||
|
progressBackup.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void hideProgress() {
|
||||||
|
btnBackup.setEnabled(true);
|
||||||
|
btnRestore.setEnabled(true);
|
||||||
|
chkOldFormat.setEnabled(true);
|
||||||
|
swReplace.setEnabled(true);
|
||||||
|
|
||||||
|
progressRestore.setVisibility(View.GONE);
|
||||||
|
progressBackup.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
|
||||||
// Get the result from external activities
|
// Get the result from external activities
|
||||||
@Override
|
@Override
|
||||||
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
|
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
|
||||||
|
@ -293,26 +363,11 @@ public class BackupActivity extends BaseActivity {
|
||||||
} else {
|
} else {
|
||||||
if (settings.isBackupLocationSet()) {
|
if (settings.isBackupLocationSet()) {
|
||||||
if (intentId == Constants.INTENT_BACKUP_SAVE_DOCUMENT_PLAIN) {
|
if (intentId == Constants.INTENT_BACKUP_SAVE_DOCUMENT_PLAIN) {
|
||||||
BackupHelper.BackupFile plainBackupFile = BackupHelper.backupFile(this, settings.getBackupLocation(), Constants.BackupType.PLAIN_TEXT);
|
doBackupPlain(null);
|
||||||
|
|
||||||
if (plainBackupFile.file != null)
|
|
||||||
doBackupPlain(plainBackupFile.file.getUri());
|
|
||||||
else
|
|
||||||
Toast.makeText(this, plainBackupFile.errorMessage, Toast.LENGTH_LONG).show();
|
|
||||||
} else if (intentId == Constants.INTENT_BACKUP_SAVE_DOCUMENT_CRYPT) {
|
} else if (intentId == Constants.INTENT_BACKUP_SAVE_DOCUMENT_CRYPT) {
|
||||||
BackupHelper.BackupFile cryptBackupFile = BackupHelper.backupFile(this, settings.getBackupLocation(), Constants.BackupType.ENCRYPTED);
|
doBackupCrypt(null);
|
||||||
|
|
||||||
if (cryptBackupFile.file != null)
|
|
||||||
doBackupCrypt(cryptBackupFile.file.getUri());
|
|
||||||
else
|
|
||||||
Toast.makeText(this, cryptBackupFile.errorMessage, Toast.LENGTH_LONG).show();
|
|
||||||
} else if (intentId == Constants.INTENT_BACKUP_SAVE_DOCUMENT_PGP) {
|
} else if (intentId == Constants.INTENT_BACKUP_SAVE_DOCUMENT_PGP) {
|
||||||
BackupHelper.BackupFile pgpBackupFile = BackupHelper.backupFile(this, settings.getBackupLocation(), Constants.BackupType.OPEN_PGP);
|
backupEncryptedWithPGP(null, null);
|
||||||
|
|
||||||
if (pgpBackupFile.file != null)
|
|
||||||
backupEncryptedWithPGP(pgpBackupFile.file.getUri(), null);
|
|
||||||
else
|
|
||||||
Toast.makeText(this, pgpBackupFile.errorMessage, Toast.LENGTH_LONG).show();
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(this, R.string.backup_toast_no_location, Toast.LENGTH_LONG).show();
|
Toast.makeText(this, R.string.backup_toast_no_location, Toast.LENGTH_LONG).show();
|
||||||
|
@ -324,7 +379,7 @@ public class BackupActivity extends BaseActivity {
|
||||||
ArrayList<Entry> entries = DatabaseHelper.stringToEntries(text);
|
ArrayList<Entry> entries = DatabaseHelper.stringToEntries(text);
|
||||||
|
|
||||||
if (entries.size() > 0) {
|
if (entries.size() > 0) {
|
||||||
if (! replace.isChecked()) {
|
if (! swReplace.isChecked()) {
|
||||||
ArrayList<Entry> currentEntries = DatabaseHelper.loadDatabase(this, encryptionKey);
|
ArrayList<Entry> currentEntries = DatabaseHelper.loadDatabase(this, encryptionKey);
|
||||||
|
|
||||||
entries.removeAll(currentEntries);
|
entries.removeAll(currentEntries);
|
||||||
|
@ -360,14 +415,17 @@ public class BackupActivity extends BaseActivity {
|
||||||
ArrayList<Entry> entries = DatabaseHelper.loadDatabase(this, encryptionKey);
|
ArrayList<Entry> entries = DatabaseHelper.loadDatabase(this, encryptionKey);
|
||||||
|
|
||||||
ExecutorService executor = Executors.newSingleThreadExecutor();
|
ExecutorService executor = Executors.newSingleThreadExecutor();
|
||||||
BackupHelper.SaveStringToFile runnable = new BackupHelper.SaveStringToFile(this, uri, DatabaseHelper.entriesToString(entries));
|
|
||||||
|
|
||||||
executor.execute(runnable);
|
BackupTask backupTask = new BackupTask(this, Constants.BackupType.PLAIN_TEXT, DatabaseHelper.entriesToString(entries), this);
|
||||||
|
|
||||||
|
if (uri != null)
|
||||||
|
backupTask.setUri(uri);
|
||||||
|
|
||||||
|
showProgress(false);
|
||||||
|
executor.execute(backupTask);
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(this, R.string.backup_toast_storage_not_accessible, Toast.LENGTH_LONG).show();
|
Toast.makeText(this, R.string.backup_toast_storage_not_accessible, Toast.LENGTH_LONG).show();
|
||||||
}
|
}
|
||||||
|
|
||||||
finishWithResult();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void backupPlainWithWarning() {
|
private void backupPlainWithWarning() {
|
||||||
|
@ -466,12 +524,11 @@ public class BackupActivity extends BaseActivity {
|
||||||
|
|
||||||
private void doBackupCryptWithPassword(Uri uri, String password) {
|
private void doBackupCryptWithPassword(Uri uri, String password) {
|
||||||
if (Tools.isExternalStorageWritable()) {
|
if (Tools.isExternalStorageWritable()) {
|
||||||
BackupHelper.backupToFileAsync(this, uri, password, encryptionKey, false);
|
showProgress(false);
|
||||||
|
BackupHelper.backupToFileAsync(this, uri, password, encryptionKey, this, false);
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(this, R.string.backup_toast_storage_not_accessible, Toast.LENGTH_LONG).show();
|
Toast.makeText(this, R.string.backup_toast_storage_not_accessible, Toast.LENGTH_LONG).show();
|
||||||
}
|
}
|
||||||
|
|
||||||
finishWithResult();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* OpenPGP backup functions */
|
/* OpenPGP backup functions */
|
||||||
|
@ -492,14 +549,17 @@ public class BackupActivity extends BaseActivity {
|
||||||
private void doBackupEncrypted(Uri uri, String data) {
|
private void doBackupEncrypted(Uri uri, String data) {
|
||||||
if (Tools.isExternalStorageWritable()) {
|
if (Tools.isExternalStorageWritable()) {
|
||||||
ExecutorService executor = Executors.newSingleThreadExecutor();
|
ExecutorService executor = Executors.newSingleThreadExecutor();
|
||||||
BackupHelper.SaveStringToFile runnable = new BackupHelper.SaveStringToFile(this, uri, data);
|
|
||||||
|
|
||||||
executor.execute(runnable);
|
BackupTask backupTask = new BackupTask(this, Constants.BackupType.OPEN_PGP, data, this);
|
||||||
|
|
||||||
|
if (uri != null)
|
||||||
|
backupTask.setUri(uri);
|
||||||
|
|
||||||
|
showProgress(false);
|
||||||
|
executor.execute(backupTask);
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(this, R.string.backup_toast_storage_not_accessible, Toast.LENGTH_LONG).show();
|
Toast.makeText(this, R.string.backup_toast_storage_not_accessible, Toast.LENGTH_LONG).show();
|
||||||
}
|
}
|
||||||
|
|
||||||
finishWithResult();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void backupEncryptedWithPGP(Uri uri, Intent encryptIntent) {
|
private void backupEncryptedWithPGP(Uri uri, Intent encryptIntent) {
|
||||||
|
|
|
@ -0,0 +1,124 @@
|
||||||
|
package org.shadowice.flocke.andotp.Tasks;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import org.shadowice.flocke.andotp.R;
|
||||||
|
import org.shadowice.flocke.andotp.Utilities.BackupHelper;
|
||||||
|
import org.shadowice.flocke.andotp.Utilities.Constants;
|
||||||
|
import org.shadowice.flocke.andotp.Utilities.Settings;
|
||||||
|
import org.shadowice.flocke.andotp.Utilities.StorageAccessHelper;
|
||||||
|
|
||||||
|
public class BackupTask implements Runnable {
|
||||||
|
final private Context context;
|
||||||
|
final private String payload;
|
||||||
|
final private Constants.BackupType type;
|
||||||
|
final private BackupCallback callback;
|
||||||
|
|
||||||
|
final private Handler handler;
|
||||||
|
|
||||||
|
private boolean silent = false;
|
||||||
|
private Uri uri = null;
|
||||||
|
private String password = null;
|
||||||
|
|
||||||
|
public BackupTask(Context context, Constants.BackupType type, String payload, BackupCallback callback) {
|
||||||
|
this.context = context;
|
||||||
|
this.payload = payload;
|
||||||
|
this.type = type;
|
||||||
|
this.callback = callback;
|
||||||
|
|
||||||
|
this.handler = new Handler(Looper.getMainLooper());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUri(Uri uri) {
|
||||||
|
this.uri = uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPassword(String password) {
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSilent(boolean silent) {
|
||||||
|
this.silent = silent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
boolean success;
|
||||||
|
|
||||||
|
if (uri == null)
|
||||||
|
uri = getTargetUri();
|
||||||
|
|
||||||
|
if (uri == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (type == Constants.BackupType.PLAIN_TEXT) {
|
||||||
|
success = StorageAccessHelper.saveFile(context, uri, payload);
|
||||||
|
} else if (type == Constants.BackupType.ENCRYPTED) {
|
||||||
|
success = BackupHelper.backupToFile(context, uri, password, payload);
|
||||||
|
} else if (type == Constants.BackupType.OPEN_PGP) {
|
||||||
|
success = StorageAccessHelper.saveFile(context, uri, payload);
|
||||||
|
} else {
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (success)
|
||||||
|
onFinished();
|
||||||
|
else
|
||||||
|
onFailed();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Uri getTargetUri() {
|
||||||
|
Settings settings = new Settings(context);
|
||||||
|
|
||||||
|
BackupHelper.BackupFile backupFile = BackupHelper.backupFile(context, settings.getBackupLocation(), type);
|
||||||
|
|
||||||
|
if (backupFile.file != null) {
|
||||||
|
return backupFile.file.getUri();
|
||||||
|
} else {
|
||||||
|
showToast(context, backupFile.errorMessage);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showToast(Context context, int msgId) {
|
||||||
|
if (!this.silent) {
|
||||||
|
this.handler.post(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
Toast.makeText(context, msgId, Toast.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onFinished() {
|
||||||
|
this.handler.post(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
Toast.makeText(context, R.string.backup_toast_export_success, Toast.LENGTH_LONG).show();
|
||||||
|
if (callback != null)
|
||||||
|
callback.onBackupFinished();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onFailed() {
|
||||||
|
this.handler.post(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
Toast.makeText(context, R.string.backup_toast_export_failed, Toast.LENGTH_LONG).show();
|
||||||
|
if (callback != null)
|
||||||
|
callback.onBackupFailed();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface BackupCallback {
|
||||||
|
void onBackupFinished();
|
||||||
|
void onBackupFailed();
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,14 +2,12 @@ package org.shadowice.flocke.andotp.Utilities;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Handler;
|
|
||||||
import android.os.Looper;
|
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import androidx.documentfile.provider.DocumentFile;
|
import androidx.documentfile.provider.DocumentFile;
|
||||||
|
|
||||||
import org.shadowice.flocke.andotp.Database.Entry;
|
import org.shadowice.flocke.andotp.Database.Entry;
|
||||||
import org.shadowice.flocke.andotp.R;
|
import org.shadowice.flocke.andotp.R;
|
||||||
|
import org.shadowice.flocke.andotp.Tasks.BackupTask;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
@ -106,25 +104,31 @@ public class BackupHelper {
|
||||||
return Constants.BackupType.UNAVAILABLE;
|
return Constants.BackupType.UNAVAILABLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void backupToFileAsync(Context context, Uri uri, String password, SecretKey encryptionKey, boolean silent) {
|
public static void backupToFileAsync(Context context, Uri uri, String password, SecretKey encryptionKey, BackupTask.BackupCallback callback, boolean silent) {
|
||||||
ArrayList<Entry> entries = DatabaseHelper.loadDatabase(context, encryptionKey);
|
ArrayList<Entry> entries = DatabaseHelper.loadDatabase(context, encryptionKey);
|
||||||
|
|
||||||
ExecutorService executor = Executors.newSingleThreadExecutor();
|
ExecutorService executor = Executors.newSingleThreadExecutor();
|
||||||
BackupCrypt runnable = new BackupCrypt(context, uri, password, entries, silent);
|
|
||||||
|
|
||||||
executor.execute(runnable);
|
BackupTask backupTask = new BackupTask(context, Constants.BackupType.ENCRYPTED, DatabaseHelper.entriesToString(entries), callback);
|
||||||
|
|
||||||
|
if (uri != null)
|
||||||
|
backupTask.setUri(uri);
|
||||||
|
|
||||||
|
backupTask.setPassword(password);
|
||||||
|
backupTask.setSilent(silent);
|
||||||
|
|
||||||
|
executor.execute(backupTask);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean backupToFile(Context context, Uri uri, String password, SecretKey encryptionKey) {
|
public static boolean backupToFile(Context context, Uri uri, String password, SecretKey encryptionKey) {
|
||||||
ArrayList<Entry> entries = DatabaseHelper.loadDatabase(context, encryptionKey);
|
ArrayList<Entry> entries = DatabaseHelper.loadDatabase(context, encryptionKey);
|
||||||
return backupToFile(context, uri, password, entries);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean backupToFile(Context context, Uri uri, String password, ArrayList<Entry> entries)
|
|
||||||
{
|
|
||||||
|
|
||||||
String plain = DatabaseHelper.entriesToString(entries);
|
String plain = DatabaseHelper.entriesToString(entries);
|
||||||
|
|
||||||
|
return backupToFile(context, uri, password, plain);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean backupToFile(Context context, Uri uri, String password, String plain)
|
||||||
|
{
|
||||||
boolean success = true;
|
boolean success = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -149,73 +153,4 @@ public class BackupHelper {
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class BackupCrypt implements Runnable {
|
|
||||||
final private Context context;
|
|
||||||
final private Uri uri;
|
|
||||||
final private String password;
|
|
||||||
final private ArrayList<Entry> entries;
|
|
||||||
final private boolean silent;
|
|
||||||
|
|
||||||
public BackupCrypt(Context context, Uri uri, String password, ArrayList<Entry> entries, boolean silent) {
|
|
||||||
this.context = context;
|
|
||||||
this.uri = uri;
|
|
||||||
this.password = password;
|
|
||||||
this.entries = entries;
|
|
||||||
this.silent = silent;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
boolean success = backupToFile(context, uri, password, entries);
|
|
||||||
|
|
||||||
if (!silent) {
|
|
||||||
if (success) {
|
|
||||||
postMessage(R.string.backup_toast_export_success);
|
|
||||||
} else {
|
|
||||||
postMessage(R.string.backup_toast_export_failed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void postMessage(int msgId) {
|
|
||||||
new Handler(Looper.getMainLooper()).post(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
Toast.makeText(context, msgId, Toast.LENGTH_LONG).show();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class SaveStringToFile implements Runnable {
|
|
||||||
final private Context context;
|
|
||||||
final private Uri uri;
|
|
||||||
final private String data;
|
|
||||||
|
|
||||||
public SaveStringToFile(Context context, Uri uri, String data) {
|
|
||||||
this.context = context;
|
|
||||||
this.uri = uri;
|
|
||||||
this.data = data;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
boolean success = StorageAccessHelper.saveFile(context, uri, data);
|
|
||||||
|
|
||||||
if (success)
|
|
||||||
postMessage(R.string.backup_toast_export_success);
|
|
||||||
else
|
|
||||||
postMessage(R.string.backup_toast_export_failed);
|
|
||||||
}
|
|
||||||
|
|
||||||
void postMessage(int msgId) {
|
|
||||||
new Handler(Looper.getMainLooper()).post(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
Toast.makeText(context, msgId, Toast.LENGTH_LONG).show();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -605,4 +605,13 @@ public class Settings {
|
||||||
public boolean getBlockAutofill() {
|
public boolean getBlockAutofill() {
|
||||||
return getBoolean(R.string.settings_key_block_autofill, false);
|
return getBoolean(R.string.settings_key_block_autofill, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setDefaultBackupType(Constants.BackupType type) {
|
||||||
|
setString(R.string.settings_key_backup_default_type, type.name().toLowerCase(Locale.ENGLISH));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Constants.BackupType getDefaultBackupType() {
|
||||||
|
String defaultType = getString(R.string.settings_key_backup_default_type, Constants.BackupType.ENCRYPTED.name());
|
||||||
|
return Constants.BackupType.valueOf(defaultType.toUpperCase(Locale.ENGLISH));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,222 +2,78 @@
|
||||||
<androidx.core.widget.NestedScrollView
|
<androidx.core.widget.NestedScrollView
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:id="@+id/scroll_view"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:overScrollMode="never"
|
android:overScrollMode="never"
|
||||||
app:layout_behavior="@string/appbar_scrolling_view_behavior" >
|
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="@dimen/activity_margin"
|
||||||
<TextView
|
android:layout_marginTop="@dimen/activity_margin_large"
|
||||||
android:layout_width="match_parent"
|
android:gravity="center_horizontal">
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:paddingStart="@dimen/activity_margin"
|
|
||||||
android:paddingEnd="@dimen/activity_margin"
|
|
||||||
android:paddingTop="@dimen/activity_margin"
|
|
||||||
android:textColor="@color/colorAccent"
|
|
||||||
android:textStyle="bold"
|
|
||||||
android:text="@string/backup_category_plain" />
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/button_backup_plain"
|
android:orientation="horizontal"
|
||||||
android:orientation="vertical"
|
android:layout_width="wrap_content"
|
||||||
android:layout_width="match_parent"
|
android:layout_height="wrap_content">
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:padding="@dimen/activity_margin"
|
|
||||||
android:background="?android:attr/selectableItemBackground" >
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:textAppearance="?android:attr/textAppearanceListItem"
|
android:textColor="@color/colorAccent"
|
||||||
android:text="@string/backup_title_export_plain" />
|
android:textStyle="bold"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Widget.TextView.SpinnerItem"
|
||||||
|
android:text="@string/backup_label_type"/>
|
||||||
|
|
||||||
<TextView
|
<Spinner
|
||||||
|
android:id="@+id/backupType"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
android:entries="@array/backup_list_type_names" />
|
||||||
android:text="@string/backup_desc_export_plain"/>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/button_restore_plain"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:padding="@dimen/activity_margin"
|
|
||||||
android:background="?android:attr/selectableItemBackground" >
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:textAppearance="?android:attr/textAppearanceListItem"
|
|
||||||
android:text="@string/backup_title_import_plain" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
|
||||||
android:text="@string/backup_desc_import_plain"/>
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="match_parent"
|
android:id="@+id/backupLabel"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:paddingStart="@dimen/activity_margin"
|
android:layout_marginTop="@dimen/activity_margin"
|
||||||
android:paddingEnd="@dimen/activity_margin"
|
android:padding="@dimen/activity_margin"
|
||||||
android:paddingTop="@dimen/activity_margin"
|
android:text="@string/backup_label_warning_plain"/>
|
||||||
android:textColor="@color/colorAccent"
|
|
||||||
android:textStyle="bold"
|
|
||||||
android:text="@string/backup_category_crypt" />
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/msg_crypt_setup"
|
android:id="@+id/backupErrorLabel"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:padding="@dimen/activity_margin"
|
android:padding="@dimen/activity_margin"
|
||||||
android:visibility="gone"
|
android:textColor="?attr/colorExpiring"
|
||||||
android:text="@string/backup_desc_crypt_setup"/>
|
android:text="@string/backup_desc_openpgp_provider"
|
||||||
|
android:visibility="gone"/>
|
||||||
|
|
||||||
<LinearLayout
|
<Button
|
||||||
android:id="@+id/button_backup_crypt"
|
android:id="@+id/buttonBackup"
|
||||||
android:orientation="vertical"
|
android:layout_width="wrap_content"
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:padding="@dimen/activity_margin"
|
android:text="@string/backup_button_backup"/>
|
||||||
android:background="?android:attr/selectableItemBackground" >
|
|
||||||
|
|
||||||
<TextView
|
<ProgressBar
|
||||||
android:layout_width="wrap_content"
|
android:id="@+id/progressBarBackup"
|
||||||
android:layout_height="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:textAppearance="?android:attr/textAppearanceListItem"
|
|
||||||
android:text="@string/backup_title_export_crypt" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
|
||||||
android:text="@string/backup_desc_export_crypt"/>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/button_restore_crypt"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:padding="@dimen/activity_margin"
|
android:layout_marginTop="@dimen/activity_margin"
|
||||||
android:background="?android:attr/selectableItemBackground" >
|
android:indeterminate="true"
|
||||||
|
style="?android:attr/progressBarStyle"
|
||||||
<TextView
|
android:visibility="gone"/>
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:textAppearance="?android:attr/textAppearanceListItem"
|
|
||||||
android:text="@string/backup_title_import_crypt" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
|
||||||
android:text="@string/backup_desc_import_crypt"/>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/button_restore_crypt_old"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:padding="@dimen/activity_margin"
|
|
||||||
android:background="?android:attr/selectableItemBackground" >
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:textAppearance="?android:attr/textAppearanceListItem"
|
|
||||||
android:text="@string/backup_title_import_crypt_old" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
|
||||||
android:text="@string/backup_desc_import_crypt_old"/>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:paddingStart="@dimen/activity_margin"
|
|
||||||
android:paddingEnd="@dimen/activity_margin"
|
|
||||||
android:paddingTop="@dimen/activity_margin"
|
|
||||||
android:textColor="@color/colorAccent"
|
|
||||||
android:textStyle="bold"
|
|
||||||
android:text="@string/backup_category_openpgp" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/msg_openpgp_setup"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:padding="@dimen/activity_margin"
|
|
||||||
android:visibility="gone"
|
|
||||||
android:text="@string/backup_desc_openpgp_provider"/>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/button_backup_openpgp"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:padding="@dimen/activity_margin"
|
|
||||||
android:background="?android:attr/selectableItemBackground" >
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:textAppearance="?android:attr/textAppearanceListItem"
|
|
||||||
android:text="@string/backup_title_export_openpgp" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
|
||||||
android:text="@string/backup_desc_export_openpgp"/>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/button_restore_openpgp"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:padding="@dimen/activity_margin"
|
|
||||||
android:background="?android:attr/selectableItemBackground" >
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:textAppearance="?android:attr/textAppearanceListItem"
|
|
||||||
android:text="@string/backup_title_import_openpgp" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
|
||||||
android:text="@string/backup_desc_import_openpgp"/>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<RelativeLayout
|
<RelativeLayout
|
||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="@dimen/activity_margin"
|
android:layout_marginTop="@dimen/activity_margin_large"
|
||||||
|
android:layout_marginBottom="@dimen/activity_margin"
|
||||||
android:padding="@dimen/activity_margin"
|
android:padding="@dimen/activity_margin"
|
||||||
android:background="?android:attr/selectableItemBackground" >
|
android:background="?android:attr/selectableItemBackground" >
|
||||||
|
|
||||||
|
@ -242,7 +98,7 @@
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<Switch
|
<com.google.android.material.switchmaterial.SwitchMaterial
|
||||||
android:id="@+id/backup_replace"
|
android:id="@+id/backup_replace"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
@ -252,5 +108,30 @@
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<CheckBox
|
||||||
|
android:id="@+id/restoreOldCrypt"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginHorizontal="@dimen/activity_margin"
|
||||||
|
android:layout_marginBottom="@dimen/activity_margin"
|
||||||
|
android:text="@string/backup_check_restore_old"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/buttonRestore"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/backup_button_restore" />
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/progressBarRestore"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="@dimen/activity_margin"
|
||||||
|
android:indeterminate="true"
|
||||||
|
style="?android:attr/progressBarStyle"
|
||||||
|
android:visibility="gone"/>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</androidx.core.widget.NestedScrollView>
|
</androidx.core.widget.NestedScrollView>
|
|
@ -53,6 +53,7 @@
|
||||||
<string name="settings_key_openpgp_key_sign" translatable="false">pref_openpgp_key_sign</string>
|
<string name="settings_key_openpgp_key_sign" translatable="false">pref_openpgp_key_sign</string>
|
||||||
<string name="settings_key_openpgp_verify" translatable="false">pref_openpgp_verify</string>
|
<string name="settings_key_openpgp_verify" translatable="false">pref_openpgp_verify</string>
|
||||||
<string name="settings_key_new_backup_format_dialog_shown" translatable="false">pref_new_backup_dialog_shown</string> <!--Deprecated -->
|
<string name="settings_key_new_backup_format_dialog_shown" translatable="false">pref_new_backup_dialog_shown</string> <!--Deprecated -->
|
||||||
|
<string name="settings_key_backup_default_type" translatable="false">pref_backup_default_type</string>
|
||||||
|
|
||||||
<string name="settings_key_security_backup_warning" translatable="false">pref_security_backup_warning_shown</string>
|
<string name="settings_key_security_backup_warning" translatable="false">pref_security_backup_warning_shown</string>
|
||||||
<string name="settings_key_sort_mode" translatable="false">pref_sort_mode</string>
|
<string name="settings_key_sort_mode" translatable="false">pref_sort_mode</string>
|
||||||
|
|
|
@ -2,33 +2,10 @@
|
||||||
<resources>
|
<resources>
|
||||||
<string name="backup_activity_title">Backups</string>
|
<string name="backup_activity_title">Backups</string>
|
||||||
|
|
||||||
<string name="backup_category_plain">Plain-text backups</string>
|
|
||||||
<string name="backup_category_crypt">Encrypted backups</string>
|
|
||||||
<string name="backup_category_openpgp">OpenPGP backups</string>
|
|
||||||
|
|
||||||
<string name="backup_title_export_plain">Backup (plain-text)</string>
|
|
||||||
<string name="backup_title_export_crypt">Backup (encrypted)</string>
|
|
||||||
<string name="backup_title_export_openpgp">Backup (OpenPGP)</string>
|
|
||||||
<string name="backup_title_import_plain">Restore (plain-text)</string>
|
|
||||||
<string name="backup_title_import_crypt">Restore (encrypted)</string>
|
|
||||||
<string name="backup_title_import_crypt_old">Restore (encrypted, old encryption)</string>
|
|
||||||
<string name="backup_title_import_openpgp">Restore (OpenPGP)</string>
|
|
||||||
|
|
||||||
<string name="backup_title_replace">Replace existing entries</string>
|
<string name="backup_title_replace">Replace existing entries</string>
|
||||||
|
<string name="backup_desc_replace">If enabled all old entries are replaced when importing a
|
||||||
<string name="backup_desc_export_plain">Backup all accounts in a plain-text JSON file</string>
|
backup and only the backup is present. If disabled the old entries and the backups content
|
||||||
<string name="backup_desc_export_crypt">Backup all accounts in a password-protected JSON file</string>
|
are merged.</string>
|
||||||
<string name="backup_desc_export_openpgp">Backup all accounts in an OpenPGP-encrypted JSON file</string>
|
|
||||||
<string name="backup_desc_import_plain">Restore accounts from a plain-text JSON file</string>
|
|
||||||
<string name="backup_desc_import_crypt">Restore accounts from a password-protected JSON file</string>
|
|
||||||
<string name="backup_desc_import_crypt_old">Restore accounts from a password-protected JSON file
|
|
||||||
created with an <b>andOTP version lower than 0.6.3</b></string>
|
|
||||||
<string name="backup_desc_import_openpgp">Restore accounts from an OpenPGP-encrypted JSON file</string>
|
|
||||||
|
|
||||||
<string name="backup_desc_crypt_setup">Failed to load the backup password from the <b>Settings</b>,
|
|
||||||
this either means no password was set or something went wrong. You will be asked to enter
|
|
||||||
the password manually when creating or importing a backup.
|
|
||||||
</string>
|
|
||||||
|
|
||||||
<string name="backup_desc_openpgp_provider">You need to install an OpenPGP provider and enable
|
<string name="backup_desc_openpgp_provider">You need to install an OpenPGP provider and enable
|
||||||
it in the <b>Settings</b> to use this feature.
|
it in the <b>Settings</b> to use this feature.
|
||||||
|
@ -37,18 +14,12 @@
|
||||||
before you can create encrypted backups.
|
before you can create encrypted backups.
|
||||||
</string>
|
</string>
|
||||||
|
|
||||||
<string name="backup_desc_replace">If enabled all old entries are replaced when importing a
|
|
||||||
backup and only the backup is present. If disabled the old entries and the backups content
|
|
||||||
are merged.</string>
|
|
||||||
|
|
||||||
<!-- Dialogs -->
|
<!-- Dialogs -->
|
||||||
<string name="backup_dialog_title_security_warning">Security warning</string>
|
<string name="backup_dialog_title_security_warning">Security warning</string>
|
||||||
|
|
||||||
<string name="backup_dialog_msg_export_warning">Do you really want to export the database as
|
<string name="backup_dialog_msg_export_warning">Do you really want to export the database as
|
||||||
plain-text JSON file? This file contains all your secret keys, please <b>keep it safe</b>!
|
plain-text JSON file? This file contains all your secret keys, please <b>keep it safe</b>!
|
||||||
</string>
|
</string>
|
||||||
|
|
||||||
|
|
||||||
<string name="backup_receiver_title_backup_failed">Backup failed</string>
|
<string name="backup_receiver_title_backup_failed">Backup failed</string>
|
||||||
<string name="backup_receiver_title_backup_success">Backup successful</string>
|
<string name="backup_receiver_title_backup_success">Backup successful</string>
|
||||||
|
|
||||||
|
@ -89,4 +60,32 @@
|
||||||
<string name="backup_toast_openpgp_not_verified">No verified signature detected</string>
|
<string name="backup_toast_openpgp_not_verified">No verified signature detected</string>
|
||||||
<string name="backup_toast_crypt_password_not_set">Password not set, check the <b>Settings</b></string>
|
<string name="backup_toast_crypt_password_not_set">Password not set, check the <b>Settings</b></string>
|
||||||
<string name="backup_toast_file_selection_failed">Can\'t open file selection dialog!</string>
|
<string name="backup_toast_file_selection_failed">Can\'t open file selection dialog!</string>
|
||||||
|
|
||||||
|
<string name="backup_label_type">Backup type: </string>
|
||||||
|
|
||||||
|
<string name="backup_label_warning_plain">The backup will be stored in an unencrypted plain-text
|
||||||
|
file. Please only use if strictly necessary and <b>keep the file safe</b>!</string>
|
||||||
|
<string name="backup_label_crypt">The backup will be stored encrypted with a custom password
|
||||||
|
using AES 256-bit encryption. You can setup a default password in the settings if you
|
||||||
|
don\'t want to have to enter it every time you create a backup.</string>
|
||||||
|
<string name="backup_label_pgp">The backup will be stored encrypted using the PGP key you
|
||||||
|
specified in the settings. The encryption will be handled by a 3rd party app.</string>
|
||||||
|
|
||||||
|
<string name="backup_check_restore_old">Restore old backup format (created with an andOTP version
|
||||||
|
before 0.6.3)</string>
|
||||||
|
|
||||||
|
<string name="backup_button_backup">Create backup</string>
|
||||||
|
<string name="backup_button_restore">Restore backup</string>
|
||||||
|
|
||||||
|
<string-array name="backup_list_type_names">
|
||||||
|
<item>Plain-text</item>
|
||||||
|
<item>Encrypted</item>
|
||||||
|
<item>OpenPGP</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
|
<string-array name="backup_list_type_values" translatable="false">
|
||||||
|
<item>plain</item>
|
||||||
|
<item>crypt</item>
|
||||||
|
<item>pgp</item>
|
||||||
|
</string-array>
|
||||||
</resources>
|
</resources>
|
Loading…
Reference in a new issue