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 | |
| 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')
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  | 
