diff options
Diffstat (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java')
-rw-r--r-- | OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java | 330 |
1 files changed, 196 insertions, 134 deletions
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 eb807792b..ed3be0e7f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java @@ -18,16 +18,25 @@ package org.sufficientlysecure.keychain.ui; import android.app.Activity; -import android.content.Intent; +import android.content.Context; +import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.support.v4.app.Fragment; +import android.support.v4.app.LoaderManager; +import android.support.v4.content.CursorLoader; +import android.support.v4.content.Loader; +import android.support.v4.widget.CursorAdapter; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.CheckBox; +import android.widget.AdapterView; +import android.widget.BaseAdapter; +import android.widget.Spinner; +import android.widget.SpinnerAdapter; import android.widget.TextView; -import android.widget.Button; + +import com.tokenautocomplete.TokenCompleteTextView; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; @@ -37,61 +46,52 @@ import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; 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.util.Log; -import org.sufficientlysecure.keychain.util.Notify; -import java.util.Vector; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; -public class EncryptAsymmetricFragment extends Fragment { +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"; - public static final int REQUEST_CODE_PUBLIC_KEYS = 0x00007001; - public static final int REQUEST_CODE_SECRET_KEYS = 0x00007002; - ProviderHelper mProviderHelper; - OnAsymmetricKeySelection mKeySelectionListener; - // view - private Button mSelectKeysButton; - private CheckBox mSign; - private TextView mMainUserId; - private TextView mMainUserIdRest; + private Spinner mSign; + private EncryptKeyCompletionView mEncryptKeyView; + private SelectSignKeyCursorAdapter mSignAdapter = new SelectSignKeyCursorAdapter(); // model - private long mSecretKeyId = Constants.key.none; - private long mEncryptionKeyIds[] = null; + private EncryptActivityInterface mEncryptInterface; - // Container Activity must implement this interface - public interface OnAsymmetricKeySelection { - public void onSigningKeySelected(long signingKeyId); + @Override + public void onNotifyUpdate() { - public void onEncryptionKeysSelected(long[] encryptionKeyIds); } @Override public void onAttach(Activity activity) { super.onAttach(activity); try { - mKeySelectionListener = (OnAsymmetricKeySelection) activity; + mEncryptInterface = (EncryptActivityInterface) activity; } catch (ClassCastException e) { - throw new ClassCastException(activity.toString() + " must implement OnAsymmetricKeySelection"); + throw new ClassCastException(activity.toString() + " must implement EncryptActivityInterface"); } } private void setSignatureKeyId(long signatureKeyId) { - mSecretKeyId = signatureKeyId; - // update key selection in EncryptActivity - mKeySelectionListener.onSigningKeySelected(signatureKeyId); - updateView(); + mEncryptInterface.setSignatureKey(signatureKeyId); } private void setEncryptionKeyIds(long[] encryptionKeyIds) { - mEncryptionKeyIds = encryptionKeyIds; - // update key selection in EncryptActivity - mKeySelectionListener.onEncryptionKeysSelected(encryptionKeyIds); - updateView(); + mEncryptInterface.setEncryptionKeys(encryptionKeyIds); + } + + private void setEncryptionUserIds(String[] encryptionUserIds) { + mEncryptInterface.setEncryptionUsers(encryptionUserIds); } /** @@ -101,25 +101,20 @@ public class EncryptAsymmetricFragment extends Fragment { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.encrypt_asymmetric_fragment, container, false); - mSelectKeysButton = (Button) view.findViewById(R.id.btn_selectEncryptKeys); - mSign = (CheckBox) view.findViewById(R.id.sign); - mMainUserId = (TextView) view.findViewById(R.id.mainUserId); - mMainUserIdRest = (TextView) view.findViewById(R.id.mainUserIdRest); - mSelectKeysButton.setOnClickListener(new View.OnClickListener() { - public void onClick(View v) { - selectPublicKeys(); + 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.setOnClickListener(new View.OnClickListener() { - public void onClick(View v) { - CheckBox checkBox = (CheckBox) v; - if (checkBox.isChecked()) { - selectSecretKey(); - } else { - setSignatureKeyId(Constants.key.none); - } + + @Override + public void onNothingSelected(AdapterView<?> parent) { + setSignatureKeyId(Constants.key.none); } }); + mEncryptKeyView = (EncryptKeyCompletionView) view.findViewById(R.id.recipient_list); return view; } @@ -135,6 +130,65 @@ public class EncryptAsymmetricFragment extends Fragment { // preselect keys given by arguments (given by Intent to EncryptActivity) preselectKeys(signatureKeyId, encryptionKeyIds, mProviderHelper); + + 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.EXPIRY, + KeyRings.IS_REVOKED, + // can certify info only related to master key + KeyRings.CAN_CERTIFY, + // has sign may be any subkey + KeyRings.HAS_SIGN, + KeyRings.HAS_ANY_SECRET, + KeyRings.HAS_SECRET + }; + + String where = KeyRings.HAS_ANY_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, null); + /*return new CursorLoader(getActivity(), KeyRings.buildUnifiedKeyRingsUri(), + new String[]{KeyRings.USER_ID, KeyRings.KEY_ID, KeyRings.MASTER_KEY_ID, KeyRings.HAS_ANY_SECRET}, SIGN_KEY_SELECTION, + 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) { + if (token instanceof EncryptKeyCompletionView.EncryptionKey) { + updateEncryptionKeys(); + } + } + + @Override + public void onTokenRemoved(Object token) { + if (token instanceof EncryptKeyCompletionView.EncryptionKey) { + updateEncryptionKeys(); + } + } + }); } /** @@ -161,117 +215,125 @@ public class EncryptAsymmetricFragment extends Fragment { } if (preselectedEncryptionKeyIds != null) { - Vector<Long> goodIds = new Vector<Long>(); - for (int i = 0; i < preselectedEncryptionKeyIds.length; ++i) { + for (long preselectedId : preselectedEncryptionKeyIds) { try { - long id = providerHelper.getCachedPublicKeyRing( - KeyRings.buildUnifiedKeyRingsFindBySubkeyUri( - preselectedEncryptionKeyIds[i]) - ).getMasterKeyId(); - goodIds.add(id); + CachedPublicKeyRing ring = providerHelper.getCachedPublicKeyRing( + KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(preselectedId)); + mEncryptKeyView.addObject(mEncryptKeyView.new EncryptionKey(ring)); } catch (PgpGeneralException e) { Log.e(Constants.TAG, "key not found!", e); } } - if (goodIds.size() > 0) { - long[] keyIds = new long[goodIds.size()]; - for (int i = 0; i < goodIds.size(); ++i) { - keyIds[i] = goodIds.get(i); - } - setEncryptionKeyIds(keyIds); - } + updateEncryptionKeys(); } } - private void updateView() { - if (mEncryptionKeyIds == null || mEncryptionKeyIds.length == 0) { - mSelectKeysButton.setText(getString(R.string.select_keys_button_default)); - } else { - mSelectKeysButton.setText(getResources().getQuantityString( - R.plurals.select_keys_button, mEncryptionKeyIds.length, - mEncryptionKeyIds.length)); + private void updateEncryptionKeys() { + List<Object> objects = mEncryptKeyView.getObjects(); + List<Long> keyIds = new ArrayList<Long>(); + List<String> userIds = new ArrayList<String>(); + for (Object object : objects) { + if (object instanceof EncryptKeyCompletionView.EncryptionKey) { + keyIds.add(((EncryptKeyCompletionView.EncryptionKey) object).getKeyId()); + userIds.add(((EncryptKeyCompletionView.EncryptionKey) object).getUserId()); + } + } + long[] keyIdsArr = new long[keyIds.size()]; + Iterator<Long> iterator = keyIds.iterator(); + for (int i = 0; i < keyIds.size(); i++) { + keyIdsArr[i] = iterator.next(); } + setEncryptionKeyIds(keyIdsArr); + setEncryptionUserIds(userIds.toArray(new String[userIds.size()])); + } - if (mSecretKeyId == Constants.key.none) { - mSign.setChecked(false); - mMainUserId.setText(""); - mMainUserIdRest.setText(""); - } else { - // See if we can get a user_id from a unified query - try { - String[] userIdSplit = mProviderHelper.getCachedPublicKeyRing( - KeyRings.buildUnifiedKeyRingUri(mSecretKeyId)).getSplitPrimaryUserIdWithFallback(); + 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); + } - if (userIdSplit[0] != null) { - mMainUserId.setText(userIdSplit[0]); - } else { - mMainUserId.setText(R.string.user_id_no_name); + @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))); } - if (userIdSplit[1] != null) { - mMainUserIdRest.setText(userIdSplit[1]); - } else { - mMainUserIdRest.setText(getString(R.string.label_key_id) + ": " - + PgpKeyHelper.convertKeyIdToHex(mSecretKeyId)); + + @Override + public long getItemId(int position) { + mCursor.moveToPosition(position); + return mCursor.getLong(mIndexMasterKeyId); } - } catch (PgpGeneralException e) { - Notify.showNotify(getActivity(), "Key not found! This is a bug!", Notify.Style.ERROR); - } - mSign.setChecked(true); + }; } - } - private void selectPublicKeys() { - Intent intent = new Intent(getActivity(), SelectPublicKeyActivity.class); - Vector<Long> keyIds = new Vector<Long>(); - if (mEncryptionKeyIds != null && mEncryptionKeyIds.length > 0) { - for (int i = 0; i < mEncryptionKeyIds.length; ++i) { - keyIds.add(mEncryptionKeyIds[i]); + 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); } - long[] initialKeyIds = null; - if (keyIds.size() > 0) { - initialKeyIds = new long[keyIds.size()]; - for (int i = 0; i < keyIds.size(); ++i) { - initialKeyIds[i] = keyIds.get(i); - } + + @Override + public int getCount() { + return inner.getCount() + 1; } - intent.putExtra(SelectPublicKeyActivity.EXTRA_SELECTED_MASTER_KEY_IDS, initialKeyIds); - startActivityForResult(intent, REQUEST_CODE_PUBLIC_KEYS); - } - private void selectSecretKey() { - Intent intent = new Intent(getActivity(), SelectSecretKeyActivity.class); - intent.putExtra(SelectSecretKeyActivity.EXTRA_FILTER_SIGN, true); - startActivityForResult(intent, REQUEST_CODE_SECRET_KEYS); - } + @Override + public Object getItem(int position) { + if (position == 0) return null; + return inner.getItem(position - 1); + } - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - switch (requestCode) { - case REQUEST_CODE_PUBLIC_KEYS: { - if (resultCode == Activity.RESULT_OK) { - Bundle bundle = data.getExtras(); - setEncryptionKeyIds(bundle - .getLongArray(SelectPublicKeyActivity.RESULT_EXTRA_MASTER_KEY_IDS)); - } - break; - } + @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; + } - case REQUEST_CODE_SECRET_KEYS: { - if (resultCode == Activity.RESULT_OK) { - Uri uriMasterKey = data.getData(); - setSignatureKeyId(Long.valueOf(uriMasterKey.getLastPathSegment())); + @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 { - setSignatureKeyId(Constants.key.none); + v = convertView; } - break; - } - - default: { - super.onActivityResult(requestCode, resultCode, data); - - break; + ((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; } } |