aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDominik Schürmann <dominik@dominikschuermann.de>2015-03-30 15:53:44 +0200
committerDominik Schürmann <dominik@dominikschuermann.de>2015-03-30 15:53:44 +0200
commit91494dd3a339ce14c3c722c22da6ff5c3241630b (patch)
treef2f35be53c35d1cc4ddc58474a7a9426bf4e90aa
parent726ff0b501644e0cef6d5d4a086e73c258b2361c (diff)
parentdcaac4f85f07efff2fdfd8a2eec9ba8ee758659c (diff)
downloadopen-keychain-91494dd3a339ce14c3c722c22da6ff5c3241630b.tar.gz
open-keychain-91494dd3a339ce14c3c722c22da6ff5c3241630b.tar.bz2
open-keychain-91494dd3a339ce14c3c722c22da6ff5c3241630b.zip
Merge branch 'development' into v/crypto-input-parcel
Conflicts: OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptModeAsymmetricFragment.java
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptModeAsymmetricFragment.java25
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java210
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyAdapter.java279
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EncryptKeyCompletionView.java278
-rw-r--r--OpenKeychain/src/main/res/layout/key_list_item.xml6
-rw-r--r--OpenKeychain/src/main/res/layout/recipient_box_entry.xml4
-rw-r--r--OpenKeychain/src/main/res/layout/recipient_selection_list_entry.xml26
7 files changed, 423 insertions, 405 deletions
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptModeAsymmetricFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptModeAsymmetricFragment.java
index 8c117deca..87c6c477c 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptModeAsymmetricFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptModeAsymmetricFragment.java
@@ -28,10 +28,14 @@ import com.tokenautocomplete.TokenCompleteTextView;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKey;
+import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing;
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
+import org.sufficientlysecure.keychain.provider.ProviderHelper.NotFoundException;
+import org.sufficientlysecure.keychain.ui.adapter.KeyAdapter.KeyItem;
import org.sufficientlysecure.keychain.ui.widget.EncryptKeyCompletionView;
import org.sufficientlysecure.keychain.ui.widget.KeySpinner;
import org.sufficientlysecure.keychain.util.Log;
@@ -91,7 +95,7 @@ public class EncryptModeAsymmetricFragment extends Fragment {
try {
mEncryptInterface = (IAsymmetric) activity;
} catch (ClassCastException e) {
- throw new ClassCastException(activity.toString() + " must implement IAsymmetric");
+ throw new ClassCastException(activity + " must implement IAsymmetric");
}
}
@@ -128,14 +132,14 @@ public class EncryptModeAsymmetricFragment extends Fragment {
mEncryptKeyView.setTokenListener(new TokenCompleteTextView.TokenListener() {
@Override
public void onTokenAdded(Object token) {
- if (token instanceof EncryptKeyCompletionView.EncryptionKey) {
+ if (token instanceof KeyItem) {
updateEncryptionKeys();
}
}
@Override
public void onTokenRemoved(Object token) {
- if (token instanceof EncryptKeyCompletionView.EncryptionKey) {
+ if (token instanceof KeyItem) {
updateEncryptionKeys();
}
}
@@ -162,10 +166,10 @@ public class EncryptModeAsymmetricFragment extends Fragment {
if (encryptionKeyIds != null) {
for (long preselectedId : encryptionKeyIds) {
try {
- CachedPublicKeyRing ring = mProviderHelper.getCachedPublicKeyRing(
- KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(preselectedId));
- mEncryptKeyView.addObject(mEncryptKeyView.new EncryptionKey(ring));
- } catch (PgpKeyNotFoundException e) {
+ CanonicalizedPublicKeyRing ring =
+ mProviderHelper.getCanonicalizedPublicKeyRing(preselectedId);
+ mEncryptKeyView.addObject(new KeyItem(ring));
+ } catch (NotFoundException e) {
Log.e(Constants.TAG, "key not found!", e);
}
}
@@ -173,6 +177,7 @@ public class EncryptModeAsymmetricFragment extends Fragment {
mEncryptKeyView.requestFocus();
updateEncryptionKeys();
}
+
}
private void updateEncryptionKeys() {
@@ -180,9 +185,9 @@ public class EncryptModeAsymmetricFragment extends Fragment {
List<Long> keyIds = new ArrayList<>();
List<String> userIds = new ArrayList<>();
for (Object object : objects) {
- if (object instanceof EncryptKeyCompletionView.EncryptionKey) {
- keyIds.add(((EncryptKeyCompletionView.EncryptionKey) object).getKeyId());
- userIds.add(((EncryptKeyCompletionView.EncryptionKey) object).getUserId());
+ if (object instanceof KeyItem) {
+ keyIds.add(((KeyItem) object).mKeyId);
+ userIds.add(((KeyItem) object).mUserIdFull);
}
}
long[] keyIdsArr = new long[keyIds.size()];
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java
index 5035c2793..4733dce01 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2013-2014 Dominik Schürmann <dominik@dominikschuermann.de>
- * Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com>
+ * Copyright (C) 2013-2015 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2014-2015 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
@@ -26,7 +26,6 @@ import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.graphics.Color;
-import android.graphics.PorterDuff;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
@@ -37,7 +36,6 @@ import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.support.v4.view.MenuItemCompat;
-import android.support.v4.widget.CursorAdapter;
import android.support.v7.widget.SearchView;
import android.view.ActionMode;
import android.view.LayoutInflater;
@@ -49,8 +47,6 @@ import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AbsListView.MultiChoiceModeListener;
import android.widget.AdapterView;
-import android.widget.ImageButton;
-import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
@@ -64,7 +60,6 @@ import org.sufficientlysecure.keychain.operations.results.ConsolidateResult;
import org.sufficientlysecure.keychain.operations.results.DeleteResult;
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult;
-import org.sufficientlysecure.keychain.pgp.KeyRing;
import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.KeychainDatabase;
@@ -75,9 +70,8 @@ import org.sufficientlysecure.keychain.service.ServiceProgressHandler;
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment;
import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment;
-import org.sufficientlysecure.keychain.ui.util.Highlighter;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
-import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.State;
+import org.sufficientlysecure.keychain.ui.adapter.KeyAdapter;
import org.sufficientlysecure.keychain.ui.util.Notify;
import org.sufficientlysecure.keychain.util.ExportHelper;
import org.sufficientlysecure.keychain.util.FabContainer;
@@ -292,26 +286,6 @@ public class KeyListFragment extends LoaderFragment
getLoaderManager().initLoader(0, null, this);
}
- // These are the rows that we will retrieve.
- static final String[] PROJECTION = new String[]{
- KeyRings._ID,
- KeyRings.MASTER_KEY_ID,
- KeyRings.USER_ID,
- KeyRings.IS_REVOKED,
- KeyRings.IS_EXPIRED,
- KeyRings.VERIFIED,
- KeyRings.HAS_ANY_SECRET,
- KeyRings.HAS_DUPLICATE_USER_ID,
- };
-
- static final int INDEX_MASTER_KEY_ID = 1;
- static final int INDEX_USER_ID = 2;
- static final int INDEX_IS_REVOKED = 3;
- static final int INDEX_IS_EXPIRED = 4;
- static final int INDEX_VERIFIED = 5;
- static final int INDEX_HAS_ANY_SECRET = 6;
- static final int INDEX_HAS_DUPLICATE_USER_ID = 7;
-
static final String ORDER =
KeyRings.HAS_ANY_SECRET + " DESC, UPPER(" + KeyRings.USER_ID + ") ASC";
@@ -339,7 +313,8 @@ public class KeyListFragment extends LoaderFragment
// Now create and return a CursorLoader that will take care of
// creating a Cursor for the data being displayed.
- return new CursorLoader(getActivity(), baseUri, PROJECTION, where, whereArgs, ORDER);
+ return new CursorLoader(getActivity(), baseUri,
+ KeyListAdapter.PROJECTION, where, whereArgs, ORDER);
}
@Override
@@ -787,148 +762,54 @@ public class KeyListFragment extends LoaderFragment
anim.start();
}
- /**
- * Implements StickyListHeadersAdapter from library
- */
- private class KeyListAdapter extends CursorAdapter implements StickyListHeadersAdapter {
- private String mQuery;
- private LayoutInflater mInflater;
+ public class KeyListAdapter extends KeyAdapter implements StickyListHeadersAdapter {
private HashMap<Integer, Boolean> mSelection = new HashMap<>();
public KeyListAdapter(Context context, Cursor c, int flags) {
super(context, c, flags);
-
- mInflater = LayoutInflater.from(context);
- }
-
- public void setSearchQuery(String query) {
- mQuery = query;
}
@Override
- public Cursor swapCursor(Cursor newCursor) {
- return super.swapCursor(newCursor);
- }
+ public View newView(Context context, Cursor cursor, ViewGroup parent) {
+ View view = super.newView(context, cursor, parent);
- private class ItemViewHolder {
- Long mMasterKeyId;
- TextView mMainUserId;
- TextView mMainUserIdRest;
- ImageView mStatus;
- View mSlinger;
- ImageButton mSlingerButton;
- }
+ final KeyItemViewHolder holder = (KeyItemViewHolder) view.getTag();
- @Override
- public View newView(Context context, Cursor cursor, ViewGroup parent) {
- View view = mInflater.inflate(R.layout.key_list_item, parent, false);
- final ItemViewHolder holder = new ItemViewHolder();
- holder.mMainUserId = (TextView) view.findViewById(R.id.key_list_item_name);
- holder.mMainUserIdRest = (TextView) view.findViewById(R.id.key_list_item_email);
- holder.mStatus = (ImageView) view.findViewById(R.id.key_list_item_status_icon);
- holder.mSlinger = view.findViewById(R.id.key_list_item_slinger_view);
- holder.mSlingerButton = (ImageButton) view.findViewById(R.id.key_list_item_slinger_button);
- holder.mSlingerButton.setColorFilter(context.getResources().getColor(R.color.tertiary_text_light),
- PorterDuff.Mode.SRC_IN);
- view.setTag(holder);
- view.findViewById(R.id.key_list_item_slinger_button).setOnClickListener(new OnClickListener() {
+ holder.mSlinger.setVisibility(View.VISIBLE);
+ holder.mSlingerButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (holder.mMasterKeyId != null) {
- Intent safeSlingerIntent = new Intent(getActivity(), SafeSlingerActivity.class);
+ Intent safeSlingerIntent = new Intent(mContext, SafeSlingerActivity.class);
safeSlingerIntent.putExtra(SafeSlingerActivity.EXTRA_MASTER_KEY_ID, holder.mMasterKeyId);
startActivityForResult(safeSlingerIntent, REQUEST_ACTION);
}
}
});
+
return view;
}
- /**
- * Bind cursor data to the item list view
- */
@Override
- public void bindView(View view, Context context, Cursor cursor) {
- Highlighter highlighter = new Highlighter(context, mQuery);
- ItemViewHolder h = (ItemViewHolder) view.getTag();
-
- { // set name and stuff, common to both key types
- String userId = cursor.getString(INDEX_USER_ID);
- KeyRing.UserId userIdSplit = KeyRing.splitUserId(userId);
- if (userIdSplit.name != null) {
- h.mMainUserId.setText(highlighter.highlight(userIdSplit.name));
- } else {
- h.mMainUserId.setText(R.string.user_id_no_name);
- }
- if (userIdSplit.email != null) {
- h.mMainUserIdRest.setText(highlighter.highlight(userIdSplit.email));
- h.mMainUserIdRest.setVisibility(View.VISIBLE);
- } else {
- h.mMainUserIdRest.setVisibility(View.GONE);
- }
- }
-
- { // set edit button and status, specific by key type
-
- long masterKeyId = cursor.getLong(INDEX_MASTER_KEY_ID);
- boolean isSecret = cursor.getInt(INDEX_HAS_ANY_SECRET) != 0;
- boolean isRevoked = cursor.getInt(INDEX_IS_REVOKED) > 0;
- boolean isExpired = cursor.getInt(INDEX_IS_EXPIRED) != 0;
- boolean isVerified = cursor.getInt(INDEX_VERIFIED) > 0;
- boolean hasDuplicate = cursor.getInt(INDEX_HAS_DUPLICATE_USER_ID) == 1;
-
- h.mMasterKeyId = masterKeyId;
-
- // Note: order is important!
- if (isRevoked) {
- KeyFormattingUtils.setStatusImage(getActivity(), h.mStatus, null, State.REVOKED, R.color.bg_gray);
- h.mStatus.setVisibility(View.VISIBLE);
- h.mSlinger.setVisibility(View.GONE);
- h.mMainUserId.setTextColor(context.getResources().getColor(R.color.bg_gray));
- h.mMainUserIdRest.setTextColor(context.getResources().getColor(R.color.bg_gray));
- } else if (isExpired) {
- KeyFormattingUtils.setStatusImage(getActivity(), h.mStatus, null, State.EXPIRED, R.color.bg_gray);
- h.mStatus.setVisibility(View.VISIBLE);
- h.mSlinger.setVisibility(View.GONE);
- h.mMainUserId.setTextColor(context.getResources().getColor(R.color.bg_gray));
- h.mMainUserIdRest.setTextColor(context.getResources().getColor(R.color.bg_gray));
- } else if (isSecret) {
- h.mStatus.setVisibility(View.GONE);
- h.mSlinger.setVisibility(View.VISIBLE);
- h.mMainUserId.setTextColor(context.getResources().getColor(R.color.black));
- h.mMainUserIdRest.setTextColor(context.getResources().getColor(R.color.black));
- } else {
- // this is a public key - show if it's verified
- if (isVerified) {
- KeyFormattingUtils.setStatusImage(getActivity(), h.mStatus, State.VERIFIED);
- h.mStatus.setVisibility(View.VISIBLE);
- } else {
- KeyFormattingUtils.setStatusImage(getActivity(), h.mStatus, State.UNVERIFIED);
- h.mStatus.setVisibility(View.VISIBLE);
- }
- h.mSlinger.setVisibility(View.GONE);
- h.mMainUserId.setTextColor(context.getResources().getColor(R.color.black));
- h.mMainUserIdRest.setTextColor(context.getResources().getColor(R.color.black));
- }
- }
-
- }
+ public View getView(int position, View convertView, ViewGroup parent) {
+ // let the adapter handle setting up the row views
+ View v = super.getView(position, convertView, parent);
- public boolean isSecretAvailable(int id) {
- if (!mCursor.moveToPosition(id)) {
- throw new IllegalStateException("couldn't move cursor to position " + id);
+ if (mSelection.get(position) != null) {
+ // selected position color
+ v.setBackgroundColor(parent.getResources().getColor(R.color.emphasis));
+ } else {
+ // default color
+ v.setBackgroundColor(Color.TRANSPARENT);
}
- return mCursor.getInt(INDEX_HAS_ANY_SECRET) != 0;
+ return v;
}
- public long getMasterKeyId(int id) {
- if (!mCursor.moveToPosition(id)) {
- throw new IllegalStateException("couldn't move cursor to position " + id);
- }
-
- return mCursor.getLong(INDEX_MASTER_KEY_ID);
+ private class HeaderViewHolder {
+ TextView mText;
+ TextView mCount;
}
/**
@@ -961,10 +842,10 @@ public class KeyListFragment extends LoaderFragment
throw new IllegalStateException("couldn't move cursor to position " + position);
}
- if (mCursor.getInt(KeyListFragment.INDEX_HAS_ANY_SECRET) != 0) {
+ if (mCursor.getInt(INDEX_HAS_ANY_SECRET) != 0) {
{ // set contact count
int num = mCursor.getCount();
- String contactsTotal = getResources().getQuantityString(R.plurals.n_keys, num, num);
+ String contactsTotal = mContext.getResources().getQuantityString(R.plurals.n_keys, num, num);
holder.mCount.setText(contactsTotal);
holder.mCount.setVisibility(View.VISIBLE);
}
@@ -974,7 +855,7 @@ public class KeyListFragment extends LoaderFragment
}
// set header text as first char in user id
- String userId = mCursor.getString(KeyListFragment.INDEX_USER_ID);
+ String userId = mCursor.getString(INDEX_USER_ID);
String headerText = convertView.getResources().getString(R.string.user_id_no_name);
if (userId != null && userId.length() > 0) {
headerText = "" + userId.charAt(0);
@@ -1000,11 +881,11 @@ public class KeyListFragment extends LoaderFragment
}
// early breakout: all secret keys are assigned id 0
- if (mCursor.getInt(KeyListFragment.INDEX_HAS_ANY_SECRET) != 0) {
+ if (mCursor.getInt(INDEX_HAS_ANY_SECRET) != 0) {
return 1L;
}
// otherwise, return the first character of the name as ID
- String userId = mCursor.getString(KeyListFragment.INDEX_USER_ID);
+ String userId = mCursor.getString(INDEX_USER_ID);
if (userId != null && userId.length() > 0) {
return Character.toUpperCase(userId.charAt(0));
} else {
@@ -1012,11 +893,6 @@ public class KeyListFragment extends LoaderFragment
}
}
- private class HeaderViewHolder {
- TextView mText;
- TextView mCount;
- }
-
/**
* -------------------------- MULTI-SELECTION METHODS --------------
*/
@@ -1027,7 +903,7 @@ public class KeyListFragment extends LoaderFragment
public boolean isAnySecretSelected() {
for (int pos : mSelection.keySet()) {
- if (mAdapter.isSecretAvailable(pos))
+ if (isSecretAvailable(pos))
return true;
}
return false;
@@ -1038,7 +914,7 @@ public class KeyListFragment extends LoaderFragment
int i = 0;
// get master key ids
for (int pos : mSelection.keySet()) {
- ids[i++] = mAdapter.getMasterKeyId(pos);
+ ids[i++] = getMasterKeyId(pos);
}
return ids;
}
@@ -1053,26 +929,6 @@ public class KeyListFragment extends LoaderFragment
notifyDataSetChanged();
}
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- // let the adapter handle setting up the row views
- View v = super.getView(position, convertView, parent);
-
- /**
- * Change color for multi-selection
- */
- if (mSelection.get(position) != null) {
- // selected position color
- v.setBackgroundColor(parent.getResources().getColor(R.color.emphasis));
- } else {
- // default color
- v.setBackgroundColor(Color.TRANSPARENT);
- }
-
- return v;
- }
-
}
-
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyAdapter.java
new file mode 100644
index 000000000..9304b14f1
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyAdapter.java
@@ -0,0 +1,279 @@
+/*
+ * Copyright (C) 2015 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.adapter;
+
+
+import java.util.Calendar;
+import java.util.Date;
+import java.util.TimeZone;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.graphics.PorterDuff;
+import android.support.v4.widget.CursorAdapter;
+import android.text.format.DateFormat;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKey;
+import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing;
+import org.sufficientlysecure.keychain.pgp.KeyRing;
+import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
+import org.sufficientlysecure.keychain.ui.util.Highlighter;
+import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
+import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.State;
+
+public class KeyAdapter extends CursorAdapter {
+
+ protected String mQuery;
+ protected LayoutInflater mInflater;
+
+ // These are the rows that we will retrieve.
+ public static final String[] PROJECTION = new String[]{
+ KeyRings._ID,
+ KeyRings.MASTER_KEY_ID,
+ KeyRings.USER_ID,
+ KeyRings.IS_REVOKED,
+ KeyRings.IS_EXPIRED,
+ KeyRings.VERIFIED,
+ KeyRings.HAS_ANY_SECRET,
+ KeyRings.HAS_DUPLICATE_USER_ID,
+ KeyRings.HAS_ENCRYPT,
+ KeyRings.FINGERPRINT,
+ KeyRings.CREATION,
+ };
+
+ public static final int INDEX_MASTER_KEY_ID = 1;
+ public static final int INDEX_USER_ID = 2;
+ public static final int INDEX_IS_REVOKED = 3;
+ public static final int INDEX_IS_EXPIRED = 4;
+ public static final int INDEX_VERIFIED = 5;
+ public static final int INDEX_HAS_ANY_SECRET = 6;
+ public static final int INDEX_HAS_DUPLICATE_USER_ID = 7;
+ public static final int INDEX_HAS_ENCRYPT = 8;
+ public static final int INDEX_FINGERPRINT = 9;
+ public static final int INDEX_CREATION = 10;
+
+ public KeyAdapter(Context context, Cursor c, int flags) {
+ super(context, c, flags);
+
+ mInflater = LayoutInflater.from(context);
+ }
+
+ public void setSearchQuery(String query) {
+ mQuery = query;
+ }
+
+ public static class KeyItemViewHolder {
+ public Long mMasterKeyId;
+ public TextView mMainUserId;
+ public TextView mMainUserIdRest;
+ public ImageView mStatus;
+ public View mSlinger;
+ public ImageButton mSlingerButton;
+
+ public KeyItemViewHolder(View view) {
+ mMainUserId = (TextView) view.findViewById(R.id.key_list_item_name);
+ mMainUserIdRest = (TextView) view.findViewById(R.id.key_list_item_email);
+ mStatus = (ImageView) view.findViewById(R.id.key_list_item_status_icon);
+ mSlinger = view.findViewById(R.id.key_list_item_slinger_view);
+ mSlingerButton = (ImageButton) view.findViewById(R.id.key_list_item_slinger_button);
+ }
+
+ public void setData(Context context, Cursor cursor, Highlighter highlighter) {
+
+ { // set name and stuff, common to both key types
+ String userId = cursor.getString(INDEX_USER_ID);
+ KeyRing.UserId userIdSplit = KeyRing.splitUserId(userId);
+ if (userIdSplit.name != null) {
+ mMainUserId.setText(highlighter.highlight(userIdSplit.name));
+ } else {
+ mMainUserId.setText(R.string.user_id_no_name);
+ }
+ if (userIdSplit.email != null) {
+ mMainUserIdRest.setText(highlighter.highlight(userIdSplit.email));
+ mMainUserIdRest.setVisibility(View.VISIBLE);
+ } else {
+ mMainUserIdRest.setVisibility(View.GONE);
+ }
+ }
+
+ { // set edit button and status, specific by key type
+
+ long masterKeyId = cursor.getLong(INDEX_MASTER_KEY_ID);
+ boolean isSecret = cursor.getInt(INDEX_HAS_ANY_SECRET) != 0;
+ boolean isRevoked = cursor.getInt(INDEX_IS_REVOKED) > 0;
+ boolean isExpired = cursor.getInt(INDEX_IS_EXPIRED) != 0;
+ boolean isVerified = cursor.getInt(INDEX_VERIFIED) > 0;
+ // boolean hasDuplicate = cursor.getInt(INDEX_HAS_DUPLICATE_USER_ID) == 1;
+
+ mMasterKeyId = masterKeyId;
+
+ // Note: order is important!
+ if (isRevoked) {
+ KeyFormattingUtils
+ .setStatusImage(context, mStatus, null, State.REVOKED, R.color.bg_gray);
+ mStatus.setVisibility(View.VISIBLE);
+ mSlinger.setVisibility(View.GONE);
+ mMainUserId.setTextColor(context.getResources().getColor(R.color.bg_gray));
+ mMainUserIdRest.setTextColor(context.getResources().getColor(R.color.bg_gray));
+ } else if (isExpired) {
+ KeyFormattingUtils.setStatusImage(context, mStatus, null, State.EXPIRED, R.color.bg_gray);
+ mStatus.setVisibility(View.VISIBLE);
+ mSlinger.setVisibility(View.GONE);
+ mMainUserId.setTextColor(context.getResources().getColor(R.color.bg_gray));
+ mMainUserIdRest.setTextColor(context.getResources().getColor(R.color.bg_gray));
+ } else if (isSecret) {
+ mStatus.setVisibility(View.GONE);
+ if (mSlingerButton.hasOnClickListeners()) {
+ mSlinger.setVisibility(View.VISIBLE);
+ }
+ mMainUserId.setTextColor(context.getResources().getColor(R.color.black));
+ mMainUserIdRest.setTextColor(context.getResources().getColor(R.color.black));
+ } else {
+ // this is a public key - show if it's verified
+ if (isVerified) {
+ KeyFormattingUtils.setStatusImage(context, mStatus, State.VERIFIED);
+ mStatus.setVisibility(View.VISIBLE);
+ } else {
+ KeyFormattingUtils.setStatusImage(context, mStatus, State.UNVERIFIED);
+ mStatus.setVisibility(View.VISIBLE);
+ }
+ mSlinger.setVisibility(View.GONE);
+ mMainUserId.setTextColor(context.getResources().getColor(R.color.black));
+ mMainUserIdRest.setTextColor(context.getResources().getColor(R.color.black));
+ }
+ }
+
+ }
+
+ }
+
+ @Override
+ public View newView(Context context, Cursor cursor, ViewGroup parent) {
+ View view = mInflater.inflate(R.layout.key_list_item, parent, false);
+ KeyItemViewHolder holder = new KeyItemViewHolder(view);
+ view.setTag(holder);
+ holder.mSlingerButton.setColorFilter(context.getResources().getColor(R.color.tertiary_text_light),
+ PorterDuff.Mode.SRC_IN);
+ return view;
+ }
+
+ @Override
+ public void bindView(View view, Context context, Cursor cursor) {
+ Highlighter highlighter = new Highlighter(context, mQuery);
+ KeyItemViewHolder h = (KeyItemViewHolder) view.getTag();
+ h.setData(context, cursor, highlighter);
+ }
+
+ public boolean isSecretAvailable(int id) {
+ if (!mCursor.moveToPosition(id)) {
+ throw new IllegalStateException("couldn't move cursor to position " + id);
+ }
+
+ return mCursor.getInt(INDEX_HAS_ANY_SECRET) != 0;
+ }
+
+ public long getMasterKeyId(int id) {
+ if (!mCursor.moveToPosition(id)) {
+ throw new IllegalStateException("couldn't move cursor to position " + id);
+ }
+
+ return mCursor.getLong(INDEX_MASTER_KEY_ID);
+ }
+
+ @Override
+ public KeyItem getItem(int position) {
+ Cursor c = getCursor();
+ if (c.isClosed() || !c.moveToPosition(position)) {
+ return null;
+ }
+ return new KeyItem(c);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ // prevent a crash on rapid cursor changes
+ if (getCursor().isClosed()) {
+ return 0L;
+ }
+ return super.getItemId(position);
+ }
+
+ public static class KeyItem {
+
+ public final String mUserIdFull;
+ public final KeyRing.UserId mUserId;
+ public final long mKeyId;
+ public final boolean mHasDuplicate;
+ public final Date mCreation;
+ public final String mFingerprint;
+
+ private KeyItem(Cursor cursor) {
+ String userId = cursor.getString(INDEX_USER_ID);
+ mUserId = KeyRing.splitUserId(userId);
+ mUserIdFull = userId;
+ mKeyId = cursor.getLong(INDEX_MASTER_KEY_ID);
+ mHasDuplicate = cursor.getLong(INDEX_HAS_DUPLICATE_USER_ID) > 0;
+ mCreation = new Date(cursor.getLong(INDEX_CREATION) * 1000);
+ mFingerprint = KeyFormattingUtils.convertFingerprintToHex(
+ cursor.getBlob(INDEX_FINGERPRINT));
+ }
+
+ public KeyItem(CanonicalizedPublicKeyRing ring) {
+ CanonicalizedPublicKey key = ring.getPublicKey();
+ String userId = key.getPrimaryUserIdWithFallback();
+ mUserId = KeyRing.splitUserId(userId);
+ mUserIdFull = userId;
+ mKeyId = ring.getMasterKeyId();
+ mHasDuplicate = false;
+ mCreation = key.getCreationTime();
+ mFingerprint = KeyFormattingUtils.convertFingerprintToHex(
+ ring.getFingerprint());
+ }
+
+ public String getReadableName() {
+ if (mUserId.name != null) {
+ return mUserId.name;
+ } else {
+ return mUserId.email;
+ }
+ }
+
+ public boolean hasDuplicate() {
+ return mHasDuplicate;
+ }
+
+ public String getCreationDate(Context context) {
+ Calendar creationCal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
+ creationCal.setTime(mCreation);
+ // convert from UTC to time zone of device
+ creationCal.setTimeZone(TimeZone.getDefault());
+
+ return context.getString(R.string.label_creation) + ": "
+ + DateFormat.getDateFormat(context).format(creationCal.getTime());
+ }
+
+ }
+
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EncryptKeyCompletionView.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EncryptKeyCompletionView.java
index ceace1d26..b2dfb2493 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EncryptKeyCompletionView.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EncryptKeyCompletionView.java
@@ -1,5 +1,6 @@
/*
- * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2014-2015 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2015 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
@@ -17,49 +18,42 @@
package org.sufficientlysecure.keychain.ui.widget;
-import android.app.Activity;
import android.content.Context;
import android.database.Cursor;
-import android.graphics.Bitmap;
import android.graphics.Rect;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.LoaderManager;
+import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
-import android.text.format.DateFormat;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
-import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
-import android.widget.ImageView;
import android.widget.TextView;
-import com.tokenautocomplete.FilteredArrayAdapter;
import com.tokenautocomplete.TokenCompleteTextView;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.pgp.KeyRing;
-import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
-import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables;
-import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
-import org.sufficientlysecure.keychain.util.ContactHelper;
+import org.sufficientlysecure.keychain.ui.adapter.KeyAdapter;
+import org.sufficientlysecure.keychain.ui.adapter.KeyAdapter.KeyItem;
import org.sufficientlysecure.keychain.util.Log;
-import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
-import java.util.Locale;
-import java.util.TimeZone;
-public class EncryptKeyCompletionView extends TokenCompleteTextView {
+public class EncryptKeyCompletionView extends TokenCompleteTextView
+ implements LoaderCallbacks<Cursor> {
+
+ public static final String ARG_QUERY = "query";
+
+ private KeyAdapter mAdapter;
+ private LoaderManager mLoaderManager;
+ private String mPrefix;
+
public EncryptKeyCompletionView(Context context) {
super(context);
initView();
@@ -76,33 +70,31 @@ public class EncryptKeyCompletionView extends TokenCompleteTextView {
}
private void initView() {
- swapCursor(null);
setPrefix(getContext().getString(R.string.label_to) + " ");
+
allowDuplicates(false);
+ mAdapter = new KeyAdapter(getContext(), null, 0);
+ setAdapter(mAdapter);
+ }
+
+ @Override
+ public void setPrefix(String p) {
+ // this one is private in the superclass, but we need it here
+ mPrefix = p;
+ super.setPrefix(p);
}
@Override
protected View getViewForObject(Object object) {
- if (object instanceof EncryptionKey) {
- LayoutInflater l = (LayoutInflater) getContext().getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
+ if (object instanceof KeyItem) {
+ LayoutInflater l = LayoutInflater.from(getContext());
View view = l.inflate(R.layout.recipient_box_entry, null);
- ((TextView) view.findViewById(android.R.id.text1)).setText(((EncryptionKey) object).getPrimary());
- setImageByKey((ImageView) view.findViewById(android.R.id.icon), (EncryptionKey) object);
+ ((TextView) view.findViewById(android.R.id.text1)).setText(((KeyItem) object).getReadableName());
return view;
}
return null;
}
- private void setImageByKey(ImageView view, EncryptionKey key) {
- Bitmap photo = ContactHelper.getCachedPhotoByMasterKeyId(getContext().getContentResolver(), key.getKeyId());
-
- if (photo != null) {
- view.setImageBitmap(photo);
- } else {
- view.setImageResource(R.drawable.ic_generic_man);
- }
- }
-
@Override
protected Object defaultObject(String completionText) {
// TODO: We could try to automagically download the key if it's unknown but a key id
@@ -115,196 +107,72 @@ public class EncryptKeyCompletionView extends TokenCompleteTextView {
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
+
+ mLoaderManager = ((FragmentActivity) getContext()).getSupportLoaderManager();
+
if (getContext() instanceof FragmentActivity) {
- ((FragmentActivity) getContext()).getSupportLoaderManager().initLoader(hashCode(), null, new LoaderManager.LoaderCallbacks<Cursor>() {
- @Override
- public Loader<Cursor> onCreateLoader(int id, Bundle args) {
- // These are the rows that we will retrieve.
- Uri baseUri = KeyRings.buildUnifiedKeyRingsUri();
-
- String[] projection = new String[]{
- KeyRings._ID,
- KeyRings.MASTER_KEY_ID,
- KeyRings.KEY_ID,
- KeyRings.USER_ID,
- KeyRings.FINGERPRINT,
- KeyRings.IS_EXPIRED,
- KeyRings.HAS_ENCRYPT,
- KeyRings.HAS_DUPLICATE_USER_ID,
- KeyRings.CREATION
- };
-
- String where = KeyRings.HAS_ENCRYPT + " NOT NULL AND " + KeyRings.IS_EXPIRED + " = 0 AND "
- + Tables.KEYS + "." + KeyRings.IS_REVOKED + " = 0";
-
- return new CursorLoader(getContext(), baseUri, projection, where, null, null);
- }
-
- @Override
- public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
- swapCursor(data);
- }
-
- @Override
- public void onLoaderReset(Loader<Cursor> loader) {
- swapCursor(null);
- }
- });
+ mLoaderManager.initLoader(hashCode(), null, this);
} else {
Log.e(Constants.TAG, "EncryptKeyCompletionView must be attached to a FragmentActivity, this is " + getContext().getClass());
}
}
@Override
- public void onFocusChanged(boolean hasFocus, int direction, Rect previous) {
- super.onFocusChanged(hasFocus, direction, previous);
- if (hasFocus) {
- ((InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE))
- .showSoftInput(this, InputMethodManager.SHOW_IMPLICIT);
- }
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ mLoaderManager = null;
}
- public void swapCursor(Cursor cursor) {
- if (cursor == null) {
- setAdapter(new EncryptKeyAdapter(Collections.<EncryptionKey>emptyList()));
- return;
- }
- ArrayList<EncryptionKey> keys = new ArrayList<>();
- while (cursor.moveToNext()) {
- try {
- EncryptionKey key = new EncryptionKey(cursor);
- keys.add(key);
- } catch (Exception e) {
- Log.w(Constants.TAG, e);
- return;
- }
- }
- setAdapter(new EncryptKeyAdapter(keys));
- }
-
- public class EncryptionKey {
- private String mUserIdFull;
- private KeyRing.UserId mUserId;
- private long mKeyId;
- private boolean mHasDuplicate;
- private Date mCreation;
- private String mFingerprint;
-
- public EncryptionKey(String userId, long keyId, boolean hasDuplicate, Date creation, String fingerprint) {
- mUserId = KeyRing.splitUserId(userId);
- mUserIdFull = userId;
- mKeyId = keyId;
- mHasDuplicate = hasDuplicate;
- mCreation = creation;
- mFingerprint = fingerprint;
- }
-
- public EncryptionKey(Cursor cursor) {
- this(cursor.getString(cursor.getColumnIndexOrThrow(KeyRings.USER_ID)),
- cursor.getLong(cursor.getColumnIndexOrThrow(KeyRings.KEY_ID)),
- cursor.getLong(cursor.getColumnIndexOrThrow(KeyRings.HAS_DUPLICATE_USER_ID)) > 0,
- new Date(cursor.getLong(cursor.getColumnIndexOrThrow(KeyRings.CREATION)) * 1000),
- KeyFormattingUtils.convertFingerprintToHex(
- cursor.getBlob(cursor.getColumnIndexOrThrow(KeyRings.FINGERPRINT))));
- }
-
- public EncryptionKey(CachedPublicKeyRing ring) throws PgpKeyNotFoundException {
- this(ring.getPrimaryUserId(), ring.extractOrGetMasterKeyId(), false, null,
- KeyFormattingUtils.convertFingerprintToHex(ring.getFingerprint()));
- }
-
- public String getUserId() {
- return mUserIdFull;
- }
-
- public String getFingerprint() {
- return mFingerprint;
- }
-
- public String getPrimary() {
- if (mUserId.name != null) {
- return mUserId.name;
- } else {
- return mUserId.email;
- }
- }
-
- public String getSecondary() {
- if (mUserId.email != null) {
- return mUserId.email;
- } else {
- return getCreationDate();
- }
- }
-
- public String getTertiary() {
- if (mUserId.name != null) {
- return getCreationDate();
- } else {
- return null;
- }
- }
+ @Override
+ public Loader<Cursor> onCreateLoader(int id, Bundle args) {
+ // These are the rows that we will retrieve.
+ Uri baseUri = KeyRings.buildUnifiedKeyRingsUri();
+ String where = KeyRings.HAS_ENCRYPT + " NOT NULL AND " + KeyRings.IS_EXPIRED + " = 0 AND "
+ + Tables.KEYS + "." + KeyRings.IS_REVOKED + " = 0";
- public long getKeyId() {
- return mKeyId;
- }
+ if (args != null && args.containsKey(ARG_QUERY)) {
+ String query = args.getString(ARG_QUERY);
+ mAdapter.setSearchQuery(query);
- public String getCreationDate() {
- if (mHasDuplicate) {
- Calendar creationCal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
- creationCal.setTime(mCreation);
- // convert from UTC to time zone of device
- creationCal.setTimeZone(TimeZone.getDefault());
-
- return getContext().getString(R.string.label_creation) + ": "
- + DateFormat.getDateFormat(getContext()).format(creationCal.getTime());
- } else {
- return null;
- }
- }
+ where += " AND " + KeyRings.USER_ID + " LIKE ?";
- public String getKeyIdHex() {
- return KeyFormattingUtils.beautifyKeyIdWithPrefix(getContext(), mKeyId);
+ return new CursorLoader(getContext(), baseUri, KeyAdapter.PROJECTION, where,
+ new String[] { "%" + query + "%" }, null);
}
- public String getKeyIdHexShort() {
- return KeyFormattingUtils.convertKeyIdToHexShort(mKeyId);
- }
+ mAdapter.setSearchQuery(null);
+ return new CursorLoader(getContext(), baseUri, KeyAdapter.PROJECTION, where, null, null);
- @Override
- public String toString() {
- return Long.toString(mKeyId);
- }
}
- private class EncryptKeyAdapter extends FilteredArrayAdapter<EncryptionKey> {
+ @Override
+ public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
+ mAdapter.swapCursor(data);
+ }
- public EncryptKeyAdapter(List<EncryptionKey> objs) {
- super(EncryptKeyCompletionView.this.getContext(), 0, 0, objs);
- }
+ @Override
+ public void onLoaderReset(Loader<Cursor> loader) {
+ mAdapter.swapCursor(null);
+ }
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- LayoutInflater l = (LayoutInflater) getContext().getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
- View view;
- if (convertView != null) {
- view = convertView;
- } else {
- view = l.inflate(R.layout.recipient_selection_list_entry, null);
- }
- ((TextView) view.findViewById(android.R.id.title)).setText(getItem(position).getPrimary());
- ((TextView) view.findViewById(android.R.id.text1)).setText(getItem(position).getSecondary());
- ((TextView) view.findViewById(android.R.id.text2)).setText(getItem(position).getTertiary());
- setImageByKey((ImageView) view.findViewById(android.R.id.icon), getItem(position));
- return view;
+ @Override
+ public void onFocusChanged(boolean hasFocus, int direction, Rect previous) {
+ super.onFocusChanged(hasFocus, direction, previous);
+ if (hasFocus) {
+ ((InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE))
+ .showSoftInput(this, InputMethodManager.SHOW_IMPLICIT);
}
+ }
- @Override
- protected boolean keepObject(EncryptionKey obj, String mask) {
- String m = mask.toLowerCase(Locale.ENGLISH);
- return obj.getUserId().toLowerCase(Locale.ENGLISH).contains(m) ||
- obj.getKeyIdHex().contains(m) ||
- obj.getKeyIdHexShort().startsWith(m);
- }
+ @Override
+ protected void performFiltering(CharSequence text, int start, int end, int keyCode) {
+ super.performFiltering(text, start, end, keyCode);
+ if (start < mPrefix.length()) {
+ start = mPrefix.length();
+ }
+ Bundle args = new Bundle();
+ args.putString(ARG_QUERY, text.subSequence(start, end).toString());
+ mLoaderManager.restartLoader(hashCode(), args, this);
}
+
}
diff --git a/OpenKeychain/src/main/res/layout/key_list_item.xml b/OpenKeychain/src/main/res/layout/key_list_item.xml
index db0462c6d..fbe5f1326 100644
--- a/OpenKeychain/src/main/res/layout/key_list_item.xml
+++ b/OpenKeychain/src/main/res/layout/key_list_item.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
@@ -69,7 +70,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
- android:src="@drawable/status_signature_revoked_cutout_24dp"
- android:padding="16dp" />
+ android:padding="16dp"
+ tools:src="@drawable/status_signature_revoked_cutout_24dp"
+ />
</LinearLayout>
diff --git a/OpenKeychain/src/main/res/layout/recipient_box_entry.xml b/OpenKeychain/src/main/res/layout/recipient_box_entry.xml
index ab7e5c54f..8857a89af 100644
--- a/OpenKeychain/src/main/res/layout/recipient_box_entry.xml
+++ b/OpenKeychain/src/main/res/layout/recipient_box_entry.xml
@@ -19,5 +19,7 @@
android:layout_marginLeft="12dip"
android:cropToPadding="true"
android:background="#ccc"
- android:scaleType="centerCrop" />
+ android:scaleType="centerCrop"
+ android:src="@drawable/ic_person_grey_24dp" />
+
</LinearLayout> \ No newline at end of file
diff --git a/OpenKeychain/src/main/res/layout/recipient_selection_list_entry.xml b/OpenKeychain/src/main/res/layout/recipient_selection_list_entry.xml
index 57ca9b9d8..a9e86057c 100644
--- a/OpenKeychain/src/main/res/layout/recipient_selection_list_entry.xml
+++ b/OpenKeychain/src/main/res/layout/recipient_selection_list_entry.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="48dip"
@@ -21,7 +22,8 @@
android:layout_height="wrap_content"
android:paddingLeft="8dip"
android:singleLine="true"
- android:ellipsize="end" />
+ android:ellipsize="end"
+ tools:text="Alice" />
<TextView
android:id="@android:id/text1"
@@ -32,7 +34,8 @@
android:paddingLeft="16dip"
android:singleLine="true"
android:ellipsize="end"
- android:layout_marginTop="-4dip" />
+ android:layout_marginTop="-4dip"
+ tools:text="alice@example.com" />
<TextView
android:id="@android:id/text2"
@@ -43,15 +46,18 @@
android:paddingLeft="16dip"
android:singleLine="true"
android:ellipsize="end"
- android:layout_marginTop="-4dip" />
+ android:layout_marginTop="-4dip"
+ tools:text="Creation 12.03.2015" />
+
</LinearLayout>
<ImageView
- android:id="@android:id/icon"
- android:layout_width="56dip"
- android:layout_height="56dip"
- android:layout_marginLeft="12dip"
- android:cropToPadding="true"
- android:background="#ccc"
- android:scaleType="centerCrop" />
+ android:id="@+id/status_icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:padding="16dp"
+ tools:src="@drawable/status_signature_revoked_cutout_24dp"
+ />
+
</LinearLayout> \ No newline at end of file