integrate display of trust ids into other identities

This commit is contained in:
Vincent Breitmoser
2017-05-29 19:42:24 +02:00
parent 846692e8ba
commit 0edbe9f1b2
15 changed files with 241 additions and 471 deletions

View File

@@ -38,6 +38,7 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.Certs;
import org.sufficientlysecure.keychain.ui.adapter.IdentityAdapter.ViewHolder; 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.IdentityInfo;
import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityLoader.LinkedIdInfo; import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityLoader.LinkedIdInfo;
import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityLoader.TrustIdInfo;
import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityLoader.UserIdInfo; import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityLoader.UserIdInfo;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.State; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.State;
@@ -75,7 +76,11 @@ public class IdentityAdapter extends RecyclerView.Adapter<ViewHolder> {
int viewType = getItemViewType(position); int viewType = getItemViewType(position);
if (viewType == VIEW_TYPE_USER_ID) { if (viewType == VIEW_TYPE_USER_ID) {
((UserIdViewHolder) holder).bind((UserIdInfo) info); if (info instanceof TrustIdInfo) {
((UserIdViewHolder) holder).bind((TrustIdInfo) info);
} else {
((UserIdViewHolder) holder).bind((UserIdInfo) info);
}
} else if (viewType == VIEW_TYPE_LINKED_ID) { } else if (viewType == VIEW_TYPE_LINKED_ID) {
((LinkedIdViewHolder) holder).bind(context, (LinkedIdInfo) info, isSecret); ((LinkedIdViewHolder) holder).bind(context, (LinkedIdInfo) info, isSecret);
} else { } else {
@@ -97,7 +102,7 @@ public class IdentityAdapter extends RecyclerView.Adapter<ViewHolder> {
@Override @Override
public int getItemViewType(int position) { public int getItemViewType(int position) {
IdentityInfo info = data.get(position); IdentityInfo info = data.get(position);
if (info instanceof UserIdInfo) { if (info instanceof UserIdInfo || info instanceof TrustIdInfo) {
return VIEW_TYPE_USER_ID; return VIEW_TYPE_USER_ID;
} else if (info instanceof LinkedIdInfo) { } else if (info instanceof LinkedIdInfo) {
return VIEW_TYPE_LINKED_ID; return VIEW_TYPE_LINKED_ID;
@@ -189,6 +194,8 @@ public class IdentityAdapter extends RecyclerView.Adapter<ViewHolder> {
private final TextView vName; private final TextView vName;
private final TextView vAddress; private final TextView vAddress;
private final TextView vComment; private final TextView vComment;
private final ImageView vIcon;
private final ImageView vTrustIdAction;
private UserIdViewHolder(View view) { private UserIdViewHolder(View view) {
super(view); super(view);
@@ -196,9 +203,36 @@ public class IdentityAdapter extends RecyclerView.Adapter<ViewHolder> {
vName = (TextView) view.findViewById(R.id.user_id_item_name); vName = (TextView) view.findViewById(R.id.user_id_item_name);
vAddress = (TextView) view.findViewById(R.id.user_id_item_address); vAddress = (TextView) view.findViewById(R.id.user_id_item_address);
vComment = (TextView) view.findViewById(R.id.user_id_item_comment); 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);
}
public void bind(TrustIdInfo info) {
if (info.getUserIdInfo() != null) {
bindUserIdInfo(info.getUserIdInfo());
} else {
vName.setVisibility(View.GONE);
vComment.setVisibility(View.GONE);
vAddress.setText(info.getTrustId());
vAddress.setTypeface(null, Typeface.NORMAL);
}
vIcon.setImageDrawable(info.getAppIcon());
if (info.getTrustIdIntent() != null) {
vTrustIdAction.setVisibility(View.VISIBLE);
}
} }
public void bind(UserIdInfo info) { public void bind(UserIdInfo info) {
bindUserIdInfo(info);
vIcon.setVisibility(View.GONE);
vTrustIdAction.setVisibility(View.GONE);
}
private void bindUserIdInfo(UserIdInfo info) {
if (info.getName() != null) { if (info.getName() != null) {
vName.setText(info.getName()); vName.setText(info.getName());
} else { } else {
@@ -224,7 +258,6 @@ public class IdentityAdapter extends RecyclerView.Adapter<ViewHolder> {
vName.setTypeface(null, Typeface.NORMAL); vName.setTypeface(null, Typeface.NORMAL);
vAddress.setTypeface(null, Typeface.NORMAL); vAddress.setTypeface(null, Typeface.NORMAL);
} }
} }
} }

View File

@@ -1,200 +0,0 @@
/*
* Copyright (C) 2016 Vincent Breitmoser <look@my.amazin.horse>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.sufficientlysecure.keychain.ui.adapter;
import java.util.HashMap;
import java.util.List;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.database.Cursor;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.support.v4.content.CursorLoader;
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.openintents.openpgp.util.OpenPgpApi;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.provider.KeychainContract.ApiTrustIdentity;
import org.sufficientlysecure.keychain.ui.adapter.TrustIdsAdapter.ViewHolder;
import org.sufficientlysecure.keychain.ui.util.adapter.CursorAdapter;
import org.sufficientlysecure.keychain.ui.util.adapter.CursorAdapter.SimpleCursor;
import org.sufficientlysecure.keychain.ui.util.recyclerview.RecyclerItemClickListener;
import org.sufficientlysecure.keychain.ui.util.recyclerview.RecyclerItemClickListener.OnItemClickListener;
public class TrustIdsAdapter extends CursorAdapter<SimpleCursor, ViewHolder> {
private static final String[] TRUST_IDS_PROJECTION = new String[] {
ApiTrustIdentity._ID,
ApiTrustIdentity.PACKAGE_NAME,
ApiTrustIdentity.IDENTIFIER,
};
private static final int INDEX_PACKAGE_NAME = 1;
private static final int INDEX_TRUST_ID = 2;
private HashMap<String, Drawable> appIconCache = new HashMap<>();
private Integer expandedPosition;
private OnItemClickListener onItemClickListener;
public TrustIdsAdapter(Context context, SimpleCursor simpleCursor) {
super(context, simpleCursor, FLAG_REGISTER_CONTENT_OBSERVER);
}
private void launchTrustIdActivity(String packageName, String trustId, Context context) {
try {
Intent intent = createTrustIdActivityIntent(packageName, trustId);
context.startActivity(intent);
} catch (ActivityNotFoundException e) {
// can't help it
}
}
private Intent createTrustIdActivityIntent(String packageName, String trustId) {
Intent intent = new Intent();
intent.setAction(packageName + ".TRUST_ID_ACTION");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(OpenPgpApi.EXTRA_TRUST_IDENTITY, trustId);
return intent;
}
private boolean isTrustIdActivityAvailable(String packageName, String trustId, Context context) {
Intent intent = createTrustIdActivityIntent(packageName, trustId);
List<ResolveInfo> resolveInfos = context.getPackageManager().queryIntentActivities(intent, 0);
return resolveInfos != null && !resolveInfos.isEmpty();
}
private Drawable getDrawableForPackageName(String packageName) {
if (appIconCache.containsKey(packageName)) {
return appIconCache.get(packageName);
}
PackageManager pm = getContext().getPackageManager();
try {
ApplicationInfo ai = pm.getApplicationInfo(packageName, 0);
Drawable appIcon = pm.getApplicationIcon(ai);
appIconCache.put(packageName, appIcon);
return appIcon;
} catch (PackageManager.NameNotFoundException e) {
return null;
}
}
public static CursorLoader createLoader(Context context, Uri dataUri) {
Uri baseUri = ApiTrustIdentity.buildByKeyUri(dataUri);
return new CursorLoader(context, baseUri, TrustIdsAdapter.TRUST_IDS_PROJECTION, null, null, null);
}
public void setExpandedView(Integer position) {
if (position == null) {
if (expandedPosition != null) {
notifyItemChanged(expandedPosition);
}
expandedPosition = null;
} else if (expandedPosition == null || !expandedPosition.equals(position)) {
if (expandedPosition != null) {
notifyItemChanged(expandedPosition);
}
expandedPosition = position;
notifyItemChanged(position);
}
}
public void setOnItemClickListener(RecyclerItemClickListener.OnItemClickListener onItemClickListener) {
this.onItemClickListener = onItemClickListener;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(getContext()).inflate(R.layout.view_key_trust_id_item, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
moveCursorOrThrow(position);
SimpleCursor cursor = getCursor();
final String packageName = cursor.getString(INDEX_PACKAGE_NAME);
final String trustId = cursor.getString(INDEX_TRUST_ID);
Drawable drawable = getDrawableForPackageName(packageName);
holder.vTrustId.setText(trustId);
holder.vAppIcon.setImageDrawable(drawable);
if (isTrustIdActivityAvailable(packageName, trustId, getContext())) {
holder.vActionIcon.setVisibility(View.VISIBLE);
holder.vActionIcon.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
launchTrustIdActivity(packageName, trustId, getContext());
}
});
} else {
holder.vActionIcon.setVisibility(View.GONE);
}
if (expandedPosition != null && position == expandedPosition) {
holder.vButtonBar.setVisibility(View.VISIBLE);
} else {
holder.vButtonBar.setVisibility(View.GONE);
}
holder.itemView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
if (onItemClickListener != null) {
onItemClickListener.onItemClick(holder.itemView, position);
}
}
});
}
public void swapCursor(Cursor data) {
swapCursor(new SimpleCursor(data));
}
public static class ViewHolder extends RecyclerView.ViewHolder {
private final TextView vTrustId;
private final ImageView vAppIcon;
private final ImageView vActionIcon;
private final View vButtonBar;
public ViewHolder(View view) {
super(view);
vTrustId = (TextView) view.findViewById(R.id.trust_id_name);
vAppIcon = (ImageView) view.findViewById(R.id.trust_id_app_icon);
vActionIcon = (ImageView) view.findViewById(R.id.trust_id_action);
vButtonBar = view.findViewById(R.id.trust_id_button_bar);
}
}
}

View File

@@ -24,8 +24,6 @@ import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.support.v4.app.DialogFragment; import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentManager.OnBackStackChangedListener;
import android.support.v4.app.FragmentTransaction; import android.support.v4.app.FragmentTransaction;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
@@ -39,14 +37,11 @@ import org.sufficientlysecure.keychain.ui.keyview.presenter.IdentitiesPresenter;
import org.sufficientlysecure.keychain.ui.keyview.presenter.KeyHealthPresenter; import org.sufficientlysecure.keychain.ui.keyview.presenter.KeyHealthPresenter;
import org.sufficientlysecure.keychain.ui.keyview.presenter.KeyserverStatusPresenter; import org.sufficientlysecure.keychain.ui.keyview.presenter.KeyserverStatusPresenter;
import org.sufficientlysecure.keychain.ui.keyview.presenter.SystemContactPresenter; import org.sufficientlysecure.keychain.ui.keyview.presenter.SystemContactPresenter;
import org.sufficientlysecure.keychain.ui.keyview.presenter.TrustIdsPresenter;
import org.sufficientlysecure.keychain.ui.keyview.presenter.ViewKeyMvpView; import org.sufficientlysecure.keychain.ui.keyview.presenter.ViewKeyMvpView;
import org.sufficientlysecure.keychain.ui.keyview.view.IdentitiesCardView; import org.sufficientlysecure.keychain.ui.keyview.view.IdentitiesCardView;
import org.sufficientlysecure.keychain.ui.keyview.view.KeyHealthView; import org.sufficientlysecure.keychain.ui.keyview.view.KeyHealthView;
import org.sufficientlysecure.keychain.ui.keyview.view.KeyserverStatusView; import org.sufficientlysecure.keychain.ui.keyview.view.KeyserverStatusView;
import org.sufficientlysecure.keychain.ui.keyview.view.SystemContactCardView; import org.sufficientlysecure.keychain.ui.keyview.view.SystemContactCardView;
import org.sufficientlysecure.keychain.ui.keyview.view.TrustIdsIdCardView;
import org.sufficientlysecure.keychain.util.Preferences;
public class ViewKeyFragment extends LoaderFragment implements ViewKeyMvpView { public class ViewKeyFragment extends LoaderFragment implements ViewKeyMvpView {
@@ -59,14 +54,10 @@ public class ViewKeyFragment extends LoaderFragment implements ViewKeyMvpView {
private static final int LOADER_ID_LINKED_CONTACT = 2; private static final int LOADER_ID_LINKED_CONTACT = 2;
private static final int LOADER_ID_SUBKEY_STATUS = 3; private static final int LOADER_ID_SUBKEY_STATUS = 3;
private static final int LOADER_ID_KEYSERVER_STATUS = 4; private static final int LOADER_ID_KEYSERVER_STATUS = 4;
private static final int LOADER_ID_TRUST_IDS = 5;
private IdentitiesCardView mIdentitiesCardView; private IdentitiesCardView mIdentitiesCardView;
private IdentitiesPresenter mIdentitiesPresenter; private IdentitiesPresenter mIdentitiesPresenter;
private TrustIdsIdCardView mTrustIdsCard;
private TrustIdsPresenter mTrustIdsPresenter;
SystemContactCardView mSystemContactCard; SystemContactCardView mSystemContactCard;
SystemContactPresenter mSystemContactPresenter; SystemContactPresenter mSystemContactPresenter;
@@ -97,8 +88,6 @@ public class ViewKeyFragment extends LoaderFragment implements ViewKeyMvpView {
mIdentitiesCardView = (IdentitiesCardView) view.findViewById(R.id.card_identities); mIdentitiesCardView = (IdentitiesCardView) view.findViewById(R.id.card_identities);
mTrustIdsCard = (TrustIdsIdCardView) view.findViewById(R.id.view_key_card_trust_ids);
mSystemContactCard = (SystemContactCardView) view.findViewById(R.id.linked_system_contact_card); mSystemContactCard = (SystemContactCardView) view.findViewById(R.id.linked_system_contact_card);
mKeyStatusHealth = (KeyHealthView) view.findViewById(R.id.key_status_health); mKeyStatusHealth = (KeyHealthView) view.findViewById(R.id.key_status_health);
mKeyStatusKeyserver = (KeyserverStatusView) view.findViewById(R.id.key_status_keyserver); mKeyStatusKeyserver = (KeyserverStatusView) view.findViewById(R.id.key_status_keyserver);
@@ -128,10 +117,6 @@ public class ViewKeyFragment extends LoaderFragment implements ViewKeyMvpView {
mKeyserverStatusPresenter = new KeyserverStatusPresenter( mKeyserverStatusPresenter = new KeyserverStatusPresenter(
getContext(), mKeyStatusKeyserver, LOADER_ID_KEYSERVER_STATUS, masterKeyId, mIsSecret); getContext(), mKeyStatusKeyserver, LOADER_ID_KEYSERVER_STATUS, masterKeyId, mIsSecret);
mKeyserverStatusPresenter.startLoader(getLoaderManager()); mKeyserverStatusPresenter.startLoader(getLoaderManager());
mTrustIdsPresenter = new TrustIdsPresenter(
getContext(), mTrustIdsCard, this, LOADER_ID_TRUST_IDS, masterKeyId, false);
mTrustIdsPresenter.startLoader(getLoaderManager());
} }
@Override @Override
@@ -176,28 +161,4 @@ public class ViewKeyFragment extends LoaderFragment implements ViewKeyMvpView {
} }
}); });
} }
@Override
public void addFakeBackStackItem(String tag, final OnBackStackPoppedListener listener) {
FragmentManager fragmentManager = getFragmentManager();
if (fragmentManager.getBackStackEntryCount() > 0) {
return;
}
fragmentManager.beginTransaction()
.addToBackStack("expand_trust_id")
.commitAllowingStateLoss();
fragmentManager.executePendingTransactions();
fragmentManager.addOnBackStackChangedListener(new OnBackStackChangedListener() {
@Override
public void onBackStackChanged() {
FragmentManager fragMan = getFragmentManager();
fragMan.popBackStack("expand_trust_id", FragmentManager.POP_BACK_STACK_INCLUSIVE);
fragMan.removeOnBackStackChangedListener(this);
listener.onBackStackPopped();
}
});
}
} }

View File

@@ -25,18 +25,25 @@ import java.util.List;
import android.content.ContentResolver; import android.content.ContentResolver;
import android.content.Context; import android.content.Context;
import android.content.Intent;
import android.content.pm.ResolveInfo;
import android.database.Cursor; import android.database.Cursor;
import android.graphics.drawable.Drawable;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.v4.content.AsyncTaskLoader; import android.support.v4.content.AsyncTaskLoader;
import android.util.Log; import android.util.Log;
import com.google.auto.value.AutoValue; import com.google.auto.value.AutoValue;
import org.openintents.openpgp.util.OpenPgpApi;
import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.linked.LinkedAttribute; import org.sufficientlysecure.keychain.linked.LinkedAttribute;
import org.sufficientlysecure.keychain.linked.UriAttribute; import org.sufficientlysecure.keychain.linked.UriAttribute;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.KeychainContract.ApiTrustIdentity;
import org.sufficientlysecure.keychain.provider.KeychainContract.Certs;
import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets; import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets;
import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityLoader.IdentityInfo; import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityLoader.IdentityInfo;
import org.sufficientlysecure.keychain.ui.util.PackageIconGetter;
public class IdentityLoader extends AsyncTaskLoader<List<IdentityInfo>> { public class IdentityLoader extends AsyncTaskLoader<List<IdentityInfo>> {
@@ -68,6 +75,7 @@ public class IdentityLoader extends AsyncTaskLoader<List<IdentityInfo>> {
private static final String USER_IDS_WHERE = UserPackets.IS_REVOKED + " = 0"; private static final String USER_IDS_WHERE = UserPackets.IS_REVOKED + " = 0";
private final ContentResolver contentResolver; private final ContentResolver contentResolver;
private final PackageIconGetter packageIconGetter;
private final long masterKeyId; private final long masterKeyId;
private final boolean showLinkedIds; private final boolean showLinkedIds;
@@ -83,6 +91,7 @@ public class IdentityLoader extends AsyncTaskLoader<List<IdentityInfo>> {
this.showLinkedIds = showLinkedIds; this.showLinkedIds = showLinkedIds;
this.identityObserver = new ForceLoadContentObserver(); this.identityObserver = new ForceLoadContentObserver();
this.packageIconGetter = PackageIconGetter.getInstance(context);
} }
@Override @Override
@@ -93,10 +102,76 @@ public class IdentityLoader extends AsyncTaskLoader<List<IdentityInfo>> {
loadLinkedIds(identities); loadLinkedIds(identities);
} }
loadUserIds(identities); loadUserIds(identities);
correlateOrAddTrustIds(identities);
return Collections.unmodifiableList(identities); return Collections.unmodifiableList(identities);
} }
private static final String[] TRUST_IDS_PROJECTION = new String[] {
ApiTrustIdentity._ID,
ApiTrustIdentity.PACKAGE_NAME,
ApiTrustIdentity.IDENTIFIER,
};
private static final int INDEX_PACKAGE_NAME = 1;
private static final int INDEX_TRUST_ID = 2;
private void correlateOrAddTrustIds(ArrayList<IdentityInfo> identities) {
Cursor cursor = contentResolver.query(ApiTrustIdentity.buildByMasterKeyId(masterKeyId),
TRUST_IDS_PROJECTION, null, null, null);
if (cursor == null) {
Log.e(Constants.TAG, "Error loading trust ids!");
return;
}
try {
while (cursor.moveToNext()) {
String packageName = cursor.getString(INDEX_PACKAGE_NAME);
String trustId = cursor.getString(INDEX_TRUST_ID);
Drawable drawable = packageIconGetter.getDrawableForPackageName(packageName);
Intent trustIdIntent = getTrustIdActivityIntentIfResolvable(packageName, trustId);
UserIdInfo associatedUserIdInfo = findUserIdMatchingTrustId(identities, trustId);
if (associatedUserIdInfo != null) {
int position = identities.indexOf(associatedUserIdInfo);
TrustIdInfo trustIdInfo = TrustIdInfo.create(associatedUserIdInfo, trustId, drawable, trustIdIntent);
identities.set(position, trustIdInfo);
} else {
TrustIdInfo trustIdInfo = TrustIdInfo.create(trustId, drawable, trustIdIntent);
identities.add(trustIdInfo);
}
}
} finally {
cursor.close();
}
}
private Intent getTrustIdActivityIntentIfResolvable(String packageName, String trustId) {
Intent intent = new Intent();
intent.setAction(packageName + ".AUTOCRYPT_PEER_ACTION");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(OpenPgpApi.EXTRA_TRUST_IDENTITY, trustId);
List<ResolveInfo> resolveInfos = getContext().getPackageManager().queryIntentActivities(intent, 0);
if (resolveInfos != null && !resolveInfos.isEmpty()) {
return intent;
} else {
return null;
}
}
private static UserIdInfo findUserIdMatchingTrustId(List<IdentityInfo> identities, String trustId) {
for (IdentityInfo identityInfo : identities) {
if (identityInfo instanceof UserIdInfo) {
UserIdInfo userIdInfo = (UserIdInfo) identityInfo;
if (trustId.equals(userIdInfo.getEmail())) {
return userIdInfo;
}
}
}
return null;
}
private void loadLinkedIds(ArrayList<IdentityInfo> identities) { private void loadLinkedIds(ArrayList<IdentityInfo> identities) {
Cursor cursor = contentResolver.query(UserPackets.buildLinkedIdsUri(masterKeyId), Cursor cursor = contentResolver.query(UserPackets.buildLinkedIdsUri(masterKeyId),
USER_PACKETS_PROJECTION, USER_IDS_WHERE, null, null); USER_PACKETS_PROJECTION, USER_IDS_WHERE, null, null);
@@ -222,4 +297,30 @@ public class IdentityLoader extends AsyncTaskLoader<List<IdentityInfo>> {
return new AutoValue_IdentityLoader_LinkedIdInfo(rank, verified, isPrimary, uriAttribute); return new AutoValue_IdentityLoader_LinkedIdInfo(rank, verified, isPrimary, uriAttribute);
} }
} }
@AutoValue
public abstract static class TrustIdInfo implements IdentityInfo {
public abstract int getRank();
public abstract int getVerified();
public abstract boolean isPrimary();
public abstract String getTrustId();
@Nullable
public abstract Drawable getAppIcon();
@Nullable
public abstract UserIdInfo getUserIdInfo();
@Nullable
public abstract Intent getTrustIdIntent();
static TrustIdInfo create(UserIdInfo userIdInfo, String trustId, Drawable appIcon, Intent trustIdIntent) {
return new AutoValue_IdentityLoader_TrustIdInfo(userIdInfo.getRank(), userIdInfo.getVerified(),
userIdInfo.isPrimary(), trustId, appIcon, userIdInfo, trustIdIntent);
}
static TrustIdInfo create(String trustId, Drawable appIcon, Intent trustIdIntent) {
return new AutoValue_IdentityLoader_TrustIdInfo(
0, Certs.VERIFIED_SELF, false, trustId, appIcon, null, trustIdIntent);
}
}
} }

View File

@@ -40,6 +40,7 @@ import org.sufficientlysecure.keychain.ui.keyview.LinkedIdViewFragment;
import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityLoader; 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.IdentityInfo;
import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityLoader.LinkedIdInfo; import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityLoader.LinkedIdInfo;
import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityLoader.TrustIdInfo;
import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityLoader.UserIdInfo; import org.sufficientlysecure.keychain.ui.keyview.loader.IdentityLoader.UserIdInfo;
import org.sufficientlysecure.keychain.ui.linked.LinkedIdWizard; import org.sufficientlysecure.keychain.ui.linked.LinkedIdWizard;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
@@ -117,6 +118,9 @@ public class IdentitiesPresenter implements LoaderCallbacks<List<IdentityInfo>>
showLinkedId((LinkedIdInfo) info); showLinkedId((LinkedIdInfo) info);
} else if (info instanceof UserIdInfo) { } else if (info instanceof UserIdInfo) {
showUserIdInfo((UserIdInfo) info); showUserIdInfo((UserIdInfo) info);
} else if (info instanceof TrustIdInfo) {
Intent trustIdIntent = ((TrustIdInfo) info).getTrustIdIntent();
viewKeyMvpView.startActivity(trustIdIntent);
} }
} }

View File

@@ -1,102 +0,0 @@
/*
* Copyright (C) 2017 Vincent Breitmoser <v.breitmoser@mugenguild.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.sufficientlysecure.keychain.ui.keyview.presenter;
import android.content.Context;
import android.database.Cursor;
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.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.ui.adapter.TrustIdsAdapter;
import org.sufficientlysecure.keychain.ui.keyview.presenter.ViewKeyMvpView.OnBackStackPoppedListener;
import org.sufficientlysecure.keychain.ui.util.recyclerview.RecyclerItemClickListener.OnItemClickListener;
public class TrustIdsPresenter implements LoaderCallbacks<Cursor> {
private final Context context;
private final TrustIdsMvpView view;
private final ViewKeyMvpView viewKeyMvpView;
private final int loaderId;
private final TrustIdsAdapter trustIdsAdapter;
private final long masterKeyId;
private final boolean isSecret;
public TrustIdsPresenter(Context context, TrustIdsMvpView view, ViewKeyMvpView viewKeyMvpView, int loaderId,
long masterKeyId, boolean isSecret) {
this.context = context;
this.view = view;
this.viewKeyMvpView = viewKeyMvpView;
this.loaderId = loaderId;
this.masterKeyId = masterKeyId;
this.isSecret = isSecret;
trustIdsAdapter = new TrustIdsAdapter(context, null);
view.setTrustIdAdapter(trustIdsAdapter);
trustIdsAdapter.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(View view, int position) {
onClickTrustId(position);
}
});
}
public void startLoader(LoaderManager loaderManager) {
loaderManager.restartLoader(loaderId, null, this);
}
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
return TrustIdsAdapter.createLoader(context, KeyRings.buildUnifiedKeyRingUri(masterKeyId));
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
trustIdsAdapter.swapCursor(data);
view.showCard(data.getCount() > 0);
}
@Override
public void onLoaderReset(Loader loader) {
trustIdsAdapter.swapCursor(null);
}
private void onClickTrustId(int position) {
trustIdsAdapter.setExpandedView(position);
viewKeyMvpView.addFakeBackStackItem("expand_trust_id", new OnBackStackPoppedListener() {
@Override
public void onBackStackPopped() {
trustIdsAdapter.setExpandedView(null);
}
});
}
public interface TrustIdsMvpView {
void setTrustIdAdapter(TrustIdsAdapter trustIdsAdapter);
void showCard(boolean show);
}
}

View File

@@ -9,13 +9,8 @@ import android.support.v4.app.Fragment;
public interface ViewKeyMvpView { public interface ViewKeyMvpView {
void switchToFragment(Fragment frag, String backStackName); void switchToFragment(Fragment frag, String backStackName);
void startActivity(Intent intent);
void startActivityAndShowResultSnackbar(Intent intent); void startActivityAndShowResultSnackbar(Intent intent);
void showDialogFragment(DialogFragment dialogFragment, final String tag); void showDialogFragment(DialogFragment dialogFragment, final String tag);
void setContentShown(boolean show, boolean animate); void setContentShown(boolean show, boolean animate);
void addFakeBackStackItem(String tag, OnBackStackPoppedListener listener);
interface OnBackStackPoppedListener {
void onBackStackPopped();
}
} }

View File

@@ -1,55 +0,0 @@
/*
* Copyright (C) 2017 Vincent Breitmoser <v.breitmoser@mugenguild.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.sufficientlysecure.keychain.ui.keyview.view;
import android.content.Context;
import android.support.v7.widget.CardView;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.ui.adapter.TrustIdsAdapter;
import org.sufficientlysecure.keychain.ui.keyview.presenter.TrustIdsPresenter.TrustIdsMvpView;
public class TrustIdsIdCardView extends CardView implements TrustIdsMvpView {
private RecyclerView vTrustIds;
public TrustIdsIdCardView(Context context, AttributeSet attrs) {
super(context, attrs);
View view = LayoutInflater.from(context).inflate(R.layout.trust_ids_card, this, true);
vTrustIds = (RecyclerView) view.findViewById(R.id.view_key_trust_ids);
vTrustIds.setLayoutManager(new LinearLayoutManager(getContext()));
}
@Override
public void setTrustIdAdapter(TrustIdsAdapter trustIdsAdapter) {
vTrustIds.setAdapter(trustIdsAdapter);
}
@Override
public void showCard(boolean show) {
setVisibility(show ? View.VISIBLE : View.GONE);
}
}

View File

@@ -0,0 +1,44 @@
package org.sufficientlysecure.keychain.ui.util;
import java.util.HashMap;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
public class PackageIconGetter {
private final PackageManager packageManager;
private final HashMap<String, Drawable> appIconCache = new HashMap<>();
public static PackageIconGetter getInstance(Context context) {
PackageManager pm = context.getPackageManager();
return new PackageIconGetter(pm);
}
private PackageIconGetter(PackageManager packageManager) {
this.packageManager = packageManager;
}
public Drawable getDrawableForPackageName(String packageName) {
if (appIconCache.containsKey(packageName)) {
return appIconCache.get(packageName);
}
try {
ApplicationInfo ai = packageManager.getApplicationInfo(packageName, 0);
Drawable appIcon = packageManager.getApplicationIcon(ai);
appIconCache.put(packageName, appIcon);
return appIcon;
} catch (PackageManager.NameNotFoundException e) {
return null;
}
}
}

View File

@@ -6,6 +6,7 @@
android:minHeight="?android:attr/listPreferredItemHeight" android:minHeight="?android:attr/listPreferredItemHeight"
android:orientation="horizontal" android:orientation="horizontal"
android:singleLine="true" android:singleLine="true"
android:background="?selectableItemBackground"
tools:showIn="@layout/linked_id_view_fragment"> tools:showIn="@layout/linked_id_view_fragment">
<ImageView <ImageView

View File

@@ -3,7 +3,8 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
tools:parentTag="LinearLayout" tools:parentTag="LinearLayout"
tools:layout_width="match_parent" tools:layout_width="match_parent"
tools:layout_height="match_parent"> tools:layout_height="match_parent"
tools:orientation="vertical">
<LinearLayout <LinearLayout
android:orientation="horizontal" android:orientation="horizontal"

View File

@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="@layout/subkey_status_card_content" />
</LinearLayout>

View File

@@ -1,23 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
style="@style/CardViewHeader"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Known to Apps as" />
<android.support.v7.widget.RecyclerView
android:id="@+id/view_key_trust_ids"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp" />
</LinearLayout>
</merge>

View File

@@ -52,17 +52,6 @@
</android.support.v7.widget.CardView> </android.support.v7.widget.CardView>
<org.sufficientlysecure.keychain.ui.keyview.view.TrustIdsIdCardView
android:id="@+id/view_key_card_trust_ids"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
card_view:cardBackgroundColor="?attr/colorCardViewBackground"
card_view:cardCornerRadius="4dp"
card_view:cardElevation="2dp"
card_view:cardUseCompatPadding="true"
/>
<org.sufficientlysecure.keychain.ui.keyview.view.IdentitiesCardView <org.sufficientlysecure.keychain.ui.keyview.view.IdentitiesCardView
android:id="@+id/card_identities" android:id="@+id/card_identities"
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@@ -3,31 +3,61 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center_vertical"
android:minHeight="?android:attr/listPreferredItemHeight" android:minHeight="?android:attr/listPreferredItemHeight"
android:paddingLeft="8dp" android:orientation="horizontal"
android:paddingTop="4dp" android:maxLines="1"
android:paddingBottom="4dp"> android:padding="8dp"
android:background="?selectableItemBackground"
>
<TextView <ImageView
android:id="@+id/user_id_item_address" android:layout_width="48dp"
android:layout_height="48dp"
android:layout_gravity="center_vertical"
android:padding="8dp"
android:id="@+id/trust_id_app_icon"
tools:src="@drawable/apps_k9"/>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical"
android:layout_gravity="center_vertical">
<TextView
android:id="@+id/user_id_item_address"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="alice@example.com"
android:textAppearance="?android:attr/textAppearanceMedium" />
<TextView
android:id="@+id/user_id_item_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="Alice"
android:textAppearance="?android:attr/textAppearanceSmall" />
<TextView
android:id="@+id/user_id_item_comment"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="comment"
tools:visibility="gone"
android:textAppearance="?android:attr/textAppearanceSmall" />
</LinearLayout>
<ImageView
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
tools:text="alice@example.com" android:layout_gravity="center_vertical"
android:textAppearance="?android:attr/textAppearanceMedium" /> android:padding="8dp"
android:id="@+id/trust_id_action"
android:background="?selectableItemBackground"
android:src="@drawable/ic_chat_black_24dp"
android:visibility="gone"
tools:visibility="visible"
/>
<TextView
android:id="@+id/user_id_item_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="Alice"
android:textAppearance="?android:attr/textAppearanceSmall" />
<TextView
android:id="@+id/user_id_item_comment"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="comment"
android:textAppearance="?android:attr/textAppearanceSmall" />
</LinearLayout> </LinearLayout>