diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/AutocryptPeerDataAccessObject.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/AutocryptPeerDataAccessObject.java index cde27b506..768ec6321 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/AutocryptPeerDataAccessObject.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/AutocryptPeerDataAccessObject.java @@ -149,4 +149,8 @@ public class AutocryptPeerDataAccessObject { cv.put(ApiAutocryptPeer.STATE, status); mQueryInterface.update(ApiAutocryptPeer.buildByPackageNameAndAutocryptId(packageName, autocryptId), cv, null, null); } + + public void delete(String autocryptId) { + mQueryInterface.delete(ApiAutocryptPeer.buildByPackageNameAndAutocryptId(packageName, autocryptId), null, null); + } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java index 50bba9730..7ea06a773 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java @@ -932,6 +932,25 @@ public class KeychainProvider extends ContentProvider { break; } + case AUTOCRYPT_PEERS_BY_PACKAGE_NAME_AND_TRUST_ID: { + String packageName = uri.getPathSegments().get(2); + String autocryptPeer = uri.getPathSegments().get(3); + + String selection = ApiAutocryptPeer.PACKAGE_NAME + " = ? AND " + ApiAutocryptPeer.IDENTIFIER + " = ?"; + selectionArgs = new String[] { packageName, autocryptPeer }; + + Cursor cursor = db.query(Tables.API_AUTOCRYPT_PEERS, new String[] { ApiAutocryptPeer.MASTER_KEY_ID }, + selection, selectionArgs, null, null, null); + Long masterKeyId = null; + if (cursor != null && cursor.moveToNext() && !cursor.isNull(0)) { + masterKeyId = cursor.getLong(0); + } + + count = db.delete(Tables.API_AUTOCRYPT_PEERS, selection, selectionArgs); + + break; + } + case AUTOCRYPT_PEERS_BY_MASTER_KEY_ID: String selection = ApiAutocryptPeer.MASTER_KEY_ID + " = " + uri.getLastPathSegment(); if (!TextUtils.isEmpty(additionalSelection)) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/IdentityAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/IdentityAdapter.java index 4206cf3bf..52ef50b5c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/IdentityAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/IdentityAdapter.java @@ -28,6 +28,7 @@ import android.os.Build.VERSION_CODES; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; +import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; @@ -53,15 +54,17 @@ public class IdentityAdapter extends RecyclerView.Adapter { private final Context context; private final LayoutInflater layoutInflater; private final boolean isSecret; + private final IdentityClickListener identityClickListener; private List data; - public IdentityAdapter(Context context, boolean isSecret) { + public IdentityAdapter(Context context, boolean isSecret, IdentityClickListener identityClickListener) { super(); this.layoutInflater = LayoutInflater.from(context); this.context = context; this.isSecret = isSecret; + this.identityClickListener = identityClickListener; } public void setData(List data) { @@ -91,7 +94,8 @@ public class IdentityAdapter extends RecyclerView.Adapter { @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { if (viewType == VIEW_TYPE_USER_ID) { - return new UserIdViewHolder(layoutInflater.inflate(R.layout.view_key_identity_user_id, parent, false)); + return new UserIdViewHolder( + layoutInflater.inflate(R.layout.view_key_identity_user_id, parent, false), identityClickListener); } else if (viewType == VIEW_TYPE_LINKED_ID) { return new LinkedIdViewHolder(layoutInflater.inflate(R.layout.linked_id_item, parent, false)); } else { @@ -195,9 +199,9 @@ public class IdentityAdapter extends RecyclerView.Adapter { private final TextView vAddress; private final TextView vComment; private final ImageView vIcon; - private final ImageView vTrustIdAction; + private final ImageView vMore; - private UserIdViewHolder(View view) { + private UserIdViewHolder(View view, final IdentityClickListener identityClickListener) { super(view); vName = (TextView) view.findViewById(R.id.user_id_item_name); @@ -205,7 +209,21 @@ public class IdentityAdapter extends RecyclerView.Adapter { vComment = (TextView) view.findViewById(R.id.user_id_item_comment); vIcon = (ImageView) view.findViewById(R.id.trust_id_app_icon); - vTrustIdAction = (ImageView) view.findViewById(R.id.trust_id_action); + vMore = (ImageView) view.findViewById(R.id.user_id_item_more); + + view.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + identityClickListener.onClickIdentity(getAdapterPosition()); + } + }); + + vMore.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + identityClickListener.onClickIdentityMore(getAdapterPosition(), v); + } + }); } public void bind(TrustIdInfo info) { @@ -220,16 +238,16 @@ public class IdentityAdapter extends RecyclerView.Adapter { } vIcon.setImageDrawable(info.getAppIcon()); - if (info.getTrustIdIntent() != null) { - vTrustIdAction.setVisibility(View.VISIBLE); - } + vMore.setVisibility(View.VISIBLE); + + itemView.setClickable(info.getTrustIdIntent() != null); } public void bind(UserIdInfo info) { bindUserIdInfo(info); vIcon.setVisibility(View.GONE); - vTrustIdAction.setVisibility(View.GONE); + vMore.setVisibility(View.GONE); } private void bindUserIdInfo(UserIdInfo info) { @@ -261,4 +279,9 @@ public class IdentityAdapter extends RecyclerView.Adapter { } } + + public interface IdentityClickListener { + void onClickIdentity(int position); + void onClickIdentityMore(int position, View anchor); + } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/ViewKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/ViewKeyFragment.java index a5e6af591..fb7335373 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/ViewKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/ViewKeyFragment.java @@ -25,7 +25,11 @@ import android.os.Handler; import android.support.v4.app.DialogFragment; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentTransaction; +import android.support.v7.widget.PopupMenu; +import android.support.v7.widget.PopupMenu.OnDismissListener; +import android.support.v7.widget.PopupMenu.OnMenuItemClickListener; import android.view.LayoutInflater; +import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; @@ -44,7 +48,7 @@ import org.sufficientlysecure.keychain.ui.keyview.view.KeyserverStatusView; import org.sufficientlysecure.keychain.ui.keyview.view.SystemContactCardView; -public class ViewKeyFragment extends LoaderFragment implements ViewKeyMvpView { +public class ViewKeyFragment extends LoaderFragment implements ViewKeyMvpView, OnMenuItemClickListener { public static final String ARG_MASTER_KEY_ID = "master_key_id"; public static final String ARG_IS_SECRET = "is_secret"; @@ -67,6 +71,8 @@ public class ViewKeyFragment extends LoaderFragment implements ViewKeyMvpView { KeyHealthPresenter mKeyHealthPresenter; KeyserverStatusPresenter mKeyserverStatusPresenter; + private Integer displayedContextMenuPosition; + /** * Creates new instance of this fragment */ @@ -161,4 +167,37 @@ public class ViewKeyFragment extends LoaderFragment implements ViewKeyMvpView { } }); } + + @Override + public void showContextMenu(int position, View anchor) { + displayedContextMenuPosition = position; + + PopupMenu menu = new PopupMenu(getContext(), anchor); + menu.inflate(R.menu.identity_context_menu); + menu.setOnMenuItemClickListener(this); + menu.setOnDismissListener(new OnDismissListener() { + @Override + public void onDismiss(PopupMenu popupMenu) { + displayedContextMenuPosition = null; + } + }); + menu.show(); + } + + @Override + public boolean onMenuItemClick(MenuItem item) { + if (displayedContextMenuPosition == null) { + return false; + } + + switch (item.getItemId()) { + case R.id.autocrypt_forget: + int position = displayedContextMenuPosition; + displayedContextMenuPosition = null; + mIdentitiesPresenter.onClickForgetIdentity(position); + return true; + } + + return false; + } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/loader/IdentityLoader.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/loader/IdentityLoader.java index fc816ca6a..d90c60245 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/loader/IdentityLoader.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/loader/IdentityLoader.java @@ -134,10 +134,10 @@ public class IdentityLoader extends AsyncTaskLoader> { UserIdInfo associatedUserIdInfo = findUserIdMatchingTrustId(identities, autocryptPeer); if (associatedUserIdInfo != null) { int position = identities.indexOf(associatedUserIdInfo); - TrustIdInfo autocryptPeerInfo = TrustIdInfo.create(associatedUserIdInfo, autocryptPeer, drawable, autocryptPeerIntent); + TrustIdInfo autocryptPeerInfo = TrustIdInfo.create(associatedUserIdInfo, autocryptPeer, packageName, drawable, autocryptPeerIntent); identities.set(position, autocryptPeerInfo); } else { - TrustIdInfo autocryptPeerInfo = TrustIdInfo.create(autocryptPeer, drawable, autocryptPeerIntent); + TrustIdInfo autocryptPeerInfo = TrustIdInfo.create(autocryptPeer, packageName, drawable, autocryptPeerIntent); identities.add(autocryptPeerInfo); } } @@ -305,6 +305,7 @@ public class IdentityLoader extends AsyncTaskLoader> { public abstract boolean isPrimary(); public abstract String getTrustId(); + public abstract String getPackageName(); @Nullable public abstract Drawable getAppIcon(); @Nullable @@ -312,14 +313,15 @@ public class IdentityLoader extends AsyncTaskLoader> { @Nullable public abstract Intent getTrustIdIntent(); - static TrustIdInfo create(UserIdInfo userIdInfo, String autocryptPeer, Drawable appIcon, Intent autocryptPeerIntent) { + static TrustIdInfo create(UserIdInfo userIdInfo, String autocryptPeer, String packageName, + Drawable appIcon, Intent autocryptPeerIntent) { return new AutoValue_IdentityLoader_TrustIdInfo(userIdInfo.getRank(), userIdInfo.getVerified(), - userIdInfo.isPrimary(), autocryptPeer, appIcon, userIdInfo, autocryptPeerIntent); + userIdInfo.isPrimary(), autocryptPeer, packageName, appIcon, userIdInfo, autocryptPeerIntent); } - static TrustIdInfo create(String autocryptPeer, Drawable appIcon, Intent autocryptPeerIntent) { + static TrustIdInfo create(String autocryptPeer, String packageName, Drawable appIcon, Intent autocryptPeerIntent) { return new AutoValue_IdentityLoader_TrustIdInfo( - 0, Certs.VERIFIED_SELF, false, autocryptPeer, appIcon, null, autocryptPeerIntent); + 0, Certs.VERIFIED_SELF, false, autocryptPeer, packageName, appIcon, null, autocryptPeerIntent); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/presenter/IdentitiesPresenter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/presenter/IdentitiesPresenter.java index d9b1ce04d..0680e09fe 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/presenter/IdentitiesPresenter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/presenter/IdentitiesPresenter.java @@ -28,13 +28,16 @@ import android.os.Bundle; import android.support.v4.app.LoaderManager; import android.support.v4.app.LoaderManager.LoaderCallbacks; import android.support.v4.content.Loader; +import android.view.View; import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.provider.AutocryptPeerDataAccessObject; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets; import org.sufficientlysecure.keychain.ui.EditIdentitiesActivity; import org.sufficientlysecure.keychain.ui.adapter.IdentityAdapter; +import org.sufficientlysecure.keychain.ui.adapter.IdentityAdapter.IdentityClickListener; import org.sufficientlysecure.keychain.ui.dialog.UserIdInfoDialogFragment; import org.sufficientlysecure.keychain.ui.keyview.LinkedIdViewFragment; import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityLoader; @@ -68,17 +71,23 @@ public class IdentitiesPresenter implements LoaderCallbacks> this.masterKeyId = masterKeyId; this.isSecret = isSecret; - identitiesAdapter = new IdentityAdapter(context, isSecret); + identitiesAdapter = new IdentityAdapter(context, isSecret, new IdentityClickListener() { + @Override + public void onClickIdentity(int position) { + showIdentityInfo(position); + } + + @Override + public void onClickIdentityMore(int position, View anchor) { + showIdentityContextMenu(position, anchor); + + } + }); view.setIdentitiesAdapter(identitiesAdapter); view.setEditIdentitiesButtonVisible(isSecret); view.setIdentitiesCardListener(new IdentitiesCardListener() { - @Override - public void onIdentityItemClick(int position) { - showIdentityInfo(position); - } - @Override public void onClickEditIdentities() { editIdentities(); @@ -120,10 +129,16 @@ public class IdentitiesPresenter implements LoaderCallbacks> showUserIdInfo((UserIdInfo) info); } else if (info instanceof TrustIdInfo) { Intent autocryptPeerIntent = ((TrustIdInfo) info).getTrustIdIntent(); - viewKeyMvpView.startActivity(autocryptPeerIntent); + if (autocryptPeerIntent != null) { + viewKeyMvpView.startActivity(autocryptPeerIntent); + } } } + private void showIdentityContextMenu(int position, View anchor) { + viewKeyMvpView.showContextMenu(position, anchor); + } + private void showLinkedId(final LinkedIdInfo info) { final LinkedIdViewFragment frag; try { @@ -158,6 +173,18 @@ public class IdentitiesPresenter implements LoaderCallbacks> context.startActivity(intent); } + public void onClickForgetIdentity(int position) { + TrustIdInfo info = (TrustIdInfo) identitiesAdapter.getInfo(position); + if (info == null) { + Log.e(Constants.TAG, "got a 'forget' click on a bad trust id"); + return; + } + + AutocryptPeerDataAccessObject autocryptPeerDao = + new AutocryptPeerDataAccessObject(context, info.getPackageName()); + autocryptPeerDao.delete(info.getTrustId()); + } + public interface IdentitiesMvpView { void setIdentitiesAdapter(IdentityAdapter userIdsAdapter); void setIdentitiesCardListener(IdentitiesCardListener identitiesCardListener); @@ -165,8 +192,6 @@ public class IdentitiesPresenter implements LoaderCallbacks> } public interface IdentitiesCardListener { - void onIdentityItemClick(int position); - void onClickEditIdentities(); void onClickAddIdentity(); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/presenter/ViewKeyMvpView.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/presenter/ViewKeyMvpView.java index 561af713d..3a4fa7f59 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/presenter/ViewKeyMvpView.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/presenter/ViewKeyMvpView.java @@ -4,6 +4,7 @@ package org.sufficientlysecure.keychain.ui.keyview.presenter; import android.content.Intent; import android.support.v4.app.DialogFragment; import android.support.v4.app.Fragment; +import android.view.View; public interface ViewKeyMvpView { @@ -13,4 +14,6 @@ public interface ViewKeyMvpView { void startActivityAndShowResultSnackbar(Intent intent); void showDialogFragment(DialogFragment dialogFragment, final String tag); void setContentShown(boolean show, boolean animate); + + void showContextMenu(int position, View anchor); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/view/IdentitiesCardView.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/view/IdentitiesCardView.java index d30f93093..0ddc6b160 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/view/IdentitiesCardView.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/view/IdentitiesCardView.java @@ -32,7 +32,6 @@ import org.sufficientlysecure.keychain.ui.adapter.IdentityAdapter; import org.sufficientlysecure.keychain.ui.keyview.presenter.IdentitiesPresenter.IdentitiesCardListener; import org.sufficientlysecure.keychain.ui.keyview.presenter.IdentitiesPresenter.IdentitiesMvpView; import org.sufficientlysecure.keychain.ui.util.recyclerview.DividerItemDecoration; -import org.sufficientlysecure.keychain.ui.util.recyclerview.RecyclerItemClickListener; public class IdentitiesCardView extends CardView implements IdentitiesMvpView { @@ -59,16 +58,6 @@ public class IdentitiesCardView extends CardView implements IdentitiesMvpView { } }); - vIdentities.addOnItemTouchListener(new RecyclerItemClickListener(context, - new RecyclerItemClickListener.OnItemClickListener() { - @Override - public void onItemClick(View view, int position) { - if (identitiesCardListener != null) { - identitiesCardListener.onIdentityItemClick(position); - } - } - })); - Button linkedIdsAddButton = (Button) view.findViewById(R.id.view_key_card_linked_ids_add); linkedIdsAddButton.setOnClickListener(new View.OnClickListener() { diff --git a/OpenKeychain/src/main/res/layout/view_key_identity_user_id.xml b/OpenKeychain/src/main/res/layout/view_key_identity_user_id.xml index 1cec5cdc1..7fb3abecb 100644 --- a/OpenKeychain/src/main/res/layout/view_key_identity_user_id.xml +++ b/OpenKeychain/src/main/res/layout/view_key_identity_user_id.xml @@ -53,9 +53,9 @@ android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:padding="8dp" - android:id="@+id/trust_id_action" + android:id="@+id/user_id_item_more" android:background="?selectableItemBackground" - android:src="@drawable/ic_chat_black_24dp" + android:src="@drawable/ic_more_vert_black_24dp" android:visibility="gone" tools:visibility="visible" /> diff --git a/OpenKeychain/src/main/res/layout/view_key_trust_id_item.xml b/OpenKeychain/src/main/res/layout/view_key_trust_id_item.xml index 68be3a8e4..101caa48b 100644 --- a/OpenKeychain/src/main/res/layout/view_key_trust_id_item.xml +++ b/OpenKeychain/src/main/res/layout/view_key_trust_id_item.xml @@ -39,7 +39,7 @@ android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:padding="8dp" - android:id="@+id/trust_id_action" + android:id="@+id/user_id_item_more" android:background="?selectableItemBackground" android:src="@drawable/ic_chat_black_24dp" android:visibility="gone" diff --git a/OpenKeychain/src/main/res/menu/identity_context_menu.xml b/OpenKeychain/src/main/res/menu/identity_context_menu.xml new file mode 100644 index 000000000..1cb44614b --- /dev/null +++ b/OpenKeychain/src/main/res/menu/identity_context_menu.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml index 680d27bac..23c94a904 100644 --- a/OpenKeychain/src/main/res/values/strings.xml +++ b/OpenKeychain/src/main/res/values/strings.xml @@ -1886,4 +1886,6 @@ View Key Got it + Forget +