aboutsummaryrefslogtreecommitdiffstats
path: root/OpenKeychain
diff options
context:
space:
mode:
authorDominik Schürmann <dominik@dominikschuermann.de>2015-07-08 13:25:07 +0200
committerDominik Schürmann <dominik@dominikschuermann.de>2015-07-08 13:25:07 +0200
commitd4fbaf9397da725489c6b86341d9eb9db6c14bdb (patch)
tree95dd580aaa85ec6e41981165fb98bf5ac47560dc /OpenKeychain
parent7b35f9b07aef6b36e7cb7bdedf178d2c5a4588ad (diff)
downloadopen-keychain-d4fbaf9397da725489c6b86341d9eb9db6c14bdb.tar.gz
open-keychain-d4fbaf9397da725489c6b86341d9eb9db6c14bdb.tar.bz2
open-keychain-d4fbaf9397da725489c6b86341d9eb9db6c14bdb.zip
Rudimentary backup feature
Diffstat (limited to 'OpenKeychain')
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/compatibility/DialogFragmentWorkaround.java2
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BackupFragment.java137
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java73
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java21
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java2
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java28
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/FileDialogFragment.java1
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ExportHelper.java4
-rw-r--r--OpenKeychain/src/main/res/layout/backup_fragment.xml71
-rw-r--r--OpenKeychain/src/main/res/layout/view_key_adv_share_fragment.xml17
-rw-r--r--OpenKeychain/src/main/res/menu/key_list_multi.xml20
-rw-r--r--OpenKeychain/src/main/res/values/strings.xml8
12 files changed, 288 insertions, 96 deletions
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/compatibility/DialogFragmentWorkaround.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/compatibility/DialogFragmentWorkaround.java
index 07799f466..e1d8c0da7 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/compatibility/DialogFragmentWorkaround.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/compatibility/DialogFragmentWorkaround.java
@@ -21,7 +21,7 @@ import android.os.Build;
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
*
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BackupFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BackupFragment.java
new file mode 100644
index 000000000..714623ad4
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BackupFragment.java
@@ -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);
+ }
+ }
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java
index bb19fe2b1..9bffea504 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java
@@ -116,12 +116,6 @@ public class KeyListFragment extends LoaderFragment
// for ConsolidateOperation
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
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -242,18 +236,6 @@ public class KeyListFragment extends LoaderFragment
showDeleteKeyDialog(mode, ids, mAdapter.isAnySecretSelected());
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;
}
@@ -641,48 +623,6 @@ public class KeyListFragment extends LoaderFragment
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
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (mImportOpHelper != null) {
@@ -693,19 +633,6 @@ public class KeyListFragment extends LoaderFragment
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 a result has been returned, display a notify
if (data != null && data.hasExtra(OperationResult.EXTRA_RESULT)) {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java
index 51ed2b012..bdcc0b82f 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java
@@ -48,8 +48,9 @@ public class MainActivity extends BaseNfcActivity implements FabContainer, OnBac
static final int ID_KEYS = 1;
static final int ID_ENCRYPT_DECRYPT = 2;
static final int ID_APPS = 3;
- static final int ID_SETTINGS = 4;
- static final int ID_HELP = 5;
+ static final int ID_BACKUP = 4;
+ static final int ID_SETTINGS = 5;
+ static final int ID_HELP = 6;
// both of these are used for instrumentation testing only
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)
.withIdentifier(ID_ENCRYPT_DECRYPT).withCheckable(false),
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(
// display and stick on bottom of drawer
@@ -99,6 +102,9 @@ public class MainActivity extends BaseNfcActivity implements FabContainer, OnBac
case ID_APPS:
onAppsSelected();
break;
+ case ID_BACKUP:
+ onBackupSelected();
+ break;
case ID_SETTINGS:
intent = new Intent(MainActivity.this, SettingsActivity.class);
break;
@@ -192,6 +198,13 @@ public class MainActivity extends BaseNfcActivity implements FabContainer, OnBac
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
protected void onSaveInstanceState(Bundle outState) {
// 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);
} else if (frag instanceof AppsListFragment) {
mDrawerResult.setSelection(mDrawerResult.getPositionFromIdentifier(ID_APPS), false);
+ } else if (frag instanceof BackupFragment) {
+ mDrawerResult.setSelection(mDrawerResult.getPositionFromIdentifier(ID_BACKUP), false);
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java
index a50696cf3..3d6ffb39c 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java
@@ -363,6 +363,8 @@ public class ViewKeyActivity extends BaseNfcActivity implements
public boolean onPrepareOptionsMenu(Menu menu) {
MenuItem editKey = menu.findItem(R.id.menu_key_view_edit);
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);
certifyFingerprint.setVisible(!mIsSecret && !mIsVerified && !mIsExpired && !mIsRevoked);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java
index f46b30137..0613388d7 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java
@@ -22,6 +22,7 @@ import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStreamWriter;
+import java.util.HashMap;
import android.app.Activity;
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.Style;
import org.sufficientlysecure.keychain.ui.util.QrCodeUtils;
+import org.sufficientlysecure.keychain.util.ExportHelper;
import org.sufficientlysecure.keychain.util.Log;
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 vFingerprintClipboardButton = view.findViewById(R.id.view_key_action_fingerprint_clipboard);
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 vKeyClipboardButton = view.findViewById(R.id.view_key_action_key_clipboard);
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);
}
});
+ vKeySafeButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ exportToFile(mDataUri, new ProviderHelper(getActivity()));
+ }
+ });
vKeyClipboardButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
@@ -164,6 +173,25 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements
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) {
long keyId = 0;
try {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/FileDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/FileDialogFragment.java
index 63b6d26ac..5ef8618ce 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/FileDialogFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/FileDialogFragment.java
@@ -136,6 +136,7 @@ public class FileDialogFragment extends DialogFragment {
mCheckBox.setEnabled(true);
mCheckBox.setVisibility(View.VISIBLE);
mCheckBox.setText(checkboxText);
+ mCheckBox.setChecked(true);
}
alert.setView(view);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ExportHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ExportHelper.java
index 9567fc9c0..cc51ef700 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ExportHelper.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ExportHelper.java
@@ -49,7 +49,7 @@ public class ExportHelper
final boolean showSecretCheckbox) {
mExportFile = exportFile;
- String title = null;
+ String title;
if (masterKeyIds == null) {
// export all keys
title = mActivity.getString(R.string.title_export_keys);
@@ -68,7 +68,7 @@ public class ExportHelper
mExportFile = file;
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
diff --git a/OpenKeychain/src/main/res/layout/backup_fragment.xml b/OpenKeychain/src/main/res/layout/backup_fragment.xml
new file mode 100644
index 000000000..96fba954b
--- /dev/null
+++ b/OpenKeychain/src/main/res/layout/backup_fragment.xml
@@ -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> \ No newline at end of file
diff --git a/OpenKeychain/src/main/res/layout/view_key_adv_share_fragment.xml b/OpenKeychain/src/main/res/layout/view_key_adv_share_fragment.xml
index c08d66cc1..d82506e74 100644
--- a/OpenKeychain/src/main/res/layout/view_key_adv_share_fragment.xml
+++ b/OpenKeychain/src/main/res/layout/view_key_adv_share_fragment.xml
@@ -126,6 +126,23 @@
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
android:id="@+id/view_key_action_key_nfc"
android:layout_width="wrap_content"
android:layout_height="match_parent"
diff --git a/OpenKeychain/src/main/res/menu/key_list_multi.xml b/OpenKeychain/src/main/res/menu/key_list_multi.xml
index 7fdf4a5c1..77d61788e 100644
--- a/OpenKeychain/src/main/res/menu/key_list_multi.xml
+++ b/OpenKeychain/src/main/res/menu/key_list_multi.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
-<menu xmlns:tools="http://schemas.android.com/tools"
- xmlns:android="http://schemas.android.com/apk/res/android">
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools">
<item
android:id="@+id/menu_key_list_multi_encrypt"
@@ -8,21 +8,9 @@
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
android:id="@+id/menu_key_list_multi_delete"
android:showAsAction="never"
- tools:ignore="AppCompatResource"
- android:title="@string/menu_delete_key" />
-
- <item
- android:id="@+id/menu_key_list_multi_select_all"
- android:showAsAction="never"
- tools:ignore="AppCompatResource"
- android:title="@string/menu_select_all" />
+ android:title="@string/menu_delete_key"
+ tools:ignore="AppCompatResource" />
</menu>
diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml
index 9135c24c5..86fcdbf7e 100644
--- a/OpenKeychain/src/main/res/values/strings.xml
+++ b/OpenKeychain/src/main/res/values/strings.xml
@@ -96,7 +96,7 @@
<!-- menu -->
<string name="menu_preferences">"Settings"</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_manage_keys">"Manage my keys"</string>
<string name="menu_search">"Search"</string>
@@ -736,6 +736,7 @@
<string name="drawer_open">"Open navigation drawer"</string>
<string name="drawer_close">"Close navigation drawer"</string>
<string name="my_keys">"My Keys"</string>
+ <string name="nav_backup">"Backup"</string>
<!-- hints -->
<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_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 -->
<string name="section_certifier_id">"Certifier"</string>
<string name="section_cert">"Certificate Details"</string>