Rudimentary backup feature
This commit is contained in:
@@ -21,7 +21,7 @@ import android.os.Build;
|
|||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bug on Android >= 4.2
|
* Bug on Android >= 4.2. Fixed in 4.2.2 ?
|
||||||
*
|
*
|
||||||
* http://code.google.com/p/android/issues/detail?id=41901
|
* http://code.google.com/p/android/issues/detail?id=41901
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -0,0 +1,137 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 Dominik Schürmann <dominik@dominikschuermann.de>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.sufficientlysecure.keychain.ui;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.database.Cursor;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
import android.support.v4.app.Fragment;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
|
import org.sufficientlysecure.keychain.R;
|
||||||
|
import org.sufficientlysecure.keychain.provider.KeychainContract;
|
||||||
|
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
|
||||||
|
import org.sufficientlysecure.keychain.util.ExportHelper;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
public class BackupFragment extends Fragment {
|
||||||
|
|
||||||
|
// This ids for multiple key export.
|
||||||
|
private ArrayList<Long> mIdsForRepeatAskPassphrase;
|
||||||
|
private ArrayList<Long> mIdsForExport;
|
||||||
|
// This index for remembering the number of master key.
|
||||||
|
private int mIndex;
|
||||||
|
|
||||||
|
static final int REQUEST_REPEAT_PASSPHRASE = 1;
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||||
|
View view = inflater.inflate(R.layout.backup_fragment, container, false);
|
||||||
|
|
||||||
|
View mBackupAll = view.findViewById(R.id.backup_all);
|
||||||
|
View mBackupPublicKeys = view.findViewById(R.id.backup_public_keys);
|
||||||
|
|
||||||
|
mBackupAll.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
exportToFile(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
mBackupPublicKeys.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
exportToFile(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void exportToFile(boolean includeSecretKeys) {
|
||||||
|
if (includeSecretKeys) {
|
||||||
|
mIdsForRepeatAskPassphrase = new ArrayList<>();
|
||||||
|
|
||||||
|
Cursor cursor = getActivity().getContentResolver().query(
|
||||||
|
KeychainContract.KeyRingData.buildSecretKeyRingUri(), null, null, null, null);
|
||||||
|
try {
|
||||||
|
if (cursor != null) {
|
||||||
|
int keyIdColumn = cursor.getColumnIndex(KeychainContract.KeyRingData.MASTER_KEY_ID);
|
||||||
|
while (cursor.moveToNext()) {
|
||||||
|
long keyId = cursor.getLong(keyIdColumn);
|
||||||
|
try {
|
||||||
|
if (PassphraseCacheService.getCachedPassphrase(
|
||||||
|
getActivity(), keyId, keyId) == null) {
|
||||||
|
mIdsForRepeatAskPassphrase.add(keyId);
|
||||||
|
}
|
||||||
|
} catch (PassphraseCacheService.KeyNotFoundException e) {
|
||||||
|
// This happens when the master key is stripped
|
||||||
|
// and ignore this key.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
if (cursor != null) {
|
||||||
|
cursor.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mIndex = 0;
|
||||||
|
if (mIdsForRepeatAskPassphrase.size() != 0) {
|
||||||
|
startPassphraseActivity();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExportHelper exportHelper = new ExportHelper(getActivity());
|
||||||
|
exportHelper.showExportKeysDialog(null, Constants.Path.APP_DIR_FILE, true);
|
||||||
|
} else {
|
||||||
|
ExportHelper exportHelper = new ExportHelper(getActivity());
|
||||||
|
exportHelper.showExportKeysDialog(null, Constants.Path.APP_DIR_FILE, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startPassphraseActivity() {
|
||||||
|
Intent intent = new Intent(getActivity(), PassphraseDialogActivity.class);
|
||||||
|
long masterKeyId = mIdsForRepeatAskPassphrase.get(mIndex++);
|
||||||
|
intent.putExtra(PassphraseDialogActivity.EXTRA_SUBKEY_ID, masterKeyId);
|
||||||
|
startActivityForResult(intent, REQUEST_REPEAT_PASSPHRASE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
|
if (requestCode == REQUEST_REPEAT_PASSPHRASE) {
|
||||||
|
if (resultCode != Activity.RESULT_OK) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (mIndex < mIdsForRepeatAskPassphrase.size()) {
|
||||||
|
startPassphraseActivity();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExportHelper exportHelper = new ExportHelper(getActivity());
|
||||||
|
exportHelper.showExportKeysDialog(null, Constants.Path.APP_DIR_FILE, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -116,12 +116,6 @@ public class KeyListFragment extends LoaderFragment
|
|||||||
// for ConsolidateOperation
|
// for ConsolidateOperation
|
||||||
private CryptoOperationHelper<ConsolidateInputParcel, ConsolidateResult> mConsolidateOpHelper;
|
private CryptoOperationHelper<ConsolidateInputParcel, ConsolidateResult> mConsolidateOpHelper;
|
||||||
|
|
||||||
// This ids for multiple key export.
|
|
||||||
private ArrayList<Long> mIdsForRepeatAskPassphrase;
|
|
||||||
private ArrayList<Long> mIdsForExport;
|
|
||||||
// This index for remembering the number of master key.
|
|
||||||
private int mIndex;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
@@ -242,18 +236,6 @@ public class KeyListFragment extends LoaderFragment
|
|||||||
showDeleteKeyDialog(mode, ids, mAdapter.isAnySecretSelected());
|
showDeleteKeyDialog(mode, ids, mAdapter.isAnySecretSelected());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case R.id.menu_key_list_multi_export: {
|
|
||||||
ids = mAdapter.getCurrentSelectedMasterKeyIds();
|
|
||||||
showMultiExportDialog(ids);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case R.id.menu_key_list_multi_select_all: {
|
|
||||||
// select all
|
|
||||||
for (int i = 0; i < mAdapter.getCount(); i++) {
|
|
||||||
mStickyList.setItemChecked(i, true);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -641,48 +623,6 @@ public class KeyListFragment extends LoaderFragment
|
|||||||
mConsolidateOpHelper.cryptoOperation();
|
mConsolidateOpHelper.cryptoOperation();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showMultiExportDialog(long[] masterKeyIds) {
|
|
||||||
mIdsForRepeatAskPassphrase = new ArrayList<>();
|
|
||||||
mIdsForExport = new ArrayList<>();
|
|
||||||
for (long id : masterKeyIds) {
|
|
||||||
try {
|
|
||||||
if (PassphraseCacheService.getCachedPassphrase(
|
|
||||||
getActivity(), id, id) == null) {
|
|
||||||
mIdsForRepeatAskPassphrase.add(id);
|
|
||||||
}
|
|
||||||
} catch (PassphraseCacheService.KeyNotFoundException e) {
|
|
||||||
// This happens when the master key is stripped
|
|
||||||
// and ignore this key.
|
|
||||||
mIdsForExport.add(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mIndex = 0;
|
|
||||||
if (mIdsForRepeatAskPassphrase.size() != 0) {
|
|
||||||
startPassphraseActivity();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
mIdsForExport.addAll(mIdsForRepeatAskPassphrase);
|
|
||||||
finishExport();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void startPassphraseActivity() {
|
|
||||||
Intent intent = new Intent(getActivity(), PassphraseDialogActivity.class);
|
|
||||||
long masterKeyId = mIdsForRepeatAskPassphrase.get(mIndex++);
|
|
||||||
intent.putExtra(PassphraseDialogActivity.EXTRA_SUBKEY_ID, masterKeyId);
|
|
||||||
startActivityForResult(intent, REQUEST_REPEAT_PASSPHRASE);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void finishExport() {
|
|
||||||
long[] idsForMultiExport = new long[mIdsForExport.size()];
|
|
||||||
for (int i = 0; i < mIdsForExport.size(); i++) {
|
|
||||||
idsForMultiExport[i] = mIdsForExport.get(i);
|
|
||||||
}
|
|
||||||
mExportHelper.showExportKeysDialog(idsForMultiExport,
|
|
||||||
Constants.Path.APP_DIR_FILE,
|
|
||||||
mAdapter.isAnySecretSelected());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
if (mImportOpHelper != null) {
|
if (mImportOpHelper != null) {
|
||||||
@@ -693,19 +633,6 @@ public class KeyListFragment extends LoaderFragment
|
|||||||
mConsolidateOpHelper.handleActivityResult(requestCode, resultCode, data);
|
mConsolidateOpHelper.handleActivityResult(requestCode, resultCode, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (requestCode == REQUEST_REPEAT_PASSPHRASE) {
|
|
||||||
if (resultCode != Activity.RESULT_OK) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (mIndex < mIdsForRepeatAskPassphrase.size()) {
|
|
||||||
startPassphraseActivity();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
mIdsForExport.addAll(mIdsForRepeatAskPassphrase);
|
|
||||||
finishExport();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (requestCode == REQUEST_ACTION) {
|
if (requestCode == REQUEST_ACTION) {
|
||||||
// if a result has been returned, display a notify
|
// if a result has been returned, display a notify
|
||||||
if (data != null && data.hasExtra(OperationResult.EXTRA_RESULT)) {
|
if (data != null && data.hasExtra(OperationResult.EXTRA_RESULT)) {
|
||||||
|
|||||||
@@ -48,8 +48,9 @@ public class MainActivity extends BaseNfcActivity implements FabContainer, OnBac
|
|||||||
static final int ID_KEYS = 1;
|
static final int ID_KEYS = 1;
|
||||||
static final int ID_ENCRYPT_DECRYPT = 2;
|
static final int ID_ENCRYPT_DECRYPT = 2;
|
||||||
static final int ID_APPS = 3;
|
static final int ID_APPS = 3;
|
||||||
static final int ID_SETTINGS = 4;
|
static final int ID_BACKUP = 4;
|
||||||
static final int ID_HELP = 5;
|
static final int ID_SETTINGS = 5;
|
||||||
|
static final int ID_HELP = 6;
|
||||||
|
|
||||||
// both of these are used for instrumentation testing only
|
// both of these are used for instrumentation testing only
|
||||||
public static final String EXTRA_SKIP_FIRST_TIME = "skip_first_time";
|
public static final String EXTRA_SKIP_FIRST_TIME = "skip_first_time";
|
||||||
@@ -77,7 +78,9 @@ public class MainActivity extends BaseNfcActivity implements FabContainer, OnBac
|
|||||||
new PrimaryDrawerItem().withName(R.string.nav_encrypt_decrypt).withIcon(FontAwesome.Icon.faw_lock)
|
new PrimaryDrawerItem().withName(R.string.nav_encrypt_decrypt).withIcon(FontAwesome.Icon.faw_lock)
|
||||||
.withIdentifier(ID_ENCRYPT_DECRYPT).withCheckable(false),
|
.withIdentifier(ID_ENCRYPT_DECRYPT).withCheckable(false),
|
||||||
new PrimaryDrawerItem().withName(R.string.title_api_registered_apps).withIcon(CommunityMaterial.Icon.cmd_apps)
|
new PrimaryDrawerItem().withName(R.string.title_api_registered_apps).withIcon(CommunityMaterial.Icon.cmd_apps)
|
||||||
.withIdentifier(ID_APPS).withCheckable(false)
|
.withIdentifier(ID_APPS).withCheckable(false),
|
||||||
|
new PrimaryDrawerItem().withName(R.string.nav_backup).withIcon(CommunityMaterial.Icon.cmd_backup_restore)
|
||||||
|
.withIdentifier(ID_BACKUP).withCheckable(false)
|
||||||
)
|
)
|
||||||
.addStickyDrawerItems(
|
.addStickyDrawerItems(
|
||||||
// display and stick on bottom of drawer
|
// display and stick on bottom of drawer
|
||||||
@@ -99,6 +102,9 @@ public class MainActivity extends BaseNfcActivity implements FabContainer, OnBac
|
|||||||
case ID_APPS:
|
case ID_APPS:
|
||||||
onAppsSelected();
|
onAppsSelected();
|
||||||
break;
|
break;
|
||||||
|
case ID_BACKUP:
|
||||||
|
onBackupSelected();
|
||||||
|
break;
|
||||||
case ID_SETTINGS:
|
case ID_SETTINGS:
|
||||||
intent = new Intent(MainActivity.this, SettingsActivity.class);
|
intent = new Intent(MainActivity.this, SettingsActivity.class);
|
||||||
break;
|
break;
|
||||||
@@ -192,6 +198,13 @@ public class MainActivity extends BaseNfcActivity implements FabContainer, OnBac
|
|||||||
setFragment(frag, true);
|
setFragment(frag, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void onBackupSelected() {
|
||||||
|
mToolbar.setTitle(R.string.nav_backup);
|
||||||
|
mDrawerResult.setSelectionByIdentifier(ID_APPS, false);
|
||||||
|
Fragment frag = new BackupFragment();
|
||||||
|
setFragment(frag, true);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onSaveInstanceState(Bundle outState) {
|
protected void onSaveInstanceState(Bundle outState) {
|
||||||
// add the values which need to be saved from the drawer to the bundle
|
// add the values which need to be saved from the drawer to the bundle
|
||||||
@@ -246,6 +259,8 @@ public class MainActivity extends BaseNfcActivity implements FabContainer, OnBac
|
|||||||
mDrawerResult.setSelection(mDrawerResult.getPositionFromIdentifier(ID_ENCRYPT_DECRYPT), false);
|
mDrawerResult.setSelection(mDrawerResult.getPositionFromIdentifier(ID_ENCRYPT_DECRYPT), false);
|
||||||
} else if (frag instanceof AppsListFragment) {
|
} else if (frag instanceof AppsListFragment) {
|
||||||
mDrawerResult.setSelection(mDrawerResult.getPositionFromIdentifier(ID_APPS), false);
|
mDrawerResult.setSelection(mDrawerResult.getPositionFromIdentifier(ID_APPS), false);
|
||||||
|
} else if (frag instanceof BackupFragment) {
|
||||||
|
mDrawerResult.setSelection(mDrawerResult.getPositionFromIdentifier(ID_BACKUP), false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -363,6 +363,8 @@ public class ViewKeyActivity extends BaseNfcActivity implements
|
|||||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||||
MenuItem editKey = menu.findItem(R.id.menu_key_view_edit);
|
MenuItem editKey = menu.findItem(R.id.menu_key_view_edit);
|
||||||
editKey.setVisible(mIsSecret);
|
editKey.setVisible(mIsSecret);
|
||||||
|
MenuItem exportKey = menu.findItem(R.id.menu_key_view_export_file);
|
||||||
|
exportKey.setVisible(mIsSecret);
|
||||||
MenuItem certifyFingerprint = menu.findItem(R.id.menu_key_view_certify_fingerprint);
|
MenuItem certifyFingerprint = menu.findItem(R.id.menu_key_view_certify_fingerprint);
|
||||||
certifyFingerprint.setVisible(!mIsSecret && !mIsVerified && !mIsExpired && !mIsRevoked);
|
certifyFingerprint.setVisible(!mIsSecret && !mIsVerified && !mIsExpired && !mIsRevoked);
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import java.io.BufferedWriter;
|
|||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStreamWriter;
|
import java.io.OutputStreamWriter;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.ActivityOptions;
|
import android.app.ActivityOptions;
|
||||||
@@ -62,6 +63,7 @@ import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
|||||||
import org.sufficientlysecure.keychain.ui.util.Notify;
|
import org.sufficientlysecure.keychain.ui.util.Notify;
|
||||||
import org.sufficientlysecure.keychain.ui.util.Notify.Style;
|
import org.sufficientlysecure.keychain.ui.util.Notify.Style;
|
||||||
import org.sufficientlysecure.keychain.ui.util.QrCodeUtils;
|
import org.sufficientlysecure.keychain.ui.util.QrCodeUtils;
|
||||||
|
import org.sufficientlysecure.keychain.util.ExportHelper;
|
||||||
import org.sufficientlysecure.keychain.util.Log;
|
import org.sufficientlysecure.keychain.util.Log;
|
||||||
import org.sufficientlysecure.keychain.util.NfcHelper;
|
import org.sufficientlysecure.keychain.util.NfcHelper;
|
||||||
|
|
||||||
@@ -104,6 +106,7 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements
|
|||||||
View vFingerprintShareButton = view.findViewById(R.id.view_key_action_fingerprint_share);
|
View vFingerprintShareButton = view.findViewById(R.id.view_key_action_fingerprint_share);
|
||||||
View vFingerprintClipboardButton = view.findViewById(R.id.view_key_action_fingerprint_clipboard);
|
View vFingerprintClipboardButton = view.findViewById(R.id.view_key_action_fingerprint_clipboard);
|
||||||
View vKeyShareButton = view.findViewById(R.id.view_key_action_key_share);
|
View vKeyShareButton = view.findViewById(R.id.view_key_action_key_share);
|
||||||
|
View vKeySafeButton = view.findViewById(R.id.view_key_action_key_export);
|
||||||
View vKeyNfcButton = view.findViewById(R.id.view_key_action_key_nfc);
|
View vKeyNfcButton = view.findViewById(R.id.view_key_action_key_nfc);
|
||||||
View vKeyClipboardButton = view.findViewById(R.id.view_key_action_key_clipboard);
|
View vKeyClipboardButton = view.findViewById(R.id.view_key_action_key_clipboard);
|
||||||
ImageButton vKeySafeSlingerButton = (ImageButton) view.findViewById(R.id.view_key_action_key_safeslinger);
|
ImageButton vKeySafeSlingerButton = (ImageButton) view.findViewById(R.id.view_key_action_key_safeslinger);
|
||||||
@@ -129,6 +132,12 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements
|
|||||||
share(false, false);
|
share(false, false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
vKeySafeButton.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
exportToFile(mDataUri, new ProviderHelper(getActivity()));
|
||||||
|
}
|
||||||
|
});
|
||||||
vKeyClipboardButton.setOnClickListener(new View.OnClickListener() {
|
vKeyClipboardButton.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
@@ -164,6 +173,25 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements
|
|||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void exportToFile(Uri dataUri, ProviderHelper providerHelper) {
|
||||||
|
try {
|
||||||
|
Uri baseUri = KeychainContract.KeyRings.buildUnifiedKeyRingUri(dataUri);
|
||||||
|
|
||||||
|
HashMap<String, Object> data = providerHelper.getGenericData(
|
||||||
|
baseUri,
|
||||||
|
new String[]{KeychainContract.Keys.MASTER_KEY_ID, KeychainContract.KeyRings.HAS_SECRET},
|
||||||
|
new int[]{ProviderHelper.FIELD_TYPE_INTEGER, ProviderHelper.FIELD_TYPE_INTEGER});
|
||||||
|
|
||||||
|
new ExportHelper(getActivity()).showExportKeysDialog(
|
||||||
|
new long[]{(Long) data.get(KeychainContract.KeyRings.MASTER_KEY_ID)},
|
||||||
|
Constants.Path.APP_DIR_FILE, ((Long) data.get(KeychainContract.KeyRings.HAS_SECRET) != 0)
|
||||||
|
);
|
||||||
|
} catch (ProviderHelper.NotFoundException e) {
|
||||||
|
Notify.create(getActivity(), R.string.error_key_not_found, Notify.Style.ERROR).show();
|
||||||
|
Log.e(Constants.TAG, "Key not found", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void startSafeSlinger(Uri dataUri) {
|
private void startSafeSlinger(Uri dataUri) {
|
||||||
long keyId = 0;
|
long keyId = 0;
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -136,6 +136,7 @@ public class FileDialogFragment extends DialogFragment {
|
|||||||
mCheckBox.setEnabled(true);
|
mCheckBox.setEnabled(true);
|
||||||
mCheckBox.setVisibility(View.VISIBLE);
|
mCheckBox.setVisibility(View.VISIBLE);
|
||||||
mCheckBox.setText(checkboxText);
|
mCheckBox.setText(checkboxText);
|
||||||
|
mCheckBox.setChecked(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
alert.setView(view);
|
alert.setView(view);
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ public class ExportHelper
|
|||||||
final boolean showSecretCheckbox) {
|
final boolean showSecretCheckbox) {
|
||||||
mExportFile = exportFile;
|
mExportFile = exportFile;
|
||||||
|
|
||||||
String title = null;
|
String title;
|
||||||
if (masterKeyIds == null) {
|
if (masterKeyIds == null) {
|
||||||
// export all keys
|
// export all keys
|
||||||
title = mActivity.getString(R.string.title_export_keys);
|
title = mActivity.getString(R.string.title_export_keys);
|
||||||
@@ -68,7 +68,7 @@ public class ExportHelper
|
|||||||
mExportFile = file;
|
mExportFile = file;
|
||||||
exportKeys(masterKeyIds, checked);
|
exportKeys(masterKeyIds, checked);
|
||||||
}
|
}
|
||||||
}, mActivity.getSupportFragmentManager() ,title, message, exportFile, checkMsg);
|
}, mActivity.getSupportFragmentManager(), title, message, exportFile, checkMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: If ExportHelper requires pending data (see CryptoOPerationHelper), activities using
|
// TODO: If ExportHelper requires pending data (see CryptoOPerationHelper), activities using
|
||||||
|
|||||||
71
OpenKeychain/src/main/res/layout/backup_fragment.xml
Normal file
71
OpenKeychain/src/main/res/layout/backup_fragment.xml
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingLeft="16dp"
|
||||||
|
android:paddingRight="16dp"
|
||||||
|
android:paddingTop="24dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingBottom="8dip"
|
||||||
|
android:text="@string/backup_text"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceMedium" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
style="@style/SectionHeader"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:text="@string/backup_section" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/backup_all"
|
||||||
|
style="?android:attr/borderlessButtonStyle"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:clickable="true"
|
||||||
|
android:drawablePadding="8dp"
|
||||||
|
android:drawableRight="@drawable/ic_save_grey_24dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:minHeight="?android:attr/listPreferredItemHeight"
|
||||||
|
android:paddingLeft="8dp"
|
||||||
|
android:paddingRight="8dp"
|
||||||
|
android:text="@string/backup_all"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceMedium" />
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dip"
|
||||||
|
android:background="?android:attr/listDivider" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/backup_public_keys"
|
||||||
|
style="?android:attr/borderlessButtonStyle"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:clickable="true"
|
||||||
|
android:drawablePadding="8dp"
|
||||||
|
android:drawableRight="@drawable/ic_save_grey_24dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:minHeight="?android:attr/listPreferredItemHeight"
|
||||||
|
android:paddingLeft="8dp"
|
||||||
|
android:paddingRight="8dp"
|
||||||
|
android:text="@string/backup_public_keys"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceMedium" />
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dip"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:background="?android:attr/listDivider" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</ScrollView>
|
||||||
@@ -125,6 +125,23 @@
|
|||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
android:background="?android:attr/listDivider" />
|
android:background="?android:attr/listDivider" />
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/view_key_action_key_export"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:padding="8dp"
|
||||||
|
android:src="@drawable/ic_save_grey_24dp"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:background="?android:selectableItemBackground" />
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="1dip"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="right"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:background="?android:attr/listDivider" />
|
||||||
|
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/view_key_action_key_nfc"
|
android:id="@+id/view_key_action_key_nfc"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
|||||||
@@ -1,28 +1,16 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<menu xmlns:tools="http://schemas.android.com/tools"
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/menu_key_list_multi_encrypt"
|
android:id="@+id/menu_key_list_multi_encrypt"
|
||||||
android:icon="@drawable/ic_lock_white_24dp"
|
android:icon="@drawable/ic_lock_white_24dp"
|
||||||
android:title="@string/menu_encrypt_to" />
|
android:title="@string/menu_encrypt_to" />
|
||||||
|
|
||||||
<item
|
|
||||||
android:id="@+id/menu_key_list_multi_export"
|
|
||||||
android:showAsAction="never"
|
|
||||||
tools:ignore="AppCompatResource"
|
|
||||||
android:title="@string/menu_export_key" />
|
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/menu_key_list_multi_delete"
|
android:id="@+id/menu_key_list_multi_delete"
|
||||||
android:showAsAction="never"
|
android:showAsAction="never"
|
||||||
tools:ignore="AppCompatResource"
|
android:title="@string/menu_delete_key"
|
||||||
android:title="@string/menu_delete_key" />
|
tools:ignore="AppCompatResource" />
|
||||||
|
|
||||||
<item
|
|
||||||
android:id="@+id/menu_key_list_multi_select_all"
|
|
||||||
android:showAsAction="never"
|
|
||||||
tools:ignore="AppCompatResource"
|
|
||||||
android:title="@string/menu_select_all" />
|
|
||||||
|
|
||||||
</menu>
|
</menu>
|
||||||
|
|||||||
@@ -96,7 +96,7 @@
|
|||||||
<!-- menu -->
|
<!-- menu -->
|
||||||
<string name="menu_preferences">"Settings"</string>
|
<string name="menu_preferences">"Settings"</string>
|
||||||
<string name="menu_help">"Help"</string>
|
<string name="menu_help">"Help"</string>
|
||||||
<string name="menu_export_key">"Export to file"</string>
|
<string name="menu_export_key">"Backup to file"</string>
|
||||||
<string name="menu_delete_key">"Delete key"</string>
|
<string name="menu_delete_key">"Delete key"</string>
|
||||||
<string name="menu_manage_keys">"Manage my keys"</string>
|
<string name="menu_manage_keys">"Manage my keys"</string>
|
||||||
<string name="menu_search">"Search"</string>
|
<string name="menu_search">"Search"</string>
|
||||||
@@ -736,6 +736,7 @@
|
|||||||
<string name="drawer_open">"Open navigation drawer"</string>
|
<string name="drawer_open">"Open navigation drawer"</string>
|
||||||
<string name="drawer_close">"Close navigation drawer"</string>
|
<string name="drawer_close">"Close navigation drawer"</string>
|
||||||
<string name="my_keys">"My Keys"</string>
|
<string name="my_keys">"My Keys"</string>
|
||||||
|
<string name="nav_backup">"Backup"</string>
|
||||||
|
|
||||||
<!-- hints -->
|
<!-- hints -->
|
||||||
<string name="encrypt_content_edit_text_hint">"Type text"</string>
|
<string name="encrypt_content_edit_text_hint">"Type text"</string>
|
||||||
@@ -1316,6 +1317,11 @@
|
|||||||
<string name="first_time_blank_yubikey">"Would you like to use this blank YubiKey NEO with OpenKeychain?\n\nPlease take away the YubiKey now, you will be prompted when it is needed again!"</string>
|
<string name="first_time_blank_yubikey">"Would you like to use this blank YubiKey NEO with OpenKeychain?\n\nPlease take away the YubiKey now, you will be prompted when it is needed again!"</string>
|
||||||
<string name="first_time_blank_yubikey_yes">"Use this YubiKey"</string>
|
<string name="first_time_blank_yubikey_yes">"Use this YubiKey"</string>
|
||||||
|
|
||||||
|
<string name="backup_text">"Backups that include your own keys must never be shared with other people!"</string>
|
||||||
|
<string name="backup_all">"All keys + your own keys"</string>
|
||||||
|
<string name="backup_public_keys">"All keys"</string>
|
||||||
|
<string name="backup_section">"Backup"</string>
|
||||||
|
|
||||||
<!-- unsorted -->
|
<!-- unsorted -->
|
||||||
<string name="section_certifier_id">"Certifier"</string>
|
<string name="section_certifier_id">"Certifier"</string>
|
||||||
<string name="section_cert">"Certificate Details"</string>
|
<string name="section_cert">"Certificate Details"</string>
|
||||||
|
|||||||
Reference in New Issue
Block a user