Select*KeyFragment rewrites

- moved all specific Public/Secret logic from the Adapter class into
  inner subclasses in the Fragments
- more versatile status display ("revoked", "expired", "can certify"...)
- applied view holder pattern
- query logic, including subqueries, moved into provider classes

Closes #375
This commit is contained in:
Vincent Breitmoser 2014-04-10 18:40:32 +02:00
parent ce6a4041fd
commit 593d6ad3f7
7 changed files with 211 additions and 137 deletions

View File

@ -112,6 +112,8 @@ public class KeychainContract {
public static final String IS_REVOKED = KeysColumns.IS_REVOKED; public static final String IS_REVOKED = KeysColumns.IS_REVOKED;
public static final String VERIFIED = CertsColumns.VERIFIED; public static final String VERIFIED = CertsColumns.VERIFIED;
public static final String HAS_SECRET = "has_secret"; 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() public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon()
.appendPath(BASE_KEY_RINGS).build(); .appendPath(BASE_KEY_RINGS).build();

View File

@ -38,9 +38,11 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.Keys;
import org.sufficientlysecure.keychain.provider.KeychainContract.Certs; import org.sufficientlysecure.keychain.provider.KeychainContract.Certs;
import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds; import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables; import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables;
import org.sufficientlysecure.keychain.ui.adapter.SelectKeyCursorAdapter;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
import java.util.Arrays; import java.util.Arrays;
import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
public class KeychainProvider extends ContentProvider { public class KeychainProvider extends ContentProvider {
@ -264,7 +266,29 @@ public class KeychainProvider extends ContentProvider {
projectionMap.put(KeyRings.FINGERPRINT, Keys.FINGERPRINT); projectionMap.put(KeyRings.FINGERPRINT, Keys.FINGERPRINT);
projectionMap.put(KeyRings.USER_ID, UserIds.USER_ID); projectionMap.put(KeyRings.USER_ID, UserIds.USER_ID);
projectionMap.put(KeyRings.VERIFIED, KeyRings.VERIFIED); 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.setProjectionMap(projectionMap);
qb.setTables( qb.setTables(
@ -274,10 +298,6 @@ public class KeychainProvider extends ContentProvider {
+ " = " + " = "
+ Tables.USER_IDS + "." + UserIds.MASTER_KEY_ID + Tables.USER_IDS + "." + UserIds.MASTER_KEY_ID
+ " AND " + Tables.USER_IDS + "." + UserIds.RANK + " = 0" + " 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 (" + ") LEFT JOIN " + Tables.CERTS + " ON ("
+ Tables.KEYS + "." + Keys.MASTER_KEY_ID + Tables.KEYS + "." + Keys.MASTER_KEY_ID
+ " = " + " = "
@ -345,9 +365,7 @@ public class KeychainProvider extends ContentProvider {
} }
if (TextUtils.isEmpty(sortOrder)) { if (TextUtils.isEmpty(sortOrder)) {
sortOrder = sortOrder = Tables.USER_IDS + "." + UserIds.USER_ID + " ASC";
Tables.KEY_RINGS_SECRET + "." + KeyRings.MASTER_KEY_ID + " IS NULL ASC, "
+ Tables.USER_IDS + "." + UserIds.USER_ID + " ASC";
} }
// uri to watch is all /key_rings/ // uri to watch is all /key_rings/

View File

@ -265,6 +265,10 @@ public class KeyListFragment extends Fragment
static final int INDEX_VERIFIED = 5; static final int INDEX_VERIFIED = 5;
static final int INDEX_HAS_SECRET = 6; static final int INDEX_HAS_SECRET = 6;
static final String ORDER = // IN THE COURT
KeyRings.HAS_SECRET + " DESC, " + KeyRings.USER_ID + " ASC";
@Override @Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) { public Loader<Cursor> onCreateLoader(int id, Bundle args) {
// This is called when a new Loader needs to be created. This // 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 ?"; where = KeyRings.USER_ID + " LIKE ?";
whereArgs = new String[]{"%" + mCurQuery + "%"}; whereArgs = new String[]{"%" + mCurQuery + "%"};
} }
// Now create and return a CursorLoader that will take care of // Now create and return a CursorLoader that will take care of
// creating a Cursor for the data being displayed. // 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 @Override

View File

@ -40,17 +40,12 @@ import android.widget.ListView;
import android.widget.ProgressBar; import android.widget.ProgressBar;
import android.widget.TextView; import android.widget.TextView;
import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.compatibility.ListFragmentWorkaround; import org.sufficientlysecure.keychain.compatibility.ListFragmentWorkaround;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; 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.provider.KeychainDatabase.Tables;
import org.sufficientlysecure.keychain.ui.adapter.SelectKeyCursorAdapter; import org.sufficientlysecure.keychain.ui.adapter.SelectKeyCursorAdapter;
import java.util.Date;
import java.util.Vector; import java.util.Vector;
public class SelectPublicKeyFragment extends ListFragmentWorkaround implements TextWatcher, public class SelectPublicKeyFragment extends ListFragmentWorkaround implements TextWatcher,
@ -180,7 +175,7 @@ public class SelectPublicKeyFragment extends ListFragmentWorkaround implements T
mSearchView.addTextChangedListener(this); mSearchView.addTextChangedListener(this);
mAdapter = new SelectKeyCursorAdapter(getActivity(), null, 0, getListView(), Id.type.public_key); mAdapter = new SelectPublicKeyCursorAdapter(getActivity(), null, 0, getListView());
setListAdapter(mAdapter); setListAdapter(mAdapter);
@ -258,25 +253,14 @@ public class SelectPublicKeyFragment extends ListFragmentWorkaround implements T
Uri baseUri = KeyRings.buildUnifiedKeyRingsUri(); Uri baseUri = KeyRings.buildUnifiedKeyRingsUri();
// These are the rows that we will retrieve. // These are the rows that we will retrieve.
long now = new Date().getTime() / 1000;
String[] projection = new String[]{ String[] projection = new String[]{
KeyRings._ID, KeyRings._ID,
KeyRings.MASTER_KEY_ID, KeyRings.MASTER_KEY_ID,
UserIds.USER_ID, KeyRings.USER_ID,
"(SELECT COUNT(*) FROM " + Tables.KEYS + " AS k" KeyRings.EXPIRY,
+" WHERE k." + Keys.MASTER_KEY_ID + " = " KeyRings.IS_REVOKED,
+ KeychainDatabase.Tables.KEYS + "." + Keys.MASTER_KEY_ID KeyRings.HAS_ENCRYPT,
+ " 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, };
String inMasterKeyList = null; String inMasterKeyList = null;
if (mSelectedMasterKeyIds != null && mSelectedMasterKeyIds.length > 0) { if (mSelectedMasterKeyIds != null && mSelectedMasterKeyIds.length > 0) {
@ -290,7 +274,7 @@ public class SelectPublicKeyFragment extends ListFragmentWorkaround implements T
inMasterKeyList += ")"; inMasterKeyList += ")";
} }
String orderBy = UserIds.USER_ID + " ASC"; String orderBy = KeyRings.USER_ID + " ASC";
if (inMasterKeyList != null) { if (inMasterKeyList != null) {
// sort by selected master keys // sort by selected master keys
orderBy = inMasterKeyList + " DESC, " + orderBy; orderBy = inMasterKeyList + " DESC, " + orderBy;
@ -298,7 +282,7 @@ public class SelectPublicKeyFragment extends ListFragmentWorkaround implements T
String where = null; String where = null;
String whereArgs[] = null; String whereArgs[] = null;
if (mCurQuery != null) { if (mCurQuery != null) {
where = UserIds.USER_ID + " LIKE ?"; where = KeyRings.USER_ID + " LIKE ?";
whereArgs = new String[]{"%" + mCurQuery + "%"}; whereArgs = new String[]{"%" + mCurQuery + "%"};
} }
@ -348,4 +332,47 @@ public class SelectPublicKeyFragment extends ListFragmentWorkaround implements T
mCurQuery = !TextUtils.isEmpty(editable.toString()) ? editable.toString() : null; mCurQuery = !TextUtils.isEmpty(editable.toString()) ? editable.toString() : null;
getLoaderManager().restartLoader(0, null, this); 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);
}
}
} }

View File

@ -18,6 +18,7 @@
package org.sufficientlysecure.keychain.ui; package org.sufficientlysecure.keychain.ui;
import android.content.Context;
import android.database.Cursor; import android.database.Cursor;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
@ -30,23 +31,15 @@ import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener; import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView; import android.widget.ListView;
import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; 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 org.sufficientlysecure.keychain.ui.adapter.SelectKeyCursorAdapter;
import java.util.Date;
public class SelectSecretKeyFragment extends ListFragment implements public class SelectSecretKeyFragment extends ListFragment implements
LoaderManager.LoaderCallbacks<Cursor> { LoaderManager.LoaderCallbacks<Cursor> {
private SelectSecretKeyActivity mActivity; private SelectSecretKeyActivity mActivity;
private SelectKeyCursorAdapter mAdapter; private SelectKeyCursorAdapter mAdapter;
private ListView mListView;
private boolean mFilterCertify; private boolean mFilterCertify;
@ -80,9 +73,9 @@ public class SelectSecretKeyFragment extends ListFragment implements
super.onActivityCreated(savedInstanceState); super.onActivityCreated(savedInstanceState);
mActivity = (SelectSecretKeyActivity) getActivity(); mActivity = (SelectSecretKeyActivity) getActivity();
mListView = getListView();
mListView.setOnItemClickListener(new OnItemClickListener() { ListView listView = getListView();
listView.setOnItemClickListener(new OnItemClickListener() {
@Override @Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) { public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
long masterKeyId = mAdapter.getMasterKeyId(position); long masterKeyId = mAdapter.getMasterKeyId(position);
@ -97,7 +90,7 @@ public class SelectSecretKeyFragment extends ListFragment implements
// application this would come from a resource. // application this would come from a resource.
setEmptyText(getString(R.string.list_empty)); 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); setListAdapter(mAdapter);
@ -116,41 +109,22 @@ public class SelectSecretKeyFragment extends ListFragment implements
Uri baseUri = KeyRings.buildUnifiedKeyRingsUri(); Uri baseUri = KeyRings.buildUnifiedKeyRingsUri();
// These are the rows that we will retrieve. // These are the rows that we will retrieve.
long now = new Date().getTime() / 1000;
String[] projection = new String[]{ String[] projection = new String[]{
KeyRings._ID, KeyRings._ID,
KeyRings.MASTER_KEY_ID, KeyRings.MASTER_KEY_ID,
UserIds.USER_ID, KeyRings.USER_ID,
"(SELECT COUNT(*) FROM " + Tables.KEYS + " AS k" KeyRings.EXPIRY,
+ " WHERE k." + Keys.MASTER_KEY_ID + " = " KeyRings.IS_REVOKED,
+ KeychainDatabase.Tables.KEYS + "." + KeyRings.MASTER_KEY_ID KeyRings.CAN_CERTIFY,
+ " AND k." + Keys.CAN_CERTIFY + " = '1'" KeyRings.HAS_SIGN,
+ ") AS cert", KeyRings.HAS_SECRET
"(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 = KeyRings.HAS_SECRET + " = 1";
String where = Tables.KEY_RINGS_SECRET + "." + KeyRings.MASTER_KEY_ID + " IS NOT NULL";
if (mFilterCertify) {
where += " AND (cert > 0)";
}
// Now create and return a CursorLoader that will take care of // Now create and return a CursorLoader that will take care of
// creating a Cursor for the data being displayed. // 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 @Override
@ -174,4 +148,57 @@ public class SelectSecretKeyFragment extends ListFragment implements
// longer using it. // longer using it.
mAdapter.swapCursor(null); 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);
}
}
} }

View File

@ -26,35 +26,25 @@ import android.widget.CheckBox;
import android.widget.ListView; import android.widget.ListView;
import android.widget.TextView; import android.widget.TextView;
import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds;
import java.util.Date;
public class SelectKeyCursorAdapter extends HighlightQueryCursorAdapter { /**
* Yes this class is abstract!
protected int mKeyType; */
abstract public class SelectKeyCursorAdapter extends HighlightQueryCursorAdapter {
private LayoutInflater mInflater; private LayoutInflater mInflater;
private ListView mListView;
private int mIndexUserId; protected int mIndexUserId, mIndexMasterKeyId, mIndexRevoked, mIndexExpiry;
private int mIndexMasterKeyId;
private int mIndexProjectionValid;
private int mIndexProjectionAvailable;
public static final String PROJECTION_ROW_AVAILABLE = "available"; public SelectKeyCursorAdapter(Context context, Cursor c, int flags, ListView listView) {
public static final String PROJECTION_ROW_VALID = "valid";
public SelectKeyCursorAdapter(Context context, Cursor c, int flags, ListView listView,
int keyType) {
super(context, c, flags); super(context, c, flags);
mInflater = LayoutInflater.from(context); mInflater = LayoutInflater.from(context);
mListView = listView;
mKeyType = keyType;
initIndex(c); initIndex(c);
} }
@ -71,12 +61,12 @@ public class SelectKeyCursorAdapter extends HighlightQueryCursorAdapter {
* *
* @param cursor * @param cursor
*/ */
private void initIndex(Cursor cursor) { protected void initIndex(Cursor cursor) {
if (cursor != null) { if (cursor != null) {
mIndexUserId = cursor.getColumnIndexOrThrow(UserIds.USER_ID); mIndexUserId = cursor.getColumnIndexOrThrow(KeyRings.USER_ID);
mIndexMasterKeyId = cursor.getColumnIndexOrThrow(KeyRings.MASTER_KEY_ID); mIndexMasterKeyId = cursor.getColumnIndexOrThrow(KeyRings.MASTER_KEY_ID);
mIndexProjectionValid = cursor.getColumnIndexOrThrow(PROJECTION_ROW_VALID); mIndexExpiry= cursor.getColumnIndexOrThrow(KeyRings.EXPIRY);
mIndexProjectionAvailable = cursor.getColumnIndexOrThrow(PROJECTION_ROW_AVAILABLE); mIndexRevoked= cursor.getColumnIndexOrThrow(KeyRings.IS_REVOKED);
} }
} }
@ -90,70 +80,73 @@ public class SelectKeyCursorAdapter extends HighlightQueryCursorAdapter {
return mCursor.getLong(mIndexMasterKeyId); 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 @Override
public void bindView(View view, Context context, Cursor cursor) { public void bindView(View view, Context context, Cursor cursor) {
TextView mainUserId = (TextView) view.findViewById(R.id.mainUserId); ViewHolderItem h = (ViewHolderItem) view.getTag();
TextView mainUserIdRest = (TextView) view.findViewById(R.id.mainUserIdRest);
TextView keyId = (TextView) view.findViewById(R.id.keyId);
TextView status = (TextView) view.findViewById(R.id.status);
String userId = cursor.getString(mIndexUserId); String userId = cursor.getString(mIndexUserId);
String[] userIdSplit = PgpKeyHelper.splitUserId(userId); String[] userIdSplit = PgpKeyHelper.splitUserId(userId);
if (userIdSplit[0] != null) { if (userIdSplit[0] != null) {
mainUserId.setText(highlightSearchQuery(userIdSplit[0])); h.mainUserId.setText(highlightSearchQuery(userIdSplit[0]));
} else { } else {
mainUserId.setText(R.string.user_id_no_name); h.mainUserId.setText(R.string.user_id_no_name);
} }
if (userIdSplit[1] != null) { if (userIdSplit[1] != null) {
mainUserIdRest.setText(highlightSearchQuery(userIdSplit[1])); h.mainUserIdRest.setText(highlightSearchQuery(userIdSplit[1]));
} else { } else {
mainUserIdRest.setText(""); h.mainUserIdRest.setText("");
} }
long masterKeyId = cursor.getLong(mIndexMasterKeyId); long masterKeyId = cursor.getLong(mIndexMasterKeyId);
keyId.setText(PgpKeyHelper.convertKeyIdToHexShort(masterKeyId)); h.keyId.setText(PgpKeyHelper.convertKeyIdToHexShort(masterKeyId));
boolean valid = cursor.getInt(mIndexProjectionValid) > 0; boolean enabled = true;
if (valid) { if(cursor.getInt(mIndexRevoked) != 0) {
if (mKeyType == Id.type.public_key) { h.status.setText(R.string.revoked);
status.setText(R.string.can_encrypt); 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 { } else {
status.setText(R.string.can_sign); h.status.setText("");
}
} 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);
}
} }
CheckBox selected = (CheckBox) view.findViewById(R.id.selected); h.status.setTag(enabled);
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);
}
view.setEnabled(valid);
mainUserId.setEnabled(valid);
mainUserIdRest.setEnabled(valid);
keyId.setEnabled(valid);
status.setEnabled(valid);
} }
@Override @Override
public View newView(Context context, Cursor cursor, ViewGroup parent) { 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;
} }
} }

View File

@ -523,5 +523,7 @@
<string name="label_revocation">Revocation Reason</string> <string name="label_revocation">Revocation Reason</string>
<string name="label_verify_status">Verification Status</string> <string name="label_verify_status">Verification Status</string>
<string name="label_cert_type">Type</string> <string name="label_cert_type">Type</string>
<string name="can_certify">can certify</string>
<string name="can_certify_not">cannot certify</string>
</resources> </resources>