add context menu to autocrypt identity items

This commit is contained in:
Vincent Breitmoser 2017-06-28 14:41:03 +02:00
parent dc33fc7982
commit 226182e51c
12 changed files with 155 additions and 39 deletions

View file

@ -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);
}
}

View file

@ -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)) {

View file

@ -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<ViewHolder> {
private final Context context;
private final LayoutInflater layoutInflater;
private final boolean isSecret;
private final IdentityClickListener identityClickListener;
private List<IdentityInfo> 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<IdentityInfo> data) {
@ -91,7 +94,8 @@ public class IdentityAdapter extends RecyclerView.Adapter<ViewHolder> {
@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<ViewHolder> {
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<ViewHolder> {
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<ViewHolder> {
}
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<ViewHolder> {
}
}
public interface IdentityClickListener {
void onClickIdentity(int position);
void onClickIdentityMore(int position, View anchor);
}
}

View file

@ -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;
}
}

View file

@ -134,10 +134,10 @@ public class IdentityLoader extends AsyncTaskLoader<List<IdentityInfo>> {
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<List<IdentityInfo>> {
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<List<IdentityInfo>> {
@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);
}
}

View file

@ -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<List<IdentityInfo>>
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<List<IdentityInfo>>
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<List<IdentityInfo>>
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<List<IdentityInfo>>
}
public interface IdentitiesCardListener {
void onIdentityItemClick(int position);
void onClickEditIdentities();
void onClickAddIdentity();
}

View file

@ -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);
}

View file

@ -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() {

View file

@ -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"
/>

View file

@ -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"

View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/autocrypt_forget"
android:title="@string/identity_context_forget"
android:icon="@drawable/ic_delete_grey_24dp"
/>
</menu>

View file

@ -1886,4 +1886,6 @@
<string name="dialog_insecure_button_view_key">View Key</string>
<string name="dialog_insecure_button_ok">Got it</string>
<string name="identity_context_forget">Forget</string>
</resources>