From 7fc805d70cbfad255aea756cf78929a9917a1da0 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Mon, 29 May 2017 17:06:00 +0200 Subject: [PATCH] move linked identities into loader structure --- .../keychain/provider/KeychainContract.java | 4 + .../keychain/ui/adapter/IdentityAdapter.java | 182 +++++++++++++--- .../keychain/ui/adapter/LinkedIdsAdapter.java | 205 ------------------ .../ui/keyview/LinkedIdViewFragment.java | 13 +- .../keychain/ui/keyview/ViewKeyFragment.java | 21 +- .../ui/keyview/loader/IdentityLoader.java | 122 ++++++++--- .../presenter/IdentitiesPresenter.java | 69 +++++- .../presenter/LinkedIdentitiesPresenter.java | 133 ------------ .../ui/keyview/presenter/ViewKeyMvpView.java | 3 + .../ui/keyview/view/IdentitiesCardView.java | 44 +--- .../recyclerview/DividerItemDecoration.java | 4 +- .../src/main/res/layout/identities_card.xml | 15 -- .../res/layout/view_key_identity_user_id.xml | 16 +- 13 files changed, 335 insertions(+), 496 deletions(-) delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/LinkedIdsAdapter.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/presenter/LinkedIdentitiesPresenter.java diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java index a75d1e04a..2f6f4042e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java @@ -284,6 +284,10 @@ public class KeychainContract { return CONTENT_URI.buildUpon().appendPath(uri.getPathSegments().get(1)).appendPath(PATH_USER_IDS).build(); } + public static Uri buildLinkedIdsUri(long masterKeyId) { + return CONTENT_URI.buildUpon().appendPath(Long.toString(masterKeyId)).appendPath(PATH_LINKED_IDS).build(); + } + public static Uri buildLinkedIdsUri(Uri uri) { return CONTENT_URI.buildUpon().appendPath(uri.getPathSegments().get(1)).appendPath(PATH_LINKED_IDS).build(); } 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 75df9ae1c..d7b7fea8d 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 @@ -1,6 +1,5 @@ /* - * Copyright (C) 2014-2015 Dominik Schürmann - * Copyright (C) 2015 Vincent Breitmoser + * Copyright (C) 2017 Vincent Breitmoser * * 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 @@ -21,29 +20,47 @@ package org.sufficientlysecure.keychain.ui.adapter; import java.util.List; +import android.animation.ObjectAnimator; import android.content.Context; import android.graphics.Typeface; +import android.os.Build; +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; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.linked.UriAttribute; +import org.sufficientlysecure.keychain.provider.KeychainContract.Certs; import org.sufficientlysecure.keychain.ui.adapter.IdentityAdapter.ViewHolder; import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityLoader.IdentityInfo; +import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityLoader.LinkedIdInfo; +import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityLoader.UserIdInfo; +import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; +import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.State; +import org.sufficientlysecure.keychain.ui.util.SubtleAttentionSeeker; public class IdentityAdapter extends RecyclerView.Adapter { + private static final int VIEW_TYPE_USER_ID = 0; + private static final int VIEW_TYPE_LINKED_ID = 1; + + private final Context context; private final LayoutInflater layoutInflater; + private final boolean isSecret; + private List data; - public IdentityAdapter(Context context) { + + public IdentityAdapter(Context context, boolean isSecret) { super(); this.layoutInflater = LayoutInflater.from(context); this.context = context; + this.isSecret = isSecret; } public void setData(List data) { @@ -56,36 +73,37 @@ public class IdentityAdapter extends RecyclerView.Adapter { public void onBindViewHolder(ViewHolder holder, int position) { IdentityInfo info = data.get(position); - if (info.name != null) { - holder.vName.setText(info.name); + int viewType = getItemViewType(position); + if (viewType == VIEW_TYPE_USER_ID) { + ((UserIdViewHolder) holder).bind((UserIdInfo) info); + } else if (viewType == VIEW_TYPE_LINKED_ID) { + ((LinkedIdViewHolder) holder).bind(context, (LinkedIdInfo) info, isSecret); } else { - holder.vName.setText(R.string.user_id_no_name); - } - if (info.email != null) { - holder.vAddress.setText(info.email); - holder.vAddress.setVisibility(View.VISIBLE); - } else { - holder.vAddress.setVisibility(View.GONE); - } - if (info.comment != null) { - holder.vComment.setText(info.comment); - holder.vComment.setVisibility(View.VISIBLE); - } else { - holder.vComment.setVisibility(View.GONE); - } - - if (info.isPrimary) { - holder.vName.setTypeface(null, Typeface.BOLD); - holder.vAddress.setTypeface(null, Typeface.BOLD); - } else { - holder.vName.setTypeface(null, Typeface.NORMAL); - holder.vAddress.setTypeface(null, Typeface.NORMAL); + throw new IllegalStateException("unhandled identitytype!"); } } @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - return new ViewHolder(layoutInflater.inflate(R.layout.view_key_identity_user_id, null)); + if (viewType == VIEW_TYPE_USER_ID) { + return new UserIdViewHolder(layoutInflater.inflate(R.layout.view_key_identity_user_id, parent, false)); + } else if (viewType == VIEW_TYPE_LINKED_ID) { + return new LinkedIdViewHolder(layoutInflater.inflate(R.layout.linked_id_item, parent, false)); + } else { + throw new IllegalStateException("unhandled identitytype!"); + } + } + + @Override + public int getItemViewType(int position) { + IdentityInfo info = data.get(position); + if (info instanceof UserIdInfo) { + return VIEW_TYPE_USER_ID; + } else if (info instanceof LinkedIdInfo) { + return VIEW_TYPE_LINKED_ID; + } else { + throw new IllegalStateException("unhandled identitytype!"); + } } @Override @@ -93,19 +111,121 @@ public class IdentityAdapter extends RecyclerView.Adapter { return data != null ? data.size() : 0; } - public class ViewHolder extends RecyclerView.ViewHolder { - private View v; + public IdentityInfo getInfo(int position) { + return data.get(position); + } + abstract static class ViewHolder extends RecyclerView.ViewHolder { + public ViewHolder(View itemView) { + super(itemView); + } + } + + public static class LinkedIdViewHolder extends ViewHolder { + public final ImageView vVerified; + final private ImageView vIcon; + final private TextView vTitle; + final private TextView vComment; + + public LinkedIdViewHolder(View view) { + super(view); + + vVerified = (ImageView) view.findViewById(R.id.linked_id_certified_icon); + vIcon = (ImageView) view.findViewById(R.id.linked_id_type_icon); + vTitle = (TextView) view.findViewById(R.id.linked_id_title); + vComment = (TextView) view.findViewById(R.id.linked_id_comment); + } + + public void bind(Context context, LinkedIdInfo info, boolean isSecret) { + bindVerified(context, info, isSecret); + + UriAttribute uriAttribute = info.getUriAttribute(); + bind(context, uriAttribute); + } + + public void bind(Context context, UriAttribute uriAttribute) { + vTitle.setText(uriAttribute.getDisplayTitle(context)); + + String comment = uriAttribute.getDisplayComment(context); + if (comment != null) { + vComment.setVisibility(View.VISIBLE); + vComment.setText(comment); + } else { + vComment.setVisibility(View.GONE); + } + + vIcon.setImageResource(uriAttribute.getDisplayIcon()); + } + + private void bindVerified(Context context, IdentityInfo info, boolean isSecret) { + if (!isSecret) { + switch (info.getVerified()) { + case Certs.VERIFIED_SECRET: + KeyFormattingUtils.setStatusImage(context, vVerified, + null, State.VERIFIED, KeyFormattingUtils.DEFAULT_COLOR); + break; + case Certs.VERIFIED_SELF: + KeyFormattingUtils.setStatusImage(context, vVerified, + null, State.UNVERIFIED, KeyFormattingUtils.DEFAULT_COLOR); + break; + default: + KeyFormattingUtils.setStatusImage(context, vVerified, + null, State.INVALID, KeyFormattingUtils.DEFAULT_COLOR); + break; + } + } + } + + public void seekAttention() { + if (Build.VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) { + ObjectAnimator anim = SubtleAttentionSeeker.tintText(vComment, 1000); + anim.setStartDelay(200); + anim.start(); + } + } + } + + private static class UserIdViewHolder extends ViewHolder { private final TextView vName; private final TextView vAddress; private final TextView vComment; - public ViewHolder(View view) { + private UserIdViewHolder(View view) { super(view); vName = (TextView) view.findViewById(R.id.user_id_item_name); vAddress = (TextView) view.findViewById(R.id.user_id_item_address); vComment = (TextView) view.findViewById(R.id.user_id_item_comment); } + + public void bind(UserIdInfo info) { + if (info.getName() != null) { + vName.setText(info.getName()); + } else { + vName.setText(R.string.user_id_no_name); + } + if (info.getEmail() != null) { + vAddress.setText(info.getEmail()); + vAddress.setVisibility(View.VISIBLE); + } else { + vAddress.setVisibility(View.GONE); + } + if (info.getComment() != null) { + vComment.setText(info.getComment()); + vComment.setVisibility(View.VISIBLE); + } else { + vComment.setVisibility(View.GONE); + } + + if (info.isPrimary()) { + vName.setTypeface(null, Typeface.BOLD); + vAddress.setTypeface(null, Typeface.BOLD); + } else { + vName.setTypeface(null, Typeface.NORMAL); + vAddress.setTypeface(null, Typeface.NORMAL); + } + + } + } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/LinkedIdsAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/LinkedIdsAdapter.java deleted file mode 100644 index 92b460375..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/LinkedIdsAdapter.java +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Copyright (C) 2014-2015 Dominik Schürmann - * Copyright (C) 2015 Vincent Breitmoser - * - * 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 . - */ - -package org.sufficientlysecure.keychain.ui.adapter; - - -import java.io.IOException; -import java.util.WeakHashMap; - -import android.animation.ObjectAnimator; -import android.content.Context; -import android.database.Cursor; -import android.net.Uri; -import android.os.Build; -import android.os.Build.VERSION_CODES; -import android.support.v4.content.CursorLoader; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.TextView; - -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.linked.LinkedAttribute; -import org.sufficientlysecure.keychain.linked.UriAttribute; -import org.sufficientlysecure.keychain.provider.KeychainContract.Certs; -import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; -import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets; -import org.sufficientlysecure.keychain.ui.keyview.LinkedIdViewFragment; -import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; -import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.State; -import org.sufficientlysecure.keychain.ui.util.SubtleAttentionSeeker; -import org.sufficientlysecure.keychain.util.FilterCursorWrapper; -import org.sufficientlysecure.keychain.util.Log; - -public class LinkedIdsAdapter extends UserAttributesAdapter { - private final boolean mIsSecret; - protected LayoutInflater mInflater; - WeakHashMap mLinkedIdentityCache = new WeakHashMap<>(); - - public LinkedIdsAdapter(Context context, Cursor c, int flags, boolean isSecret) { - super(context, c, flags); - mInflater = LayoutInflater.from(context); - mIsSecret = isSecret; - } - - @Override - public Cursor swapCursor(Cursor cursor) { - if (cursor == null) { - return super.swapCursor(null); - } - FilterCursorWrapper filteredCursor = new FilterCursorWrapper(cursor) { - @Override - public boolean isVisible(Cursor cursor) { - UriAttribute id = getItemAtPosition(cursor); - return id instanceof LinkedAttribute; - } - }; - - return super.swapCursor(filteredCursor); - } - - @Override - public void bindView(View view, Context context, Cursor cursor) { - - ViewHolder holder = (ViewHolder) view.getTag(); - - if (!mIsSecret) { - int isVerified = cursor.getInt(INDEX_VERIFIED); - switch (isVerified) { - case Certs.VERIFIED_SECRET: - KeyFormattingUtils.setStatusImage(mContext, holder.vVerified, - null, State.VERIFIED, KeyFormattingUtils.DEFAULT_COLOR); - break; - case Certs.VERIFIED_SELF: - KeyFormattingUtils.setStatusImage(mContext, holder.vVerified, - null, State.UNVERIFIED, KeyFormattingUtils.DEFAULT_COLOR); - break; - default: - KeyFormattingUtils.setStatusImage(mContext, holder.vVerified, - null, State.INVALID, KeyFormattingUtils.DEFAULT_COLOR); - break; - } - } - - UriAttribute id = getItemAtPosition(cursor); - holder.setData(mContext, id); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - view.setTransitionName(id.mUri.toString()); - } - - } - - public UriAttribute getItemAtPosition(Cursor cursor) { - int rank = cursor.getInt(INDEX_RANK); - Log.d(Constants.TAG, "requested rank: " + rank); - - UriAttribute ret = mLinkedIdentityCache.get(rank); - if (ret != null) { - Log.d(Constants.TAG, "cached!"); - return ret; - } - Log.d(Constants.TAG, "not cached!"); - - try { - byte[] data = cursor.getBlob(INDEX_ATTRIBUTE_DATA); - ret = LinkedAttribute.fromAttributeData(data); - mLinkedIdentityCache.put(rank, ret); - return ret; - } catch (IOException e) { - Log.e(Constants.TAG, "could not read linked identity subpacket data", e); - return null; - } - } - - @Override - public UriAttribute getItem(int position) { - Cursor cursor = getCursor(); - cursor.moveToPosition(position); - return getItemAtPosition(cursor); - } - - @Override - public View newView(Context context, Cursor cursor, ViewGroup parent) { - View v = mInflater.inflate(R.layout.linked_id_item, null); - ViewHolder holder = new ViewHolder(v); - v.setTag(holder); - return v; - } - - // don't show revoked user ids, irrelevant for average users - public static final String LINKED_IDS_WHERE = UserPackets.IS_REVOKED + " = 0"; - - public static CursorLoader createLoader(Context context, Uri dataUri) { - Uri baseUri = UserPackets.buildLinkedIdsUri(dataUri); - return new CursorLoader(context, baseUri, - UserIdsAdapter.USER_PACKETS_PROJECTION, LINKED_IDS_WHERE, null, null); - } - - public LinkedIdViewFragment getLinkedIdFragment(int position, long masterKeyId) throws IOException { - Cursor c = getCursor(); - c.moveToPosition(position); - int rank = c.getInt(UserIdsAdapter.INDEX_RANK); - - Uri dataUri = UserPackets.buildLinkedIdsUri(KeyRings.buildGenericKeyRingUri(masterKeyId)); - return LinkedIdViewFragment.newInstance(dataUri, rank, mIsSecret, masterKeyId); - } - - public static class ViewHolder { - final public ImageView vVerified; - final public ImageView vIcon; - final public TextView vTitle; - final public TextView vComment; - - public ViewHolder(View view) { - vVerified = (ImageView) view.findViewById(R.id.linked_id_certified_icon); - vIcon = (ImageView) view.findViewById(R.id.linked_id_type_icon); - vTitle = (TextView) view.findViewById(R.id.linked_id_title); - vComment = (TextView) view.findViewById(R.id.linked_id_comment); - } - - public void setData(Context context, UriAttribute id) { - - vTitle.setText(id.getDisplayTitle(context)); - - String comment = id.getDisplayComment(context); - if (comment != null) { - vComment.setVisibility(View.VISIBLE); - vComment.setText(comment); - } else { - vComment.setVisibility(View.GONE); - } - - vIcon.setImageResource(id.getDisplayIcon()); - - } - - public void seekAttention() { - if (Build.VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) { - ObjectAnimator anim = SubtleAttentionSeeker.tintText(vComment, 1000); - anim.setStartDelay(200); - anim.start(); - } - } - - } - -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/LinkedIdViewFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/LinkedIdViewFragment.java index 12f54b238..a0a14440c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/LinkedIdViewFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/LinkedIdViewFragment.java @@ -17,6 +17,7 @@ package org.sufficientlysecure.keychain.ui.keyview; + import java.io.IOException; import java.util.Collections; @@ -50,11 +51,11 @@ import android.widget.ViewAnimator; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants.key; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.operations.results.LinkedVerifyResult; -import org.sufficientlysecure.keychain.linked.LinkedTokenResource; import org.sufficientlysecure.keychain.linked.LinkedAttribute; import org.sufficientlysecure.keychain.linked.LinkedResource; +import org.sufficientlysecure.keychain.linked.LinkedTokenResource; import org.sufficientlysecure.keychain.linked.UriAttribute; +import org.sufficientlysecure.keychain.operations.results.LinkedVerifyResult; import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.provider.KeyRepository; @@ -63,7 +64,7 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets; import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables; import org.sufficientlysecure.keychain.service.CertifyActionsParcel; import org.sufficientlysecure.keychain.service.CertifyActionsParcel.CertifyAction; -import org.sufficientlysecure.keychain.ui.adapter.LinkedIdsAdapter; +import org.sufficientlysecure.keychain.ui.adapter.IdentityAdapter; import org.sufficientlysecure.keychain.ui.adapter.UserIdsAdapter; import org.sufficientlysecure.keychain.ui.base.CryptoOperationFragment; import org.sufficientlysecure.keychain.ui.keyview.LinkedIdViewFragment.ViewHolder.VerifyState; @@ -217,7 +218,7 @@ public class LinkedIdViewFragment extends CryptoOperationFragment implements mViewHolder.mLinkedIdHolder.vVerified.setImageResource(R.drawable.octo_link_24dp); } - mViewHolder.mLinkedIdHolder.setData(mContext, mLinkedId); + mViewHolder.mLinkedIdHolder.bind(mContext, mLinkedId); setShowVerifying(false); @@ -256,7 +257,7 @@ public class LinkedIdViewFragment extends CryptoOperationFragment implements private final ViewAnimator vVerifyingContainer; private final ViewAnimator vItemCertified; private final View vKeySpinnerContainer; - LinkedIdsAdapter.ViewHolder mLinkedIdHolder; + IdentityAdapter.LinkedIdViewHolder mLinkedIdHolder; private ViewAnimator vButtonSwitcher; private CertListWidget vLinkedCerts; @@ -274,7 +275,7 @@ public class LinkedIdViewFragment extends CryptoOperationFragment implements vKeySpinnerContainer = root.findViewById(R.id.cert_key_spincontainer); vButtonSwitcher = (ViewAnimator) root.findViewById(R.id.button_animator); - mLinkedIdHolder = new LinkedIdsAdapter.ViewHolder(root); + mLinkedIdHolder = new IdentityAdapter.LinkedIdViewHolder(root); vButtonVerify = root.findViewById(R.id.button_verify); vButtonRetry = root.findViewById(R.id.button_retry); 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 14e6375a3..bd61897c1 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 @@ -35,30 +35,25 @@ import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.ui.base.LoaderFragment; import org.sufficientlysecure.keychain.ui.keyview.presenter.IdentitiesPresenter; import org.sufficientlysecure.keychain.ui.keyview.presenter.KeyHealthPresenter; -import org.sufficientlysecure.keychain.ui.keyview.presenter.LinkedIdentitiesPresenter; -import org.sufficientlysecure.keychain.ui.keyview.presenter.LinkedIdentitiesPresenter.LinkedIdsFragMvpView; import org.sufficientlysecure.keychain.ui.keyview.presenter.SystemContactPresenter; import org.sufficientlysecure.keychain.ui.keyview.presenter.ViewKeyMvpView; import org.sufficientlysecure.keychain.ui.keyview.view.IdentitiesCardView; import org.sufficientlysecure.keychain.ui.keyview.view.KeyHealthView; import org.sufficientlysecure.keychain.ui.keyview.view.SystemContactCardView; -import org.sufficientlysecure.keychain.util.Preferences; -public class ViewKeyFragment extends LoaderFragment implements LinkedIdsFragMvpView, ViewKeyMvpView { +public class ViewKeyFragment extends LoaderFragment implements ViewKeyMvpView { public static final String ARG_MASTER_KEY_ID = "master_key_id"; public static final String ARG_IS_SECRET = "is_secret"; boolean mIsSecret = false; - private static final int LOADER_ID_USER_IDS = 1; - private static final int LOADER_ID_LINKED_IDS = 2; - private static final int LOADER_ID_LINKED_CONTACT = 3; - private static final int LOADER_ID_SUBKEY_STATUS = 4; + private static final int LOADER_IDENTITIES = 1; + private static final int LOADER_ID_LINKED_CONTACT = 2; + private static final int LOADER_ID_SUBKEY_STATUS = 3; private IdentitiesCardView mIdentitiesCardView; private IdentitiesPresenter mIdentitiesPresenter; - private LinkedIdentitiesPresenter mLinkedIdentitiesPresenter; SystemContactCardView mSystemContactCard; SystemContactPresenter mSystemContactPresenter; @@ -102,15 +97,9 @@ public class ViewKeyFragment extends LoaderFragment implements LinkedIdsFragMvpV mIsSecret = getArguments().getBoolean(ARG_IS_SECRET); mIdentitiesPresenter = new IdentitiesPresenter( - getContext(), mIdentitiesCardView, this, LOADER_ID_USER_IDS, masterKeyId, mIsSecret); + getContext(), mIdentitiesCardView, this, LOADER_IDENTITIES, masterKeyId, mIsSecret); mIdentitiesPresenter.startLoader(getLoaderManager()); - if (Preferences.getPreferences(getActivity()).getExperimentalEnableLinkedIdentities()) { - mLinkedIdentitiesPresenter = new LinkedIdentitiesPresenter( - getContext(), mIdentitiesCardView, this, LOADER_ID_LINKED_IDS, masterKeyId, mIsSecret); - mLinkedIdentitiesPresenter.startLoader(getLoaderManager()); - } - mSystemContactPresenter = new SystemContactPresenter( getContext(), mSystemContactCard, LOADER_ID_LINKED_CONTACT, masterKeyId, mIsSecret); mSystemContactPresenter.startLoader(getLoaderManager()); 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 a5070c1c8..cf62eec0a 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 @@ -18,6 +18,7 @@ package org.sufficientlysecure.keychain.ui.keyview.loader; +import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -25,10 +26,14 @@ import java.util.List; import android.content.ContentResolver; import android.content.Context; import android.database.Cursor; +import android.support.annotation.Nullable; import android.support.v4.content.AsyncTaskLoader; import android.util.Log; +import com.google.auto.value.AutoValue; import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.linked.LinkedAttribute; +import org.sufficientlysecure.keychain.linked.UriAttribute; import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets; import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityLoader.IdentityInfo; @@ -63,34 +68,84 @@ public class IdentityLoader extends AsyncTaskLoader> { private final ContentResolver contentResolver; private final long masterKeyId; + private final boolean showLinkedIds; private List cachedResult; - public IdentityLoader(Context context, ContentResolver contentResolver, long masterKeyId) { + public IdentityLoader(Context context, ContentResolver contentResolver, long masterKeyId, boolean showLinkedIds) { super(context); this.contentResolver = contentResolver; this.masterKeyId = masterKeyId; + this.showLinkedIds = showLinkedIds; } @Override public List loadInBackground() { + ArrayList identities = new ArrayList<>(); + + if (showLinkedIds) { + loadLinkedIds(identities); + } + loadUserIds(identities); + + return Collections.unmodifiableList(identities); + } + + private void loadLinkedIds(ArrayList identities) { + Cursor cursor = contentResolver.query(UserPackets.buildLinkedIdsUri(masterKeyId), + USER_PACKETS_PROJECTION, USER_IDS_WHERE, null, null); + if (cursor == null) { + Log.e(Constants.TAG, "Error loading key items!"); + return; + } + + try { + while (cursor.moveToNext()) { + int rank = cursor.getInt(INDEX_RANK); + int verified = cursor.getInt(INDEX_VERIFIED); + boolean isPrimary = cursor.getInt(INDEX_IS_PRIMARY) != 0; + + byte[] data = cursor.getBlob(INDEX_ATTRIBUTE_DATA); + try { + UriAttribute uriAttribute = LinkedAttribute.fromAttributeData(data); + if (uriAttribute instanceof LinkedAttribute) { + LinkedIdInfo identityInfo = LinkedIdInfo.create(rank, verified, isPrimary, uriAttribute); + identities.add(identityInfo); + } + } catch (IOException e) { + Log.e(Constants.TAG, "Failed parsing uri attribute", e); + } + } + } finally { + cursor.close(); + } + } + + private void loadUserIds(ArrayList identities) { Cursor cursor = contentResolver.query(UserPackets.buildUserIdsUri(masterKeyId), USER_PACKETS_PROJECTION, USER_IDS_WHERE, null, null); if (cursor == null) { Log.e(Constants.TAG, "Error loading key items!"); - return null; + return; } try { - ArrayList identities = new ArrayList<>(); while (cursor.moveToNext()) { - IdentityInfo identityInfo = new IdentityInfo(masterKeyId, cursor); - identities.add(identityInfo); - } + int rank = cursor.getInt(INDEX_RANK); + int verified = cursor.getInt(INDEX_VERIFIED); + boolean isPrimary = cursor.getInt(INDEX_IS_PRIMARY) != 0; - return Collections.unmodifiableList(identities); + if (!cursor.isNull(INDEX_NAME) || !cursor.isNull(INDEX_EMAIL)) { + String name = cursor.getString(INDEX_NAME); + String email = cursor.getString(INDEX_EMAIL); + String comment = cursor.getString(INDEX_COMMENT); + + IdentityInfo identityInfo = UserIdInfo.create(rank, verified, isPrimary, name, email, comment); + identities.add(identityInfo); + } + } } finally { cursor.close(); } @@ -116,36 +171,41 @@ public class IdentityLoader extends AsyncTaskLoader> { } } - public static class IdentityInfo { - final int position; + public interface IdentityInfo { + int getRank(); + int getVerified(); + boolean isPrimary(); + } - public final int verified; - public final byte[] data; - public final String name; - public final String email; - public final String comment; + @AutoValue + public abstract static class UserIdInfo implements IdentityInfo { + public abstract int getRank(); + public abstract int getVerified(); + public abstract boolean isPrimary(); - public boolean isPrimary; + @Nullable + public abstract String getName(); + @Nullable + public abstract String getEmail(); + @Nullable + public abstract String getComment(); - IdentityInfo(long masterKeyId, Cursor cursor) { - position = cursor.getPosition(); + static UserIdInfo create(int rank, int verified, boolean isPrimary, String name, String email, + String comment) { + return new AutoValue_IdentityLoader_UserIdInfo(rank, verified, isPrimary, name, email, comment); + } + } - verified = cursor.getInt(INDEX_VERIFIED); - if (cursor.isNull(INDEX_NAME)) { - data = cursor.getBlob(INDEX_ATTRIBUTE_DATA); + @AutoValue + public abstract static class LinkedIdInfo implements IdentityInfo { + public abstract int getRank(); + public abstract int getVerified(); + public abstract boolean isPrimary(); - name = null; - email = null; - comment = null; - } else { - data = null; + public abstract UriAttribute getUriAttribute(); - name = cursor.getString(INDEX_NAME); - email = cursor.getString(INDEX_EMAIL); - comment = cursor.getString(INDEX_COMMENT); - } - - isPrimary = cursor.getInt(INDEX_IS_PRIMARY) != 0; + static LinkedIdInfo create(int rank, int verified, boolean isPrimary, UriAttribute uriAttribute) { + return new AutoValue_IdentityLoader_LinkedIdInfo(rank, verified, isPrimary, uriAttribute); } } } 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 2d65f955d..0356b42d0 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 @@ -18,20 +18,32 @@ package org.sufficientlysecure.keychain.ui.keyview.presenter; +import java.io.IOException; import java.util.List; import android.content.Context; import android.content.Intent; +import android.net.Uri; import android.os.Bundle; import android.support.v4.app.LoaderManager; import android.support.v4.app.LoaderManager.LoaderCallbacks; import android.support.v4.content.Loader; +import org.sufficientlysecure.keychain.Constants; 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.dialog.UserIdInfoDialogFragment; +import org.sufficientlysecure.keychain.ui.keyview.LinkedIdViewFragment; import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityLoader; import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityLoader.IdentityInfo; +import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityLoader.LinkedIdInfo; +import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityLoader.UserIdInfo; +import org.sufficientlysecure.keychain.ui.linked.LinkedIdWizard; +import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.Preferences; public class IdentitiesPresenter implements LoaderCallbacks> { @@ -55,7 +67,7 @@ public class IdentitiesPresenter implements LoaderCallbacks> this.masterKeyId = masterKeyId; this.isSecret = isSecret; - identitiesAdapter = new IdentityAdapter(context); + identitiesAdapter = new IdentityAdapter(context, isSecret); view.setIdentitiesAdapter(identitiesAdapter); view.setEditIdentitiesButtonVisible(isSecret); @@ -63,13 +75,18 @@ public class IdentitiesPresenter implements LoaderCallbacks> view.setIdentitiesCardListener(new IdentitiesCardListener() { @Override public void onIdentityItemClick(int position) { - showUserIdInfo(position); + showIdentityInfo(position); } @Override public void onClickEditIdentities() { editIdentities(); } + + @Override + public void onClickAddIdentity() { + addLinkedIdentity(); + } }); } @@ -79,7 +96,8 @@ public class IdentitiesPresenter implements LoaderCallbacks> @Override public Loader> onCreateLoader(int id, Bundle args) { - return new IdentityLoader(context, context.getContentResolver(), masterKeyId); + boolean showLinkedIds = Preferences.getPreferences(context).getExperimentalEnableLinkedIdentities(); + return new IdentityLoader(context, context.getContentResolver(), masterKeyId, showLinkedIds); } @Override @@ -93,14 +111,35 @@ public class IdentitiesPresenter implements LoaderCallbacks> identitiesAdapter.setData(null); } - private void showUserIdInfo(final int position) { -// if (!isSecret) { -// final boolean isRevoked = identitiesAdapter.getIsRevoked(position); -// final int isVerified = identitiesAdapter.getIsVerified(position); -// -// UserIdInfoDialogFragment dialogFragment = UserIdInfoDialogFragment.newInstance(isRevoked, isVerified); -// viewKeyMvpView.showDialogFragment(dialogFragment, "userIdInfoDialog"); -// } + private void showIdentityInfo(final int position) { + IdentityInfo info = identitiesAdapter.getInfo(position); + if (info instanceof LinkedIdInfo) { + showLinkedId((LinkedIdInfo) info); + } else if (info instanceof UserIdInfo) { + showUserIdInfo((UserIdInfo) info); + } + } + + private void showLinkedId(final LinkedIdInfo info) { + final LinkedIdViewFragment frag; + try { + Uri dataUri = UserPackets.buildLinkedIdsUri(KeyRings.buildGenericKeyRingUri(masterKeyId)); + frag = LinkedIdViewFragment.newInstance(dataUri, info.getRank(), isSecret, masterKeyId); + } catch (IOException e) { + Log.e(Constants.TAG, "IOException", e); + return; + } + + viewKeyMvpView.switchToFragment(frag, "linked_id"); + } + + private void showUserIdInfo(UserIdInfo info) { + if (!isSecret) { + final int isVerified = info.getVerified(); + + UserIdInfoDialogFragment dialogFragment = UserIdInfoDialogFragment.newInstance(false, isVerified); + viewKeyMvpView.showDialogFragment(dialogFragment, "userIdInfoDialog"); + } } private void editIdentities() { @@ -109,6 +148,12 @@ public class IdentitiesPresenter implements LoaderCallbacks> viewKeyMvpView.startActivityAndShowResultSnackbar(editIntent); } + private void addLinkedIdentity() { + Intent intent = new Intent(context, LinkedIdWizard.class); + intent.setData(KeyRings.buildUnifiedKeyRingUri(masterKeyId)); + context.startActivity(intent); + } + public interface IdentitiesMvpView { void setIdentitiesAdapter(IdentityAdapter userIdsAdapter); void setIdentitiesCardListener(IdentitiesCardListener identitiesCardListener); @@ -117,6 +162,8 @@ public class IdentitiesPresenter implements LoaderCallbacks> public interface IdentitiesCardListener { void onIdentityItemClick(int position); + void onClickEditIdentities(); + void onClickAddIdentity(); } } \ No newline at end of file diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/presenter/LinkedIdentitiesPresenter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/presenter/LinkedIdentitiesPresenter.java deleted file mode 100644 index 3b72ddf2d..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/keyview/presenter/LinkedIdentitiesPresenter.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (C) 2017 Vincent Breitmoser - * - * 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 . - */ - -package org.sufficientlysecure.keychain.ui.keyview.presenter; - - -import java.io.IOException; - -import android.content.Context; -import android.content.Intent; -import android.database.Cursor; -import android.os.Bundle; -import android.support.v4.app.Fragment; -import android.support.v4.app.LoaderManager; -import android.support.v4.app.LoaderManager.LoaderCallbacks; -import android.support.v4.content.Loader; - -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; -import org.sufficientlysecure.keychain.ui.adapter.LinkedIdsAdapter; -import org.sufficientlysecure.keychain.ui.keyview.LinkedIdViewFragment; -import org.sufficientlysecure.keychain.ui.linked.LinkedIdWizard; -import org.sufficientlysecure.keychain.util.Log; - - -public class LinkedIdentitiesPresenter implements LoaderCallbacks { - private final Context context; - private final LinkedIdsMvpView view; - private final int loaderId; - private final LinkedIdsFragMvpView fragView; - - private LinkedIdsAdapter linkedIdsAdapter; - - private final long masterKeyId; - private final boolean isSecret; - - public LinkedIdentitiesPresenter( - Context context, LinkedIdsMvpView view, LinkedIdsFragMvpView fragView, int loaderId, long masterKeyId, boolean isSecret) { - this.context = context; - this.view = view; - this.fragView = fragView; - this.loaderId = loaderId; - - this.masterKeyId = masterKeyId; - this.isSecret = isSecret; - - linkedIdsAdapter = new LinkedIdsAdapter(context, null, 0, isSecret); - view.setLinkedIdsAdapter(linkedIdsAdapter); - - view.setSystemContactClickListener(new LinkedIdsClickListener() { - @Override - public void onLinkedIdItemClick(int position) { - showLinkedId(position); - } - - @Override - public void onClickAddIdentity() { - addLinkedIdentity(); - } - }); - } - - public void startLoader(LoaderManager loaderManager) { - loaderManager.restartLoader(loaderId, null, this); - } - - @Override - public Loader onCreateLoader(int id, Bundle args) { - return LinkedIdsAdapter.createLoader(context, KeyRings.buildUnifiedKeyRingUri(masterKeyId)); - } - - @Override - public void onLoadFinished(Loader loader, Cursor data) { - linkedIdsAdapter.swapCursor(data); - - boolean anyDataShown = data.getCount() > 0; - view.setShowLinkedIdDivider(anyDataShown); - } - - @Override - public void onLoaderReset(Loader loader) { - linkedIdsAdapter.swapCursor(null); - view.setShowLinkedIdDivider(false); - } - - private void showLinkedId(final int position) { - final LinkedIdViewFragment frag; - try { - frag = linkedIdsAdapter.getLinkedIdFragment(position, masterKeyId); - } catch (IOException e) { - Log.e(Constants.TAG, "IOException", e); - return; - } - - fragView.switchToFragment(frag, "linked_id"); - } - - public interface LinkedIdsMvpView { - void setSystemContactClickListener(LinkedIdsClickListener linkedIdsClickListener); - void setLinkedIdsAdapter(LinkedIdsAdapter linkedIdsAdapter); - - void setShowLinkedIdDivider(boolean show); - } - - public interface LinkedIdsFragMvpView { - void switchToFragment(Fragment frag, String backStackName); - } - - public interface LinkedIdsClickListener { - void onLinkedIdItemClick(int position); - void onClickAddIdentity(); - } - - private void addLinkedIdentity() { - Intent intent = new Intent(context, LinkedIdWizard.class); - intent.setData(KeyRings.buildUnifiedKeyRingUri(masterKeyId)); - context.startActivity(intent); - } -} \ No newline at end of file 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 a4118bff0..98399a52c 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 @@ -3,9 +3,12 @@ package org.sufficientlysecure.keychain.ui.keyview.presenter; import android.content.Intent; import android.support.v4.app.DialogFragment; +import android.support.v4.app.Fragment; public interface ViewKeyMvpView { + void switchToFragment(Fragment frag, String backStackName); + void startActivityAndShowResultSnackbar(Intent intent); void showDialogFragment(DialogFragment dialogFragment, final String tag); void setContentShown(boolean show, boolean animate); 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 b86e0894b..d30f93093 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 @@ -25,27 +25,19 @@ import android.support.v7.widget.RecyclerView; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemClickListener; import android.widget.Button; -import android.widget.ListView; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.ui.adapter.IdentityAdapter; -import org.sufficientlysecure.keychain.ui.adapter.LinkedIdsAdapter; import org.sufficientlysecure.keychain.ui.keyview.presenter.IdentitiesPresenter.IdentitiesCardListener; import org.sufficientlysecure.keychain.ui.keyview.presenter.IdentitiesPresenter.IdentitiesMvpView; -import org.sufficientlysecure.keychain.ui.keyview.presenter.LinkedIdentitiesPresenter.LinkedIdsClickListener; -import org.sufficientlysecure.keychain.ui.keyview.presenter.LinkedIdentitiesPresenter.LinkedIdsMvpView; +import org.sufficientlysecure.keychain.ui.util.recyclerview.DividerItemDecoration; import org.sufficientlysecure.keychain.ui.util.recyclerview.RecyclerItemClickListener; -public class IdentitiesCardView extends CardView implements IdentitiesMvpView, LinkedIdsMvpView { - private final ListView vLinkedIds; +public class IdentitiesCardView extends CardView implements IdentitiesMvpView { private final RecyclerView vIdentities; - private final View vLinkedIdsDivider; - private LinkedIdsClickListener linkedIdsClickListener; private IdentitiesCardListener identitiesCardListener; public IdentitiesCardView(Context context, AttributeSet attrs) { @@ -55,6 +47,7 @@ public class IdentitiesCardView extends CardView implements IdentitiesMvpView, L vIdentities = (RecyclerView) view.findViewById(R.id.view_key_user_ids); vIdentities.setLayoutManager(new LinearLayoutManager(context)); + vIdentities.addItemDecoration(new DividerItemDecoration(context, DividerItemDecoration.VERTICAL_LIST)); Button userIdsEditButton = (Button) view.findViewById(R.id.view_key_card_user_ids_edit); userIdsEditButton.setOnClickListener(new OnClickListener() { @@ -76,28 +69,16 @@ public class IdentitiesCardView extends CardView implements IdentitiesMvpView, L } })); - vLinkedIds = (ListView) view.findViewById(R.id.view_key_linked_ids); Button linkedIdsAddButton = (Button) view.findViewById(R.id.view_key_card_linked_ids_add); linkedIdsAddButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - if (linkedIdsClickListener != null) { - linkedIdsClickListener.onClickAddIdentity(); + if (identitiesCardListener != null) { + identitiesCardListener.onClickAddIdentity(); } } }); - - vLinkedIds.setOnItemClickListener(new OnItemClickListener() { - @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { - if (linkedIdsClickListener != null) { - linkedIdsClickListener.onLinkedIdItemClick(position); - } - } - }); - - vLinkedIdsDivider = view.findViewById(R.id.view_key_lid_divider); } @Override @@ -114,19 +95,4 @@ public class IdentitiesCardView extends CardView implements IdentitiesMvpView, L public void setEditIdentitiesButtonVisible(boolean show) { findViewById(R.id.view_key_card_user_ids_buttons).setVisibility(show ? View.VISIBLE : View.GONE); } - - @Override - public void setSystemContactClickListener(LinkedIdsClickListener linkedIdsClickListener) { - this.linkedIdsClickListener = linkedIdsClickListener; - } - - @Override - public void setLinkedIdsAdapter(LinkedIdsAdapter linkedIdsAdapter) { - vLinkedIds.setAdapter(linkedIdsAdapter); - } - - @Override - public void setShowLinkedIdDivider(boolean show) { - vLinkedIdsDivider.setVisibility(show ? View.VISIBLE : View.GONE); - } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/recyclerview/DividerItemDecoration.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/recyclerview/DividerItemDecoration.java index 95199bcd5..2af4e062d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/recyclerview/DividerItemDecoration.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/recyclerview/DividerItemDecoration.java @@ -67,7 +67,7 @@ public class DividerItemDecoration extends RecyclerView.ItemDecoration { final int right = parent.getWidth() - parent.getPaddingRight(); final int childCount = parent.getChildCount(); - for (int i = 0; i < childCount; i++) { + for (int i = 0; i < childCount -1; i++) { final View child = parent.getChildAt(i); final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child .getLayoutParams(); @@ -83,7 +83,7 @@ public class DividerItemDecoration extends RecyclerView.ItemDecoration { final int bottom = parent.getHeight() - parent.getPaddingBottom(); final int childCount = parent.getChildCount(); - for (int i = 0; i < childCount; i++) { + for (int i = 0; i < childCount -1; i++) { final View child = parent.getChildAt(i); final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child .getLayoutParams(); diff --git a/OpenKeychain/src/main/res/layout/identities_card.xml b/OpenKeychain/src/main/res/layout/identities_card.xml index f460c2d14..d2bcc4bd1 100644 --- a/OpenKeychain/src/main/res/layout/identities_card.xml +++ b/OpenKeychain/src/main/res/layout/identities_card.xml @@ -12,21 +12,6 @@ android:layout_height="wrap_content" android:text="@string/section_user_ids" /> - - - - + android:gravity="center_vertical" + android:minHeight="?android:attr/listPreferredItemHeight" + android:paddingLeft="8dp" + android:paddingTop="4dp" + android:paddingBottom="4dp"> -