diff options
Diffstat (limited to 'OpenKeychain/src/main/java')
6 files changed, 210 insertions, 138 deletions
| 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 fc25faecd..0999cc754 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java @@ -112,6 +112,8 @@ public class KeychainContract {          public static final String IS_REVOKED = KeysColumns.IS_REVOKED;          public static final String VERIFIED = CertsColumns.VERIFIED;          public static final String HAS_SECRET = "has_secret"; +        public static final String HAS_ENCRYPT = "has_encrypt"; +        public static final String HAS_SIGN = "has_encrypt";          public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon()                  .appendPath(BASE_KEY_RINGS).build(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java index 78eedf315..012948f63 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java @@ -38,9 +38,11 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.Keys;  import org.sufficientlysecure.keychain.provider.KeychainContract.Certs;  import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;  import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables; +import org.sufficientlysecure.keychain.ui.adapter.SelectKeyCursorAdapter;  import org.sufficientlysecure.keychain.util.Log;  import java.util.Arrays; +import java.util.Date;  import java.util.HashMap;  public class KeychainProvider extends ContentProvider { @@ -264,7 +266,29 @@ public class KeychainProvider extends ContentProvider {                  projectionMap.put(KeyRings.FINGERPRINT, Keys.FINGERPRINT);                  projectionMap.put(KeyRings.USER_ID, UserIds.USER_ID);                  projectionMap.put(KeyRings.VERIFIED, KeyRings.VERIFIED); -                projectionMap.put(KeyRings.HAS_SECRET, "(" + Tables.KEY_RINGS_SECRET + "." + KeyRings.MASTER_KEY_ID + " IS NOT NULL) AS " + KeyRings.HAS_SECRET); +                projectionMap.put(KeyRings.HAS_SECRET, +                    "(EXISTS (SELECT * FROM " + Tables.KEY_RINGS_SECRET +                        + " WHERE " + Tables.KEY_RINGS_SECRET + "." + KeyRingData.MASTER_KEY_ID +                            + " = " + Tables.KEYS + "." + Keys.MASTER_KEY_ID +                        + ")) AS " + KeyRings.HAS_SECRET); +                projectionMap.put(KeyRings.HAS_ENCRYPT, +                    "(EXISTS (SELECT COUNT(*) FROM " + Tables.KEYS + " AS k" +                        +" WHERE k." + Keys.MASTER_KEY_ID +                            + " = " + Tables.KEYS + "." + Keys.MASTER_KEY_ID +                        + " AND k." + Keys.IS_REVOKED + " = 0" +                        + " AND k." + Keys.CAN_ENCRYPT + " = 1" +                        + " AND ( k." + Keys.EXPIRY + " IS NULL OR k." + Keys.EXPIRY +                            + " >= '" + new Date().getTime() / 1000 + "' )" +                        + ")) AS " + KeyRings.HAS_ENCRYPT); +                projectionMap.put(KeyRings.HAS_SIGN, +                        "(EXISTS (SELECT COUNT(*) FROM " + Tables.KEYS + " AS k" +                                +" WHERE k." + Keys.MASTER_KEY_ID +                                + " = " + Tables.KEYS + "." + Keys.MASTER_KEY_ID +                                + " AND k." + Keys.IS_REVOKED + " = 0" +                                + " AND k." + Keys.CAN_SIGN + " = 1" +                                + " AND ( k." + Keys.EXPIRY + " IS NULL OR k." + Keys.EXPIRY +                                + " >= '" + new Date().getTime() / 1000 + "' )" +                                + ")) AS " + KeyRings.HAS_SIGN);                  qb.setProjectionMap(projectionMap);                  qb.setTables( @@ -274,10 +298,6 @@ public class KeychainProvider extends ContentProvider {                                  + " = "                                      + Tables.USER_IDS + "." + UserIds.MASTER_KEY_ID                              + " AND " + Tables.USER_IDS + "." + UserIds.RANK + " = 0" -                        + ") LEFT JOIN " + Tables.KEY_RINGS_SECRET + " ON (" -                            + Tables.KEYS + "." + Keys.MASTER_KEY_ID -                                + " = " -                            + Tables.KEY_RINGS_SECRET + "." + KeyRings.MASTER_KEY_ID                          + ") LEFT JOIN " + Tables.CERTS + " ON ("                              + Tables.KEYS + "." + Keys.MASTER_KEY_ID                                  + " = " @@ -345,9 +365,7 @@ public class KeychainProvider extends ContentProvider {                  }                  if (TextUtils.isEmpty(sortOrder)) { -                    sortOrder = -                            Tables.KEY_RINGS_SECRET + "." + KeyRings.MASTER_KEY_ID + " IS NULL ASC, " -                                    + Tables.USER_IDS + "." + UserIds.USER_ID + " ASC"; +                    sortOrder = Tables.USER_IDS + "." + UserIds.USER_ID + " ASC";                  }                  // uri to watch is all /key_rings/ 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 63f4ec7c4..0371e664f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java @@ -265,6 +265,10 @@ public class KeyListFragment extends Fragment      static final int INDEX_VERIFIED = 5;      static final int INDEX_HAS_SECRET = 6; +    static final String ORDER = // IN THE COURT +            KeyRings.HAS_SECRET + " DESC, " + KeyRings.USER_ID + " ASC"; + +      @Override      public Loader<Cursor> onCreateLoader(int id, Bundle args) {          // This is called when a new Loader needs to be created. This @@ -276,9 +280,10 @@ public class KeyListFragment extends Fragment              where = KeyRings.USER_ID + " LIKE ?";              whereArgs = new String[]{"%" + mCurQuery + "%"};          } +          // 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, null); +        return new CursorLoader(getActivity(), baseUri, PROJECTION, where, whereArgs, ORDER);      }      @Override diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyFragment.java index 52b400481..dca960e27 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyFragment.java @@ -40,17 +40,12 @@ import android.widget.ListView;  import android.widget.ProgressBar;  import android.widget.TextView; -import org.sufficientlysecure.keychain.Id;  import org.sufficientlysecure.keychain.R;  import org.sufficientlysecure.keychain.compatibility.ListFragmentWorkaround;  import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; -import org.sufficientlysecure.keychain.provider.KeychainContract.Keys; -import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds; -import org.sufficientlysecure.keychain.provider.KeychainDatabase;  import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables;  import org.sufficientlysecure.keychain.ui.adapter.SelectKeyCursorAdapter; -import java.util.Date;  import java.util.Vector;  public class SelectPublicKeyFragment extends ListFragmentWorkaround implements TextWatcher, @@ -180,7 +175,7 @@ public class SelectPublicKeyFragment extends ListFragmentWorkaround implements T          mSearchView.addTextChangedListener(this); -        mAdapter = new SelectKeyCursorAdapter(getActivity(), null, 0, getListView(), Id.type.public_key); +        mAdapter = new SelectPublicKeyCursorAdapter(getActivity(), null, 0, getListView());          setListAdapter(mAdapter); @@ -258,25 +253,14 @@ public class SelectPublicKeyFragment extends ListFragmentWorkaround implements T          Uri baseUri = KeyRings.buildUnifiedKeyRingsUri();          // These are the rows that we will retrieve. -        long now = new Date().getTime() / 1000;          String[] projection = new String[]{                  KeyRings._ID,                  KeyRings.MASTER_KEY_ID, -                UserIds.USER_ID, -                "(SELECT COUNT(*) FROM " + Tables.KEYS + " AS k" -                        +" WHERE k." + Keys.MASTER_KEY_ID + " = " -                            + KeychainDatabase.Tables.KEYS + "." + Keys.MASTER_KEY_ID -                            + " AND k." + Keys.IS_REVOKED + " = '0'" -                            + " AND k." + Keys.CAN_ENCRYPT + " = '1'" -                        + ") AS " + SelectKeyCursorAdapter.PROJECTION_ROW_AVAILABLE, -                "(SELECT COUNT(*) FROM " + Tables.KEYS + " AS k" -                        + " WHERE k." + Keys.MASTER_KEY_ID + " = " -                            + KeychainDatabase.Tables.KEYS + "." + Keys.MASTER_KEY_ID -                            + " AND k." + Keys.IS_REVOKED + " = '0'" -                            + " AND k." + Keys.CAN_ENCRYPT + " = '1'" -                            + " AND k." + Keys.CREATION + " <= '" + now + "'" -                            + " AND ( k." + Keys.EXPIRY + " IS NULL OR k." + Keys.EXPIRY + " >= '" + now + "' )" -                        + ") AS " + SelectKeyCursorAdapter.PROJECTION_ROW_VALID, }; +                KeyRings.USER_ID, +                KeyRings.EXPIRY, +                KeyRings.IS_REVOKED, +                KeyRings.HAS_ENCRYPT, +        };          String inMasterKeyList = null;          if (mSelectedMasterKeyIds != null && mSelectedMasterKeyIds.length > 0) { @@ -290,7 +274,7 @@ public class SelectPublicKeyFragment extends ListFragmentWorkaround implements T              inMasterKeyList += ")";          } -        String orderBy = UserIds.USER_ID + " ASC"; +        String orderBy = KeyRings.USER_ID + " ASC";          if (inMasterKeyList != null) {              // sort by selected master keys              orderBy = inMasterKeyList + " DESC, " + orderBy; @@ -298,7 +282,7 @@ public class SelectPublicKeyFragment extends ListFragmentWorkaround implements T          String where = null;          String whereArgs[] = null;          if (mCurQuery != null) { -            where = UserIds.USER_ID + " LIKE ?"; +            where = KeyRings.USER_ID + " LIKE ?";              whereArgs = new String[]{"%" + mCurQuery + "%"};          } @@ -348,4 +332,47 @@ public class SelectPublicKeyFragment extends ListFragmentWorkaround implements T          mCurQuery = !TextUtils.isEmpty(editable.toString()) ? editable.toString() : null;          getLoaderManager().restartLoader(0, null, this);      } + +    private class SelectPublicKeyCursorAdapter extends SelectKeyCursorAdapter { + +        private int mIndexHasEncrypt; + +        public SelectPublicKeyCursorAdapter(Context context, Cursor c, int flags, ListView listView) { +            super(context, c, flags, listView); +        } + +        @Override +        protected void initIndex(Cursor cursor) { +            super.initIndex(cursor); +            if (cursor != null) { +                mIndexHasEncrypt = cursor.getColumnIndexOrThrow(KeyRings.HAS_ENCRYPT); +            } +        } + +        @Override +        public void bindView(View view, Context context, Cursor cursor) { +            super.bindView(view, context, cursor); +            ViewHolderItem h = (SelectKeyCursorAdapter.ViewHolderItem) view.getTag(); + +            // We care about the checkbox +            h.selected.setVisibility(View.VISIBLE); +            // the getListView works because this is not a static subclass! +            h.selected.setChecked(getListView().isItemChecked(cursor.getPosition())); + +            boolean enabled = false; +            if((Boolean) h.status.getTag()) { +                // Check if key is viable for our purposes +                if (cursor.getInt(mIndexHasEncrypt) == 0) { +                    h.status.setText(R.string.no_key); +                } else { +                    h.status.setText(R.string.can_encrypt); +                    enabled = true; +                } +            } + +            h.setEnabled(enabled); +        } + +    } +  } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectSecretKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectSecretKeyFragment.java index 08ab5af77..47f4f52d7 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectSecretKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectSecretKeyFragment.java @@ -18,6 +18,7 @@  package org.sufficientlysecure.keychain.ui; +import android.content.Context;  import android.database.Cursor;  import android.net.Uri;  import android.os.Bundle; @@ -30,23 +31,15 @@ import android.widget.AdapterView;  import android.widget.AdapterView.OnItemClickListener;  import android.widget.ListView; -import org.sufficientlysecure.keychain.Id;  import org.sufficientlysecure.keychain.R;  import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; -import org.sufficientlysecure.keychain.provider.KeychainContract.Keys; -import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds; -import org.sufficientlysecure.keychain.provider.KeychainDatabase; -import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables;  import org.sufficientlysecure.keychain.ui.adapter.SelectKeyCursorAdapter; -import java.util.Date; -  public class SelectSecretKeyFragment extends ListFragment implements          LoaderManager.LoaderCallbacks<Cursor> {      private SelectSecretKeyActivity mActivity;      private SelectKeyCursorAdapter mAdapter; -    private ListView mListView;      private boolean mFilterCertify; @@ -80,9 +73,9 @@ public class SelectSecretKeyFragment extends ListFragment implements          super.onActivityCreated(savedInstanceState);          mActivity = (SelectSecretKeyActivity) getActivity(); -        mListView = getListView(); -        mListView.setOnItemClickListener(new OnItemClickListener() { +        ListView listView = getListView(); +        listView.setOnItemClickListener(new OnItemClickListener() {              @Override              public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {                  long masterKeyId = mAdapter.getMasterKeyId(position); @@ -97,7 +90,7 @@ public class SelectSecretKeyFragment extends ListFragment implements          // application this would come from a resource.          setEmptyText(getString(R.string.list_empty)); -        mAdapter = new SelectKeyCursorAdapter(mActivity, null, 0, mListView, Id.type.secret_key); +        mAdapter = new SelectSecretKeyCursorAdapter(mActivity, null, 0, listView);          setListAdapter(mAdapter); @@ -116,41 +109,22 @@ public class SelectSecretKeyFragment extends ListFragment implements          Uri baseUri = KeyRings.buildUnifiedKeyRingsUri();          // These are the rows that we will retrieve. -        long now = new Date().getTime() / 1000;          String[] projection = new String[]{                  KeyRings._ID,                  KeyRings.MASTER_KEY_ID, -                UserIds.USER_ID, -                "(SELECT COUNT(*) FROM " + Tables.KEYS + " AS k" -                    + " WHERE k." + Keys.MASTER_KEY_ID + " = " -                        + KeychainDatabase.Tables.KEYS + "." + KeyRings.MASTER_KEY_ID -                            + " AND k." + Keys.CAN_CERTIFY + " = '1'" -                    + ") AS cert", -                "(SELECT COUNT(*) FROM " + Tables.KEYS + " AS k" -                    +" WHERE k." + Keys.MASTER_KEY_ID + " = " -                        + KeychainDatabase.Tables.KEYS + "." + Keys.MASTER_KEY_ID -                            + " AND k." + Keys.IS_REVOKED + " = '0'" -                            + " AND k." + Keys.CAN_SIGN + " = '1'" -                    + ") AS " + SelectKeyCursorAdapter.PROJECTION_ROW_AVAILABLE, -                "(SELECT COUNT(*) FROM " + Tables.KEYS + " AS k" -                    + " WHERE k." + Keys.MASTER_KEY_ID + " = " -                        + KeychainDatabase.Tables.KEYS + "." + Keys.MASTER_KEY_ID -                            + " AND k." + Keys.IS_REVOKED + " = '0'" -                            + " AND k." + Keys.CAN_SIGN + " = '1'" -                            + " AND k." + Keys.CREATION + " <= '" + now + "'" -                            + " AND ( k." + Keys.EXPIRY + " IS NULL OR k." + Keys.EXPIRY + " >= '" + now + "' )" -                    + ") AS " + SelectKeyCursorAdapter.PROJECTION_ROW_VALID, }; - -        String orderBy = UserIds.USER_ID + " ASC"; - -        String where = Tables.KEY_RINGS_SECRET + "." + KeyRings.MASTER_KEY_ID + " IS NOT NULL"; -        if (mFilterCertify) { -            where += " AND (cert > 0)"; -        } +                KeyRings.USER_ID, +                KeyRings.EXPIRY, +                KeyRings.IS_REVOKED, +                KeyRings.CAN_CERTIFY, +                KeyRings.HAS_SIGN, +                KeyRings.HAS_SECRET +        }; + +        String where = KeyRings.HAS_SECRET + " = 1";          // 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, null, orderBy); +        return new CursorLoader(getActivity(), baseUri, projection, where, null, null);      }      @Override @@ -174,4 +148,57 @@ public class SelectSecretKeyFragment extends ListFragment implements          // longer using it.          mAdapter.swapCursor(null);      } -} + +    private class SelectSecretKeyCursorAdapter extends SelectKeyCursorAdapter { + +        private int mIndexHasSign, mIndexCanCertify; + +        public SelectSecretKeyCursorAdapter(Context context, Cursor c, int flags, ListView listView) { +            super(context, c, flags, listView); +        } + +        @Override +        protected void initIndex(Cursor cursor) { +            super.initIndex(cursor); +            if (cursor != null) { +                mIndexCanCertify = cursor.getColumnIndexOrThrow(KeyRings.CAN_CERTIFY); +                mIndexHasSign = cursor.getColumnIndexOrThrow(KeyRings.HAS_SIGN); +            } +        } + +        @Override +        public void bindView(View view, Context context, Cursor cursor) { +            super.bindView(view, context, cursor); +            ViewHolderItem h = (SelectKeyCursorAdapter.ViewHolderItem) view.getTag(); + +            // We don't care about the checkbox +            h.selected.setVisibility(View.GONE); + +            // Special from superclass: Te +            boolean enabled = false; +            if((Boolean) h.status.getTag()) { +                // Check if key is viable for our purposes (certify or sign) +                if(mFilterCertify) { +                    if (cursor.getInt(mIndexCanCertify) == 0) { +                        h.status.setText(R.string.can_certify_not); +                    } else { +                        h.status.setText(R.string.can_certify); +                        enabled = true; +                    } +                } else { +                    if (cursor.getInt(mIndexHasSign) == 0) { +                        h.status.setText(R.string.no_key); +                    } else { +                        h.status.setText(R.string.can_sign); +                        enabled = true; +                    } +                } +            } +            h.setEnabled(enabled); +            // refresh this, too, for use in the ItemClickListener above +            h.status.setTag(enabled); +        } + +    } + +}
\ No newline at end of file diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SelectKeyCursorAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SelectKeyCursorAdapter.java index d7f8c8e7a..0c2f7add2 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SelectKeyCursorAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SelectKeyCursorAdapter.java @@ -26,35 +26,25 @@ import android.widget.CheckBox;  import android.widget.ListView;  import android.widget.TextView; -import org.sufficientlysecure.keychain.Id;  import org.sufficientlysecure.keychain.R;  import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;  import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; -import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds; +import java.util.Date; -public class SelectKeyCursorAdapter extends HighlightQueryCursorAdapter { -    protected int mKeyType; +/** + * Yes this class is abstract! + */ +abstract public class SelectKeyCursorAdapter extends HighlightQueryCursorAdapter {      private LayoutInflater mInflater; -    private ListView mListView; - -    private int mIndexUserId; -    private int mIndexMasterKeyId; -    private int mIndexProjectionValid; -    private int mIndexProjectionAvailable; -    public static final String PROJECTION_ROW_AVAILABLE = "available"; -    public static final String PROJECTION_ROW_VALID = "valid"; +    protected int mIndexUserId, mIndexMasterKeyId, mIndexRevoked, mIndexExpiry; -    public SelectKeyCursorAdapter(Context context, Cursor c, int flags, ListView listView, -                                  int keyType) { +    public SelectKeyCursorAdapter(Context context, Cursor c, int flags, ListView listView) {          super(context, c, flags); -          mInflater = LayoutInflater.from(context); -        mListView = listView; -        mKeyType = keyType;          initIndex(c);      } @@ -71,12 +61,12 @@ public class SelectKeyCursorAdapter extends HighlightQueryCursorAdapter {       *       * @param cursor       */ -    private void initIndex(Cursor cursor) { +    protected void initIndex(Cursor cursor) {          if (cursor != null) { -            mIndexUserId = cursor.getColumnIndexOrThrow(UserIds.USER_ID); +            mIndexUserId = cursor.getColumnIndexOrThrow(KeyRings.USER_ID);              mIndexMasterKeyId = cursor.getColumnIndexOrThrow(KeyRings.MASTER_KEY_ID); -            mIndexProjectionValid = cursor.getColumnIndexOrThrow(PROJECTION_ROW_VALID); -            mIndexProjectionAvailable = cursor.getColumnIndexOrThrow(PROJECTION_ROW_AVAILABLE); +            mIndexExpiry= cursor.getColumnIndexOrThrow(KeyRings.EXPIRY); +            mIndexRevoked= cursor.getColumnIndexOrThrow(KeyRings.IS_REVOKED);          }      } @@ -90,70 +80,73 @@ public class SelectKeyCursorAdapter extends HighlightQueryCursorAdapter {          return mCursor.getLong(mIndexMasterKeyId);      } +    public static class ViewHolderItem { +        public View view; +        public TextView mainUserId, mainUserIdRest, keyId, status; +        public CheckBox selected; + +        public void setEnabled(boolean enabled) { +            view.setEnabled(enabled); +            selected.setEnabled(enabled); +            mainUserId.setEnabled(enabled); +            mainUserIdRest.setEnabled(enabled); +            keyId.setEnabled(enabled); +            status.setEnabled(enabled); + +            // Sorta special: We set an item as clickable to disable it in the ListView. This works +            // because the list item will handle the clicks itself (which is a nop) +            view.setClickable(!enabled); +        } +    } +      @Override      public void bindView(View view, Context context, Cursor cursor) { -        TextView mainUserId = (TextView) view.findViewById(R.id.mainUserId); -        TextView mainUserIdRest = (TextView) view.findViewById(R.id.mainUserIdRest); -        TextView keyId = (TextView) view.findViewById(R.id.keyId); -        TextView status = (TextView) view.findViewById(R.id.status); +        ViewHolderItem h = (ViewHolderItem) view.getTag();          String userId = cursor.getString(mIndexUserId);          String[] userIdSplit = PgpKeyHelper.splitUserId(userId);          if (userIdSplit[0] != null) { -            mainUserId.setText(highlightSearchQuery(userIdSplit[0])); +            h.mainUserId.setText(highlightSearchQuery(userIdSplit[0]));          } else { -            mainUserId.setText(R.string.user_id_no_name); +            h.mainUserId.setText(R.string.user_id_no_name);          }          if (userIdSplit[1] != null) { -            mainUserIdRest.setText(highlightSearchQuery(userIdSplit[1])); +            h.mainUserIdRest.setText(highlightSearchQuery(userIdSplit[1]));          } else { -            mainUserIdRest.setText(""); +            h.mainUserIdRest.setText("");          }          long masterKeyId = cursor.getLong(mIndexMasterKeyId); -        keyId.setText(PgpKeyHelper.convertKeyIdToHexShort(masterKeyId)); - -        boolean valid = cursor.getInt(mIndexProjectionValid) > 0; -        if (valid) { -            if (mKeyType == Id.type.public_key) { -                status.setText(R.string.can_encrypt); -            } else { -                status.setText(R.string.can_sign); -            } +        h.keyId.setText(PgpKeyHelper.convertKeyIdToHexShort(masterKeyId)); + +        boolean enabled = true; +        if(cursor.getInt(mIndexRevoked) != 0) { +            h.status.setText(R.string.revoked); +            enabled = false; +        } else if (!cursor.isNull(mIndexExpiry) +                && new Date(cursor.getLong(mIndexExpiry) * 1000).before(new Date())) { +            h.status.setText(R.string.expired); +            enabled = false;          } else { -            if (cursor.getInt(mIndexProjectionAvailable) > 0) { -                // has some CAN_ENCRYPT keys, but col(ROW_VALID) = 0, so must be revoked or -                // expired -                status.setText(R.string.expired); -            } else { -                status.setText(R.string.no_key); -            } +            h.status.setText("");          } -        CheckBox selected = (CheckBox) view.findViewById(R.id.selected); -        if (mKeyType == Id.type.public_key) { -            selected.setVisibility(View.VISIBLE); - -            if (!valid) { -                mListView.setItemChecked(cursor.getPosition(), false); -            } - -            selected.setChecked(mListView.isItemChecked(cursor.getPosition())); -            selected.setEnabled(valid); -        } else { -            selected.setVisibility(View.GONE); -        } +        h.status.setTag(enabled); -        view.setEnabled(valid); -        mainUserId.setEnabled(valid); -        mainUserIdRest.setEnabled(valid); -        keyId.setEnabled(valid); -        status.setEnabled(valid);      }      @Override      public View newView(Context context, Cursor cursor, ViewGroup parent) { -        return mInflater.inflate(R.layout.select_key_item, null); +        View view = mInflater.inflate(R.layout.select_key_item, null); +        ViewHolderItem holder = new ViewHolderItem(); +        holder.view = view; +        holder.mainUserId = (TextView) view.findViewById(R.id.mainUserId); +        holder.mainUserIdRest = (TextView) view.findViewById(R.id.mainUserIdRest); +        holder.keyId = (TextView) view.findViewById(R.id.keyId); +        holder.status = (TextView) view.findViewById(R.id.status); +        holder.selected = (CheckBox) view.findViewById(R.id.selected); +        view.setTag(holder); +        return view;      }  } | 
