aboutsummaryrefslogtreecommitdiffstats
path: root/OpenKeychain/src/main/java/org/sufficientlysecure
diff options
context:
space:
mode:
authorVincent Breitmoser <valodim@mugenguild.com>2015-11-14 03:24:07 +0100
committerDominik Schürmann <dominik@dominikschuermann.de>2015-12-27 15:00:14 +0100
commit00e97586b06e5e61f6639b75423f9ec3edba47a0 (patch)
tree594795a6d66d4d3f0a09a0b9108b2d533691397f /OpenKeychain/src/main/java/org/sufficientlysecure
parentfd119bda00bac1cfe6dbcafa2736c65e3624c083 (diff)
downloadopen-keychain-00e97586b06e5e61f6639b75423f9ec3edba47a0.tar.gz
open-keychain-00e97586b06e5e61f6639b75423f9ec3edba47a0.tar.bz2
open-keychain-00e97586b06e5e61f6639b75423f9ec3edba47a0.zip
inline subkey editing (wip commit)
Diffstat (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure')
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java3
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvSubkeysFragment.java272
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvUserIdsFragment.java4
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java29
4 files changed, 294 insertions, 14 deletions
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java
index fa0edec48..969a84f14 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java
@@ -231,7 +231,8 @@ public class EditKeyFragment extends QueueingCryptoOperationFragment<SaveKeyring
mUserIdsAddedAdapter = new UserIdsAddedAdapter(getActivity(), mSaveKeyringParcel.mAddUserIds, false);
mUserIdsAddedList.setAdapter(mUserIdsAddedAdapter);
- mSubkeysAdapter = new SubkeysAdapter(getActivity(), null, 0, mSaveKeyringParcel);
+ mSubkeysAdapter = new SubkeysAdapter(getActivity(), null, 0);
+ mSubkeysAdapter.setEditMode(mSaveKeyringParcel);
mSubkeysList.setAdapter(mSubkeysAdapter);
mSubkeysAddedAdapter = new SubkeysAddedAdapter(getActivity(), mSaveKeyringParcel.mAddSubKeys, false);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvSubkeysFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvSubkeysFragment.java
index bd00c6780..ce68bfab1 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvSubkeysFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvSubkeysFragment.java
@@ -20,30 +20,59 @@ package org.sufficientlysecure.keychain.ui;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.os.Messenger;
+import android.support.v4.app.FragmentActivity;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
+import android.view.ActionMode;
+import android.view.ActionMode.Callback;
import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.AdapterView;
import android.widget.ListView;
+import android.widget.ViewAnimator;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround;
+import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
import org.sufficientlysecure.keychain.provider.KeychainContract;
+import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
+import org.sufficientlysecure.keychain.service.SaveKeyringParcel.SubkeyChange;
import org.sufficientlysecure.keychain.ui.adapter.SubkeysAdapter;
+import org.sufficientlysecure.keychain.ui.adapter.SubkeysAddedAdapter;
+import org.sufficientlysecure.keychain.ui.adapter.UserIdsAddedAdapter;
+import org.sufficientlysecure.keychain.ui.dialog.AddSubkeyDialogFragment;
+import org.sufficientlysecure.keychain.ui.dialog.EditSubkeyDialogFragment;
+import org.sufficientlysecure.keychain.ui.dialog.EditSubkeyExpiryDialogFragment;
+import org.sufficientlysecure.keychain.ui.util.Notify;
import org.sufficientlysecure.keychain.util.Log;
public class ViewKeyAdvSubkeysFragment extends LoaderFragment implements
LoaderManager.LoaderCallbacks<Cursor> {
public static final String ARG_DATA_URI = "data_uri";
+ public static final int LOADER_ID_SUBKEYS = 0;
private ListView mSubkeysList;
+ private ListView mSubkeysAddedList;
+ private View mSubkeysAddedLayout;
+ private ViewAnimator mSubkeyAddFabLayout;
+
private SubkeysAdapter mSubkeysAdapter;
+ private SubkeysAddedAdapter mSubkeysAddedAdapter;
private Uri mDataUriSubkeys;
+ private boolean mHasSecret;
+ private SaveKeyringParcel mEditModeSaveKeyringParcel;
+
/**
* Creates new instance of this fragment
*/
@@ -64,6 +93,36 @@ public class ViewKeyAdvSubkeysFragment extends LoaderFragment implements
mSubkeysList = (ListView) view.findViewById(R.id.keys);
+ mSubkeysList = (ListView) view.findViewById(R.id.view_key_user_ids);
+ mSubkeysAddedList = (ListView) view.findViewById(R.id.view_key_user_ids_added);
+ mSubkeysAddedLayout = view.findViewById(R.id.view_key_user_ids_add_layout);
+
+ mSubkeysList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ editSubkey(position);
+ }
+ });
+
+ View footer = new View(getActivity());
+ int spacing = (int) android.util.TypedValue.applyDimension(
+ android.util.TypedValue.COMPLEX_UNIT_DIP, 72, getResources().getDisplayMetrics()
+ );
+ android.widget.AbsListView.LayoutParams params = new android.widget.AbsListView.LayoutParams(
+ android.widget.AbsListView.LayoutParams.MATCH_PARENT,
+ spacing
+ );
+ footer.setLayoutParams(params);
+ mSubkeysAddedList.addFooterView(footer, null, false);
+
+ mSubkeyAddFabLayout = (ViewAnimator) view.findViewById(R.id.view_key_subkey_fab_layout);
+ view.findViewById(R.id.view_key_subkey_fab).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ addSubkey();
+ }
+ });
+
return root;
}
@@ -90,7 +149,7 @@ public class ViewKeyAdvSubkeysFragment extends LoaderFragment implements
// Prepare the loaders. Either re-connect with an existing ones,
// or start new ones.
- getLoaderManager().initLoader(0, null, this);
+ getLoaderManager().initLoader(LOADER_ID_SUBKEYS, null, this);
}
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
@@ -122,4 +181,215 @@ public class ViewKeyAdvSubkeysFragment extends LoaderFragment implements
mSubkeysAdapter.swapCursor(null);
}
+ private void enterEditMode() {
+ FragmentActivity activity = getActivity();
+ activity.startActionMode(new Callback() {
+ @Override
+ public boolean onCreateActionMode(ActionMode mode, Menu menu) {
+
+ mEditModeSaveKeyringParcel = new SaveKeyringParcel(0L, new byte[0]);
+
+ mSubkeysAddedAdapter =
+ new SubkeysAddedAdapter(getActivity(), mEditModeSaveKeyringParcel.mAddSubKeys, false);
+ mSubkeysAddedList.setAdapter(mSubkeysAddedAdapter);
+ mSubkeysAddedLayout.setVisibility(View.VISIBLE);
+ mSubkeyAddFabLayout.setDisplayedChild(1);
+
+ mSubkeysAdapter.setEditMode(mEditModeSaveKeyringParcel);
+ getLoaderManager().restartLoader(LOADER_ID_SUBKEYS, null, ViewKeyAdvSubkeysFragment.this);
+
+ mode.setTitle(R.string.title_edit_subkeys);
+ mode.getMenuInflater().inflate(R.menu.action_edit_uids, menu);
+
+ return true;
+ }
+
+ @Override
+ public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
+ return false;
+ }
+
+ @Override
+ public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
+ mode.finish();
+ return true;
+ }
+
+ @Override
+ public void onDestroyActionMode(ActionMode mode) {
+ mEditModeSaveKeyringParcel = null;
+ mSubkeysAdapter.setEditMode(null);
+ mSubkeysAddedLayout.setVisibility(View.GONE);
+ mSubkeyAddFabLayout.setDisplayedChild(0);
+ getLoaderManager().restartLoader(0, null, ViewKeyAdvSubkeysFragment.this);
+ }
+ });
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case R.id.menu_edit_subkeys:
+ enterEditMode();
+ return true;
+ default:
+ return super.onOptionsItemSelected(item);
+ }
+ }
+
+ private void addSubkey() {
+ boolean willBeMasterKey;
+ if (mSubkeysAdapter != null) {
+ willBeMasterKey = mSubkeysAdapter.getCount() == 0 && mSubkeysAddedAdapter.getCount() == 0;
+ } else {
+ willBeMasterKey = mSubkeysAddedAdapter.getCount() == 0;
+ }
+
+ AddSubkeyDialogFragment addSubkeyDialogFragment =
+ AddSubkeyDialogFragment.newInstance(willBeMasterKey);
+ addSubkeyDialogFragment
+ .setOnAlgorithmSelectedListener(
+ new AddSubkeyDialogFragment.OnAlgorithmSelectedListener() {
+ @Override
+ public void onAlgorithmSelected(SaveKeyringParcel.SubkeyAdd newSubkey) {
+ mSubkeysAddedAdapter.add(newSubkey);
+ }
+ }
+ );
+ addSubkeyDialogFragment.show(getActivity().getSupportFragmentManager(), "addSubkeyDialog");
+ }
+
+ private void editSubkey(final int position) {
+ final long keyId = mSubkeysAdapter.getKeyId(position);
+
+ Handler returnHandler = new Handler() {
+ @Override
+ public void handleMessage(Message message) {
+ switch (message.what) {
+ case EditSubkeyDialogFragment.MESSAGE_CHANGE_EXPIRY:
+ editSubkeyExpiry(position);
+ break;
+ case EditSubkeyDialogFragment.MESSAGE_REVOKE:
+ // toggle
+ if (mEditModeSaveKeyringParcel.mRevokeSubKeys.contains(keyId)) {
+ mEditModeSaveKeyringParcel.mRevokeSubKeys.remove(keyId);
+ } else {
+ mEditModeSaveKeyringParcel.mRevokeSubKeys.add(keyId);
+ }
+ break;
+ case EditSubkeyDialogFragment.MESSAGE_STRIP: {
+ SecretKeyType secretKeyType = mSubkeysAdapter.getSecretKeyType(position);
+ if (secretKeyType == SecretKeyType.GNU_DUMMY) {
+ // Key is already stripped; this is a no-op.
+ break;
+ }
+
+ SubkeyChange change = mEditModeSaveKeyringParcel.getSubkeyChange(keyId);
+ if (change == null) {
+ mEditModeSaveKeyringParcel.mChangeSubKeys.add(new SubkeyChange(keyId, true, false));
+ break;
+ }
+ // toggle
+ change.mDummyStrip = !change.mDummyStrip;
+ if (change.mDummyStrip && change.mMoveKeyToCard) {
+ // User had chosen to divert key, but now wants to strip it instead.
+ change.mMoveKeyToCard = false;
+ }
+ break;
+ }
+ case EditSubkeyDialogFragment.MESSAGE_MOVE_KEY_TO_CARD: {
+ // TODO: enable later when Admin PIN handling is resolved
+ Notify.create(getActivity(),
+ "This feature will be available in an upcoming OpenKeychain version.",
+ Notify.Style.WARN).show();
+ break;
+
+// Activity activity = EditKeyFragment.this.getActivity();
+// SecretKeyType secretKeyType = mSubkeysAdapter.getSecretKeyType(position);
+// if (secretKeyType == SecretKeyType.DIVERT_TO_CARD ||
+// secretKeyType == SecretKeyType.GNU_DUMMY) {
+// Notify.create(activity, R.string.edit_key_error_bad_nfc_stripped, Notify.Style.ERROR)
+// .show((ViewGroup) activity.findViewById(R.id.import_snackbar));
+// break;
+// }
+// int algorithm = mSubkeysAdapter.getAlgorithm(position);
+// // these are the PGP constants for RSA_GENERAL, RSA_ENCRYPT and RSA_SIGN
+// if (algorithm != 1 && algorithm != 2 && algorithm != 3) {
+// Notify.create(activity, R.string.edit_key_error_bad_nfc_algo, Notify.Style.ERROR)
+// .show((ViewGroup) activity.findViewById(R.id.import_snackbar));
+// break;
+// }
+// if (mSubkeysAdapter.getKeySize(position) != 2048) {
+// Notify.create(activity, R.string.edit_key_error_bad_nfc_size, Notify.Style.ERROR)
+// .show((ViewGroup) activity.findViewById(R.id.import_snackbar));
+// break;
+// }
+//
+//
+// SubkeyChange change;
+// change = mSaveKeyringParcel.getSubkeyChange(keyId);
+// if (change == null) {
+// mSaveKeyringParcel.mChangeSubKeys.add(
+// new SubkeyChange(keyId, false, true)
+// );
+// break;
+// }
+// // toggle
+// change.mMoveKeyToCard = !change.mMoveKeyToCard;
+// if (change.mMoveKeyToCard && change.mDummyStrip) {
+// // User had chosen to strip key, but now wants to divert it.
+// change.mDummyStrip = false;
+// }
+// break;
+ }
+ }
+ getLoaderManager().getLoader(LOADER_ID_SUBKEYS).forceLoad();
+ }
+ };
+
+ // Create a new Messenger for the communication back
+ final Messenger messenger = new Messenger(returnHandler);
+
+ DialogFragmentWorkaround.INTERFACE.runnableRunDelayed(new Runnable() {
+ public void run() {
+ EditSubkeyDialogFragment dialogFragment =
+ EditSubkeyDialogFragment.newInstance(messenger);
+
+ dialogFragment.show(getActivity().getSupportFragmentManager(), "editSubkeyDialog");
+ }
+ });
+ }
+
+ private void editSubkeyExpiry(final int position) {
+ final long keyId = mSubkeysAdapter.getKeyId(position);
+ final Long creationDate = mSubkeysAdapter.getCreationDate(position);
+ final Long expiryDate = mSubkeysAdapter.getExpiryDate(position);
+
+ Handler returnHandler = new Handler() {
+ @Override
+ public void handleMessage(Message message) {
+ switch (message.what) {
+ case EditSubkeyExpiryDialogFragment.MESSAGE_NEW_EXPIRY:
+ mEditModeSaveKeyringParcel.getOrCreateSubkeyChange(keyId).mExpiry =
+ (Long) message.getData().getSerializable(
+ EditSubkeyExpiryDialogFragment.MESSAGE_DATA_EXPIRY);
+ break;
+ }
+ getLoaderManager().getLoader(LOADER_ID_SUBKEYS).forceLoad();
+ }
+ };
+
+ // Create a new Messenger for the communication back
+ final Messenger messenger = new Messenger(returnHandler);
+
+ DialogFragmentWorkaround.INTERFACE.runnableRunDelayed(new Runnable() {
+ public void run() {
+ EditSubkeyExpiryDialogFragment dialogFragment =
+ EditSubkeyExpiryDialogFragment.newInstance(messenger, creationDate, expiryDate);
+
+ dialogFragment.show(getActivity().getSupportFragmentManager(), "editSubkeyExpiryDialog");
+ }
+ });
+ }
+
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvUserIdsFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvUserIdsFragment.java
index e98970754..c8e892276 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvUserIdsFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvUserIdsFragment.java
@@ -101,8 +101,8 @@ public class ViewKeyAdvUserIdsFragment extends LoaderFragment implements
footer.setLayoutParams(params);
mUserIdsAddedList.addFooterView(footer, null, false);
- mUserIdAddFabLayout = (ViewAnimator) view.findViewById(R.id.view_key_user_id_fab_layout);
- view.findViewById(R.id.view_key_user_id_fab).setOnClickListener(new View.OnClickListener() {
+ mUserIdAddFabLayout = (ViewAnimator) view.findViewById(R.id.view_key_subkey_fab_layout);
+ view.findViewById(R.id.view_key_subkey_fab).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
addUserId();
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java
index 24f5f04a1..84608f2dc 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java
@@ -22,6 +22,7 @@ import android.content.res.ColorStateList;
import android.database.Cursor;
import android.graphics.PorterDuff;
import android.graphics.Typeface;
+import android.support.annotation.Nullable;
import android.support.v4.widget.CursorAdapter;
import android.text.Spannable;
import android.text.SpannableString;
@@ -49,7 +50,7 @@ public class SubkeysAdapter extends CursorAdapter {
private LayoutInflater mInflater;
private SaveKeyringParcel mSaveKeyringParcel;
- private boolean hasAnySecret;
+ private boolean mHasAnySecret;
private ColorStateList mDefaultTextColor;
public static final String[] SUBKEYS_PROJECTION = new String[]{
@@ -85,16 +86,10 @@ public class SubkeysAdapter extends CursorAdapter {
private static final int INDEX_EXPIRY = 13;
private static final int INDEX_FINGERPRINT = 14;
- public SubkeysAdapter(Context context, Cursor c, int flags,
- SaveKeyringParcel saveKeyringParcel) {
+ public SubkeysAdapter(Context context, Cursor c, int flags) {
super(context, c, flags);
mInflater = LayoutInflater.from(context);
- mSaveKeyringParcel = saveKeyringParcel;
- }
-
- public SubkeysAdapter(Context context, Cursor c, int flags) {
- this(context, c, flags, null);
}
public long getKeyId(int position) {
@@ -133,12 +128,12 @@ public class SubkeysAdapter extends CursorAdapter {
@Override
public Cursor swapCursor(Cursor newCursor) {
- hasAnySecret = false;
+ mHasAnySecret = false;
if (newCursor != null && newCursor.moveToFirst()) {
do {
SecretKeyType hasSecret = SecretKeyType.fromNum(newCursor.getInt(INDEX_HAS_SECRET));
if (hasSecret.isUsable()) {
- hasAnySecret = true;
+ mHasAnySecret = true;
break;
}
} while (newCursor.moveToNext());
@@ -354,4 +349,18 @@ public class SubkeysAdapter extends CursorAdapter {
}
}
+ /** Set this adapter into edit mode. This mode displays additional info for
+ * each item from a supplied SaveKeyringParcel reference.
+ *
+ * Note that it is up to the caller to reload the underlying cursor after
+ * updating the SaveKeyringParcel!
+ *
+ * @see SaveKeyringParcel
+ *
+ * @param saveKeyringParcel The parcel to get info from, or null to leave edit mode.
+ */
+ public void setEditMode(@Nullable SaveKeyringParcel saveKeyringParcel) {
+ mSaveKeyringParcel = saveKeyringParcel;
+ }
+
}