aboutsummaryrefslogtreecommitdiffstats
path: root/OpenKeychain/src/main
diff options
context:
space:
mode:
authorDominik Schürmann <dominik@dominikschuermann.de>2015-06-17 19:56:13 +0200
committerDominik Schürmann <dominik@dominikschuermann.de>2015-06-17 19:56:13 +0200
commit300fd8e0f26c328aa351318fdea17485d2d940d4 (patch)
treed028024da0370f50eeed4bb1a76cf9c1a7baeb36 /OpenKeychain/src/main
parent0b3317600bf7641425cfacb9709333c11a897414 (diff)
parent04d2b6a5076a1a7264687999152f8c24ece773ab (diff)
downloadopen-keychain-300fd8e0f26c328aa351318fdea17485d2d940d4.tar.gz
open-keychain-300fd8e0f26c328aa351318fdea17485d2d940d4.tar.bz2
open-keychain-300fd8e0f26c328aa351318fdea17485d2d940d4.zip
Merge pull request #1352 from open-keychain/v/instrument
instrumentation branch
Diffstat (limited to 'OpenKeychain/src/main')
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/compatibility/ClipboardReflection.java4
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java2
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java6
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java15
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java9
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java2
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java8
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextFragment.java4
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptModeAsymmetricFragment.java3
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java2
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java4
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java108
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyFragment.java2
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyAdapter.java69
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/Notify.java23
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/CertifyKeySpinner.java36
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EncryptKeyCompletionView.java13
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeySpinner.java170
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SignKeySpinner.java33
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/ToolableViewAnimator.java61
-rw-r--r--OpenKeychain/src/main/res/layout/create_key_passphrase_fragment.xml3
-rw-r--r--OpenKeychain/src/main/res/layout/decrypt_text_fragment.xml3
-rw-r--r--OpenKeychain/src/main/res/layout/keyspinner_item.xml57
-rw-r--r--OpenKeychain/src/main/res/layout/keyspinner_item_none.xml19
-rw-r--r--OpenKeychain/src/main/res/layout/view_key_activity.xml11
-rw-r--r--OpenKeychain/src/main/res/values/attr.xml4
26 files changed, 300 insertions, 371 deletions
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/compatibility/ClipboardReflection.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/compatibility/ClipboardReflection.java
index fa3600ffb..2f2838f70 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/compatibility/ClipboardReflection.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/compatibility/ClipboardReflection.java
@@ -74,6 +74,10 @@ public class ClipboardReflection {
Method methodGetPrimaryClip = clipboard.getClass().getMethod("getPrimaryClip");
Object clipData = methodGetPrimaryClip.invoke(clipboard);
+ if (clipData == null) {
+ return null;
+ }
+
// ClipData.Item clipDataItem = clipData.getItemAt(0);
Method methodGetItemAt = clipData.getClass().getMethod("getItemAt", int.class);
Object clipDataItem = methodGetItemAt.invoke(clipData, 0);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java
index 469e386cb..da0aef018 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java
@@ -82,7 +82,7 @@ public class EditKeyOperation extends BaseOperation<SaveKeyringParcel> {
CanonicalizedSecretKeyRing secRing =
mProviderHelper.getCanonicalizedSecretKeyRing(saveParcel.mMasterKeyId);
- modifyResult = keyOperations.modifySecretKeyRing(secRing, cryptoInput, saveParcel, log, 2);
+ modifyResult = keyOperations.modifySecretKeyRing(secRing, cryptoInput, saveParcel);
if (modifyResult.isPending()) {
return modifyResult;
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java
index 707cf0af1..8c68bda19 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java
@@ -854,7 +854,11 @@ public abstract class OperationResult implements Parcelable {
if (mParcels.isEmpty()) {
return null;
}
- return mParcels.get(mParcels.size() -1);
+ LogEntryParcel last = mParcels.get(mParcels.size() -1);
+ if (last instanceof SubLogEntryParcel) {
+ return ((SubLogEntryParcel) last).getSubResult().getLog().getLast();
+ }
+ return last;
}
@Override
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java
index fd3d41f93..e3059defb 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java
@@ -149,7 +149,7 @@ public class PgpDecryptVerify extends BaseOperation<PgpDecryptVerifyInputParcel>
return verifySignedLiteralData(input, aIn, outputStream, 0);
} else if (aIn.isClearText()) {
// a cleartext signature, verify it with the other method
- return verifyCleartextSignature(aIn, 0);
+ return verifyCleartextSignature(aIn, outputStream, 0);
} else {
// else: ascii armored encryption! go on...
return decryptVerify(input, cryptoInput, in, outputStream, 0);
@@ -757,6 +757,12 @@ public class PgpDecryptVerify extends BaseOperation<PgpDecryptVerifyInputParcel>
// TODO: slow annealing to fake a progress?
}
+ metadata = new OpenPgpMetadata(
+ originalFilename,
+ mimeType,
+ literalData.getModificationTime().getTime(),
+ alreadyWritten);
+
if (signature != null) {
updateProgress(R.string.progress_verifying_signature, 90, 100);
log.add(LogType.MSG_DC_CLEAR_SIGNATURE_CHECK, indent);
@@ -833,7 +839,7 @@ public class PgpDecryptVerify extends BaseOperation<PgpDecryptVerifyInputParcel>
* pg/src/main/java/org/spongycastle/openpgp/examples/ClearSignedFileProcessor.java
*/
private DecryptVerifyResult verifyCleartextSignature(
- ArmoredInputStream aIn, int indent) throws IOException, PGPException {
+ ArmoredInputStream aIn, OutputStream outputStream, int indent) throws IOException, PGPException {
OperationLog log = new OperationLog();
@@ -863,8 +869,9 @@ public class PgpDecryptVerify extends BaseOperation<PgpDecryptVerifyInputParcel>
out.close();
byte[] clearText = out.toByteArray();
- if (out != null) {
- out.write(clearText);
+ if (outputStream != null) {
+ outputStream.write(clearText);
+ outputStream.close();
}
updateProgress(R.string.progress_processing_signature, 60, 100);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
index 1da13023d..a018815f3 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
@@ -365,14 +365,9 @@ public class PgpKeyOperation {
public PgpEditKeyResult modifySecretKeyRing(CanonicalizedSecretKeyRing wsKR,
CryptoInputParcel cryptoInput,
SaveKeyringParcel saveParcel) {
- return modifySecretKeyRing(wsKR, cryptoInput, saveParcel, new OperationLog(), 0);
- }
- public PgpEditKeyResult modifySecretKeyRing(CanonicalizedSecretKeyRing wsKR,
- CryptoInputParcel cryptoInput,
- SaveKeyringParcel saveParcel,
- OperationLog log,
- int indent) {
+ OperationLog log = new OperationLog();
+ int indent = 0;
/*
* 1. Unlock private key
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java
index 8253801d9..36ba47672 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java
@@ -179,7 +179,7 @@ public class KeychainDatabase extends SQLiteOpenHelper {
+ Tables.API_APPS + "(" + ApiAppsAllowedKeysColumns.PACKAGE_NAME + ") ON DELETE CASCADE"
+ ")";
- KeychainDatabase(Context context) {
+ public KeychainDatabase(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
mContext = context;
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java
index 72100677c..dbbfe3133 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java
@@ -149,6 +149,14 @@ public class PassphraseCacheService extends Service {
context.startService(intent);
}
+ public static void clearCachedPassphrases(Context context) {
+ Log.d(Constants.TAG, "PassphraseCacheService.clearCachedPassphrase()");
+
+ Intent intent = new Intent(context, PassphraseCacheService.class);
+ intent.setAction(ACTION_PASSPHRASE_CACHE_CLEAR);
+
+ context.startService(intent);
+ }
/**
* Gets a cached passphrase from memory by sending an intent to the service. This method is
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextFragment.java
index 1dcda5b8d..051da5d6b 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextFragment.java
@@ -153,7 +153,9 @@ public class DecryptTextFragment extends DecryptFragment {
@Override
protected PgpDecryptVerifyInputParcel createOperationInput() {
- return new PgpDecryptVerifyInputParcel(mCiphertext.getBytes());
+ PgpDecryptVerifyInputParcel input = new PgpDecryptVerifyInputParcel(mCiphertext.getBytes());
+ input.setAllowSymmetricDecryption(true);
+ return input;
}
@Override
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptModeAsymmetricFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptModeAsymmetricFragment.java
index 1a23dda93..355c649e7 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptModeAsymmetricFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptModeAsymmetricFragment.java
@@ -75,7 +75,6 @@ public class EncryptModeAsymmetricFragment extends EncryptModeFragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.encrypt_asymmetric_fragment, container, false);
-
mSignKeySpinner = (KeySpinner) view.findViewById(R.id.sign);
mEncryptKeyView = (EncryptKeyCompletionView) view.findViewById(R.id.recipient_list);
mEncryptKeyView.setThreshold(1); // Start working from first character
@@ -168,7 +167,7 @@ public class EncryptModeAsymmetricFragment extends EncryptModeFragment {
@Override
public long getAsymmetricSigningKeyId() {
- return mSignKeySpinner.getSelectedItemId();
+ return mSignKeySpinner.getSelectedKeyId();
}
@Override
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java
index 83fede917..d93b52453 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextFragment.java
@@ -240,7 +240,7 @@ public class EncryptTextFragment
boolean gotEncryptionKeys = (encryptionKeyIds != null
&& encryptionKeyIds.length > 0);
- if (!gotEncryptionKeys && signingKeyId == 0L) {
+ if (!gotEncryptionKeys && signingKeyId == Constants.key.none) {
Notify.create(getActivity(), R.string.select_encryption_or_signature_key, Notify.Style.ERROR)
.show(this);
return null;
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java
index f5a909676..a0f6d0e1b 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java
@@ -51,6 +51,8 @@ public class MainActivity extends BaseNfcActivity implements FabContainer, OnBac
private static final int ID_SETTINGS = 4;
private static final int ID_HELP = 5;
+ public static final String EXTRA_SKIP_FIRST_TIME = "skip_first_time";
+
public Drawer.Result mDrawerResult;
private Toolbar mToolbar;
@@ -114,7 +116,7 @@ public class MainActivity extends BaseNfcActivity implements FabContainer, OnBac
// if this is the first time show first time activity
Preferences prefs = Preferences.getPreferences(this);
- if (prefs.isFirstTime()) {
+ if (!getIntent().getBooleanExtra(EXTRA_SKIP_FIRST_TIME, false) && prefs.isFirstTime()) {
Intent intent = new Intent(this, CreateKeyActivity.class);
intent.putExtra(CreateKeyActivity.EXTRA_FIRST_TIME, true);
startActivity(intent);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java
index 4b4e71f6e..bb12cd7ff 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java
@@ -17,6 +17,7 @@
package org.sufficientlysecure.keychain.ui;
+
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
@@ -43,14 +44,12 @@ import android.widget.Toast;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround;
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey;
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType;
import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKeyRing;
import org.sufficientlysecure.keychain.pgp.KeyRing;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
-import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing;
import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.provider.ProviderHelper.NotFoundException;
@@ -75,8 +74,7 @@ public class PassphraseDialogActivity extends FragmentActivity {
// special extra for OpenPgpService
public static final String EXTRA_SERVICE_INTENT = "data";
-
- private static final int REQUEST_CODE_ENTER_PATTERN = 2;
+ private long mSubKeyId;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -93,14 +91,13 @@ public class PassphraseDialogActivity extends FragmentActivity {
// this activity itself has no content view (see manifest)
- long keyId;
if (getIntent().hasExtra(EXTRA_SUBKEY_ID)) {
- keyId = getIntent().getLongExtra(EXTRA_SUBKEY_ID, 0);
+ mSubKeyId = getIntent().getLongExtra(EXTRA_SUBKEY_ID, 0);
} else {
RequiredInputParcel requiredInput = getIntent().getParcelableExtra(EXTRA_REQUIRED_INPUT);
switch (requiredInput.mType) {
case PASSPHRASE_SYMMETRIC: {
- keyId = Constants.key.symmetric;
+ mSubKeyId = Constants.key.symmetric;
break;
}
case PASSPHRASE: {
@@ -127,7 +124,7 @@ public class PassphraseDialogActivity extends FragmentActivity {
return;
}
- keyId = requiredInput.getSubKeyId();
+ mSubKeyId = requiredInput.getSubKeyId();
break;
}
default: {
@@ -136,62 +133,35 @@ public class PassphraseDialogActivity extends FragmentActivity {
}
}
- Intent serviceIntent = getIntent().getParcelableExtra(EXTRA_SERVICE_INTENT);
-
- show(this, keyId, serviceIntent);
}
@Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- switch (requestCode) {
- case REQUEST_CODE_ENTER_PATTERN: {
- /*
- * NOTE that there are 4 possible result codes!!!
- */
- switch (resultCode) {
- case RESULT_OK:
- // The user passed
- break;
- case RESULT_CANCELED:
- // The user cancelled the task
- break;
-// case LockPatternActivity.RESULT_FAILED:
-// // The user failed to enter the pattern
-// break;
-// case LockPatternActivity.RESULT_FORGOT_PATTERN:
-// // The user forgot the pattern and invoked your recovery Activity.
-// break;
- }
+ protected void onResume() {
+ super.onResume();
- /*
- * In any case, there's always a key EXTRA_RETRY_COUNT, which holds
- * the number of tries that the user did.
- */
-// int retryCount = data.getIntExtra(
-// LockPatternActivity.EXTRA_RETRY_COUNT, 0);
+ /* Show passphrase dialog to cache a new passphrase the user enters for using it later for
+ * encryption. Based on mSecretKeyId it asks for a passphrase to open a private key or it asks
+ * for a symmetric passphrase
+ */
- break;
- }
- }
+ Intent serviceIntent = getIntent().getParcelableExtra(EXTRA_SERVICE_INTENT);
+
+ PassphraseDialogFragment frag = new PassphraseDialogFragment();
+ Bundle args = new Bundle();
+ args.putLong(EXTRA_SUBKEY_ID, mSubKeyId);
+ args.putParcelable(EXTRA_SERVICE_INTENT, serviceIntent);
+ frag.setArguments(args);
+ frag.show(getSupportFragmentManager(), "passphraseDialog");
}
- /**
- * Shows passphrase dialog to cache a new passphrase the user enters for using it later for
- * encryption. Based on mSecretKeyId it asks for a passphrase to open a private key or it asks
- * for a symmetric passphrase
- */
- public static void show(final FragmentActivity context, final long keyId, final Intent serviceIntent) {
- DialogFragmentWorkaround.INTERFACE.runnableRunDelayed(new Runnable() {
- public void run() {
- // do NOT check if the key even needs a passphrase. that's not our job here.
- PassphraseDialogFragment frag = new PassphraseDialogFragment();
- Bundle args = new Bundle();
- args.putLong(EXTRA_SUBKEY_ID, keyId);
- args.putParcelable(EXTRA_SERVICE_INTENT, serviceIntent);
- frag.setArguments(args);
- frag.show(context.getSupportFragmentManager(), "passphraseDialog");
- }
- });
+ @Override
+ protected void onPause() {
+ super.onPause();
+
+ DialogFragment dialog = (DialogFragment) getSupportFragmentManager().findFragmentByTag("passphraseDialog");
+ if (dialog != null) {
+ dialog.dismiss();
+ }
}
public static class PassphraseDialogFragment extends DialogFragment implements TextView.OnEditorActionListener {
@@ -205,9 +175,6 @@ public class PassphraseDialogActivity extends FragmentActivity {
private Intent mServiceIntent;
- /**
- * Creates dialog
- */
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final Activity activity = getActivity();
@@ -268,12 +235,7 @@ public class PassphraseDialogActivity extends FragmentActivity {
userId = null;
}
- /* Get key type for message */
- // find a master key id for our key
- long masterKeyId = new ProviderHelper(activity).getMasterKeyId(mSubKeyId);
- CachedPublicKeyRing keyRing = new ProviderHelper(activity).getCachedPublicKeyRing(masterKeyId);
- // get the type of key (from the database)
- keyType = keyRing.getSecretKeyType(mSubKeyId);
+ keyType = mSecretRing.getSecretKey(mSubKeyId).getSecretKeyType();
switch (keyType) {
case PASSPHRASE:
message = getString(R.string.passphrase_for, userId);
@@ -468,20 +430,16 @@ public class PassphraseDialogActivity extends FragmentActivity {
// note we need no synchronization here, this variable is only accessed in the ui thread
mIsCancelled = true;
+
+ getActivity().setResult(RESULT_CANCELED);
+ getActivity().finish();
}
@Override
public void onDismiss(DialogInterface dialog) {
super.onDismiss(dialog);
- if (getActivity() == null) {
- return;
- }
-
hideKeyboard();
-
- getActivity().setResult(RESULT_CANCELED);
- getActivity().finish();
}
private void hideKeyboard() {
@@ -495,11 +453,9 @@ public class PassphraseDialogActivity extends FragmentActivity {
inputManager.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
}
- /**
- * Associate the "done" button on the soft keyboard with the okay button in the view
- */
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+ // Associate the "done" button on the soft keyboard with the okay button in the view
if (EditorInfo.IME_ACTION_DONE == actionId) {
AlertDialog dialog = ((AlertDialog) getDialog());
Button bt = dialog.getButton(AlertDialog.BUTTON_POSITIVE);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyFragment.java
index b92163b59..a929d52f0 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyFragment.java
@@ -300,7 +300,7 @@ public class ViewKeyFragment extends LoaderFragment implements
* because the notification triggers faster than the activity closes.
*/
// Avoid NullPointerExceptions...
- if (data.getCount() == 0) {
+ if (data == null || data.getCount() == 0) {
return;
}
// Swap the new cursor in. (The framework will take care of closing the
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyAdapter.java
index deaaee87a..1fc24775b 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyAdapter.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyAdapter.java
@@ -19,15 +19,16 @@ package org.sufficientlysecure.keychain.ui.adapter;
import java.io.Serializable;
-import java.util.Calendar;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
import java.util.Date;
-import java.util.TimeZone;
+import java.util.List;
import android.content.Context;
import android.database.Cursor;
import android.graphics.PorterDuff;
import android.support.v4.widget.CursorAdapter;
-import android.text.format.DateFormat;
import android.text.format.DateUtils;
import android.view.LayoutInflater;
import android.view.View;
@@ -60,7 +61,6 @@ public class KeyAdapter extends CursorAdapter {
KeyRings.VERIFIED,
KeyRings.HAS_ANY_SECRET,
KeyRings.HAS_DUPLICATE_USER_ID,
- KeyRings.HAS_ENCRYPT,
KeyRings.FINGERPRINT,
KeyRings.CREATION,
};
@@ -72,9 +72,8 @@ public class KeyAdapter extends CursorAdapter {
public static final int INDEX_VERIFIED = 5;
public static final int INDEX_HAS_ANY_SECRET = 6;
public static final int INDEX_HAS_DUPLICATE_USER_ID = 7;
- public static final int INDEX_HAS_ENCRYPT = 8;
- public static final int INDEX_FINGERPRINT = 9;
- public static final int INDEX_CREATION = 10;
+ public static final int INDEX_FINGERPRINT = 8;
+ public static final int INDEX_CREATION = 9;
public KeyAdapter(Context context, Cursor c, int flags) {
super(context, c, flags);
@@ -87,6 +86,7 @@ public class KeyAdapter extends CursorAdapter {
}
public static class KeyItemViewHolder {
+ public View mView;
public Long mMasterKeyId;
public TextView mMainUserId;
public TextView mMainUserIdRest;
@@ -96,6 +96,7 @@ public class KeyAdapter extends CursorAdapter {
public ImageButton mSlingerButton;
public KeyItemViewHolder(View view) {
+ mView = view;
mMainUserId = (TextView) view.findViewById(R.id.key_list_item_name);
mMainUserIdRest = (TextView) view.findViewById(R.id.key_list_item_email);
mStatus = (ImageView) view.findViewById(R.id.key_list_item_status_icon);
@@ -104,11 +105,10 @@ public class KeyAdapter extends CursorAdapter {
mCreationDate = (TextView) view.findViewById(R.id.key_list_item_creation);
}
- public void setData(Context context, Cursor cursor, Highlighter highlighter) {
+ public void setData(Context context, KeyItem item, Highlighter highlighter) {
{ // set name and stuff, common to both key types
- String userId = cursor.getString(INDEX_USER_ID);
- KeyRing.UserId userIdSplit = KeyRing.splitUserId(userId);
+ KeyRing.UserId userIdSplit = item.mUserId;
if (userIdSplit.name != null) {
mMainUserId.setText(highlighter.highlight(userIdSplit.name));
} else {
@@ -124,30 +124,23 @@ public class KeyAdapter extends CursorAdapter {
{ // set edit button and status, specific by key type
- long masterKeyId = cursor.getLong(INDEX_MASTER_KEY_ID);
- boolean isSecret = cursor.getInt(INDEX_HAS_ANY_SECRET) != 0;
- boolean isRevoked = cursor.getInt(INDEX_IS_REVOKED) > 0;
- boolean isExpired = cursor.getInt(INDEX_IS_EXPIRED) != 0;
- boolean isVerified = cursor.getInt(INDEX_VERIFIED) > 0;
- boolean hasDuplicate = cursor.getInt(INDEX_HAS_DUPLICATE_USER_ID) != 0;
-
- mMasterKeyId = masterKeyId;
+ mMasterKeyId = item.mKeyId;
// Note: order is important!
- if (isRevoked) {
+ if (item.mIsRevoked) {
KeyFormattingUtils
.setStatusImage(context, mStatus, null, State.REVOKED, R.color.bg_gray);
mStatus.setVisibility(View.VISIBLE);
mSlinger.setVisibility(View.GONE);
mMainUserId.setTextColor(context.getResources().getColor(R.color.bg_gray));
mMainUserIdRest.setTextColor(context.getResources().getColor(R.color.bg_gray));
- } else if (isExpired) {
+ } else if (item.mIsExpired) {
KeyFormattingUtils.setStatusImage(context, mStatus, null, State.EXPIRED, R.color.bg_gray);
mStatus.setVisibility(View.VISIBLE);
mSlinger.setVisibility(View.GONE);
mMainUserId.setTextColor(context.getResources().getColor(R.color.bg_gray));
mMainUserIdRest.setTextColor(context.getResources().getColor(R.color.bg_gray));
- } else if (isSecret) {
+ } else if (item.mIsSecret) {
mStatus.setVisibility(View.GONE);
if (mSlingerButton.hasOnClickListeners()) {
mSlinger.setVisibility(View.VISIBLE);
@@ -158,7 +151,7 @@ public class KeyAdapter extends CursorAdapter {
mMainUserIdRest.setTextColor(context.getResources().getColor(R.color.black));
} else {
// this is a public key - show if it's verified
- if (isVerified) {
+ if (item.mIsVerified) {
KeyFormattingUtils.setStatusImage(context, mStatus, State.VERIFIED);
mStatus.setVisibility(View.VISIBLE);
} else {
@@ -170,9 +163,9 @@ public class KeyAdapter extends CursorAdapter {
mMainUserIdRest.setTextColor(context.getResources().getColor(R.color.black));
}
- if (hasDuplicate) {
+ if (item.mHasDuplicate) {
String dateTime = DateUtils.formatDateTime(context,
- cursor.getLong(INDEX_CREATION) * 1000,
+ item.mCreation.getTime(),
DateUtils.FORMAT_SHOW_DATE
| DateUtils.FORMAT_SHOW_YEAR
| DateUtils.FORMAT_ABBREV_MONTH);
@@ -190,6 +183,10 @@ public class KeyAdapter extends CursorAdapter {
}
+ public boolean isEnabled(Cursor cursor) {
+ return true;
+ }
+
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
View view = mInflater.inflate(R.layout.key_list_item, parent, false);
@@ -204,7 +201,8 @@ public class KeyAdapter extends CursorAdapter {
public void bindView(View view, Context context, Cursor cursor) {
Highlighter highlighter = new Highlighter(context, mQuery);
KeyItemViewHolder h = (KeyItemViewHolder) view.getTag();
- h.setData(context, cursor, highlighter);
+ KeyItem item = new KeyItem(cursor);
+ h.setData(context, item, highlighter);
}
public boolean isSecretAvailable(int id) {
@@ -234,8 +232,9 @@ public class KeyAdapter extends CursorAdapter {
@Override
public long getItemId(int position) {
+ Cursor cursor = getCursor();
// prevent a crash on rapid cursor changes
- if (getCursor().isClosed()) {
+ if (cursor != null && getCursor().isClosed()) {
return 0L;
}
return super.getItemId(position);
@@ -250,6 +249,7 @@ public class KeyAdapter extends CursorAdapter {
public final boolean mHasDuplicate;
public final Date mCreation;
public final String mFingerprint;
+ public final boolean mIsSecret, mIsRevoked, mIsExpired, mIsVerified;
private KeyItem(Cursor cursor) {
String userId = cursor.getString(INDEX_USER_ID);
@@ -260,6 +260,10 @@ public class KeyAdapter extends CursorAdapter {
mCreation = new Date(cursor.getLong(INDEX_CREATION) * 1000);
mFingerprint = KeyFormattingUtils.convertFingerprintToHex(
cursor.getBlob(INDEX_FINGERPRINT));
+ mIsSecret = cursor.getInt(INDEX_HAS_ANY_SECRET) != 0;
+ mIsRevoked = cursor.getInt(INDEX_IS_REVOKED) > 0;
+ mIsExpired = cursor.getInt(INDEX_IS_EXPIRED) > 0;
+ mIsVerified = cursor.getInt(INDEX_VERIFIED) > 0;
}
public KeyItem(CanonicalizedPublicKeyRing ring) {
@@ -272,6 +276,12 @@ public class KeyAdapter extends CursorAdapter {
mCreation = key.getCreationTime();
mFingerprint = KeyFormattingUtils.convertFingerprintToHex(
ring.getFingerprint());
+ mIsRevoked = key.isRevoked();
+ mIsExpired = key.isExpired();
+
+ // these two are actually "don't know"s
+ mIsSecret = false;
+ mIsVerified = false;
}
public String getReadableName() {
@@ -284,4 +294,11 @@ public class KeyAdapter extends CursorAdapter {
}
+ public static String[] getProjectionWith(String[] projection) {
+ List<String> list = new ArrayList<>();
+ list.addAll(Arrays.asList(PROJECTION));
+ list.addAll(Arrays.asList(projection));
+ return list.toArray(new String[list.size()]);
+ }
+
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/Notify.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/Notify.java
index 8c554dbde..7dfd56430 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/Notify.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/Notify.java
@@ -38,25 +38,16 @@ import org.sufficientlysecure.keychain.util.FabContainer;
public class Notify {
public static enum Style {
- OK, WARN, ERROR;
+ OK (R.color.android_green_light), WARN(R.color.android_orange_light), ERROR(R.color.android_red_light);
- public void applyToBar(Snackbar bar) {
+ public final int mLineColor;
- switch (this) {
- case OK:
- // bar.actionColorResource(R.color.android_green_light);
- bar.lineColorResource(R.color.android_green_light);
- break;
- case WARN:
- // bar.textColorResource(R.color.android_orange_light);
- bar.lineColorResource(R.color.android_orange_light);
- break;
- case ERROR:
- // bar.textColorResource(R.color.android_red_light);
- bar.lineColorResource(R.color.android_red_light);
- break;
- }
+ Style(int color) {
+ mLineColor = color;
+ }
+ public void applyToBar(Snackbar bar) {
+ bar.lineColorResource(mLineColor);
}
}
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
index 845b35512..0fed46544 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/CertifyKeySpinner.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/CertifyKeySpinner.java
@@ -17,6 +17,10 @@
package org.sufficientlysecure.keychain.ui.widget;
+
+import java.util.Arrays;
+import java.util.List;
+
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
@@ -24,14 +28,11 @@ import android.os.Bundle;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.util.AttributeSet;
-import android.widget.ImageView;
import org.sufficientlysecure.keychain.Constants;
-import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.KeychainDatabase;
-import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
-import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.State;
+import org.sufficientlysecure.keychain.ui.adapter.KeyAdapter;
public class CertifyKeySpinner extends KeySpinner {
private long mHiddenMasterKeyId = Constants.key.none;
@@ -59,19 +60,9 @@ public class CertifyKeySpinner extends KeySpinner {
// 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_REVOKED,
- KeychainContract.KeyRings.IS_EXPIRED,
+ String[] projection = KeyAdapter.getProjectionWith(new String[] {
KeychainContract.KeyRings.HAS_CERTIFY,
- KeychainContract.KeyRings.HAS_ANY_SECRET,
- KeychainContract.KeyRings.HAS_DUPLICATE_USER_ID,
- KeychainContract.KeyRings.CREATION
- };
+ });
String where = KeychainContract.KeyRings.HAS_ANY_SECRET + " = 1 AND "
+ KeychainDatabase.Tables.KEYS + "." + KeychainContract.KeyRings.MASTER_KEY_ID
@@ -82,7 +73,7 @@ public class CertifyKeySpinner extends KeySpinner {
return new CursorLoader(getContext(), baseUri, projection, where, null, null);
}
- private int mIndexHasCertify, mIndexIsRevoked, mIndexIsExpired;
+ private int mIndexHasCertify;
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
@@ -90,8 +81,6 @@ public class CertifyKeySpinner extends KeySpinner {
if (loader.getId() == LOADER_ID) {
mIndexHasCertify = data.getColumnIndex(KeychainContract.KeyRings.HAS_CERTIFY);
- mIndexIsRevoked = data.getColumnIndex(KeychainContract.KeyRings.IS_REVOKED);
- mIndexIsExpired = data.getColumnIndex(KeychainContract.KeyRings.IS_EXPIRED);
// If:
// - no key has been pre-selected (e.g. by SageSlinger)
@@ -119,18 +108,15 @@ public class CertifyKeySpinner extends KeySpinner {
@Override
- boolean setStatus(Context context, Cursor cursor, ImageView statusView) {
- if (cursor.getInt(mIndexIsRevoked) != 0) {
- KeyFormattingUtils.setStatusImage(getContext(), statusView, null, State.REVOKED, R.color.bg_gray);
+ boolean isItemEnabled(Cursor cursor) {
+ if (cursor.getInt(KeyAdapter.INDEX_IS_REVOKED) != 0) {
return false;
}
- if (cursor.getInt(mIndexIsExpired) != 0) {
- KeyFormattingUtils.setStatusImage(getContext(), statusView, null, State.EXPIRED, R.color.bg_gray);
+ if (cursor.getInt(KeyAdapter.INDEX_IS_EXPIRED) != 0) {
return false;
}
// don't invalidate the "None" entry, which is also null!
if (cursor.getPosition() != 0 && cursor.isNull(mIndexHasCertify)) {
- KeyFormattingUtils.setStatusImage(getContext(), statusView, null, State.UNAVAILABLE, R.color.bg_gray);
return false;
}
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 63a1aade9..48e6c2cee 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
@@ -38,6 +38,7 @@ import com.tokenautocomplete.TokenCompleteTextView;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables;
import org.sufficientlysecure.keychain.ui.adapter.KeyAdapter;
@@ -126,7 +127,13 @@ public class EncryptKeyCompletionView extends TokenCompleteTextView
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
// These are the rows that we will retrieve.
Uri baseUri = KeyRings.buildUnifiedKeyRingsUri();
- String where = KeyRings.HAS_ENCRYPT + " NOT NULL AND " + KeyRings.IS_EXPIRED + " = 0 AND "
+
+ String[] projection = KeyAdapter.getProjectionWith(new String[] {
+ KeychainContract.KeyRings.HAS_ENCRYPT,
+ });
+
+ String where = KeyRings.HAS_ENCRYPT + " NOT NULL AND "
+ + KeyRings.IS_EXPIRED + " = 0 AND "
+ Tables.KEYS + "." + KeyRings.IS_REVOKED + " = 0";
if (args != null && args.containsKey(ARG_QUERY)) {
@@ -135,12 +142,12 @@ public class EncryptKeyCompletionView extends TokenCompleteTextView
where += " AND " + KeyRings.USER_ID + " LIKE ?";
- return new CursorLoader(getContext(), baseUri, KeyAdapter.PROJECTION, where,
+ return new CursorLoader(getContext(), baseUri, projection, where,
new String[]{"%" + query + "%"}, null);
}
mAdapter.setSearchQuery(null);
- return new CursorLoader(getContext(), baseUri, KeyAdapter.PROJECTION, where, null, null);
+ return new CursorLoader(getContext(), baseUri, projection, where, null, null);
}
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
index ad1a14a33..5050c01af 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeySpinner.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeySpinner.java
@@ -17,33 +17,30 @@
package org.sufficientlysecure.keychain.ui.widget;
-import android.annotation.SuppressLint;
+
import android.content.Context;
import android.database.Cursor;
-import android.graphics.Color;
import android.os.Bundle;
import android.os.Parcelable;
import android.support.annotation.NonNull;
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.support.v7.widget.AppCompatSpinner;
-import android.text.format.DateUtils;
import android.util.AttributeSet;
+import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
-import android.widget.ImageView;
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.provider.KeychainContract;
-import org.sufficientlysecure.keychain.util.Log;
+import org.sufficientlysecure.keychain.ui.adapter.KeyAdapter;
+import org.sufficientlysecure.keychain.ui.adapter.KeyAdapter.KeyItem;
+
/**
* Use AppCompatSpinner from AppCompat lib instead of Spinner. Fixes white dropdown icon.
@@ -119,7 +116,8 @@ public abstract class KeySpinner extends AppCompatSpinner implements
if (getContext() instanceof FragmentActivity) {
((FragmentActivity) getContext()).getSupportLoaderManager().restartLoader(LOADER_ID, null, this);
} else {
- Log.e(Constants.TAG, "KeySpinner must be attached to FragmentActivity, this is " + getContext().getClass());
+ throw new AssertionError("KeySpinner must be attached to FragmentActivity, this is "
+ + getContext().getClass());
}
}
@@ -138,7 +136,11 @@ public abstract class KeySpinner extends AppCompatSpinner implements
}
public long getSelectedKeyId() {
- return getSelectedItemId();
+ Object item = getSelectedItem();
+ if (item instanceof KeyItem) {
+ return ((KeyItem) item).mKeyId;
+ }
+ return Constants.key.none;
}
public void setPreSelectedKeyId(long selectedKeyId) {
@@ -146,161 +148,87 @@ public abstract class KeySpinner extends AppCompatSpinner implements
}
protected class SelectKeyAdapter extends BaseAdapter implements SpinnerAdapter {
- private CursorAdapter inner;
- private int mIndexUserId;
- private int mIndexDuplicate;
+ private KeyAdapter inner;
private int mIndexMasterKeyId;
- private int mIndexCreationDate;
public SelectKeyAdapter() {
- inner = new CursorAdapter(getContext(), null, 0) {
- @Override
- public View newView(Context context, Cursor cursor, ViewGroup parent) {
- return View.inflate(getContext(), R.layout.keyspinner_item, null);
- }
+ inner = new KeyAdapter(getContext(), null, 0) {
@Override
- public void bindView(View view, Context context, Cursor cursor) {
- TextView vKeyName = (TextView) view.findViewById(R.id.keyspinner_key_name);
- ImageView vKeyStatus = (ImageView) view.findViewById(R.id.keyspinner_key_status);
- TextView vKeyEmail = (TextView) view.findViewById(R.id.keyspinner_key_email);
- TextView vDuplicate = (TextView) view.findViewById(R.id.keyspinner_duplicate);
-
- KeyRing.UserId userId = KeyRing.splitUserId(cursor.getString(mIndexUserId));
- vKeyName.setText(userId.name);
- vKeyEmail.setText(userId.email);
-
- boolean duplicate = cursor.getLong(mIndexDuplicate) > 0;
- if (duplicate) {
- String dateTime = DateUtils.formatDateTime(context,
- cursor.getLong(mIndexCreationDate) * 1000,
- DateUtils.FORMAT_SHOW_DATE
- | DateUtils.FORMAT_SHOW_YEAR
- | DateUtils.FORMAT_ABBREV_MONTH);
-
- vDuplicate.setText(context.getString(R.string.label_key_created, dateTime));
- vDuplicate.setVisibility(View.VISIBLE);
- } else {
- vDuplicate.setVisibility(View.GONE);
- }
-
- boolean valid = setStatus(getContext(), cursor, vKeyStatus);
- setItemEnabled(view, valid);
+ public boolean isEnabled(Cursor cursor) {
+ return KeySpinner.this.isItemEnabled(cursor);
}
- @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;
- }
- }
};
}
- private void setItemEnabled(View view, boolean enabled) {
- TextView vKeyName = (TextView) view.findViewById(R.id.keyspinner_key_name);
- ImageView vKeyStatus = (ImageView) view.findViewById(R.id.keyspinner_key_status);
- TextView vKeyEmail = (TextView) view.findViewById(R.id.keyspinner_key_email);
- TextView vKeyDuplicate = (TextView) view.findViewById(R.id.keyspinner_duplicate);
-
- if (enabled) {
- vKeyName.setTextColor(Color.BLACK);
- vKeyEmail.setTextColor(Color.BLACK);
- vKeyDuplicate.setTextColor(Color.BLACK);
- vKeyStatus.setVisibility(View.GONE);
- view.setClickable(false);
- } else {
- vKeyName.setTextColor(Color.GRAY);
- vKeyEmail.setTextColor(Color.GRAY);
- vKeyDuplicate.setTextColor(Color.GRAY);
- vKeyStatus.setVisibility(View.VISIBLE);
- // this is a HACK. the trick is, if the element itself is clickable, the
- // click is not passed on to the view list
- view.setClickable(true);
- }
- }
-
public Cursor swapCursor(Cursor newCursor) {
if (newCursor == null) return inner.swapCursor(null);
- mIndexDuplicate = newCursor.getColumnIndex(KeychainContract.KeyRings.HAS_DUPLICATE_USER_ID);
- mIndexUserId = newCursor.getColumnIndex(KeychainContract.KeyRings.USER_ID);
mIndexMasterKeyId = newCursor.getColumnIndex(KeychainContract.KeyRings.MASTER_KEY_ID);
- mIndexCreationDate = newCursor.getColumnIndex(KeychainContract.KeyRings.CREATION);
+
+ Cursor oldCursor = inner.swapCursor(newCursor);
// pre-select key if mPreSelectedKeyId is given
if (mPreSelectedKeyId != Constants.key.none && newCursor.moveToFirst()) {
do {
if (newCursor.getLong(mIndexMasterKeyId) == mPreSelectedKeyId) {
- setSelection(newCursor.getPosition() + 1);
+ setSelection(newCursor.getPosition() +1);
}
} while (newCursor.moveToNext());
}
- return inner.swapCursor(newCursor);
+ return oldCursor;
}
@Override
public int getCount() {
- return inner.getCount() + 1;
+ return inner.getCount() +1;
}
@Override
public Object getItem(int position) {
- if (position == 0) return null;
- return inner.getItem(position - 1);
+ 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);
+ if (position == 0) {
+ return Constants.key.none;
+ }
+ return inner.getItemId(position -1);
}
- @SuppressLint("ViewHolder") // inflate call is for the preview only
@Override
public View getView(int position, View convertView, ViewGroup parent) {
- try {
- View v = getDropDownView(position, convertView, parent);
- v.findViewById(R.id.keyspinner_key_email).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 view;
- if (position == 0) {
- if (convertView == null) {
- view = inner.newView(null, null, parent);
- } else {
- view = convertView;
+ // Unfortunately, SpinnerAdapter does not support multiple view
+ // types. For this reason, we throw away convertViews of a bad
+ // type. This is sort of a hack, but since the number of elements
+ // we deal with in KeySpinners is usually very small (number of
+ // secret keys), this is the easiest solution. (I'm sorry.)
+ if (convertView != null) {
+ // This assumes that the inner view has non-null tags on its views!
+ boolean isWrongType = (convertView.getTag() == null) != (position == 0);
+ if (isWrongType) {
+ convertView = null;
}
- TextView vKeyName = (TextView) view.findViewById(R.id.keyspinner_key_name);
- ImageView vKeyStatus = (ImageView) view.findViewById(R.id.keyspinner_key_status);
- TextView vKeyEmail = (TextView) view.findViewById(R.id.keyspinner_key_email);
- TextView vKeyDuplicate = (TextView) view.findViewById(R.id.keyspinner_duplicate);
-
- vKeyName.setText(R.string.choice_none);
- vKeyEmail.setVisibility(View.GONE);
- vKeyDuplicate.setVisibility(View.GONE);
- vKeyStatus.setVisibility(View.GONE);
- setItemEnabled(view, true);
- } else {
- view = inner.getView(position - 1, convertView, parent);
- TextView vKeyEmail = (TextView) view.findViewById(R.id.keyspinner_key_email);
- vKeyEmail.setVisibility(View.VISIBLE);
}
- return view;
+
+ if (position > 0) {
+ return inner.getView(position -1, convertView, parent);
+ }
+
+ return convertView != null ? convertView :
+ LayoutInflater.from(getContext()).inflate(
+ R.layout.keyspinner_item_none, parent, false);
}
+
}
- boolean setStatus(Context context, Cursor cursor, ImageView statusView) {
+ boolean isItemEnabled(Cursor cursor) {
return true;
}
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
index df7347fa4..c59ad7a12 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SignKeySpinner.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SignKeySpinner.java
@@ -17,6 +17,7 @@
package org.sufficientlysecure.keychain.ui.widget;
+
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
@@ -24,12 +25,9 @@ import android.os.Bundle;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.util.AttributeSet;
-import android.widget.ImageView;
-import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.provider.KeychainContract;
-import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
-import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils.State;
+import org.sufficientlysecure.keychain.ui.adapter.KeyAdapter;
public class SignKeySpinner extends KeySpinner {
public SignKeySpinner(Context context) {
@@ -50,19 +48,9 @@ public class SignKeySpinner extends KeySpinner {
// 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_REVOKED,
- KeychainContract.KeyRings.IS_EXPIRED,
+ String[] projection = KeyAdapter.getProjectionWith(new String[] {
KeychainContract.KeyRings.HAS_SIGN,
- KeychainContract.KeyRings.HAS_ANY_SECRET,
- KeychainContract.KeyRings.HAS_DUPLICATE_USER_ID,
- KeychainContract.KeyRings.CREATION
- };
+ });
String where = KeychainContract.KeyRings.HAS_ANY_SECRET + " = 1";
@@ -71,7 +59,7 @@ public class SignKeySpinner extends KeySpinner {
return new CursorLoader(getContext(), baseUri, projection, where, null, null);
}
- private int mIndexHasSign, mIndexIsRevoked, mIndexIsExpired;
+ private int mIndexHasSign;
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
@@ -79,23 +67,18 @@ public class SignKeySpinner extends KeySpinner {
if (loader.getId() == LOADER_ID) {
mIndexHasSign = data.getColumnIndex(KeychainContract.KeyRings.HAS_SIGN);
- mIndexIsRevoked = data.getColumnIndex(KeychainContract.KeyRings.IS_REVOKED);
- mIndexIsExpired = data.getColumnIndex(KeychainContract.KeyRings.IS_EXPIRED);
}
}
@Override
- boolean setStatus(Context context, Cursor cursor, ImageView statusView) {
- if (cursor.getInt(mIndexIsRevoked) != 0) {
- KeyFormattingUtils.setStatusImage(getContext(), statusView, null, State.REVOKED, R.color.bg_gray);
+ boolean isItemEnabled(Cursor cursor) {
+ if (cursor.getInt(KeyAdapter.INDEX_IS_REVOKED) != 0) {
return false;
}
- if (cursor.getInt(mIndexIsExpired) != 0) {
- KeyFormattingUtils.setStatusImage(getContext(), statusView, null, State.EXPIRED, R.color.bg_gray);
+ if (cursor.getInt(KeyAdapter.INDEX_IS_EXPIRED) != 0) {
return false;
}
if (cursor.getInt(mIndexHasSign) == 0) {
- KeyFormattingUtils.setStatusImage(getContext(), statusView, null, State.UNAVAILABLE, R.color.bg_gray);
return false;
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/ToolableViewAnimator.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/ToolableViewAnimator.java
new file mode 100644
index 000000000..44f2b7c3e
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/ToolableViewAnimator.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2015 Vincent Breitmoser <look@my.amazin.horse>
+ *
+ * The MIT License (MIT)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package org.sufficientlysecure.keychain.ui.widget;
+
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ViewAnimator;
+
+import org.sufficientlysecure.keychain.R;
+
+
+/** This view is essentially identical to ViewAnimator, but allows specifying the initial view
+ * for preview as an xml attribute. */
+public class ToolableViewAnimator extends ViewAnimator {
+
+ private int mInitChild = -1;
+
+ public ToolableViewAnimator(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs);
+
+ if (isInEditMode()) {
+ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ToolableViewAnimator, defStyleAttr, 0);
+ mInitChild = a.getInt(R.styleable.ToolableViewAnimator_initialView, -1);
+ a.recycle();
+ }
+ }
+
+ @Override
+ public void addView(View child, int index, ViewGroup.LayoutParams params) {
+ if (isInEditMode() && mInitChild-- > 0) {
+ return;
+ }
+ super.addView(child, index, params);
+ }
+}
diff --git a/OpenKeychain/src/main/res/layout/create_key_passphrase_fragment.xml b/OpenKeychain/src/main/res/layout/create_key_passphrase_fragment.xml
index 48b86765a..abfb2861b 100644
--- a/OpenKeychain/src/main/res/layout/create_key_passphrase_fragment.xml
+++ b/OpenKeychain/src/main/res/layout/create_key_passphrase_fragment.xml
@@ -34,7 +34,8 @@
android:inputType="textPassword"
android:hint="@string/label_passphrase"
android:ems="10"
- android:layout_gravity="center_horizontal" />
+ android:layout_gravity="center_horizontal"
+ />
<EditText
android:id="@+id/create_key_passphrase_again"
diff --git a/OpenKeychain/src/main/res/layout/decrypt_text_fragment.xml b/OpenKeychain/src/main/res/layout/decrypt_text_fragment.xml
index ea6be462f..cb20254ff 100644
--- a/OpenKeychain/src/main/res/layout/decrypt_text_fragment.xml
+++ b/OpenKeychain/src/main/res/layout/decrypt_text_fragment.xml
@@ -1,11 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:visibility="gone"
+ tools:visibility="visible"
android:id="@+id/decrypt_content"
android:layout_width="match_parent"
android:layout_height="match_parent"
@@ -28,6 +30,7 @@
android:layout_height="wrap_content"
android:gravity="top"
android:hint=""
+ tools:text="This is the plaintext"
android:textIsSelectable="true" />
</ScrollView>
diff --git a/OpenKeychain/src/main/res/layout/keyspinner_item.xml b/OpenKeychain/src/main/res/layout/keyspinner_item.xml
deleted file mode 100644
index eea81eba5..000000000
--- a/OpenKeychain/src/main/res/layout/keyspinner_item.xml
+++ /dev/null
@@ -1,57 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center_vertical"
- android:singleLine="true"
- android:orientation="horizontal"
- android:descendantFocusability="blocksDescendants"
- android:focusable="false"
- android:minHeight="44dip">
-
- <LinearLayout
- android:layout_width="0dip"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:layout_weight="1"
- android:focusable="true"
- android:orientation="vertical"
- android:paddingLeft="8dp"
- android:paddingRight="4dp">
-
- <TextView
- android:id="@+id/keyspinner_key_name"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/label_main_user_id"
- android:textAppearance="?android:attr/textAppearanceMedium" />
-
- <TextView
- android:id="@+id/keyspinner_key_email"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:singleLine="true"
- android:ellipsize="end"
- android:text="user@example.com"
- android:textAppearance="?android:attr/textAppearanceSmall" />
-
- <TextView
- android:id="@+id/keyspinner_duplicate"
- android:text="creation: bla"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:singleLine="true"
- android:ellipsize="end"
- android:textAppearance="?android:attr/textAppearanceSmall" />
- </LinearLayout>
-
- <ImageView
- android:id="@+id/keyspinner_key_status"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:src="@drawable/status_signature_revoked_cutout_24dp"
- android:paddingLeft="16dp"
- android:paddingRight="16dp" />
-
-</LinearLayout> \ No newline at end of file
diff --git a/OpenKeychain/src/main/res/layout/keyspinner_item_none.xml b/OpenKeychain/src/main/res/layout/keyspinner_item_none.xml
new file mode 100644
index 000000000..bd1d4ac11
--- /dev/null
+++ b/OpenKeychain/src/main/res/layout/keyspinner_item_none.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_vertical"
+ android:singleLine="true"
+ android:orientation="horizontal"
+ android:minHeight="44dip"
+ android:paddingLeft="8dp"
+ android:paddingRight="4dp">
+
+ <TextView
+ android:id="@+id/keyspinner_key_name"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/choice_none"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+
+</LinearLayout> \ No newline at end of file
diff --git a/OpenKeychain/src/main/res/layout/view_key_activity.xml b/OpenKeychain/src/main/res/layout/view_key_activity.xml
index 4dbd793ea..b3f4e721d 100644
--- a/OpenKeychain/src/main/res/layout/view_key_activity.xml
+++ b/OpenKeychain/src/main/res/layout/view_key_activity.xml
@@ -60,6 +60,7 @@
android:layout_marginRight="48dp"
android:layout_marginEnd="48dp"
android:text=""
+ tools:text="Alice Skywalker"
android:textColor="@color/icons"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_above="@+id/view_key_status" />
@@ -73,6 +74,7 @@
android:layout_marginRight="48dp"
android:layout_marginEnd="48dp"
android:text=""
+ tools:text="My Key"
android:textColor="@color/tab_text"
android:textAppearance="?android:attr/textAppearanceSmall"
android:layout_above="@+id/toolbar2" />
@@ -95,6 +97,7 @@
android:layout_width="64dp"
android:layout_height="64dp"
android:visibility="invisible"
+ tools:visibility="visible"
style="?android:attr/borderlessButtonStyle"
android:src="@drawable/ic_action_encrypt_file_24dp" />
@@ -103,6 +106,7 @@
android:layout_width="64dp"
android:layout_height="64dp"
android:visibility="invisible"
+ tools:visibility="visible"
style="?android:attr/borderlessButtonStyle"
android:src="@drawable/ic_action_encrypt_text_24dp" />
@@ -111,6 +115,7 @@
android:layout_width="64dp"
android:layout_height="64dp"
android:visibility="invisible"
+ tools:visibility="visible"
style="?android:attr/borderlessButtonStyle"
android:src="@drawable/ic_nfc_white_24dp" />
@@ -120,6 +125,7 @@
android:id="@+id/view_key_status_image"
android:layout_width="96dp"
android:visibility="invisible"
+ tools:visibility="visible"
android:src="@drawable/status_signature_unverified_cutout_96dp"
android:layout_height="96dp"
android:layout_above="@id/toolbar2"
@@ -139,6 +145,7 @@
android:layout_height="wrap_content"
android:clickable="true"
android:foreground="?android:attr/selectableItemBackground"
+ tools:visibility="invisible"
card_view:cardBackgroundColor="@android:color/white"
card_view:cardElevation="2dp"
card_view:cardUseCompatPadding="true"
@@ -147,7 +154,8 @@
<ImageView
android:id="@+id/view_key_qr_code"
android:layout_width="96dp"
- android:layout_height="96dp" />
+ android:layout_height="96dp"
+ />
</android.support.v7.widget.CardView>
</RelativeLayout>
@@ -189,6 +197,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="invisible"
+ tools:visibility="visible"
android:elevation="4dp"
fab:fab_icon="@drawable/ic_qrcode_white_24dp"
fab:fab_colorNormal="@color/fab"
diff --git a/OpenKeychain/src/main/res/values/attr.xml b/OpenKeychain/src/main/res/values/attr.xml
index 7a2f3054e..04642cabb 100644
--- a/OpenKeychain/src/main/res/values/attr.xml
+++ b/OpenKeychain/src/main/res/values/attr.xml
@@ -1,6 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
+ <declare-styleable name="ToolableViewAnimator">
+ <attr name="initialView" format="integer" />
+ </declare-styleable>
+
<declare-styleable name="FoldableLinearLayout">
<attr name="foldedLabel" format="string" />
<attr name="unFoldedLabel" format="string" />