diff options
author | Dominik Schürmann <dominik@dominikschuermann.de> | 2014-08-14 18:53:40 +0200 |
---|---|---|
committer | Dominik Schürmann <dominik@dominikschuermann.de> | 2014-08-14 18:53:40 +0200 |
commit | 28df004cbb27677b5d7fac8a7bbe3d75618c036c (patch) | |
tree | 9f5adac6ad67f24384b94d1f3a8e09caa6cf5903 /OpenKeychain/src | |
parent | a58440b85dc45fab3f3b403e062ead7354c31105 (diff) | |
parent | e1958009bd022021971c1fd2f81557fb4fe99e4e (diff) | |
download | open-keychain-28df004cbb27677b5d7fac8a7bbe3d75618c036c.tar.gz open-keychain-28df004cbb27677b5d7fac8a7bbe3d75618c036c.tar.bz2 open-keychain-28df004cbb27677b5d7fac8a7bbe3d75618c036c.zip |
Merge pull request #767 from mar-v-in/issue-763
Use dropdown in CertifyActivity
Diffstat (limited to 'OpenKeychain/src')
11 files changed, 367 insertions, 171 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 dd59f8603..c239ea7f7 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java @@ -111,6 +111,7 @@ public class KeychainContract { public static final String HAS_ANY_SECRET = "has_any_secret"; public static final String HAS_ENCRYPT = "has_encrypt"; public static final String HAS_SIGN = "has_sign"; + public static final String HAS_CERTIFY = "has_certify"; public static final String PUBKEY_DATA = "pubkey_data"; public static final String PRIVKEY_DATA = "privkey_data"; 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 c914cb5b7..2c552a060 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java @@ -271,6 +271,8 @@ public class KeychainProvider extends ContentProvider { "kE." + Keys.KEY_ID + " AS " + KeyRings.HAS_ENCRYPT); projectionMap.put(KeyRings.HAS_SIGN, "kS." + Keys.KEY_ID + " AS " + KeyRings.HAS_SIGN); + projectionMap.put(KeyRings.HAS_CERTIFY, + "kC." + Keys.KEY_ID + " AS " + KeyRings.HAS_CERTIFY); projectionMap.put(KeyRings.IS_EXPIRED, "(" + Tables.KEYS + "." + Keys.EXPIRY + " IS NOT NULL AND " + Tables.KEYS + "." + Keys.EXPIRY + " < " + new Date().getTime() / 1000 + ") AS " + KeyRings.IS_EXPIRED); @@ -324,6 +326,15 @@ public class KeychainProvider extends ContentProvider { + " AND ( kS." + Keys.EXPIRY + " IS NULL OR kS." + Keys.EXPIRY + " >= " + new Date().getTime() / 1000 + " )" + ")" : "") + + (plist.contains(KeyRings.HAS_CERTIFY) ? + " LEFT JOIN " + Tables.KEYS + " AS kC ON (" + +"kC." + Keys.MASTER_KEY_ID + + " = " + Tables.KEYS + "." + Keys.MASTER_KEY_ID + + " AND kC." + Keys.IS_REVOKED + " = 0" + + " AND kC." + Keys.CAN_CERTIFY + " = 1" + + " AND ( kC." + Keys.EXPIRY + " IS NULL OR kC." + Keys.EXPIRY + + " >= " + new Date().getTime() / 1000 + " )" + + ")" : "") ); qb.appendWhere(Tables.KEYS + "." + Keys.RANK + " = 0"); // in case there are multiple verifying certificates diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java index c1986825c..7c6e94d5e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java @@ -56,6 +56,8 @@ import org.sufficientlysecure.keychain.service.OperationResultParcel; import org.sufficientlysecure.keychain.service.PassphraseCacheService; import org.sufficientlysecure.keychain.ui.adapter.UserIdsAdapter; import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment; +import org.sufficientlysecure.keychain.ui.widget.CertifyKeySpinner; +import org.sufficientlysecure.keychain.ui.widget.KeySpinner; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Notify; @@ -64,18 +66,17 @@ import java.util.ArrayList; /** * Signs the specified public key with the specified secret master key */ -public class CertifyKeyActivity extends ActionBarActivity implements - SelectSecretKeyLayoutFragment.SelectSecretKeyCallback, LoaderManager.LoaderCallbacks<Cursor> { +public class CertifyKeyActivity extends ActionBarActivity implements LoaderManager.LoaderCallbacks<Cursor> { private View mCertifyButton; private ImageView mActionCertifyImage; private CheckBox mUploadKeyCheckbox; private Spinner mSelectKeyserverSpinner; - private SelectSecretKeyLayoutFragment mSelectKeyFragment; + private CertifyKeySpinner mCertifyKeySpinner; private Uri mDataUri; - private long mPubKeyId = 0; - private long mMasterKeyId = 0; + private long mPubKeyId = Constants.key.none; + private long mMasterKeyId = Constants.key.none; private ListView mUserIds; private UserIdsAdapter mUserIdsAdapter; @@ -89,8 +90,7 @@ public class CertifyKeyActivity extends ActionBarActivity implements setContentView(R.layout.certify_key_activity); - mSelectKeyFragment = (SelectSecretKeyLayoutFragment) getSupportFragmentManager() - .findFragmentById(R.id.sign_key_select_key_fragment); + mCertifyKeySpinner = (CertifyKeySpinner) findViewById(R.id.certify_key_spinner); mSelectKeyserverSpinner = (Spinner) findViewById(R.id.upload_key_keyserver); mUploadKeyCheckbox = (CheckBox) findViewById(R.id.sign_key_upload_checkbox); mCertifyButton = findViewById(R.id.certify_key_certify_button); @@ -101,8 +101,12 @@ public class CertifyKeyActivity extends ActionBarActivity implements mActionCertifyImage.setColorFilter(getResources().getColor(R.color.tertiary_text_light), PorterDuff.Mode.SRC_IN); - mSelectKeyFragment.setCallback(this); - mSelectKeyFragment.setFilterCertify(true); + mCertifyKeySpinner.setOnKeyChangedListener(new KeySpinner.OnKeyChangedListener() { + @Override + public void onKeyChanged(long masterKeyId) { + mMasterKeyId = masterKeyId; + } + }); ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, Preferences.getPreferences(this) @@ -135,7 +139,6 @@ public class CertifyKeyActivity extends ActionBarActivity implements public void onClick(View v) { if (mPubKeyId != 0) { if (mMasterKeyId == 0) { - mSelectKeyFragment.setError(getString(R.string.select_key_to_certify)); Notify.showNotify(CertifyKeyActivity.this, getString(R.string.select_key_to_certify), Notify.Style.ERROR); } else { @@ -199,6 +202,7 @@ public class CertifyKeyActivity extends ActionBarActivity implements if (data.moveToFirst()) { // TODO: put findViewById in onCreate! mPubKeyId = data.getLong(INDEX_MASTER_KEY_ID); + mCertifyKeySpinner.setHiddenMasterKeyId(mPubKeyId); String keyIdStr = PgpKeyHelper.convertKeyIdToHex(mPubKeyId); ((TextView) findViewById(R.id.key_id)).setText(keyIdStr); @@ -367,14 +371,6 @@ public class CertifyKeyActivity extends ActionBarActivity implements startService(intent); } - /** - * callback from select key fragment - */ - @Override - public void onKeySelected(long secretKeyId) { - mMasterKeyId = secretKeyId; - } - @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java index a402b6f68..748cbca14 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java @@ -47,6 +47,7 @@ import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.ui.widget.EncryptKeyCompletionView; +import org.sufficientlysecure.keychain.ui.widget.KeySpinner; import org.sufficientlysecure.keychain.util.Log; import java.util.ArrayList; @@ -54,22 +55,20 @@ import java.util.Iterator; import java.util.List; public class EncryptAsymmetricFragment extends Fragment implements EncryptActivityInterface.UpdateListener { - public static final String ARG_SIGNATURE_KEY_ID = "signature_key_id"; - public static final String ARG_ENCRYPTION_KEY_IDS = "encryption_key_ids"; - ProviderHelper mProviderHelper; // view - private Spinner mSign; + private KeySpinner mSign; private EncryptKeyCompletionView mEncryptKeyView; - private SelectSignKeyCursorAdapter mSignAdapter = new SelectSignKeyCursorAdapter(); // model private EncryptActivityInterface mEncryptInterface; @Override public void onNotifyUpdate() { - + if (mSign != null) { + mSign.setSelectedKeyId(mEncryptInterface.getSignatureKey()); + } } @Override @@ -101,17 +100,11 @@ public class EncryptAsymmetricFragment extends Fragment implements EncryptActivi public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.encrypt_asymmetric_fragment, container, false); - mSign = (Spinner) view.findViewById(R.id.sign); - mSign.setAdapter(mSignAdapter); - mSign.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { - @Override - public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { - setSignatureKeyId(parent.getAdapter().getItemId(position)); - } - + mSign = (KeySpinner) view.findViewById(R.id.sign); + mSign.setOnKeyChangedListener(new KeySpinner.OnKeyChangedListener() { @Override - public void onNothingSelected(AdapterView<?> parent) { - setSignatureKeyId(Constants.key.none); + public void onKeyChanged(long masterKeyId) { + setSignatureKeyId(masterKeyId); } }); mEncryptKeyView = (EncryptKeyCompletionView) view.findViewById(R.id.recipient_list); @@ -128,42 +121,6 @@ public class EncryptAsymmetricFragment extends Fragment implements EncryptActivi // preselect keys given preselectKeys(); - getLoaderManager().initLoader(1, null, new LoaderManager.LoaderCallbacks<Cursor>() { - @Override - public Loader<Cursor> onCreateLoader(int id, Bundle args) { - // This is called when a new Loader needs to be created. This - // sample only has one Loader, so we don't care about the ID. - Uri baseUri = KeyRings.buildUnifiedKeyRingsUri(); - - // These are the rows that we will retrieve. - String[] projection = new String[]{ - KeyRings._ID, - KeyRings.MASTER_KEY_ID, - KeyRings.KEY_ID, - KeyRings.USER_ID, - KeyRings.IS_EXPIRED, - KeyRings.HAS_SIGN, - KeyRings.HAS_ANY_SECRET - }; - - String where = KeyRings.HAS_ANY_SECRET + " = 1 AND " + KeyRings.HAS_SIGN + " NOT NULL AND " - + KeyRings.IS_REVOKED + " = 0 AND " + KeyRings.IS_EXPIRED + " = 0"; - - // 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, null); - } - - @Override - public void onLoadFinished(Loader<Cursor> loader, Cursor data) { - mSignAdapter.swapCursor(data); - } - - @Override - public void onLoaderReset(Loader<Cursor> loader) { - mSignAdapter.swapCursor(null); - } - }); mEncryptKeyView.setTokenListener(new TokenCompleteTextView.TokenListener() { @Override public void onTokenAdded(Object token) { @@ -194,6 +151,7 @@ public class EncryptAsymmetricFragment extends Fragment implements EncryptActivi KeyRings.buildUnifiedKeyRingUri(signatureKey)); if(keyring.hasAnySecret()) { setSignatureKeyId(keyring.getMasterKeyId()); + mSign.setSelectedKeyId(mEncryptInterface.getSignatureKey()); } } catch (PgpGeneralException e) { Log.e(Constants.TAG, "key not found!", e); @@ -233,95 +191,4 @@ public class EncryptAsymmetricFragment extends Fragment implements EncryptActivi setEncryptionKeyIds(keyIdsArr); setEncryptionUserIds(userIds.toArray(new String[userIds.size()])); } - - private class SelectSignKeyCursorAdapter extends BaseAdapter implements SpinnerAdapter { - private CursorAdapter inner; - private int mIndexUserId; - private int mIndexKeyId; - private int mIndexMasterKeyId; - - public SelectSignKeyCursorAdapter() { - inner = new CursorAdapter(null, null, 0) { - @Override - public View newView(Context context, Cursor cursor, ViewGroup parent) { - return getActivity().getLayoutInflater().inflate(R.layout.encrypt_asymmetric_signkey, null); - } - - @Override - public void bindView(View view, Context context, Cursor cursor) { - String[] userId = KeyRing.splitUserId(cursor.getString(mIndexUserId)); - ((TextView) view.findViewById(android.R.id.title)).setText(userId[2] == null ? userId[0] : (userId[0] + " (" + userId[2] + ")")); - ((TextView) view.findViewById(android.R.id.text1)).setText(userId[1]); - ((TextView) view.findViewById(android.R.id.text2)).setText(PgpKeyHelper.convertKeyIdToHex(cursor.getLong(mIndexKeyId))); - } - - @Override - public long getItemId(int position) { - mCursor.moveToPosition(position); - return mCursor.getLong(mIndexMasterKeyId); - } - }; - } - - public Cursor swapCursor(Cursor newCursor) { - if (newCursor == null) return inner.swapCursor(null); - - mIndexKeyId = newCursor.getColumnIndex(KeyRings.KEY_ID); - mIndexUserId = newCursor.getColumnIndex(KeyRings.USER_ID); - mIndexMasterKeyId = newCursor.getColumnIndex(KeyRings.MASTER_KEY_ID); - if (newCursor.moveToFirst()) { - do { - if (newCursor.getLong(mIndexMasterKeyId) == mEncryptInterface.getSignatureKey()) { - mSign.setSelection(newCursor.getPosition() + 1); - } - } while (newCursor.moveToNext()); - } - return inner.swapCursor(newCursor); - } - - @Override - public int getCount() { - return inner.getCount() + 1; - } - - @Override - public Object getItem(int position) { - if (position == 0) return null; - return inner.getItem(position - 1); - } - - @Override - public long getItemId(int position) { - if (position == 0) return Constants.key.none; - return inner.getItemId(position - 1); - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - View v = getDropDownView(position, convertView, parent); - v.findViewById(android.R.id.text1).setVisibility(View.GONE); - return v; - } - - @Override - public View getDropDownView(int position, View convertView, ViewGroup parent) { - View v; - if (position == 0) { - if (convertView == null) { - v = inner.newView(null, null, parent); - } else { - v = convertView; - } - ((TextView) v.findViewById(android.R.id.title)).setText("None"); - v.findViewById(android.R.id.text1).setVisibility(View.GONE); - v.findViewById(android.R.id.text2).setVisibility(View.GONE); - } else { - v = inner.getView(position - 1, convertView, parent); - v.findViewById(android.R.id.text1).setVisibility(View.VISIBLE); - v.findViewById(android.R.id.text2).setVisibility(View.VISIBLE); - } - return v; - } - } - } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/CertifyKeySpinner.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/CertifyKeySpinner.java new file mode 100644 index 000000000..030a76136 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/CertifyKeySpinner.java @@ -0,0 +1,60 @@ +package org.sufficientlysecure.keychain.ui.widget; + +import android.content.Context; +import android.database.Cursor; +import android.net.Uri; +import android.support.v4.content.CursorLoader; +import android.support.v4.content.Loader; +import android.util.AttributeSet; +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.provider.KeychainContract; +import org.sufficientlysecure.keychain.provider.KeychainDatabase; + +public class CertifyKeySpinner extends KeySpinner { + private long mHiddenMasterKeyId = Constants.key.none; + + public CertifyKeySpinner(Context context) { + super(context); + } + + public CertifyKeySpinner(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public CertifyKeySpinner(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + public void setHiddenMasterKeyId(long hiddenMasterKeyId) { + this.mHiddenMasterKeyId = hiddenMasterKeyId; + reload(); + } + + @Override + public Loader<Cursor> onCreateLoader() { + // This is called when a new Loader needs to be created. This + // sample only has one Loader, so we don't care about the ID. + Uri baseUri = KeychainContract.KeyRings.buildUnifiedKeyRingsUri(); + + // These are the rows that we will retrieve. + String[] projection = new String[]{ + KeychainContract.KeyRings._ID, + KeychainContract.KeyRings.MASTER_KEY_ID, + KeychainContract.KeyRings.KEY_ID, + KeychainContract.KeyRings.USER_ID, + KeychainContract.KeyRings.IS_EXPIRED, + KeychainContract.KeyRings.HAS_CERTIFY, + KeychainContract.KeyRings.HAS_ANY_SECRET + }; + + String where = KeychainContract.KeyRings.HAS_ANY_SECRET + " = 1 AND " + + KeychainContract.KeyRings.HAS_CERTIFY + " NOT NULL AND " + + KeychainContract.KeyRings.IS_REVOKED + " = 0 AND " + + KeychainContract.KeyRings.IS_EXPIRED + " = 0 AND " + KeychainDatabase.Tables.KEYS + "." + + KeychainContract.KeyRings.MASTER_KEY_ID + " != " + mHiddenMasterKeyId; + + // Now create and return a CursorLoader that will take care of + // creating a Cursor for the data being displayed. + return new CursorLoader(getContext(), baseUri, projection, where, null, null); + } +} 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 20b9570bb..ceb3f665f 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 @@ -111,7 +111,7 @@ public class EncryptKeyCompletionView extends TokenCompleteTextView { protected void onAttachedToWindow() { super.onAttachedToWindow(); if (getContext() instanceof FragmentActivity) { - ((FragmentActivity) getContext()).getSupportLoaderManager().initLoader(0, null, new LoaderManager.LoaderCallbacks<Cursor>() { + ((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. @@ -143,6 +143,8 @@ public class EncryptKeyCompletionView extends TokenCompleteTextView { swapCursor(null); } }); + } else { + Log.e(Constants.TAG, "EncryptKeyCompletionView must be attached to a FragmentActivity, this is " + getContext().getClass()); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeySpinner.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeySpinner.java new file mode 100644 index 000000000..b12029239 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeySpinner.java @@ -0,0 +1,215 @@ +package org.sufficientlysecure.keychain.ui.widget; + +import android.content.Context; +import android.database.Cursor; +import android.os.Bundle; +import android.support.v4.app.FragmentActivity; +import android.support.v4.app.LoaderManager; +import android.support.v4.content.Loader; +import android.support.v4.widget.CursorAdapter; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.BaseAdapter; +import android.widget.Spinner; +import android.widget.SpinnerAdapter; +import android.widget.TextView; + +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.pgp.KeyRing; +import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; +import org.sufficientlysecure.keychain.provider.KeychainContract; +import org.sufficientlysecure.keychain.util.Log; + +public abstract class KeySpinner extends Spinner { + public interface OnKeyChangedListener { + public void onKeyChanged(long masterKeyId); + } + + private long mSelectedKeyId; + private SelectKeyAdapter mAdapter = new SelectKeyAdapter(); + private OnKeyChangedListener mListener; + + public KeySpinner(Context context) { + super(context); + initView(); + } + + public KeySpinner(Context context, AttributeSet attrs) { + super(context, attrs); + initView(); + } + + public KeySpinner(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + initView(); + } + + private void initView() { + setAdapter(mAdapter); + super.setOnItemSelectedListener(new OnItemSelectedListener() { + @Override + public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { + if (mListener != null) { + mListener.onKeyChanged(id); + } + } + + @Override + public void onNothingSelected(AdapterView<?> parent) { + if (mListener != null) { + mListener.onKeyChanged(Constants.key.none); + } + } + }); + } + + public abstract Loader<Cursor> onCreateLoader(); + + @Override + public void setOnItemSelectedListener(OnItemSelectedListener listener) { + throw new UnsupportedOperationException(); + } + + public void setOnKeyChangedListener(OnKeyChangedListener listener) { + mListener = listener; + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + reload(); + } + + public void reload() { + if (getContext() instanceof FragmentActivity) { + ((FragmentActivity) getContext()).getSupportLoaderManager().restartLoader(hashCode(), null, new LoaderManager.LoaderCallbacks<Cursor>() { + @Override + public Loader<Cursor> onCreateLoader(int id, Bundle args) { + return KeySpinner.this.onCreateLoader(); + } + + @Override + public void onLoadFinished(Loader<Cursor> loader, Cursor data) { + mAdapter.swapCursor(data); + } + + @Override + public void onLoaderReset(Loader<Cursor> loader) { + mAdapter.swapCursor(null); + } + }); + } else { + Log.e(Constants.TAG, "KeySpinner must be attached to FragmentActivity, this is " + getContext().getClass()); + } + } + + public long getSelectedKeyId() { + return mSelectedKeyId; + } + + public void setSelectedKeyId(long selectedKeyId) { + this.mSelectedKeyId = selectedKeyId; + } + + private class SelectKeyAdapter extends BaseAdapter implements SpinnerAdapter { + private CursorAdapter inner; + private int mIndexUserId; + private int mIndexKeyId; + private int mIndexMasterKeyId; + + public SelectKeyAdapter() { + inner = new CursorAdapter(null, null, 0) { + @Override + public View newView(Context context, Cursor cursor, ViewGroup parent) { + return View.inflate(getContext(), R.layout.keyspinner_key, null); + } + + @Override + public void bindView(View view, Context context, Cursor cursor) { + String[] userId = KeyRing.splitUserId(cursor.getString(mIndexUserId)); + ((TextView) view.findViewById(android.R.id.title)).setText(userId[2] == null ? userId[0] : (userId[0] + " (" + userId[2] + ")")); + ((TextView) view.findViewById(android.R.id.text1)).setText(userId[1]); + ((TextView) view.findViewById(android.R.id.text2)).setText(PgpKeyHelper.convertKeyIdToHex(cursor.getLong(mIndexKeyId))); + } + + @Override + public long getItemId(int position) { + try { + return ((Cursor) getItem(position)).getLong(mIndexMasterKeyId); + } catch (Exception e) { + // This can happen on concurrent modification :( + return Constants.key.none; + } + } + }; + } + + public Cursor swapCursor(Cursor newCursor) { + if (newCursor == null) return inner.swapCursor(null); + + mIndexKeyId = newCursor.getColumnIndex(KeychainContract.KeyRings.KEY_ID); + mIndexUserId = newCursor.getColumnIndex(KeychainContract.KeyRings.USER_ID); + mIndexMasterKeyId = newCursor.getColumnIndex(KeychainContract.KeyRings.MASTER_KEY_ID); + if (newCursor.moveToFirst()) { + do { + if (newCursor.getLong(mIndexMasterKeyId) == mSelectedKeyId) { + setSelection(newCursor.getPosition() + 1); + } + } while (newCursor.moveToNext()); + } + return inner.swapCursor(newCursor); + } + + @Override + public int getCount() { + return inner.getCount() + 1; + } + + @Override + public Object getItem(int position) { + if (position == 0) return null; + return inner.getItem(position - 1); + } + + @Override + public long getItemId(int position) { + if (position == 0) return Constants.key.none; + return inner.getItemId(position - 1); + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + try { + View v = getDropDownView(position, convertView, parent); + v.findViewById(android.R.id.text1).setVisibility(View.GONE); + return v; + } catch (NullPointerException e) { + // This is for the preview... + return View.inflate(getContext(), android.R.layout.simple_list_item_1, null); + } + } + + @Override + public View getDropDownView(int position, View convertView, ViewGroup parent) { + View v; + if (position == 0) { + if (convertView == null) { + v = inner.newView(null, null, parent); + } else { + v = convertView; + } + ((TextView) v.findViewById(android.R.id.title)).setText("None"); + v.findViewById(android.R.id.text1).setVisibility(View.GONE); + v.findViewById(android.R.id.text2).setVisibility(View.GONE); + } else { + v = inner.getView(position - 1, convertView, parent); + v.findViewById(android.R.id.text1).setVisibility(View.VISIBLE); + v.findViewById(android.R.id.text2).setVisibility(View.VISIBLE); + } + return v; + } + } +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SignKeySpinner.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SignKeySpinner.java new file mode 100644 index 000000000..cbec7f920 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SignKeySpinner.java @@ -0,0 +1,48 @@ +package org.sufficientlysecure.keychain.ui.widget; + +import android.content.Context; +import android.database.Cursor; +import android.net.Uri; +import android.support.v4.content.CursorLoader; +import android.support.v4.content.Loader; +import android.util.AttributeSet; +import org.sufficientlysecure.keychain.provider.KeychainContract; + +public class SignKeySpinner extends KeySpinner { + public SignKeySpinner(Context context) { + super(context); + } + + public SignKeySpinner(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public SignKeySpinner(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + @Override + public Loader<Cursor> onCreateLoader() { + // This is called when a new Loader needs to be created. This + // sample only has one Loader, so we don't care about the ID. + Uri baseUri = KeychainContract.KeyRings.buildUnifiedKeyRingsUri(); + + // These are the rows that we will retrieve. + String[] projection = new String[]{ + KeychainContract.KeyRings._ID, + KeychainContract.KeyRings.MASTER_KEY_ID, + KeychainContract.KeyRings.KEY_ID, + KeychainContract.KeyRings.USER_ID, + KeychainContract.KeyRings.IS_EXPIRED, + KeychainContract.KeyRings.HAS_SIGN, + KeychainContract.KeyRings.HAS_ANY_SECRET + }; + + String where = KeychainContract.KeyRings.HAS_ANY_SECRET + " = 1 AND " + KeychainContract.KeyRings.HAS_SIGN + " NOT NULL AND " + + KeychainContract.KeyRings.IS_REVOKED + " = 0 AND " + KeychainContract.KeyRings.IS_EXPIRED + " = 0"; + + // Now create and return a CursorLoader that will take care of + // creating a Cursor for the data being displayed. + return new CursorLoader(getContext(), baseUri, projection, where, null, null); + } +} diff --git a/OpenKeychain/src/main/res/layout/certify_key_activity.xml b/OpenKeychain/src/main/res/layout/certify_key_activity.xml index 34d4dbd57..bce194438 100644 --- a/OpenKeychain/src/main/res/layout/certify_key_activity.xml +++ b/OpenKeychain/src/main/res/layout/certify_key_activity.xml @@ -26,14 +26,10 @@ android:layout_marginTop="14dp" android:text="@string/section_certification_key" /> - <fragment - android:id="@+id/sign_key_select_key_fragment" - android:name="org.sufficientlysecure.keychain.ui.SelectSecretKeyLayoutFragment" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginBottom="4dp" - android:layout_marginTop="4dp" - tools:layout="@layout/select_secret_key_layout_fragment" /> + <org.sufficientlysecure.keychain.ui.widget.CertifyKeySpinner + android:id="@+id/certify_key_spinner" + android:layout_width="match_parent" + android:layout_height="wrap_content" /> <TextView style="@style/SectionHeader" diff --git a/OpenKeychain/src/main/res/layout/encrypt_asymmetric_fragment.xml b/OpenKeychain/src/main/res/layout/encrypt_asymmetric_fragment.xml index 4d82477bc..2189a1f34 100644 --- a/OpenKeychain/src/main/res/layout/encrypt_asymmetric_fragment.xml +++ b/OpenKeychain/src/main/res/layout/encrypt_asymmetric_fragment.xml @@ -24,7 +24,7 @@ android:textAppearance="?android:attr/textAppearanceMedium" android:text="@string/label_asymmetric_from" /> - <Spinner + <org.sufficientlysecure.keychain.ui.widget.SignKeySpinner android:id="@+id/sign" android:layout_width="match_parent" android:layout_height="wrap_content" diff --git a/OpenKeychain/src/main/res/layout/encrypt_asymmetric_signkey.xml b/OpenKeychain/src/main/res/layout/keyspinner_key.xml index 703f9133b..703f9133b 100644 --- a/OpenKeychain/src/main/res/layout/encrypt_asymmetric_signkey.xml +++ b/OpenKeychain/src/main/res/layout/keyspinner_key.xml |