aboutsummaryrefslogtreecommitdiffstats
path: root/OpenKeychain/src/main/java
diff options
context:
space:
mode:
authormar-v-in <github@rvin.mooo.com>2014-07-06 02:24:34 +0200
committermar-v-in <github@rvin.mooo.com>2014-07-06 02:24:34 +0200
commitfdf6411d5f059a2cde6bb32841895d5bf501ebe8 (patch)
treede8f6434ad00dd2a688160204aa5762b49f14b99 /OpenKeychain/src/main/java
parent1b0666e9de5caea14997a3e638a6209b45c97d60 (diff)
parent3363507be48e6ee77341fc8d637528610dc5136f (diff)
downloadopen-keychain-fdf6411d5f059a2cde6bb32841895d5bf501ebe8.tar.gz
open-keychain-fdf6411d5f059a2cde6bb32841895d5bf501ebe8.tar.bz2
open-keychain-fdf6411d5f059a2cde6bb32841895d5bf501ebe8.zip
Merge branch 'master' into improve-file-more
Conflicts: OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java OpenKeychain/src/main/res/layout/encrypt_content.xml
Diffstat (limited to 'OpenKeychain/src/main/java')
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java281
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKeyRing.java26
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java6
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsFragment.java10
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java45
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java3
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java8
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java31
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java43
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java2
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java729
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivityNew.java68
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivityOld.java744
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java135
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java2
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java55
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java34
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LoaderFragment.java24
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyKeysFragment.java2
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java20
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/WizardActivity.java4
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java84
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAddedAdapter.java361
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java68
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAddedAdapter.java206
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsArrayAdapter.java131
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddUserIdDialogFragment.java165
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/CreateKeyDialogFragment.java8
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/EditUserIdDialogFragment.java7
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/SetPassphraseDialogFragment.java67
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/FixedListView.java4
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SectionView.java2
32 files changed, 1934 insertions, 1441 deletions
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 1b59e7cc0..9a08290e4 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java
@@ -38,6 +38,7 @@ import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor;
import org.spongycastle.openpgp.operator.PBESecretKeyEncryptor;
import org.spongycastle.openpgp.operator.PGPContentSignerBuilder;
import org.spongycastle.openpgp.operator.PGPDigestCalculator;
+import org.spongycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator;
import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder;
import org.spongycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder;
import org.spongycastle.openpgp.operator.jcajce.JcaPGPKeyPair;
@@ -50,6 +51,9 @@ import org.sufficientlysecure.keychain.service.OperationResultParcel.LogLevel;
import org.sufficientlysecure.keychain.service.OperationResultParcel.LogType;
import org.sufficientlysecure.keychain.service.OperationResultParcel.OperationLog;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
+import org.sufficientlysecure.keychain.service.SaveKeyringParcel.SubkeyAdd;
+import org.sufficientlysecure.keychain.util.IterableIterator;
+import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.Primes;
import java.io.IOException;
@@ -63,6 +67,7 @@ import java.security.SignatureException;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
+import java.util.Iterator;
import java.util.TimeZone;
/**
@@ -99,18 +104,13 @@ public class PgpKeyOperation {
}
/** Creates new secret key. */
- private PGPSecretKey createKey(int algorithmChoice, int keySize, String passphrase,
- boolean isMasterKey) throws PgpGeneralMsgIdException {
+ private PGPKeyPair createKey(int algorithmChoice, int keySize) throws PgpGeneralMsgIdException {
try {
if (keySize < 512) {
throw new PgpGeneralMsgIdException(R.string.error_key_size_minimum512bit);
}
- if (passphrase == null) {
- passphrase = "";
- }
-
int algorithm;
KeyPairGenerator keyGen;
@@ -123,9 +123,6 @@ public class PgpKeyOperation {
}
case Constants.choice.algorithm.elgamal: {
- if (isMasterKey) {
- throw new PgpGeneralMsgIdException(R.string.error_master_key_must_not_be_el_gamal);
- }
keyGen = KeyPairGenerator.getInstance("ElGamal", Constants.BOUNCY_CASTLE_PROVIDER_NAME);
BigInteger p = Primes.getBestPrime(keySize);
BigInteger g = new BigInteger("2");
@@ -151,19 +148,8 @@ public class PgpKeyOperation {
}
// build new key pair
- PGPKeyPair keyPair = new JcaPGPKeyPair(algorithm, keyGen.generateKeyPair(), new Date());
-
- // define hashing and signing algos
- PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder().build().get(
- HashAlgorithmTags.SHA1);
-
- // Build key encrypter and decrypter based on passphrase
- PBESecretKeyEncryptor keyEncryptor = new JcePBESecretKeyEncryptorBuilder(
- PGPEncryptedData.CAST5, sha1Calc)
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.toCharArray());
+ return new JcaPGPKeyPair(algorithm, keyGen.generateKeyPair(), new Date());
- return new PGPSecretKey(keyPair.getPrivateKey(), keyPair.getPublicKey(),
- sha1Calc, isMasterKey, keyEncryptor);
} catch(NoSuchProviderException e) {
throw new RuntimeException(e);
} catch(NoSuchAlgorithmException e) {
@@ -175,6 +161,55 @@ public class PgpKeyOperation {
}
}
+ public UncachedKeyRing createSecretKeyRing(SaveKeyringParcel saveParcel, OperationLog log,
+ int indent) {
+
+ try {
+
+ log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_KEYID, indent);
+ indent += 1;
+ updateProgress(R.string.progress_building_key, 0, 100);
+
+ if (saveParcel.addSubKeys == null || saveParcel.addSubKeys.isEmpty()) {
+ log.add(LogLevel.ERROR, LogType.MSG_CR_ERROR_NO_MASTER, indent);
+ return null;
+ }
+
+ SubkeyAdd add = saveParcel.addSubKeys.remove(0);
+ PGPKeyPair keyPair = createKey(add.mAlgorithm, add.mKeysize);
+
+ if (add.mAlgorithm == Constants.choice.algorithm.elgamal) {
+ throw new PgpGeneralMsgIdException(R.string.error_master_key_must_not_be_el_gamal);
+ }
+
+ // define hashing and signing algos
+ PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder()
+ .build().get(HashAlgorithmTags.SHA1);
+ // Build key encrypter and decrypter based on passphrase
+ PBESecretKeyEncryptor keyEncryptor = new JcePBESecretKeyEncryptorBuilder(
+ PGPEncryptedData.CAST5, sha1Calc)
+ .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build("".toCharArray());
+ PGPSecretKey masterSecretKey = new PGPSecretKey(keyPair.getPrivateKey(), keyPair.getPublicKey(),
+ sha1Calc, true, keyEncryptor);
+
+ PGPSecretKeyRing sKR = new PGPSecretKeyRing(
+ masterSecretKey.getEncoded(), new JcaKeyFingerprintCalculator());
+
+ return internal(sKR, masterSecretKey, saveParcel, "", log, indent);
+
+ } catch (PGPException e) {
+ Log.e(Constants.TAG, "pgp error encoding key", e);
+ return null;
+ } catch (IOException e) {
+ Log.e(Constants.TAG, "io error encoding key", e);
+ return null;
+ } catch (PgpGeneralMsgIdException e) {
+ Log.e(Constants.TAG, "pgp msg id error", e);
+ return null;
+ }
+
+ }
+
/** This method introduces a list of modifications specified by a SaveKeyringParcel to a
* WrappedSecretKeyRing.
*
@@ -204,28 +239,49 @@ public class PgpKeyOperation {
indent += 1;
updateProgress(R.string.progress_building_key, 0, 100);
+ // Make sure this is called with a proper SaveKeyringParcel
+ if (saveParcel.mMasterKeyId == null || saveParcel.mMasterKeyId != wsKR.getMasterKeyId()) {
+ log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_KEYID, indent);
+ return null;
+ }
+
// We work on bouncycastle object level here
PGPSecretKeyRing sKR = wsKR.getRing();
- PGPPublicKey masterPublicKey = sKR.getPublicKey();
PGPSecretKey masterSecretKey = sKR.getSecretKey();
+ // Make sure the fingerprint matches
+ if (saveParcel.mFingerprint == null
+ || !Arrays.equals(saveParcel.mFingerprint,
+ masterSecretKey.getPublicKey().getFingerprint())) {
+ log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_FINGERPRINT, indent);
+ return null;
+ }
+
+ return internal(sKR, masterSecretKey, saveParcel, passphrase, log, indent);
+
+ }
+
+ private UncachedKeyRing internal(PGPSecretKeyRing sKR, PGPSecretKey masterSecretKey,
+ SaveKeyringParcel saveParcel, String passphrase,
+ OperationLog log, int indent) {
+
+ updateProgress(R.string.progress_certifying_master_key, 20, 100);
+
+ PGPPublicKey masterPublicKey = masterSecretKey.getPublicKey();
+
// 1. Unlock private key
log.add(LogLevel.DEBUG, LogType.MSG_MF_UNLOCK, indent);
- PGPPrivateKey masterPrivateKey; {
+ PGPPrivateKey masterPrivateKey;
+ {
try {
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.toCharArray());
masterPrivateKey = masterSecretKey.extractPrivateKey(keyDecryptor);
} catch (PGPException e) {
- log.add(LogLevel.ERROR, LogType.MSG_MF_UNLOCK_ERROR, indent+1);
+ log.add(LogLevel.ERROR, LogType.MSG_MF_UNLOCK_ERROR, indent + 1);
return null;
}
}
- if (!Arrays.equals(saveParcel.mFingerprint, sKR.getPublicKey().getFingerprint())) {
- return null;
- }
-
- updateProgress(R.string.progress_certifying_master_key, 20, 100);
// work on master secret key
try {
@@ -235,14 +291,42 @@ public class PgpKeyOperation {
// 2a. Add certificates for new user ids
for (String userId : saveParcel.addUserIds) {
log.add(LogLevel.INFO, LogType.MSG_MF_UID_ADD, indent);
+
+ // this operation supersedes all previous binding and revocation certificates,
+ // so remove those to retain assertions from canonicalization for later operations
+ @SuppressWarnings("unchecked")
+ Iterator<PGPSignature> it = modifiedPublicKey.getSignaturesForID(userId);
+ if (it != null) {
+ for (PGPSignature cert : new IterableIterator<PGPSignature>(it)) {
+ // if it's not a self cert, never mind
+ if (cert.getKeyID() != masterPublicKey.getKeyID()) {
+ continue;
+ }
+ if (cert.getSignatureType() == PGPSignature.CERTIFICATION_REVOCATION
+ || cert.getSignatureType() == PGPSignature.NO_CERTIFICATION
+ || cert.getSignatureType() == PGPSignature.CASUAL_CERTIFICATION
+ || cert.getSignatureType() == PGPSignature.POSITIVE_CERTIFICATION
+ || cert.getSignatureType() == PGPSignature.DEFAULT_CERTIFICATION) {
+ modifiedPublicKey = PGPPublicKey.removeCertification(
+ modifiedPublicKey, userId, cert);
+ }
+ }
+ }
+
+ // if it's supposed to be primary, we can do that here as well
+ boolean isPrimary = saveParcel.changePrimaryUserId != null
+ && userId.equals(saveParcel.changePrimaryUserId);
+ // generate and add new certificate
PGPSignature cert = generateUserIdSignature(masterPrivateKey,
- masterPublicKey, userId, false);
+ masterPublicKey, userId, isPrimary);
modifiedPublicKey = PGPPublicKey.addCertification(masterPublicKey, userId, cert);
}
// 2b. Add revocations for revoked user ids
for (String userId : saveParcel.revokeUserIds) {
log.add(LogLevel.INFO, LogType.MSG_MF_UID_REVOKE, indent);
+ // a duplicate revocatin will be removed during canonicalization, so no need to
+ // take care of that here.
PGPSignature cert = generateRevocationSignature(masterPrivateKey,
masterPublicKey, userId);
modifiedPublicKey = PGPPublicKey.addCertification(masterPublicKey, userId, cert);
@@ -251,7 +335,84 @@ public class PgpKeyOperation {
// 3. If primary user id changed, generate new certificates for both old and new
if (saveParcel.changePrimaryUserId != null) {
log.add(LogLevel.INFO, LogType.MSG_MF_UID_PRIMARY, indent);
- // todo
+
+ // we work on the modifiedPublicKey here, to respect new or newly revoked uids
+ // noinspection unchecked
+ for (String userId : new IterableIterator<String>(modifiedPublicKey.getUserIDs())) {
+ boolean isRevoked = false;
+ PGPSignature currentCert = null;
+ // noinspection unchecked
+ for (PGPSignature cert : new IterableIterator<PGPSignature>(
+ masterPublicKey.getSignaturesForID(userId))) {
+ // if it's not a self cert, never mind
+ if (cert.getKeyID() != masterPublicKey.getKeyID()) {
+ continue;
+ }
+ // we know from canonicalization that if there is any revocation here, it
+ // is valid and not superseded by a newer certification.
+ if (cert.getSignatureType() == PGPSignature.CERTIFICATION_REVOCATION) {
+ isRevoked = true;
+ continue;
+ }
+ // we know from canonicalization that there is only one binding
+ // certification here, so we can just work with the first one.
+ if (cert.getSignatureType() == PGPSignature.NO_CERTIFICATION ||
+ cert.getSignatureType() == PGPSignature.CASUAL_CERTIFICATION ||
+ cert.getSignatureType() == PGPSignature.POSITIVE_CERTIFICATION ||
+ cert.getSignatureType() == PGPSignature.DEFAULT_CERTIFICATION) {
+ currentCert = cert;
+ }
+ }
+
+ if (currentCert == null) {
+ // no certificate found?! error error error
+ log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_INTEGRITY, indent);
+ return null;
+ }
+
+ // we definitely should not update certifications of revoked keys, so just leave it.
+ if (isRevoked) {
+ // revoked user ids cannot be primary!
+ if (userId.equals(saveParcel.changePrimaryUserId)) {
+ log.add(LogLevel.ERROR, LogType.MSG_MF_ERROR_REVOKED_PRIMARY, indent);
+ return null;
+ }
+ continue;
+ }
+
+ // if this is~ the/a primary user id
+ if (currentCert.hasSubpackets() && currentCert.getHashedSubPackets().isPrimaryUserID()) {
+ // if it's the one we want, just leave it as is
+ if (userId.equals(saveParcel.changePrimaryUserId)) {
+ continue;
+ }
+ // otherwise, generate new non-primary certification
+ modifiedPublicKey = PGPPublicKey.removeCertification(
+ modifiedPublicKey, userId, currentCert);
+ PGPSignature newCert = generateUserIdSignature(
+ masterPrivateKey, masterPublicKey, userId, false);
+ modifiedPublicKey = PGPPublicKey.addCertification(
+ modifiedPublicKey, userId, newCert);
+ continue;
+ }
+
+ // if we are here, this is not currently a primary user id
+
+ // if it should be
+ if (userId.equals(saveParcel.changePrimaryUserId)) {
+ // add shiny new primary user id certificate
+ modifiedPublicKey = PGPPublicKey.removeCertification(
+ modifiedPublicKey, userId, currentCert);
+ PGPSignature newCert = generateUserIdSignature(
+ masterPrivateKey, masterPublicKey, userId, true);
+ modifiedPublicKey = PGPPublicKey.addCertification(
+ modifiedPublicKey, userId, newCert);
+ }
+
+ // user id is not primary and is not supposed to be - nothing to do here.
+
+ }
+
}
// Update the secret key ring
@@ -261,8 +422,7 @@ public class PgpKeyOperation {
sKR = PGPSecretKeyRing.insertSecretKey(sKR, masterSecretKey);
}
-
- // 4a. For each subkey change, generate new subkey binding certificate
+ // 4a. For each subkey change, generate new subkey binding certificate
for (SaveKeyringParcel.SubkeyChange change : saveParcel.changeSubKeys) {
log.add(LogLevel.INFO, LogType.MSG_MF_SUBKEY_CHANGE,
indent, PgpKeyHelper.convertKeyIdToHex(change.mKeyId));
@@ -280,7 +440,8 @@ public class PgpKeyOperation {
return null;
}
- // generate and add new signature
+ // generate and add new signature. we can be sloppy here and just leave the old one,
+ // it will be removed during canonicalization
PGPSignature sig = generateSubkeyBindingSignature(masterPublicKey, masterPrivateKey,
sKey, pKey, change.mFlags, change.mExpiry, passphrase);
pKey = PGPPublicKey.addCertification(pKey, sig);
@@ -316,16 +477,36 @@ public class PgpKeyOperation {
}
log.add(LogLevel.INFO, LogType.MSG_MF_SUBKEY_NEW, indent);
- PGPSecretKey sKey = createKey(add.mAlgorithm, add.mKeysize, passphrase, false);
+
+ // generate a new secret key (privkey only for now)
+ PGPKeyPair keyPair = createKey(add.mAlgorithm, add.mKeysize);
+
+ // add subkey binding signature (making this a sub rather than master key)
+ PGPPublicKey pKey = keyPair.getPublicKey();
+ PGPSignature cert = generateSubkeyBindingSignature(
+ masterPublicKey, masterPrivateKey, keyPair.getPrivateKey(), pKey,
+ add.mFlags, add.mExpiry);
+ pKey = PGPPublicKey.addSubkeyBindingCertification(pKey, cert);
+
+ PGPSecretKey sKey; {
+ // define hashing and signing algos
+ PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder()
+ .build().get(HashAlgorithmTags.SHA1);
+
+ // Build key encrypter and decrypter based on passphrase
+ PBESecretKeyEncryptor keyEncryptor = new JcePBESecretKeyEncryptorBuilder(
+ PGPEncryptedData.CAST5, sha1Calc)
+ .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build("".toCharArray());
+
+ sKey = new PGPSecretKey(keyPair.getPrivateKey(), pKey,
+ sha1Calc, false, keyEncryptor);
+ }
+
log.add(LogLevel.DEBUG, LogType.MSG_MF_SUBKEY_NEW_ID,
indent+1, PgpKeyHelper.convertKeyIdToHex(sKey.getKeyID()));
- PGPPublicKey pKey = sKey.getPublicKey();
- PGPSignature cert = generateSubkeyBindingSignature(masterPublicKey, masterPrivateKey,
- sKey, pKey, add.mFlags, add.mExpiry, passphrase);
- pKey = PGPPublicKey.addCertification(pKey, cert);
- sKey = PGPSecretKey.replacePublicKey(sKey, pKey);
- sKR = PGPSecretKeyRing.insertSecretKey(sKR, PGPSecretKey.replacePublicKey(sKey, pKey));
+ sKR = PGPSecretKeyRing.insertSecretKey(sKR, sKey);
+
} catch (PgpGeneralMsgIdException e) {
return null;
}
@@ -420,6 +601,18 @@ public class PgpKeyOperation {
PGPPublicKey masterPublicKey, PGPPrivateKey masterPrivateKey,
PGPSecretKey sKey, PGPPublicKey pKey, int flags, Long expiry, String passphrase)
throws IOException, PGPException, SignatureException {
+ PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder()
+ .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
+ passphrase.toCharArray());
+ PGPPrivateKey subPrivateKey = sKey.extractPrivateKey(keyDecryptor);
+ return generateSubkeyBindingSignature(masterPublicKey, masterPrivateKey, subPrivateKey,
+ pKey, flags, expiry);
+ }
+
+ private static PGPSignature generateSubkeyBindingSignature(
+ PGPPublicKey masterPublicKey, PGPPrivateKey masterPrivateKey,
+ PGPPrivateKey subPrivateKey, PGPPublicKey pKey, int flags, Long expiry)
+ throws IOException, PGPException, SignatureException {
// date for signing
Date todayDate = new Date();
@@ -427,12 +620,6 @@ public class PgpKeyOperation {
// If this key can sign, we need a primary key binding signature
if ((flags & KeyFlags.SIGN_DATA) != 0) {
-
- PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder()
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(
- passphrase.toCharArray());
- PGPPrivateKey subPrivateKey = sKey.extractPrivateKey(keyDecryptor);
-
// cross-certify signing keys
PGPSignatureSubpacketGenerator subHashedPacketsGen = new PGPSignatureSubpacketGenerator();
subHashedPacketsGen.setSignatureCreationTime(false, todayDate);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKeyRing.java
index d7148f710..c737b7c46 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKeyRing.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSecretKeyRing.java
@@ -8,16 +8,13 @@ import org.spongycastle.openpgp.PGPPublicKey;
import org.spongycastle.openpgp.PGPSecretKey;
import org.spongycastle.openpgp.PGPSecretKeyRing;
import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor;
-import org.spongycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder;
import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
-import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyEncryptorBuilder;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.util.IterableIterator;
import org.sufficientlysecure.keychain.util.Log;
import java.io.IOException;
-import java.security.NoSuchProviderException;
import java.util.Iterator;
public class WrappedSecretKeyRing extends WrappedKeyRing {
@@ -91,29 +88,6 @@ public class WrappedSecretKeyRing extends WrappedKeyRing {
}
}
- public UncachedKeyRing changeSecretKeyPassphrase(String oldPassphrase,
- String newPassphrase)
- throws IOException, PGPException, NoSuchProviderException {
-
- if (oldPassphrase == null) {
- oldPassphrase = "";
- }
- if (newPassphrase == null) {
- newPassphrase = "";
- }
-
- PGPSecretKeyRing newKeyRing = PGPSecretKeyRing.copyWithNewPassword(
- mRing,
- new JcePBESecretKeyDecryptorBuilder(new JcaPGPDigestCalculatorProviderBuilder()
- .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build()).setProvider(
- Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(oldPassphrase.toCharArray()),
- new JcePBESecretKeyEncryptorBuilder(mRing.getSecretKey()
- .getKeyEncryptionAlgorithm()).build(newPassphrase.toCharArray()));
-
- return new UncachedKeyRing(newKeyRing);
-
- }
-
public IterableIterator<WrappedSecretKey> secretKeyIterator() {
final Iterator<PGPSecretKey> it = mRing.getSecretKeys();
return new IterableIterator<WrappedSecretKey>(new Iterator<WrappedSecretKey>() {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
index 4bf3a38a0..81e218ccf 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
@@ -405,7 +405,11 @@ public class ProviderHelper {
// classify and order user ids. primary are moved to the front, revoked to the back,
// otherwise the order in the keyfile is preserved.
- log(LogLevel.INFO, LogType.MSG_IP_UID_CLASSIFYING, trustedKeys.size());
+ if (trustedKeys.size() == 0) {
+ log(LogLevel.INFO, LogType.MSG_IP_UID_CLASSIFYING_ZERO);
+ } else {
+ log(LogLevel.INFO, LogType.MSG_IP_UID_CLASSIFYING, trustedKeys.size());
+ }
mIndent += 1;
List<UserIdItem> uids = new ArrayList<UserIdItem>();
for (String userId : new IterableIterator<String>(
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsFragment.java
index e49c11e08..0b1d521ad 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsFragment.java
@@ -35,7 +35,7 @@ import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.remote.AccountSettings;
-import org.sufficientlysecure.keychain.ui.EditKeyActivity;
+import org.sufficientlysecure.keychain.ui.EditKeyActivityOld;
import org.sufficientlysecure.keychain.ui.SelectSecretKeyLayoutFragment;
import org.sufficientlysecure.keychain.ui.adapter.KeyValueSpinnerAdapter;
import org.sufficientlysecure.keychain.util.AlgorithmNames;
@@ -163,11 +163,11 @@ public class AccountSettingsFragment extends Fragment implements
}
private void createKey() {
- Intent intent = new Intent(getActivity(), EditKeyActivity.class);
- intent.setAction(EditKeyActivity.ACTION_CREATE_KEY);
- intent.putExtra(EditKeyActivity.EXTRA_GENERATE_DEFAULT_KEYS, true);
+ Intent intent = new Intent(getActivity(), EditKeyActivityOld.class);
+ intent.setAction(EditKeyActivityOld.ACTION_CREATE_KEY);
+ intent.putExtra(EditKeyActivityOld.EXTRA_GENERATE_DEFAULT_KEYS, true);
// set default user id to account name
- intent.putExtra(EditKeyActivity.EXTRA_USER_IDS, mAccSettings.getAccountName());
+ intent.putExtra(EditKeyActivityOld.EXTRA_USER_IDS, mAccSettings.getAccountName());
startActivityForResult(intent, REQUEST_CODE_CREATE_KEY);
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
index d87f98775..00f210cc1 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
@@ -215,6 +215,10 @@ public class KeychainIntentService extends IntentService
mMessenger = (Messenger) extras.get(EXTRA_MESSENGER);
Bundle data = extras.getBundle(EXTRA_DATA);
+ if (data == null) {
+ Log.e(Constants.TAG, "data extra is null!");
+ return;
+ }
OtherHelper.logDebugBundle(data, "EXTRA_DATA");
@@ -331,33 +335,41 @@ public class KeychainIntentService extends IntentService
try {
/* Input */
SaveKeyringParcel saveParcel = data.getParcelable(SAVE_KEYRING_PARCEL);
- long masterKeyId = saveParcel.mMasterKeyId;
+ if (saveParcel == null) {
+ Log.e(Constants.TAG, "bug: missing save_keyring_parcel in data!");
+ return;
+ }
/* Operation */
ProviderHelper providerHelper = new ProviderHelper(this);
PgpKeyOperation keyOperations = new PgpKeyOperation(new ProgressScaler(this, 10, 50, 100));
try {
- String passphrase = data.getString(SAVE_KEYRING_PASSPHRASE);
- WrappedSecretKeyRing secRing = providerHelper.getWrappedSecretKeyRing(masterKeyId);
-
OperationLog log = new OperationLog();
- UncachedKeyRing ring = keyOperations.modifySecretKeyRing(secRing, saveParcel,
- passphrase, log, 0);
- providerHelper.saveSecretKeyRing(ring, new ProgressScaler(this, 60, 95, 100));
+ UncachedKeyRing ring;
+ if (saveParcel.mMasterKeyId != null) {
+ String passphrase = data.getString(SAVE_KEYRING_PASSPHRASE);
+ WrappedSecretKeyRing secRing =
+ providerHelper.getWrappedSecretKeyRing(saveParcel.mMasterKeyId);
+
+ ring = keyOperations.modifySecretKeyRing(secRing, saveParcel,
+ passphrase, log, 0);
+ } else {
+ ring = keyOperations.createSecretKeyRing(saveParcel, log, 0);
+ }
+
+ providerHelper.saveSecretKeyRing(ring, new ProgressScaler(this, 10, 95, 100));
+
+ // cache new passphrase
+ if (saveParcel.newPassphrase != null) {
+ PassphraseCacheService.addCachedPassphrase(this, ring.getMasterKeyId(),
+ saveParcel.newPassphrase);
+ }
} catch (ProviderHelper.NotFoundException e) {
- // UncachedKeyRing ring = keyOperations.(saveParcel); //new Keyring
- // save the pair
- setProgress(R.string.progress_saving_key_ring, 95, 100);
- // providerHelper.saveSecretKeyRing(ring);
sendErrorToHandler(e);
}
setProgress(R.string.progress_done, 100, 100);
- if (saveParcel.newPassphrase != null) {
- PassphraseCacheService.addCachedPassphrase(this, masterKeyId, saveParcel.newPassphrase);
- }
-
/* Output */
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY);
} catch (Exception e) {
@@ -458,7 +470,7 @@ public class KeychainIntentService extends IntentService
outStream);
if (mIsCanceled && outputFile != null) {
- boolean isDeleted = new File(outputFile).delete();
+ new File(outputFile).delete();
}
sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, resultData);
@@ -614,6 +626,7 @@ public class KeychainIntentService extends IntentService
return;
}
Message msg = Message.obtain();
+ assert msg != null;
msg.arg1 = arg1;
if (arg2 != null) {
msg.arg2 = arg2;
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java
index d5d02081a..755827482 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java
@@ -27,8 +27,10 @@ import android.support.v4.app.FragmentManager;
import com.devspark.appmsg.AppMsg;
+import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment;
+import org.sufficientlysecure.keychain.util.Log;
public class KeychainIntentServiceHandler extends Handler {
@@ -126,6 +128,7 @@ public class KeychainIntentServiceHandler extends Handler {
break;
default:
+ Log.e(Constants.TAG, "unknown handler message!");
break;
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java
index 7f91ab490..6bf6b655d 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java
@@ -165,6 +165,7 @@ public class OperationResultParcel implements Parcelable {
MSG_IP_UID_CERT_ERROR (R.string.msg_ip_uid_cert_error),
MSG_IP_UID_CERT_GOOD (R.string.msg_ip_uid_cert_good),
MSG_IP_UID_CERTS_UNKNOWN (R.plurals.msg_ip_uid_certs_unknown),
+ MSG_IP_UID_CLASSIFYING_ZERO (R.string.msg_ip_uid_classifying_zero),
MSG_IP_UID_CLASSIFYING (R.plurals.msg_ip_uid_classifying),
MSG_IP_UID_REORDER(R.string.msg_ip_uid_reorder),
MSG_IP_UID_PROCESSING (R.string.msg_ip_uid_processing),
@@ -233,9 +234,16 @@ public class OperationResultParcel implements Parcelable {
MSG_MG_NEW_SUBKEY (R.string.msg_mg_new_subkey),
MSG_MG_FOUND_NEW (R.string.msg_mg_found_new),
+ // secret key create
+ MSG_CR_ERROR_NO_MASTER (R.string.msg_mr),
+
// secret key modify
MSG_MF (R.string.msg_mr),
MSG_MF_ERROR_ENCODE (R.string.msg_mf_error_encode),
+ MSG_MF_ERROR_FINGERPRINT (R.string.msg_mf_error_fingerprint),
+ MSG_MF_ERROR_KEYID (R.string.msg_mf_error_keyid),
+ MSG_MF_ERROR_INTEGRITY (R.string.msg_mf_error_integrity),
+ MSG_MF_ERROR_REVOKED_PRIMARY (R.string.msg_mf_error_revoked_primary),
MSG_MF_ERROR_PGP (R.string.msg_mf_error_pgp),
MSG_MF_ERROR_SIG (R.string.msg_mf_error_sig),
MSG_MF_PASSPHRASE (R.string.msg_mf_passphrase),
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 d42bae67a..28f230f71 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java
@@ -49,7 +49,6 @@ import java.util.Date;
* convenience.
*/
public class PassphraseCacheService extends Service {
- public static final String TAG = Constants.TAG + ": PassphraseCacheService";
public static final String ACTION_PASSPHRASE_CACHE_ADD = Constants.INTENT_PREFIX
+ "PASSPHRASE_CACHE_ADD";
@@ -83,7 +82,7 @@ public class PassphraseCacheService extends Service {
* @param passphrase
*/
public static void addCachedPassphrase(Context context, long keyId, String passphrase) {
- Log.d(TAG, "cacheNewPassphrase() for " + keyId);
+ Log.d(Constants.TAG, "PassphraseCacheService.cacheNewPassphrase() for " + keyId);
Intent intent = new Intent(context, PassphraseCacheService.class);
intent.setAction(ACTION_PASSPHRASE_CACHE_ADD);
@@ -103,7 +102,7 @@ public class PassphraseCacheService extends Service {
* @return passphrase or null (if no passphrase is cached for this keyId)
*/
public static String getCachedPassphrase(Context context, long keyId) {
- Log.d(TAG, "getCachedPassphrase() get masterKeyId for " + keyId);
+ Log.d(Constants.TAG, "PassphraseCacheService.getCachedPassphrase() get masterKeyId for " + keyId);
Intent intent = new Intent(context, PassphraseCacheService.class);
intent.setAction(ACTION_PASSPHRASE_CACHE_GET);
@@ -159,7 +158,7 @@ public class PassphraseCacheService extends Service {
private String getCachedPassphraseImpl(long keyId) {
// passphrase for symmetric encryption?
if (keyId == Constants.key.symmetric) {
- Log.d(TAG, "getCachedPassphraseImpl() for symmetric encryption");
+ Log.d(Constants.TAG, "PassphraseCacheService.getCachedPassphraseImpl() for symmetric encryption");
String cachedPassphrase = mPassphraseCache.get(Constants.key.symmetric);
if (cachedPassphrase == null) {
return null;
@@ -170,7 +169,7 @@ public class PassphraseCacheService extends Service {
// try to get master key id which is used as an identifier for cached passphrases
try {
- Log.d(TAG, "getCachedPassphraseImpl() for masterKeyId " + keyId);
+ Log.d(Constants.TAG, "PassphraseCacheService.getCachedPassphraseImpl() for masterKeyId " + keyId);
WrappedSecretKeyRing key = new ProviderHelper(this).getWrappedSecretKeyRing(
KeychainContract.KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(keyId));
// no passphrase needed? just add empty string and return it, then
@@ -184,18 +183,18 @@ public class PassphraseCacheService extends Service {
// get cached passphrase
String cachedPassphrase = mPassphraseCache.get(keyId);
if (cachedPassphrase == null) {
- Log.d(TAG, "Passphrase not (yet) cached, returning null");
+ Log.d(Constants.TAG, "PassphraseCacheService Passphrase not (yet) cached, returning null");
// not really an error, just means the passphrase is not cached but not empty either
return null;
}
// set it again to reset the cache life cycle
- Log.d(TAG, "Cache passphrase again when getting it!");
+ Log.d(Constants.TAG, "PassphraseCacheService Cache passphrase again when getting it!");
addCachedPassphrase(this, keyId, cachedPassphrase);
return cachedPassphrase;
} catch (ProviderHelper.NotFoundException e) {
- Log.e(TAG, "Passphrase for unknown key was requested!");
+ Log.e(Constants.TAG, "PassphraseCacheService Passphrase for unknown key was requested!");
return null;
}
}
@@ -212,7 +211,7 @@ public class PassphraseCacheService extends Service {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
- Log.d(TAG, "Received broadcast...");
+ Log.d(Constants.TAG, "PassphraseCacheService Received broadcast...");
if (action.equals(BROADCAST_ACTION_PASSPHRASE_CACHE_SERVICE)) {
long keyId = intent.getLongExtra(EXTRA_KEY_ID, -1);
@@ -248,7 +247,7 @@ public class PassphraseCacheService extends Service {
*/
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
- Log.d(TAG, "onStartCommand()");
+ Log.d(Constants.TAG, "PassphraseCacheService.onStartCommand()");
// register broadcastreceiver
registerReceiver();
@@ -259,8 +258,8 @@ public class PassphraseCacheService extends Service {
long keyId = intent.getLongExtra(EXTRA_KEY_ID, -1);
String passphrase = intent.getStringExtra(EXTRA_PASSPHRASE);
- Log.d(TAG,
- "Received ACTION_PASSPHRASE_CACHE_ADD intent in onStartCommand() with keyId: "
+ Log.d(Constants.TAG,
+ "PassphraseCacheService Received ACTION_PASSPHRASE_CACHE_ADD intent in onStartCommand() with keyId: "
+ keyId + ", ttl: " + ttl);
// add keyId and passphrase to memory
@@ -285,10 +284,10 @@ public class PassphraseCacheService extends Service {
try {
messenger.send(msg);
} catch (RemoteException e) {
- Log.e(Constants.TAG, "Sending message failed", e);
+ Log.e(Constants.TAG, "PassphraseCacheService Sending message failed", e);
}
} else {
- Log.e(Constants.TAG, "Intent or Intent Action not supported!");
+ Log.e(Constants.TAG, "PassphraseCacheService Intent or Intent Action not supported!");
}
}
@@ -305,11 +304,11 @@ public class PassphraseCacheService extends Service {
// remove passphrase corresponding to keyId from memory
mPassphraseCache.remove(keyId);
- Log.d(TAG, "Timeout of keyId " + keyId + ", removed from memory!");
+ Log.d(Constants.TAG, "PassphraseCacheService Timeout of keyId " + keyId + ", removed from memory!");
// stop whole service if no cached passphrases remaining
if (mPassphraseCache.size() == 0) {
- Log.d(TAG, "No passphrases remaining in memory, stopping service!");
+ Log.d(Constants.TAG, "PassphraseCacheServic No passphrases remaining in memory, stopping service!");
stopSelf();
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java
index 020b808b9..a56095767 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java
@@ -22,10 +22,10 @@ import java.util.ArrayList;
*/
public class SaveKeyringParcel implements Parcelable {
- // the master key id to be edited
- public final long mMasterKeyId;
- // the key fingerprint, for safety
- public final byte[] mFingerprint;
+ // the master key id to be edited. if this is null, a new one will be created
+ public Long mMasterKeyId;
+ // the key fingerprint, for safety. MUST be null for a new key.
+ public byte[] mFingerprint;
public String newPassphrase;
@@ -38,9 +38,7 @@ public class SaveKeyringParcel implements Parcelable {
public ArrayList<String> revokeUserIds;
public ArrayList<Long> revokeSubKeys;
- public SaveKeyringParcel(long masterKeyId, byte[] fingerprint) {
- mMasterKeyId = masterKeyId;
- mFingerprint = fingerprint;
+ public SaveKeyringParcel() {
addUserIds = new ArrayList<String>();
addSubKeys = new ArrayList<SubkeyAdd>();
changeSubKeys = new ArrayList<SubkeyChange>();
@@ -48,13 +46,19 @@ public class SaveKeyringParcel implements Parcelable {
revokeSubKeys = new ArrayList<Long>();
}
+ public SaveKeyringParcel(long masterKeyId, byte[] fingerprint) {
+ this();
+ mMasterKeyId = masterKeyId;
+ mFingerprint = fingerprint;
+ }
+
// performance gain for using Parcelable here would probably be negligible,
// use Serializable instead.
public static class SubkeyAdd implements Serializable {
- public final int mAlgorithm;
- public final int mKeysize;
- public final int mFlags;
- public final Long mExpiry;
+ public int mAlgorithm;
+ public int mKeysize;
+ public int mFlags;
+ public Long mExpiry;
public SubkeyAdd(int algorithm, int keysize, int flags, Long expiry) {
mAlgorithm = algorithm;
mKeysize = keysize;
@@ -64,9 +68,9 @@ public class SaveKeyringParcel implements Parcelable {
}
public static class SubkeyChange implements Serializable {
- public final long mKeyId;
- public final Integer mFlags;
- public final Long mExpiry;
+ public long mKeyId;
+ public Integer mFlags;
+ public Long mExpiry;
public SubkeyChange(long keyId, Integer flags, Long expiry) {
mKeyId = keyId;
mFlags = flags;
@@ -75,9 +79,11 @@ public class SaveKeyringParcel implements Parcelable {
}
public SaveKeyringParcel(Parcel source) {
- mMasterKeyId = source.readLong();
+ mMasterKeyId = source.readInt() != 0 ? source.readLong() : null;
mFingerprint = source.createByteArray();
+ newPassphrase = source.readString();
+
addUserIds = source.createStringArrayList();
addSubKeys = (ArrayList<SubkeyAdd>) source.readSerializable();
@@ -90,9 +96,14 @@ public class SaveKeyringParcel implements Parcelable {
@Override
public void writeToParcel(Parcel destination, int flags) {
- destination.writeLong(mMasterKeyId);
+ destination.writeInt(mMasterKeyId == null ? 0 : 1);
+ if(mMasterKeyId != null) {
+ destination.writeLong(mMasterKeyId);
+ }
destination.writeByteArray(mFingerprint);
+ destination.writeString(newPassphrase);
+
destination.writeStringList(addUserIds);
destination.writeSerializable(addSubKeys);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java
index 33659f3e5..5d82fca6a 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java
@@ -155,7 +155,7 @@ public class DecryptActivity extends DrawerActivity {
} else if (ACTION_DECRYPT.equals(action) && uri != null) {
mFileFragmentBundle.putParcelable(DecryptFileFragment.ARG_URI, uri);
mSwitchToTab = PAGER_TAB_FILE;
- } else {
+ } else if (ACTION_DECRYPT.equals(action)) {
Log.e(Constants.TAG,
"Include the extra 'text' or an Uri with setData() in your Intent!");
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java
index d734c31db..d80425c3c 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java
@@ -1,6 +1,5 @@
/*
- * Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de>
- * Copyright (C) 2010-2014 Thialfihar <thi@thialfihar.org>
+ * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -18,732 +17,52 @@
package org.sufficientlysecure.keychain.ui;
-import android.app.Activity;
-import android.app.ProgressDialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.os.Messenger;
-import android.support.v4.app.ActivityCompat;
import android.support.v7.app.ActionBarActivity;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.ViewGroup;
-import android.widget.Button;
-import android.widget.CheckBox;
-import android.widget.CompoundButton;
-import android.widget.CompoundButton.OnCheckedChangeListener;
-import android.widget.LinearLayout;
-import android.widget.Toast;
-
-import com.devspark.appmsg.AppMsg;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.helper.ActionBarHelper;
-import org.sufficientlysecure.keychain.helper.ExportHelper;
-import org.sufficientlysecure.keychain.pgp.KeyRing;
-import org.sufficientlysecure.keychain.pgp.PgpConversionHelper;
-import org.sufficientlysecure.keychain.pgp.UncachedSecretKey;
-import org.sufficientlysecure.keychain.pgp.WrappedSecretKey;
-import org.sufficientlysecure.keychain.pgp.WrappedSecretKeyRing;
-import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
-import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
-import org.sufficientlysecure.keychain.provider.ProviderHelper;
-import org.sufficientlysecure.keychain.service.KeychainIntentService;
-import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
-import org.sufficientlysecure.keychain.service.PassphraseCacheService;
-import org.sufficientlysecure.keychain.ui.dialog.CustomAlertDialogBuilder;
-import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment;
-import org.sufficientlysecure.keychain.ui.dialog.SetPassphraseDialogFragment;
-import org.sufficientlysecure.keychain.ui.widget.Editor;
-import org.sufficientlysecure.keychain.ui.widget.Editor.EditorListener;
-import org.sufficientlysecure.keychain.ui.widget.KeyEditor;
-import org.sufficientlysecure.keychain.ui.widget.SectionView;
-import org.sufficientlysecure.keychain.ui.widget.UserIdEditor;
import org.sufficientlysecure.keychain.util.Log;
-import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.List;
-import java.util.Vector;
-
-public class EditKeyActivity extends ActionBarActivity implements EditorListener {
-
- // Actions for internal use only:
- public static final String ACTION_CREATE_KEY = Constants.INTENT_PREFIX + "CREATE_KEY";
- public static final String ACTION_EDIT_KEY = Constants.INTENT_PREFIX + "EDIT_KEY";
-
- // possible extra keys
- public static final String EXTRA_USER_IDS = "user_ids";
- public static final String EXTRA_NO_PASSPHRASE = "no_passphrase";
- public static final String EXTRA_GENERATE_DEFAULT_KEYS = "generate_default_keys";
-
- // EDIT
- private Uri mDataUri;
-
- private SectionView mUserIdsView;
- private SectionView mKeysView;
-
- private String mCurrentPassphrase = null;
- private String mNewPassphrase = null;
- private String mSavedNewPassphrase = null;
- private boolean mIsPassphraseSet;
- private boolean mNeedsSaving;
- private boolean mIsBrandNewKeyring = false;
-
- private Button mChangePassphrase;
-
- private CheckBox mNoPassphrase;
-
- Vector<String> mUserIds;
- Vector<UncachedSecretKey> mKeys;
- Vector<Integer> mKeysUsages;
- boolean mMasterCanSign = true;
-
- ExportHelper mExportHelper;
-
- public boolean needsSaving() {
- mNeedsSaving = (mUserIdsView == null) ? false : mUserIdsView.needsSaving();
- mNeedsSaving |= (mKeysView == null) ? false : mKeysView.needsSaving();
- mNeedsSaving |= hasPassphraseChanged();
- mNeedsSaving |= mIsBrandNewKeyring;
- return mNeedsSaving;
- }
-
-
- public void somethingChanged() {
- ActivityCompat.invalidateOptionsMenu(this);
- }
-
- public void onDeleted(Editor e, boolean wasNewItem) {
- somethingChanged();
- }
+public class EditKeyActivity extends ActionBarActivity {
- public void onEdited() {
- somethingChanged();
- }
+ private EditKeyFragment mEditKeyFragment;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- mExportHelper = new ExportHelper(this);
-
- // Inflate a "Done"/"Cancel" custom action bar view
- ActionBarHelper.setTwoButtonView(getSupportActionBar(),
- R.string.btn_save, R.drawable.ic_action_save,
- new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- // Save
- saveClicked();
- }
- }, R.string.menu_key_edit_cancel, R.drawable.ic_action_cancel,
- new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- // Cancel
- cancelClicked();
- }
- }
- );
-
- mUserIds = new Vector<String>();
- mKeys = new Vector<UncachedSecretKey>();
- mKeysUsages = new Vector<Integer>();
-
- // Catch Intents opened from other apps
- Intent intent = getIntent();
- String action = intent.getAction();
- if (ACTION_CREATE_KEY.equals(action)) {
- handleActionCreateKey(intent);
- } else if (ACTION_EDIT_KEY.equals(action)) {
- handleActionEditKey(intent);
- }
- }
-
- /**
- * Handle intent action to create new key
- *
- * @param intent
- */
- private void handleActionCreateKey(Intent intent) {
- Bundle extras = intent.getExtras();
-
- mCurrentPassphrase = "";
- mIsBrandNewKeyring = true;
-
- if (extras != null) {
- // if userId is given, prefill the fields
- if (extras.containsKey(EXTRA_USER_IDS)) {
- Log.d(Constants.TAG, "UserIds are given!");
- mUserIds.add(extras.getString(EXTRA_USER_IDS));
- }
-
- // if no passphrase is given
- if (extras.containsKey(EXTRA_NO_PASSPHRASE)) {
- boolean noPassphrase = extras.getBoolean(EXTRA_NO_PASSPHRASE);
- if (noPassphrase) {
- // check "no passphrase" checkbox and remove button
- mNoPassphrase.setChecked(true);
- mChangePassphrase.setVisibility(View.GONE);
- }
- }
-
- // generate key
- if (extras.containsKey(EXTRA_GENERATE_DEFAULT_KEYS)) {
- /*
- boolean generateDefaultKeys = extras.getBoolean(EXTRA_GENERATE_DEFAULT_KEYS);
- if (generateDefaultKeys) {
-
- // fill values for this action
- Bundle data = new Bundle();
- data.putString(KeychainIntentService.GENERATE_KEY_SYMMETRIC_PASSPHRASE,
- mCurrentPassphrase);
-
- serviceIntent.putExtra(KeychainIntentService.EXTRA_DATA, data);
-
- // Message is received after generating is done in KeychainIntentService
- KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(
- this, getResources().getQuantityString(R.plurals.progress_generating, 1),
- ProgressDialog.STYLE_HORIZONTAL, true,
-
- new DialogInterface.OnCancelListener() {
- @Override
- public void onCancel(DialogInterface dialog) {
- // Stop key generation on cancel
- stopService(serviceIntent);
- EditKeyActivity.this.setResult(Activity.RESULT_CANCELED);
- EditKeyActivity.this.finish();
- }
- }) {
-
- @Override
- public void handleMessage(Message message) {
- // handle messages by standard KeychainIntentServiceHandler first
- super.handleMessage(message);
-
- if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
- // get new key from data bundle returned from service
- Bundle data = message.getData();
-
- ArrayList<UncachedSecretKey> newKeys =
- PgpConversionHelper.BytesToPGPSecretKeyList(data
- .getByteArray(KeychainIntentService.RESULT_NEW_KEY));
-
- ArrayList<Integer> keyUsageFlags = data.getIntegerArrayList(
- KeychainIntentService.RESULT_KEY_USAGES);
-
- if (newKeys.size() == keyUsageFlags.size()) {
- for (int i = 0; i < newKeys.size(); ++i) {
- mKeys.add(newKeys.get(i));
- mKeysUsages.add(keyUsageFlags.get(i));
- }
- }
-
- buildLayout(true);
- }
- }
- };
-
- // Create a new Messenger for the communication back
- Messenger messenger = new Messenger(saveHandler);
- serviceIntent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger);
-
- saveHandler.showProgressDialog(this);
-
- // start service with intent
- startService(serviceIntent);
- }
- */
- }
- } else {
- buildLayout(false);
- }
- }
-
- /**
- * Handle intent action to edit existing key
- *
- * @param intent
- */
- private void handleActionEditKey(Intent intent) {
- mDataUri = intent.getData();
- if (mDataUri == null) {
- Log.e(Constants.TAG, "Intent data missing. Should be Uri of key!");
- finish();
- } else {
- Log.d(Constants.TAG, "uri: " + mDataUri);
-
- try {
- Uri secretUri = KeyRings.buildUnifiedKeyRingUri(mDataUri);
- WrappedSecretKeyRing keyRing = new ProviderHelper(this).getWrappedSecretKeyRing(secretUri);
-
- mMasterCanSign = keyRing.getSubKey().canCertify();
- for (WrappedSecretKey key : keyRing.secretKeyIterator()) {
- // Turn into uncached instance
- mKeys.add(key.getUncached());
- mKeysUsages.add(key.getKeyUsage()); // get usage when view is created
- }
-
- boolean isSet = false;
- for (String userId : keyRing.getSubKey().getUserIds()) {
- Log.d(Constants.TAG, "Added userId " + userId);
- if (!isSet) {
- isSet = true;
- String[] parts = KeyRing.splitUserId(userId);
- if (parts[0] != null) {
- setTitle(parts[0]);
- }
- }
- mUserIds.add(userId);
- }
-
- buildLayout(false);
-
- mCurrentPassphrase = "";
- mIsPassphraseSet = keyRing.hasPassphrase();
- if (!mIsPassphraseSet) {
- // check "no passphrase" checkbox and remove button
- mNoPassphrase.setChecked(true);
- mChangePassphrase.setVisibility(View.GONE);
- }
-
- } catch (ProviderHelper.NotFoundException e) {
- Log.e(Constants.TAG, "Keyring not found: " + e.getMessage(), e);
- Toast.makeText(this, R.string.error_no_secret_key_found, Toast.LENGTH_SHORT).show();
- finish();
- }
-
- }
- }
-
- /**
- * Shows the dialog to set a new passphrase
- */
- private void showSetPassphraseDialog() {
- // Message is received after passphrase is cached
- Handler returnHandler = new Handler() {
- @Override
- public void handleMessage(Message message) {
- if (message.what == SetPassphraseDialogFragment.MESSAGE_OKAY) {
- Bundle data = message.getData();
-
- // set new returned passphrase!
- mNewPassphrase = data
- .getString(SetPassphraseDialogFragment.MESSAGE_NEW_PASSPHRASE);
-
- updatePassphraseButtonText();
- somethingChanged();
- }
- }
- };
-
- // Create a new Messenger for the communication back
- Messenger messenger = new Messenger(returnHandler);
-
- // set title based on isPassphraseSet()
- int title;
- if (isPassphraseSet()) {
- title = R.string.title_change_passphrase;
- } else {
- title = R.string.title_set_passphrase;
- }
-
- SetPassphraseDialogFragment setPassphraseDialog = SetPassphraseDialogFragment.newInstance(
- messenger, title);
-
- setPassphraseDialog.show(getSupportFragmentManager(), "setPassphraseDialog");
- }
-
- /**
- * Build layout based on mUserId, mKeys and mKeysUsages Vectors. It creates Views for every user
- * id and key.
- *
- * @param newKeys
- */
- private void buildLayout(boolean newKeys) {
- setContentView(R.layout.edit_key_activity);
-
- // find views
- mChangePassphrase = (Button) findViewById(R.id.edit_key_btn_change_passphrase);
- mNoPassphrase = (CheckBox) findViewById(R.id.edit_key_no_passphrase);
- // Build layout based on given userIds and keys
-
- LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-
- LinearLayout container = (LinearLayout) findViewById(R.id.edit_key_container);
- if (mIsPassphraseSet) {
- mChangePassphrase.setText(getString(R.string.btn_change_passphrase));
- }
- mUserIdsView = (SectionView) inflater.inflate(R.layout.edit_key_section, container, false);
- mUserIdsView.setType(SectionView.TYPE_USER_ID);
- mUserIdsView.setCanBeEdited(mMasterCanSign);
- mUserIdsView.setUserIds(mUserIds);
- mUserIdsView.setEditorListener(this);
- container.addView(mUserIdsView);
- mKeysView = (SectionView) inflater.inflate(R.layout.edit_key_section, container, false);
- mKeysView.setType(SectionView.TYPE_KEY);
- mKeysView.setCanBeEdited(mMasterCanSign);
- mKeysView.setKeys(mKeys, mKeysUsages, newKeys);
- mKeysView.setEditorListener(this);
- container.addView(mKeysView);
-
- updatePassphraseButtonText();
-
- mChangePassphrase.setOnClickListener(new OnClickListener() {
- public void onClick(View v) {
- showSetPassphraseDialog();
- }
- });
+ setContentView(R.layout.edit_key_activity_new);
- // disable passphrase when no passphrase checkbox is checked!
- mNoPassphrase.setOnCheckedChangeListener(new OnCheckedChangeListener() {
-
- @Override
- public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
- if (isChecked) {
- // remove passphrase
- mSavedNewPassphrase = mNewPassphrase;
- mNewPassphrase = "";
- mChangePassphrase.setVisibility(View.GONE);
- } else {
- mNewPassphrase = mSavedNewPassphrase;
- mChangePassphrase.setVisibility(View.VISIBLE);
- }
- somethingChanged();
- }
- });
- }
-
- private long getMasterKeyId() {
- if (mKeysView.getEditors().getChildCount() == 0) {
- return 0;
- }
- return ((KeyEditor) mKeysView.getEditors().getChildAt(0)).getValue().getKeyId();
- }
-
- public boolean isPassphraseSet() {
- if (mNoPassphrase.isChecked()) {
- return true;
- } else if ((mIsPassphraseSet)
- || (mNewPassphrase != null && !mNewPassphrase.equals(""))) {
- return true;
- } else {
- return false;
- }
- }
-
- public boolean hasPassphraseChanged() {
- if (mNoPassphrase != null) {
- if (mNoPassphrase.isChecked()) {
- return mIsPassphraseSet;
- } else {
- return (mNewPassphrase != null && !mNewPassphrase.equals(""));
- }
- } else {
- return false;
- }
- }
-
- private void saveClicked() {
- final long masterKeyId = getMasterKeyId();
- if (needsSaving()) { //make sure, as some versions don't support invalidateOptionsMenu
- try {
- if (!isPassphraseSet()) {
- throw new PgpGeneralException(this.getString(R.string.set_a_passphrase));
- }
-
- String passphrase;
- if (mIsPassphraseSet) {
- passphrase = PassphraseCacheService.getCachedPassphrase(this, masterKeyId);
- } else {
- passphrase = "";
- }
- if (passphrase == null) {
- PassphraseDialogFragment.show(this, masterKeyId,
- new Handler() {
- @Override
- public void handleMessage(Message message) {
- if (message.what == PassphraseDialogFragment.MESSAGE_OKAY) {
- mCurrentPassphrase = PassphraseCacheService.getCachedPassphrase(
- EditKeyActivity.this, masterKeyId);
- checkEmptyIDsWanted();
- }
- }
- });
- } else {
- mCurrentPassphrase = passphrase;
- checkEmptyIDsWanted();
- }
- } catch (PgpGeneralException e) {
- AppMsg.makeText(this, getString(R.string.error_message, e.getMessage()),
- AppMsg.STYLE_ALERT).show();
- }
- } else {
- AppMsg.makeText(this, R.string.error_change_something_first, AppMsg.STYLE_ALERT).show();
- }
- }
-
- private void checkEmptyIDsWanted() {
- try {
- ArrayList<String> userIDs = getUserIds(mUserIdsView);
- List<Boolean> newIDs = mUserIdsView.getNewIDFlags();
- ArrayList<String> originalIDs = mUserIdsView.getOriginalIDs();
- int curID = 0;
- for (String userID : userIDs) {
- if (userID.equals("") && (!userID.equals(originalIDs.get(curID)) || newIDs.get(curID))) {
- CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(
- EditKeyActivity.this);
-
- alert.setIcon(R.drawable.ic_dialog_alert_holo_light);
- alert.setTitle(R.string.warning);
- alert.setMessage(EditKeyActivity.this.getString(R.string.ask_empty_id_ok));
-
- alert.setPositiveButton(EditKeyActivity.this.getString(android.R.string.yes),
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int id) {
- dialog.dismiss();
- finallySaveClicked();
- }
- }
- );
- alert.setNegativeButton(this.getString(android.R.string.no),
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int id) {
- dialog.dismiss();
- }
- }
- );
- alert.setCancelable(false);
- alert.show();
- return;
- }
- curID++;
- }
- } catch (PgpGeneralException e) {
- Log.e(Constants.TAG, getString(R.string.error_message, e.getMessage()));
- AppMsg.makeText(this, getString(R.string.error_message, e.getMessage()), AppMsg.STYLE_ALERT).show();
- }
- finallySaveClicked();
- }
-
- private boolean[] toPrimitiveArray(final List<Boolean> booleanList) {
- final boolean[] primitives = new boolean[booleanList.size()];
- int index = 0;
- for (Boolean object : booleanList) {
- primitives[index++] = object;
- }
- return primitives;
- }
-
- private void finallySaveClicked() {
- /*
- try {
- // Send all information needed to service to edit key in other thread
- Intent intent = new Intent(this, KeychainIntentService.class);
-
- intent.setAction(KeychainIntentService.ACTION_SAVE_KEYRING);
-
- OldSaveKeyringParcel saveParams = new OldSaveKeyringParcel();
- saveParams.userIds = getUserIds(mUserIdsView);
- saveParams.originalIDs = mUserIdsView.getOriginalIDs();
- saveParams.deletedIDs = mUserIdsView.getDeletedIDs();
- saveParams.newIDs = toPrimitiveArray(mUserIdsView.getNewIDFlags());
- saveParams.primaryIDChanged = mUserIdsView.primaryChanged();
- saveParams.moddedKeys = toPrimitiveArray(mKeysView.getNeedsSavingArray());
- saveParams.deletedKeys = mKeysView.getDeletedKeys();
- saveParams.keysExpiryDates = getKeysExpiryDates(mKeysView);
- saveParams.keysUsages = getKeysUsages(mKeysView);
- saveParams.newPassphrase = mNewPassphrase;
- saveParams.oldPassphrase = mCurrentPassphrase;
- saveParams.newKeys = toPrimitiveArray(mKeysView.getNewKeysArray());
- saveParams.keys = getKeys(mKeysView);
- saveParams.originalPrimaryID = mUserIdsView.getOriginalPrimaryID();
-
- // fill values for this action
- Bundle data = new Bundle();
- data.putBoolean(KeychainIntentService.SAVE_KEYRING_CAN_SIGN, mMasterCanSign);
- data.putParcelable(KeychainIntentService.SAVE_KEYRING_PARCEL, saveParams);
-
- intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
-
- // Message is received after saving is done in KeychainIntentService
- KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(this,
- getString(R.string.progress_saving), ProgressDialog.STYLE_HORIZONTAL) {
- public void handleMessage(Message message) {
- // handle messages by standard KeychainIntentServiceHandler first
- super.handleMessage(message);
-
- if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
- Intent data = new Intent();
-
- // return uri pointing to new created key
- Uri uri = KeyRings.buildGenericKeyRingUri(getMasterKeyId());
- data.setData(uri);
-
- setResult(RESULT_OK, data);
- finish();
- }
- }
- };
-
- // Create a new Messenger for the communication back
- Messenger messenger = new Messenger(saveHandler);
- intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger);
-
- saveHandler.showProgressDialog(this);
-
- // start service with intent
- startService(intent);
- } catch (PgpGeneralException e) {
- Log.e(Constants.TAG, getString(R.string.error_message, e.getMessage()));
- AppMsg.makeText(this, getString(R.string.error_message, e.getMessage()),
- AppMsg.STYLE_ALERT).show();
- }
- */
- }
-
- private void cancelClicked() {
- if (needsSaving()) { //ask if we want to save
- CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(
- EditKeyActivity.this);
-
- alert.setIcon(R.drawable.ic_dialog_alert_holo_light);
- alert.setTitle(R.string.warning);
- alert.setMessage(EditKeyActivity.this.getString(R.string.ask_save_changed_key));
-
- alert.setPositiveButton(EditKeyActivity.this.getString(android.R.string.yes),
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int id) {
- dialog.dismiss();
- saveClicked();
- }
- });
- alert.setNegativeButton(this.getString(android.R.string.no),
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int id) {
- dialog.dismiss();
- setResult(RESULT_CANCELED);
- finish();
- }
- });
- alert.setCancelable(false);
- alert.show();
- } else {
- setResult(RESULT_CANCELED);
+ Uri dataUri = getIntent().getData();
+ if (dataUri == null) {
+ Log.e(Constants.TAG, "Data missing. Should be Uri of key!");
finish();
- }
- }
-
- /**
- * Returns user ids from the SectionView
- *
- * @param userIdsView
- * @return
- */
- private ArrayList<String> getUserIds(SectionView userIdsView) throws PgpGeneralException {
- ArrayList<String> userIds = new ArrayList<String>();
-
- ViewGroup userIdEditors = userIdsView.getEditors();
-
- boolean gotMainUserId = false;
- for (int i = 0; i < userIdEditors.getChildCount(); ++i) {
- UserIdEditor editor = (UserIdEditor) userIdEditors.getChildAt(i);
- String userId;
- userId = editor.getValue();
-
- if (editor.isMainUserId()) {
- userIds.add(0, userId);
- gotMainUserId = true;
- } else {
- userIds.add(userId);
- }
- }
-
- if (userIds.size() == 0) {
- throw new PgpGeneralException(getString(R.string.error_key_needs_a_user_id));
- }
-
- if (!gotMainUserId) {
- throw new PgpGeneralException(getString(R.string.error_main_user_id_must_not_be_empty));
+ return;
}
- return userIds;
+ loadFragment(savedInstanceState, dataUri);
}
- /**
- * Returns keys from the SectionView
- *
- * @param keysView
- * @return
- */
- private ArrayList<UncachedSecretKey> getKeys(SectionView keysView) throws PgpGeneralException {
- ArrayList<UncachedSecretKey> keys = new ArrayList<UncachedSecretKey>();
-
- ViewGroup keyEditors = keysView.getEditors();
-
- if (keyEditors.getChildCount() == 0) {
- throw new PgpGeneralException(getString(R.string.error_key_needs_master_key));
- }
-
- for (int i = 0; i < keyEditors.getChildCount(); ++i) {
- KeyEditor editor = (KeyEditor) keyEditors.getChildAt(i);
- keys.add(editor.getValue());
+ private void loadFragment(Bundle savedInstanceState, Uri dataUri) {
+ // However, if we're being restored from a previous state,
+ // then we don't need to do anything and should return or else
+ // we could end up with overlapping fragments.
+ if (savedInstanceState != null) {
+ return;
}
- return keys;
- }
-
- /**
- * Returns usage selections of keys from the SectionView
- *
- * @param keysView
- * @return
- */
- private ArrayList<Integer> getKeysUsages(SectionView keysView) throws PgpGeneralException {
- ArrayList<Integer> keysUsages = new ArrayList<Integer>();
-
- ViewGroup keyEditors = keysView.getEditors();
-
- if (keyEditors.getChildCount() == 0) {
- throw new PgpGeneralException(getString(R.string.error_key_needs_master_key));
- }
-
- for (int i = 0; i < keyEditors.getChildCount(); ++i) {
- KeyEditor editor = (KeyEditor) keyEditors.getChildAt(i);
- keysUsages.add(editor.getUsage());
- }
-
- return keysUsages;
- }
-
- private ArrayList<Calendar> getKeysExpiryDates(SectionView keysView) throws PgpGeneralException {
- ArrayList<Calendar> keysExpiryDates = new ArrayList<Calendar>();
-
- ViewGroup keyEditors = keysView.getEditors();
-
- if (keyEditors.getChildCount() == 0) {
- throw new PgpGeneralException(getString(R.string.error_key_needs_master_key));
- }
-
- for (int i = 0; i < keyEditors.getChildCount(); ++i) {
- KeyEditor editor = (KeyEditor) keyEditors.getChildAt(i);
- keysExpiryDates.add(editor.getExpiryDate());
- }
-
- return keysExpiryDates;
- }
+ // Create an instance of the fragment
+ mEditKeyFragment = EditKeyFragment.newInstance(dataUri);
- private void updatePassphraseButtonText() {
- mChangePassphrase.setText(isPassphraseSet() ? getString(R.string.btn_change_passphrase)
- : getString(R.string.btn_set_passphrase));
+ // Add the fragment to the 'fragment_container' FrameLayout
+ // NOTE: We use commitAllowingStateLoss() to prevent weird crashes!
+ getSupportFragmentManager().beginTransaction()
+ .replace(R.id.edit_key_fragment_container, mEditKeyFragment)
+ .commitAllowingStateLoss();
+ // do it immediately!
+ getSupportFragmentManager().executePendingTransactions();
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivityNew.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivityNew.java
deleted file mode 100644
index b45e8a6bb..000000000
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivityNew.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package org.sufficientlysecure.keychain.ui;
-
-import android.net.Uri;
-import android.os.Bundle;
-import android.support.v7.app.ActionBarActivity;
-
-import org.sufficientlysecure.keychain.Constants;
-import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.util.Log;
-
-public class EditKeyActivityNew extends ActionBarActivity {
-
- private EditKeyFragment mEditKeyFragment;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- setContentView(R.layout.edit_key_activity_new);
-
- Uri dataUri = getIntent().getData();
- if (dataUri == null) {
- Log.e(Constants.TAG, "Data missing. Should be Uri of key!");
- finish();
- return;
- }
-
- loadFragment(savedInstanceState, dataUri);
- }
-
- private void loadFragment(Bundle savedInstanceState, Uri dataUri) {
- // However, if we're being restored from a previous state,
- // then we don't need to do anything and should return or else
- // we could end up with overlapping fragments.
- if (savedInstanceState != null) {
- return;
- }
-
- // Create an instance of the fragment
- mEditKeyFragment = EditKeyFragment.newInstance(dataUri);
-
- // Add the fragment to the 'fragment_container' FrameLayout
- // NOTE: We use commitAllowingStateLoss() to prevent weird crashes!
- getSupportFragmentManager().beginTransaction()
- .replace(R.id.edit_key_fragment_container, mEditKeyFragment)
- .commitAllowingStateLoss();
- // do it immediately!
- getSupportFragmentManager().executePendingTransactions();
- }
-
-}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivityOld.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivityOld.java
new file mode 100644
index 000000000..51457cd45
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivityOld.java
@@ -0,0 +1,744 @@
+/*
+ * Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2010-2014 Thialfihar <thi@thialfihar.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package org.sufficientlysecure.keychain.ui;
+
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.os.Messenger;
+import android.support.v4.app.ActivityCompat;
+import android.support.v7.app.ActionBarActivity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.CheckBox;
+import android.widget.CompoundButton;
+import android.widget.CompoundButton.OnCheckedChangeListener;
+import android.widget.LinearLayout;
+import android.widget.Toast;
+
+import com.devspark.appmsg.AppMsg;
+
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.helper.ActionBarHelper;
+import org.sufficientlysecure.keychain.helper.ExportHelper;
+import org.sufficientlysecure.keychain.pgp.KeyRing;
+import org.sufficientlysecure.keychain.pgp.UncachedSecretKey;
+import org.sufficientlysecure.keychain.pgp.WrappedSecretKey;
+import org.sufficientlysecure.keychain.pgp.WrappedSecretKeyRing;
+import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
+import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
+import org.sufficientlysecure.keychain.provider.ProviderHelper;
+import org.sufficientlysecure.keychain.service.PassphraseCacheService;
+import org.sufficientlysecure.keychain.ui.dialog.CustomAlertDialogBuilder;
+import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment;
+import org.sufficientlysecure.keychain.ui.dialog.SetPassphraseDialogFragment;
+import org.sufficientlysecure.keychain.ui.widget.Editor;
+import org.sufficientlysecure.keychain.ui.widget.Editor.EditorListener;
+import org.sufficientlysecure.keychain.ui.widget.KeyEditor;
+import org.sufficientlysecure.keychain.ui.widget.SectionView;
+import org.sufficientlysecure.keychain.ui.widget.UserIdEditor;
+import org.sufficientlysecure.keychain.util.Log;
+
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.List;
+import java.util.Vector;
+
+public class EditKeyActivityOld extends ActionBarActivity implements EditorListener {
+
+ // Actions for internal use only:
+ public static final String ACTION_CREATE_KEY = Constants.INTENT_PREFIX + "CREATE_KEY";
+ public static final String ACTION_EDIT_KEY = Constants.INTENT_PREFIX + "EDIT_KEY";
+
+ // possible extra keys
+ public static final String EXTRA_USER_IDS = "user_ids";
+ public static final String EXTRA_NO_PASSPHRASE = "no_passphrase";
+ public static final String EXTRA_GENERATE_DEFAULT_KEYS = "generate_default_keys";
+
+ // EDIT
+ private Uri mDataUri;
+
+ private SectionView mUserIdsView;
+ private SectionView mKeysView;
+
+ private String mCurrentPassphrase = null;
+ private String mNewPassphrase = null;
+ private String mSavedNewPassphrase = null;
+ private boolean mIsPassphraseSet;
+ private boolean mNeedsSaving;
+ private boolean mIsBrandNewKeyring = false;
+
+ private Button mChangePassphrase;
+
+ private CheckBox mNoPassphrase;
+
+ Vector<String> mUserIds;
+ Vector<UncachedSecretKey> mKeys;
+ Vector<Integer> mKeysUsages;
+ boolean mMasterCanSign = true;
+
+ ExportHelper mExportHelper;
+
+ public boolean needsSaving() {
+ mNeedsSaving = (mUserIdsView == null) ? false : mUserIdsView.needsSaving();
+ mNeedsSaving |= (mKeysView == null) ? false : mKeysView.needsSaving();
+ mNeedsSaving |= hasPassphraseChanged();
+ mNeedsSaving |= mIsBrandNewKeyring;
+ return mNeedsSaving;
+ }
+
+
+ public void somethingChanged() {
+ ActivityCompat.invalidateOptionsMenu(this);
+ }
+
+ public void onDeleted(Editor e, boolean wasNewItem) {
+ somethingChanged();
+ }
+
+ public void onEdited() {
+ somethingChanged();
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mExportHelper = new ExportHelper(this);
+
+ // Inflate a "Done"/"Cancel" custom action bar view
+ ActionBarHelper.setTwoButtonView(getSupportActionBar(),
+ R.string.btn_save, R.drawable.ic_action_save,
+ new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ // Save
+ saveClicked();
+ }
+ }, R.string.menu_key_edit_cancel, R.drawable.ic_action_cancel,
+ new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ // Cancel
+ cancelClicked();
+ }
+ }
+ );
+
+ mUserIds = new Vector<String>();
+ mKeys = new Vector<UncachedSecretKey>();
+ mKeysUsages = new Vector<Integer>();
+
+ // Catch Intents opened from other apps
+ Intent intent = getIntent();
+ String action = intent.getAction();
+ if (ACTION_CREATE_KEY.equals(action)) {
+ handleActionCreateKey(intent);
+ } else if (ACTION_EDIT_KEY.equals(action)) {
+ handleActionEditKey(intent);
+ }
+ }
+
+ /**
+ * Handle intent action to create new key
+ *
+ * @param intent
+ */
+ private void handleActionCreateKey(Intent intent) {
+ Bundle extras = intent.getExtras();
+
+ mCurrentPassphrase = "";
+ mIsBrandNewKeyring = true;
+
+ if (extras != null) {
+ // if userId is given, prefill the fields
+ if (extras.containsKey(EXTRA_USER_IDS)) {
+ Log.d(Constants.TAG, "UserIds are given!");
+ mUserIds.add(extras.getString(EXTRA_USER_IDS));
+ }
+
+ // if no passphrase is given
+ if (extras.containsKey(EXTRA_NO_PASSPHRASE)) {
+ boolean noPassphrase = extras.getBoolean(EXTRA_NO_PASSPHRASE);
+ if (noPassphrase) {
+ // check "no passphrase" checkbox and remove button
+ mNoPassphrase.setChecked(true);
+ mChangePassphrase.setVisibility(View.GONE);
+ }
+ }
+
+ // generate key
+ if (extras.containsKey(EXTRA_GENERATE_DEFAULT_KEYS)) {
+ /*
+ boolean generateDefaultKeys = extras.getBoolean(EXTRA_GENERATE_DEFAULT_KEYS);
+ if (generateDefaultKeys) {
+
+ // fill values for this action
+ Bundle data = new Bundle();
+ data.putString(KeychainIntentService.GENERATE_KEY_SYMMETRIC_PASSPHRASE,
+ mCurrentPassphrase);
+
+ serviceIntent.putExtra(KeychainIntentService.EXTRA_DATA, data);
+
+ // Message is received after generating is done in KeychainIntentService
+ KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(
+ this, getResources().getQuantityString(R.plurals.progress_generating, 1),
+ ProgressDialog.STYLE_HORIZONTAL, true,
+
+ new DialogInterface.OnCancelListener() {
+ @Override
+ public void onCancel(DialogInterface dialog) {
+ // Stop key generation on cancel
+ stopService(serviceIntent);
+ EditKeyActivity.this.setResult(Activity.RESULT_CANCELED);
+ EditKeyActivity.this.finish();
+ }
+ }) {
+
+ @Override
+ public void handleMessage(Message message) {
+ // handle messages by standard KeychainIntentServiceHandler first
+ super.handleMessage(message);
+
+ if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
+ // get new key from data bundle returned from service
+ Bundle data = message.getDataAsStringList();
+
+ ArrayList<UncachedSecretKey> newKeys =
+ PgpConversionHelper.BytesToPGPSecretKeyList(data
+ .getByteArray(KeychainIntentService.RESULT_NEW_KEY));
+
+ ArrayList<Integer> keyUsageFlags = data.getIntegerArrayList(
+ KeychainIntentService.RESULT_KEY_USAGES);
+
+ if (newKeys.size() == keyUsageFlags.size()) {
+ for (int i = 0; i < newKeys.size(); ++i) {
+ mKeys.add(newKeys.get(i));
+ mKeysUsages.add(keyUsageFlags.get(i));
+ }
+ }
+
+ buildLayout(true);
+ }
+ }
+ };
+
+ // Create a new Messenger for the communication back
+ Messenger messenger = new Messenger(saveHandler);
+ serviceIntent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger);
+
+ saveHandler.showProgressDialog(this);
+
+ // start service with intent
+ startService(serviceIntent);
+ }
+ */
+ }
+ } else {
+ buildLayout(false);
+ }
+ }
+
+ /**
+ * Handle intent action to edit existing key
+ *
+ * @param intent
+ */
+ private void handleActionEditKey(Intent intent) {
+ mDataUri = intent.getData();
+ if (mDataUri == null) {
+ Log.e(Constants.TAG, "Intent data missing. Should be Uri of key!");
+ finish();
+ } else {
+ Log.d(Constants.TAG, "uri: " + mDataUri);
+
+ try {
+ Uri secretUri = KeyRings.buildUnifiedKeyRingUri(mDataUri);
+ WrappedSecretKeyRing keyRing = new ProviderHelper(this).getWrappedSecretKeyRing(secretUri);
+
+ mMasterCanSign = keyRing.getSubKey().canCertify();
+ for (WrappedSecretKey key : keyRing.secretKeyIterator()) {
+ // Turn into uncached instance
+ mKeys.add(key.getUncached());
+ mKeysUsages.add(key.getKeyUsage()); // get usage when view is created
+ }
+
+ boolean isSet = false;
+ for (String userId : keyRing.getSubKey().getUserIds()) {
+ Log.d(Constants.TAG, "Added userId " + userId);
+ if (!isSet) {
+ isSet = true;
+ String[] parts = KeyRing.splitUserId(userId);
+ if (parts[0] != null) {
+ setTitle(parts[0]);
+ }
+ }
+ mUserIds.add(userId);
+ }
+
+ buildLayout(false);
+
+ mCurrentPassphrase = "";
+ mIsPassphraseSet = keyRing.hasPassphrase();
+ if (!mIsPassphraseSet) {
+ // check "no passphrase" checkbox and remove button
+ mNoPassphrase.setChecked(true);
+ mChangePassphrase.setVisibility(View.GONE);
+ }
+
+ } catch (ProviderHelper.NotFoundException e) {
+ Log.e(Constants.TAG, "Keyring not found: " + e.getMessage(), e);
+ Toast.makeText(this, R.string.error_no_secret_key_found, Toast.LENGTH_SHORT).show();
+ finish();
+ }
+
+ }
+ }
+
+ /**
+ * Shows the dialog to set a new passphrase
+ */
+ private void showSetPassphraseDialog() {
+ // Message is received after passphrase is cached
+ Handler returnHandler = new Handler() {
+ @Override
+ public void handleMessage(Message message) {
+ if (message.what == SetPassphraseDialogFragment.MESSAGE_OKAY) {
+ Bundle data = message.getData();
+
+ // set new returned passphrase!
+ mNewPassphrase = data
+ .getString(SetPassphraseDialogFragment.MESSAGE_NEW_PASSPHRASE);
+
+ updatePassphraseButtonText();
+ somethingChanged();
+ }
+ }
+ };
+
+ // Create a new Messenger for the communication back
+ Messenger messenger = new Messenger(returnHandler);
+
+ // set title based on isPassphraseSet()
+ int title;
+ if (isPassphraseSet()) {
+ title = R.string.title_change_passphrase;
+ } else {
+ title = R.string.title_set_passphrase;
+ }
+
+ SetPassphraseDialogFragment setPassphraseDialog = SetPassphraseDialogFragment.newInstance(
+ messenger, null, title);
+
+ setPassphraseDialog.show(getSupportFragmentManager(), "setPassphraseDialog");
+ }
+
+ /**
+ * Build layout based on mUserId, mKeys and mKeysUsages Vectors. It creates Views for every user
+ * id and key.
+ *
+ * @param newKeys
+ */
+ private void buildLayout(boolean newKeys) {
+ setContentView(R.layout.edit_key_activity);
+
+ // find views
+ mChangePassphrase = (Button) findViewById(R.id.edit_key_btn_change_passphrase);
+ mNoPassphrase = (CheckBox) findViewById(R.id.edit_key_no_passphrase);
+ // Build layout based on given userIds and keys
+
+ LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+ LinearLayout container = (LinearLayout) findViewById(R.id.edit_key_container);
+ if (mIsPassphraseSet) {
+ mChangePassphrase.setText(getString(R.string.btn_change_passphrase));
+ }
+ mUserIdsView = (SectionView) inflater.inflate(R.layout.edit_key_section, container, false);
+ mUserIdsView.setType(SectionView.TYPE_USER_ID);
+ mUserIdsView.setCanBeEdited(mMasterCanSign);
+ mUserIdsView.setUserIds(mUserIds);
+ mUserIdsView.setEditorListener(this);
+ container.addView(mUserIdsView);
+ mKeysView = (SectionView) inflater.inflate(R.layout.edit_key_section, container, false);
+ mKeysView.setType(SectionView.TYPE_KEY);
+ mKeysView.setCanBeEdited(mMasterCanSign);
+ mKeysView.setKeys(mKeys, mKeysUsages, newKeys);
+ mKeysView.setEditorListener(this);
+ container.addView(mKeysView);
+
+ updatePassphraseButtonText();
+
+ mChangePassphrase.setOnClickListener(new OnClickListener() {
+ public void onClick(View v) {
+ showSetPassphraseDialog();
+ }
+ });
+
+ // disable passphrase when no passphrase checkbox is checked!
+ mNoPassphrase.setOnCheckedChangeListener(new OnCheckedChangeListener() {
+
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ if (isChecked) {
+ // remove passphrase
+ mSavedNewPassphrase = mNewPassphrase;
+ mNewPassphrase = "";
+ mChangePassphrase.setVisibility(View.GONE);
+ } else {
+ mNewPassphrase = mSavedNewPassphrase;
+ mChangePassphrase.setVisibility(View.VISIBLE);
+ }
+ somethingChanged();
+ }
+ });
+ }
+
+ private long getMasterKeyId() {
+ if (mKeysView.getEditors().getChildCount() == 0) {
+ return 0;
+ }
+ return ((KeyEditor) mKeysView.getEditors().getChildAt(0)).getValue().getKeyId();
+ }
+
+ public boolean isPassphraseSet() {
+ if (mNoPassphrase.isChecked()) {
+ return true;
+ } else if ((mIsPassphraseSet)
+ || (mNewPassphrase != null && !mNewPassphrase.equals(""))) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public boolean hasPassphraseChanged() {
+ if (mNoPassphrase != null) {
+ if (mNoPassphrase.isChecked()) {
+ return mIsPassphraseSet;
+ } else {
+ return (mNewPassphrase != null && !mNewPassphrase.equals(""));
+ }
+ } else {
+ return false;
+ }
+ }
+
+ private void saveClicked() {
+ final long masterKeyId = getMasterKeyId();
+ if (needsSaving()) { //make sure, as some versions don't support invalidateOptionsMenu
+ try {
+ if (!isPassphraseSet()) {
+ throw new PgpGeneralException(this.getString(R.string.set_a_passphrase));
+ }
+
+ String passphrase;
+ if (mIsPassphraseSet) {
+ passphrase = PassphraseCacheService.getCachedPassphrase(this, masterKeyId);
+ } else {
+ passphrase = "";
+ }
+ if (passphrase == null) {
+ PassphraseDialogFragment.show(this, masterKeyId,
+ new Handler() {
+ @Override
+ public void handleMessage(Message message) {
+ if (message.what == PassphraseDialogFragment.MESSAGE_OKAY) {
+ mCurrentPassphrase = PassphraseCacheService.getCachedPassphrase(
+ EditKeyActivityOld.this, masterKeyId);
+ checkEmptyIDsWanted();
+ }
+ }
+ });
+ } else {
+ mCurrentPassphrase = passphrase;
+ checkEmptyIDsWanted();
+ }
+ } catch (PgpGeneralException e) {
+ AppMsg.makeText(this, getString(R.string.error_message, e.getMessage()),
+ AppMsg.STYLE_ALERT).show();
+ }
+ } else {
+ AppMsg.makeText(this, R.string.error_change_something_first, AppMsg.STYLE_ALERT).show();
+ }
+ }
+
+ private void checkEmptyIDsWanted() {
+ try {
+ ArrayList<String> userIDs = getUserIds(mUserIdsView);
+ List<Boolean> newIDs = mUserIdsView.getNewIDFlags();
+ ArrayList<String> originalIDs = mUserIdsView.getOriginalIDs();
+ int curID = 0;
+ for (String userID : userIDs) {
+ if (userID.equals("") && (!userID.equals(originalIDs.get(curID)) || newIDs.get(curID))) {
+ CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(
+ EditKeyActivityOld.this);
+
+ alert.setIcon(R.drawable.ic_dialog_alert_holo_light);
+ alert.setTitle(R.string.warning);
+ alert.setMessage(EditKeyActivityOld.this.getString(R.string.ask_empty_id_ok));
+
+ alert.setPositiveButton(EditKeyActivityOld.this.getString(android.R.string.yes),
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ dialog.dismiss();
+ finallySaveClicked();
+ }
+ }
+ );
+ alert.setNegativeButton(this.getString(android.R.string.no),
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ dialog.dismiss();
+ }
+ }
+ );
+ alert.setCancelable(false);
+ alert.show();
+ return;
+ }
+ curID++;
+ }
+ } catch (PgpGeneralException e) {
+ Log.e(Constants.TAG, getString(R.string.error_message, e.getMessage()));
+ AppMsg.makeText(this, getString(R.string.error_message, e.getMessage()), AppMsg.STYLE_ALERT).show();
+ }
+ finallySaveClicked();
+ }
+
+ private boolean[] toPrimitiveArray(final List<Boolean> booleanList) {
+ final boolean[] primitives = new boolean[booleanList.size()];
+ int index = 0;
+ for (Boolean object : booleanList) {
+ primitives[index++] = object;
+ }
+ return primitives;
+ }
+
+ private void finallySaveClicked() {
+ /*
+ try {
+ // Send all information needed to service to edit key in other thread
+ Intent intent = new Intent(this, KeychainIntentService.class);
+
+ intent.setAction(KeychainIntentService.ACTION_SAVE_KEYRING);
+
+ OldSaveKeyringParcel saveParams = new OldSaveKeyringParcel();
+ saveParams.userIds = getUserIds(mUserIdsView);
+ saveParams.originalIDs = mUserIdsView.getOriginalIDs();
+ saveParams.deletedIDs = mUserIdsView.getDeletedIDs();
+ saveParams.newIDs = toPrimitiveArray(mUserIdsView.getNewIDFlags());
+ saveParams.primaryIDChanged = mUserIdsView.primaryChanged();
+ saveParams.moddedKeys = toPrimitiveArray(mKeysView.getNeedsSavingArray());
+ saveParams.deletedKeys = mKeysView.getDeletedKeys();
+ saveParams.keysExpiryDates = getKeysExpiryDates(mKeysView);
+ saveParams.keysUsages = getKeysUsages(mKeysView);
+ saveParams.newPassphrase = mNewPassphrase;
+ saveParams.oldPassphrase = mCurrentPassphrase;
+ saveParams.newKeys = toPrimitiveArray(mKeysView.getNewKeysArray());
+ saveParams.keys = getKeys(mKeysView);
+ saveParams.originalPrimaryID = mUserIdsView.getOriginalPrimaryID();
+
+ // fill values for this action
+ Bundle data = new Bundle();
+ data.putBoolean(KeychainIntentService.SAVE_KEYRING_CAN_SIGN, mMasterCanSign);
+ data.putParcelable(KeychainIntentService.SAVE_KEYRING_PARCEL, saveParams);
+
+ intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
+
+ // Message is received after saving is done in KeychainIntentService
+ KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(this,
+ getString(R.string.progress_saving), ProgressDialog.STYLE_HORIZONTAL) {
+ public void handleMessage(Message message) {
+ // handle messages by standard KeychainIntentServiceHandler first
+ super.handleMessage(message);
+
+ if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
+ Intent data = new Intent();
+
+ // return uri pointing to new created key
+ Uri uri = KeyRings.buildGenericKeyRingUri(getMasterKeyId());
+ data.setData(uri);
+
+ setResult(RESULT_OK, data);
+ finish();
+ }
+ }
+ };
+
+ // Create a new Messenger for the communication back
+ Messenger messenger = new Messenger(saveHandler);
+ intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger);
+
+ saveHandler.showProgressDialog(this);
+
+ // start service with intent
+ startService(intent);
+ } catch (PgpGeneralException e) {
+ Log.e(Constants.TAG, getString(R.string.error_message, e.getMessage()));
+ AppMsg.makeText(this, getString(R.string.error_message, e.getMessage()),
+ AppMsg.STYLE_ALERT).show();
+ }
+ */
+ }
+
+ private void cancelClicked() {
+ if (needsSaving()) { //ask if we want to save
+ CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(
+ EditKeyActivityOld.this);
+
+ alert.setIcon(R.drawable.ic_dialog_alert_holo_light);
+ alert.setTitle(R.string.warning);
+ alert.setMessage(EditKeyActivityOld.this.getString(R.string.ask_save_changed_key));
+
+ alert.setPositiveButton(EditKeyActivityOld.this.getString(android.R.string.yes),
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ dialog.dismiss();
+ saveClicked();
+ }
+ });
+ alert.setNegativeButton(this.getString(android.R.string.no),
+ new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ dialog.dismiss();
+ setResult(RESULT_CANCELED);
+ finish();
+ }
+ });
+ alert.setCancelable(false);
+ alert.show();
+ } else {
+ setResult(RESULT_CANCELED);
+ finish();
+ }
+ }
+
+ /**
+ * Returns user ids from the SectionView
+ *
+ * @param userIdsView
+ * @return
+ */
+ private ArrayList<String> getUserIds(SectionView userIdsView) throws PgpGeneralException {
+ ArrayList<String> userIds = new ArrayList<String>();
+
+ ViewGroup userIdEditors = userIdsView.getEditors();
+
+ boolean gotMainUserId = false;
+ for (int i = 0; i < userIdEditors.getChildCount(); ++i) {
+ UserIdEditor editor = (UserIdEditor) userIdEditors.getChildAt(i);
+ String userId;
+ userId = editor.getValue();
+
+ if (editor.isMainUserId()) {
+ userIds.add(0, userId);
+ gotMainUserId = true;
+ } else {
+ userIds.add(userId);
+ }
+ }
+
+ if (userIds.size() == 0) {
+ throw new PgpGeneralException(getString(R.string.error_key_needs_a_user_id));
+ }
+
+ if (!gotMainUserId) {
+ throw new PgpGeneralException(getString(R.string.error_main_user_id_must_not_be_empty));
+ }
+
+ return userIds;
+ }
+
+ /**
+ * Returns keys from the SectionView
+ *
+ * @param keysView
+ * @return
+ */
+ private ArrayList<UncachedSecretKey> getKeys(SectionView keysView) throws PgpGeneralException {
+ ArrayList<UncachedSecretKey> keys = new ArrayList<UncachedSecretKey>();
+
+ ViewGroup keyEditors = keysView.getEditors();
+
+ if (keyEditors.getChildCount() == 0) {
+ throw new PgpGeneralException(getString(R.string.error_key_needs_master_key));
+ }
+
+ for (int i = 0; i < keyEditors.getChildCount(); ++i) {
+ KeyEditor editor = (KeyEditor) keyEditors.getChildAt(i);
+ keys.add(editor.getValue());
+ }
+
+ return keys;
+ }
+
+ /**
+ * Returns usage selections of keys from the SectionView
+ *
+ * @param keysView
+ * @return
+ */
+ private ArrayList<Integer> getKeysUsages(SectionView keysView) throws PgpGeneralException {
+ ArrayList<Integer> keysUsages = new ArrayList<Integer>();
+
+ ViewGroup keyEditors = keysView.getEditors();
+
+ if (keyEditors.getChildCount() == 0) {
+ throw new PgpGeneralException(getString(R.string.error_key_needs_master_key));
+ }
+
+ for (int i = 0; i < keyEditors.getChildCount(); ++i) {
+ KeyEditor editor = (KeyEditor) keyEditors.getChildAt(i);
+ keysUsages.add(editor.getUsage());
+ }
+
+ return keysUsages;
+ }
+
+ private ArrayList<Calendar> getKeysExpiryDates(SectionView keysView) throws PgpGeneralException {
+ ArrayList<Calendar> keysExpiryDates = new ArrayList<Calendar>();
+
+ ViewGroup keyEditors = keysView.getEditors();
+
+ if (keyEditors.getChildCount() == 0) {
+ throw new PgpGeneralException(getString(R.string.error_key_needs_master_key));
+ }
+
+ for (int i = 0; i < keyEditors.getChildCount(); ++i) {
+ KeyEditor editor = (KeyEditor) keyEditors.getChildAt(i);
+ keysExpiryDates.add(editor.getExpiryDate());
+ }
+
+ return keysExpiryDates;
+ }
+
+ private void updatePassphraseButtonText() {
+ mChangePassphrase.setText(isPassphraseSet() ? getString(R.string.btn_change_passphrase)
+ : getString(R.string.btn_set_passphrase));
+ }
+
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java
index b6a95a517..c76dc0164 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java
@@ -37,6 +37,7 @@ import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.Toast;
+import org.spongycastle.bcpg.sig.KeyFlags;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround;
@@ -50,38 +51,48 @@ import org.sufficientlysecure.keychain.service.OperationResults;
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
import org.sufficientlysecure.keychain.ui.adapter.SubkeysAdapter;
+import org.sufficientlysecure.keychain.ui.adapter.SubkeysAddedAdapter;
import org.sufficientlysecure.keychain.ui.adapter.UserIdsAdapter;
-import org.sufficientlysecure.keychain.ui.adapter.UserIdsArrayAdapter;
-import org.sufficientlysecure.keychain.ui.dialog.AddUserIdDialogFragment;
+import org.sufficientlysecure.keychain.ui.adapter.UserIdsAddedAdapter;
import org.sufficientlysecure.keychain.ui.dialog.EditUserIdDialogFragment;
import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment;
import org.sufficientlysecure.keychain.ui.dialog.SetPassphraseDialogFragment;
import org.sufficientlysecure.keychain.util.Log;
+import java.util.ArrayList;
+
public class EditKeyFragment extends LoaderFragment implements
LoaderManager.LoaderCallbacks<Cursor> {
public static final String ARG_DATA_URI = "uri";
private ListView mUserIdsList;
- private ListView mKeysList;
+ private ListView mSubkeysList;
private ListView mUserIdsAddedList;
- private ListView mKeysAddedList;
+ private ListView mSubkeysAddedList;
private View mChangePassphrase;
private View mAddUserId;
- private View mAddKey;
+ private View mAddSubkey;
private static final int LOADER_ID_USER_IDS = 0;
- private static final int LOADER_ID_KEYS = 1;
+ private static final int LOADER_ID_SUBKEYS = 1;
+ // cursor adapter
private UserIdsAdapter mUserIdsAdapter;
- private SubkeysAdapter mKeysAdapter;
- private UserIdsArrayAdapter mUserIdsAddedAdapter;
+ private SubkeysAdapter mSubkeysAdapter;
+
+ // array adapter
+ private UserIdsAddedAdapter mUserIdsAddedAdapter;
+ private SubkeysAddedAdapter mSubkeysAddedAdapter;
+
+ private ArrayList<UserIdsAddedAdapter.UserIdModel> mUserIdsAddedData;
private Uri mDataUri;
private SaveKeyringParcel mSaveKeyringParcel;
+ private String mCurrentPassphrase;
+
/**
* Creates new instance of this fragment
*/
@@ -102,12 +113,12 @@ public class EditKeyFragment extends LoaderFragment implements
View view = inflater.inflate(R.layout.edit_key_fragment, getContainer());
mUserIdsList = (ListView) view.findViewById(R.id.edit_key_user_ids);
- mKeysList = (ListView) view.findViewById(R.id.edit_key_keys);
+ mSubkeysList = (ListView) view.findViewById(R.id.edit_key_keys);
mUserIdsAddedList = (ListView) view.findViewById(R.id.edit_key_user_ids_added);
- mKeysAddedList = (ListView) view.findViewById(R.id.edit_key_keys_added);
+ mSubkeysAddedList = (ListView) view.findViewById(R.id.edit_key_subkeys_added);
mChangePassphrase = view.findViewById(R.id.edit_key_action_change_passphrase);
mAddUserId = view.findViewById(R.id.edit_key_action_add_user_id);
- mAddKey = view.findViewById(R.id.edit_key_action_add_key);
+ mAddSubkey = view.findViewById(R.id.edit_key_action_add_key);
return root;
}
@@ -123,7 +134,7 @@ public class EditKeyFragment extends LoaderFragment implements
@Override
public void onClick(View v) {
// Save
- save();
+ save(mCurrentPassphrase);
}
}, R.string.menu_key_edit_cancel, R.drawable.ic_action_cancel,
new OnClickListener() {
@@ -164,6 +175,8 @@ public class EditKeyFragment extends LoaderFragment implements
getActivity().finish();
}
+ cachePassphraseForEdit();
+
mChangePassphrase.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
@@ -178,6 +191,13 @@ public class EditKeyFragment extends LoaderFragment implements
}
});
+ mAddSubkey.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ addSubkey();
+ }
+ });
+
mUserIdsAdapter = new UserIdsAdapter(getActivity(), null, 0, mSaveKeyringParcel);
mUserIdsList.setAdapter(mUserIdsAdapter);
@@ -189,17 +209,21 @@ public class EditKeyFragment extends LoaderFragment implements
}
});
- mUserIdsAddedAdapter = new UserIdsArrayAdapter(getActivity());
+ // TODO: mUserIdsAddedData and SaveParcel from savedInstance?!
+ mUserIdsAddedData = new ArrayList<UserIdsAddedAdapter.UserIdModel>();
+ mUserIdsAddedAdapter = new UserIdsAddedAdapter(getActivity(), mUserIdsAddedData);
mUserIdsAddedList.setAdapter(mUserIdsAddedAdapter);
- mUserIdsAddedAdapter.setData(mSaveKeyringParcel.addUserIds);
- mKeysAdapter = new SubkeysAdapter(getActivity(), null, 0);
- mKeysList.setAdapter(mKeysAdapter);
+ mSubkeysAdapter = new SubkeysAdapter(getActivity(), null, 0);
+ mSubkeysList.setAdapter(mSubkeysAdapter);
+
+ mSubkeysAddedAdapter = new SubkeysAddedAdapter(getActivity(), mSaveKeyringParcel.addSubKeys);
+ mSubkeysAddedList.setAdapter(mSubkeysAddedAdapter);
// Prepare the loaders. Either re-connect with an existing ones,
// or start new ones.
getLoaderManager().initLoader(LOADER_ID_USER_IDS, null, this);
- getLoaderManager().initLoader(LOADER_ID_KEYS, null, this);
+ getLoaderManager().initLoader(LOADER_ID_SUBKEYS, null, this);
}
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
@@ -212,10 +236,10 @@ public class EditKeyFragment extends LoaderFragment implements
UserIdsAdapter.USER_IDS_PROJECTION, null, null, null);
}
- case LOADER_ID_KEYS: {
+ case LOADER_ID_SUBKEYS: {
Uri baseUri = KeychainContract.Keys.buildKeysUri(mDataUri);
return new CursorLoader(getActivity(), baseUri,
- SubkeysAdapter.KEYS_PROJECTION, null, null, null);
+ SubkeysAdapter.SUBKEYS_PROJECTION, null, null, null);
}
default:
@@ -231,8 +255,8 @@ public class EditKeyFragment extends LoaderFragment implements
mUserIdsAdapter.swapCursor(data);
break;
- case LOADER_ID_KEYS:
- mKeysAdapter.swapCursor(data);
+ case LOADER_ID_SUBKEYS:
+ mSubkeysAdapter.swapCursor(data);
break;
}
@@ -248,8 +272,8 @@ public class EditKeyFragment extends LoaderFragment implements
case LOADER_ID_USER_IDS:
mUserIdsAdapter.swapCursor(null);
break;
- case LOADER_ID_KEYS:
- mKeysAdapter.swapCursor(null);
+ case LOADER_ID_SUBKEYS:
+ mSubkeysAdapter.swapCursor(null);
break;
}
}
@@ -262,11 +286,9 @@ public class EditKeyFragment extends LoaderFragment implements
if (message.what == SetPassphraseDialogFragment.MESSAGE_OKAY) {
Bundle data = message.getData();
- // set new returned passphrase!
- String newPassphrase = data
+ // cache new returned passphrase!
+ mSaveKeyringParcel.newPassphrase = data
.getString(SetPassphraseDialogFragment.MESSAGE_NEW_PASSPHRASE);
-
- mSaveKeyringParcel.newPassphrase = newPassphrase;
}
}
};
@@ -275,7 +297,7 @@ public class EditKeyFragment extends LoaderFragment implements
Messenger messenger = new Messenger(returnHandler);
SetPassphraseDialogFragment setPassphraseDialog = SetPassphraseDialogFragment.newInstance(
- messenger, R.string.title_change_passphrase);
+ messenger, mCurrentPassphrase, R.string.title_change_passphrase);
setPassphraseDialog.show(getActivity().getSupportFragmentManager(), "setPassphraseDialog");
}
@@ -321,56 +343,41 @@ public class EditKeyFragment extends LoaderFragment implements
}
private void addUserId() {
- Handler returnHandler = new Handler() {
- @Override
- public void handleMessage(Message message) {
- switch (message.what) {
- case AddUserIdDialogFragment.MESSAGE_OKAY:
- Bundle data = message.getData();
- String userId = data.getString(AddUserIdDialogFragment.MESSAGE_DATA_USER_ID);
-
- if (userId != null) {
- mSaveKeyringParcel.addUserIds.add(userId);
- mUserIdsAddedAdapter.setData(mSaveKeyringParcel.addUserIds);
- }
- }
- getLoaderManager().getLoader(LOADER_ID_USER_IDS).forceLoad();
- }
- };
-
- // Create a new Messenger for the communication back
- final Messenger messenger = new Messenger(returnHandler);
-
- DialogFragmentWorkaround.INTERFACE.runnableRunDelayed(new Runnable() {
- public void run() {
- AddUserIdDialogFragment dialogFragment =
- AddUserIdDialogFragment.newInstance(messenger);
+ mUserIdsAddedAdapter.add(new UserIdsAddedAdapter.UserIdModel());
+ }
- dialogFragment.show(getActivity().getSupportFragmentManager(), "addUserIdDialog");
- }
- });
+ private void addSubkey() {
+ // default values
+ mSubkeysAddedAdapter.add(new SaveKeyringParcel.SubkeyAdd(Constants.choice.algorithm.rsa, 4096, KeyFlags.SIGN_DATA, null));
}
- private void save() {
- String passphrase = PassphraseCacheService.getCachedPassphrase(getActivity(),
+ private void cachePassphraseForEdit() {
+ mCurrentPassphrase = PassphraseCacheService.getCachedPassphrase(getActivity(),
mSaveKeyringParcel.mMasterKeyId);
- if (passphrase == null) {
+ if (mCurrentPassphrase == null) {
PassphraseDialogFragment.show(getActivity(), mSaveKeyringParcel.mMasterKeyId,
new Handler() {
@Override
public void handleMessage(Message message) {
if (message.what == PassphraseDialogFragment.MESSAGE_OKAY) {
- saveFinal();
+ mCurrentPassphrase =
+ message.getData().getString(PassphraseDialogFragment.MESSAGE_DATA_PASSPHRASE);
+ Log.d(Constants.TAG, "after caching passphrase");
+ } else {
+ EditKeyFragment.this.getActivity().finish();
}
}
}
);
-
}
-
}
- private void saveFinal() {
+ private void save(String passphrase) {
+ Log.d(Constants.TAG, "add userids to parcel: " + mUserIdsAddedAdapter.getDataAsStringList());
+ Log.d(Constants.TAG, "mSaveKeyringParcel.newPassphrase: " + mSaveKeyringParcel.newPassphrase);
+
+ mSaveKeyringParcel.addUserIds = mUserIdsAddedAdapter.getDataAsStringList();
+
// Message is received after importing is done in KeychainIntentService
KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(
getActivity(),
@@ -381,6 +388,9 @@ public class EditKeyFragment extends LoaderFragment implements
super.handleMessage(message);
if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
+ getActivity().finish();
+
+ // TODO below
// get returned data bundle
Bundle returnData = message.getData();
if (returnData == null) {
@@ -408,6 +418,7 @@ public class EditKeyFragment extends LoaderFragment implements
// fill values for this action
Bundle data = new Bundle();
+ data.putString(KeychainIntentService.SAVE_KEYRING_PASSPHRASE, passphrase);
data.putParcelable(KeychainIntentService.SAVE_KEYRING_PARCEL, mSaveKeyringParcel);
intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java
index 5542cccd1..c98171230 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java
@@ -298,7 +298,7 @@ public class EncryptActivity extends DrawerActivity implements
// encrypt file based on Uri
mFileFragmentBundle.putParcelableArrayList(EncryptFileFragment.ARG_URIS, uris);
mSwitchToContent = PAGER_CONTENT_FILE;
- } else {
+ } else if (ACTION_ENCRYPT.equals(action)) {
Log.e(Constants.TAG,
"Include the extra 'text' or an Uri with setData() in your Intent!");
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java
index 7ce7a06aa..849576284 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java
@@ -17,21 +17,33 @@
package org.sufficientlysecure.keychain.ui;
+import android.app.ProgressDialog;
import android.content.Intent;
import android.os.Bundle;
+import android.os.Message;
+import android.os.Messenger;
import android.view.Menu;
import android.view.MenuItem;
import com.devspark.appmsg.AppMsg;
+import org.spongycastle.bcpg.sig.KeyFlags;
import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.Constants.choice.algorithm;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.helper.ExportHelper;
+import org.sufficientlysecure.keychain.helper.OtherHelper;
+import org.sufficientlysecure.keychain.keyimport.ImportKeysListEntry;
import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.provider.KeychainDatabase;
+import org.sufficientlysecure.keychain.service.KeychainIntentService;
+import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler;
+import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
+import org.sufficientlysecure.keychain.service.SaveKeyringParcel.SubkeyAdd;
import org.sufficientlysecure.keychain.util.Log;
import java.io.IOException;
+import java.util.ArrayList;
public class KeyListActivity extends DrawerActivity {
@@ -121,9 +133,42 @@ public class KeyListActivity extends DrawerActivity {
}
private void createKeyExpert() {
- Intent intent = new Intent(this, EditKeyActivity.class);
- intent.setAction(EditKeyActivity.ACTION_CREATE_KEY);
- startActivityForResult(intent, 0);
+ Intent intent = new Intent(this, KeychainIntentService.class);
+ intent.setAction(KeychainIntentService.ACTION_SAVE_KEYRING);
+
+ // Message is received after importing is done in KeychainIntentService
+ KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(
+ this,
+ getString(R.string.progress_importing),
+ ProgressDialog.STYLE_HORIZONTAL) {
+ public void handleMessage(Message message) {
+ // handle messages by standard KeychainIntentServiceHandler first
+ super.handleMessage(message);
+ Bundle data = message.getData();
+ // OtherHelper.logDebugBundle(data, "message reply");
+ }
+ };
+
+ // fill values for this action
+ Bundle data = new Bundle();
+
+ SaveKeyringParcel parcel = new SaveKeyringParcel();
+ parcel.addSubKeys.add(new SubkeyAdd(algorithm.rsa, 1024, KeyFlags.CERTIFY_OTHER, null));
+ parcel.addSubKeys.add(new SubkeyAdd(algorithm.rsa, 1024, KeyFlags.SIGN_DATA, null));
+ parcel.addUserIds.add("swagerinho");
+ parcel.newPassphrase = "swag";
+
+ // get selected key entries
+ data.putParcelable(KeychainIntentService.SAVE_KEYRING_PARCEL, parcel);
+
+ intent.putExtra(KeychainIntentService.EXTRA_DATA, data);
+
+ // Create a new Messenger for the communication back
+ Messenger messenger = new Messenger(saveHandler);
+ intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger);
+
+ saveHandler.showProgressDialog(this);
+
+ startService(intent);
}
-
-}
+} \ No newline at end of file
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java
index 0940d5632..e2ca50a4c 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java
@@ -47,7 +47,6 @@ import android.view.ViewGroup;
import android.widget.AbsListView.MultiChoiceModeListener;
import android.widget.AdapterView;
import android.widget.FrameLayout;
-import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
@@ -59,7 +58,6 @@ import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.helper.ExportHelper;
import org.sufficientlysecure.keychain.pgp.KeyRing;
-import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData;
import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment;
import org.sufficientlysecure.keychain.util.Highlighter;
@@ -106,10 +104,10 @@ public class KeyListFragment extends LoaderFragment
@Override
public void onClick(View v) {
- Intent intent = new Intent(getActivity(), EditKeyActivity.class);
- intent.setAction(EditKeyActivity.ACTION_CREATE_KEY);
- intent.putExtra(EditKeyActivity.EXTRA_GENERATE_DEFAULT_KEYS, true);
- intent.putExtra(EditKeyActivity.EXTRA_USER_IDS, ""); // show user id view
+ Intent intent = new Intent(getActivity(), EditKeyActivityOld.class);
+ intent.setAction(EditKeyActivityOld.ACTION_CREATE_KEY);
+ intent.putExtra(EditKeyActivityOld.EXTRA_GENERATE_DEFAULT_KEYS, true);
+ intent.putExtra(EditKeyActivityOld.EXTRA_USER_IDS, ""); // show user id view
startActivityForResult(intent, 0);
}
});
@@ -205,7 +203,7 @@ public class KeyListFragment extends LoaderFragment
public void onItemCheckedStateChanged(ActionMode mode, int position, long id,
boolean checked) {
if (checked) {
- mAdapter.setNewSelection(position, true);
+ mAdapter.setNewSelection(position, checked);
} else {
mAdapter.removeSelection(position);
}
@@ -439,9 +437,7 @@ public class KeyListFragment extends LoaderFragment
private class ItemViewHolder {
TextView mMainUserId;
TextView mMainUserIdRest;
- View mStatusDivider;
FrameLayout mStatusLayout;
- ImageButton mButton;
TextView mRevoked;
ImageView mVerified;
}
@@ -452,9 +448,7 @@ public class KeyListFragment extends LoaderFragment
ItemViewHolder holder = new ItemViewHolder();
holder.mMainUserId = (TextView) view.findViewById(R.id.mainUserId);
holder.mMainUserIdRest = (TextView) view.findViewById(R.id.mainUserIdRest);
- holder.mStatusDivider = view.findViewById(R.id.status_divider);
holder.mStatusLayout = (FrameLayout) view.findViewById(R.id.status_layout);
- holder.mButton = (ImageButton) view.findViewById(R.id.edit);
holder.mRevoked = (TextView) view.findViewById(R.id.revoked);
holder.mVerified = (ImageView) view.findViewById(R.id.verified);
view.setTag(holder);
@@ -491,26 +485,12 @@ public class KeyListFragment extends LoaderFragment
{ // set edit button and revoked info, specific by key type
if (cursor.getInt(KeyListFragment.INDEX_HAS_ANY_SECRET) != 0) {
- // this is a secret key - show the edit mButton
- h.mStatusDivider.setVisibility(View.VISIBLE);
+ // this is a secret key
h.mStatusLayout.setVisibility(View.VISIBLE);
h.mRevoked.setVisibility(View.GONE);
h.mVerified.setVisibility(View.GONE);
- h.mButton.setVisibility(View.VISIBLE);
-
- final long id = cursor.getLong(INDEX_MASTER_KEY_ID);
- h.mButton.setOnClickListener(new OnClickListener() {
- public void onClick(View view) {
- Intent editIntent = new Intent(getActivity(), EditKeyActivity.class);
- editIntent.setData(KeyRingData.buildSecretKeyRingUri(Long.toString(id)));
- editIntent.setAction(EditKeyActivity.ACTION_EDIT_KEY);
- startActivityForResult(editIntent, 0);
- }
- });
} else {
- // this is a public key - hide the edit mButton, show if it's revoked
- h.mStatusDivider.setVisibility(View.GONE);
- h.mButton.setVisibility(View.GONE);
+ // this is a public key - show if it's revoked
boolean isRevoked = cursor.getInt(INDEX_IS_REVOKED) > 0;
boolean isExpired = !cursor.isNull(INDEX_EXPIRY)
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LoaderFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LoaderFragment.java
index 87ab1bb8c..8634070cc 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LoaderFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LoaderFragment.java
@@ -1,3 +1,20 @@
+/*
+ * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
package org.sufficientlysecure.keychain.ui;
import android.os.Bundle;
@@ -9,14 +26,14 @@ import android.view.animation.AnimationUtils;
import org.sufficientlysecure.keychain.R;
-/** This is a fragment helper class, which implements a generic
+/**
+ * This is a fragment helper class, which implements a generic
* progressbar/container view.
- *
+ * <p/>
* To use it in a fragment, simply subclass, use onCreateView to create the
* layout's root view, and ues getContainer() as root view of your subclass.
* The layout shows a progress bar by default, and can be switched to the
* actual contents by calling setContentShown().
- *
*/
public class LoaderFragment extends Fragment {
private boolean mContentShown;
@@ -35,7 +52,6 @@ public class LoaderFragment extends Fragment {
mContentShown = false;
return root;
-
}
protected ViewGroup getContainer() {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyKeysFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyKeysFragment.java
index 4be572b4e..e46637871 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyKeysFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyKeysFragment.java
@@ -87,7 +87,7 @@ public class ViewKeyKeysFragment extends LoaderFragment implements
setContentShown(false);
Uri baseUri = Keys.buildKeysUri(mDataUri);
return new CursorLoader(getActivity(), baseUri,
- SubkeysAdapter.KEYS_PROJECTION, null, null, null);
+ SubkeysAdapter.SUBKEYS_PROJECTION, null, null, null);
}
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java
index dd48f193c..f0636cf2c 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java
@@ -49,7 +49,6 @@ public class ViewKeyMainFragment extends LoaderFragment implements
public static final String ARG_DATA_URI = "uri";
private View mActionEdit;
- private View mActionEditNew;
private View mActionEditDivider;
private View mActionEncrypt;
private View mActionCertify;
@@ -74,7 +73,6 @@ public class ViewKeyMainFragment extends LoaderFragment implements
mUserIds = (ListView) view.findViewById(R.id.view_key_user_ids);
mActionEdit = view.findViewById(R.id.view_key_action_edit);
- mActionEditNew = view.findViewById(R.id.view_key_action_edit_new);
mActionEditDivider = view.findViewById(R.id.view_key_action_edit_divider);
mActionEncrypt = view.findViewById(R.id.view_key_action_encrypt);
mActionCertify = view.findViewById(R.id.view_key_action_certify);
@@ -118,11 +116,6 @@ public class ViewKeyMainFragment extends LoaderFragment implements
editKey(mDataUri);
}
});
- mActionEditNew.setOnClickListener(new View.OnClickListener() {
- public void onClick(View view) {
- editKeyNew(mDataUri);
- }
- });
mUserIdsAdapter = new UserIdsAdapter(getActivity(), null, 0);
mUserIds.setAdapter(mUserIdsAdapter);
@@ -259,16 +252,9 @@ public class ViewKeyMainFragment extends LoaderFragment implements
private void editKey(Uri dataUri) {
Intent editIntent = new Intent(getActivity(), EditKeyActivity.class);
editIntent.setData(KeychainContract.KeyRingData.buildSecretKeyRingUri(dataUri));
- editIntent.setAction(EditKeyActivity.ACTION_EDIT_KEY);
- startActivityForResult(editIntent, 0);
- }
-
- private void editKeyNew(Uri dataUri) {
- Intent editIntent = new Intent(getActivity(), EditKeyActivityNew.class);
-// editIntent.setData(KeychainContract.KeyRingData.buildSecretKeyRingUri(dataUri));
- editIntent.setData(KeychainContract.KeyRingData.buildSecretKeyRingUri(dataUri));
- editIntent.setAction(EditKeyActivity.ACTION_EDIT_KEY);
- startActivityForResult(editIntent, 0);
+// editIntent.setAction(EditKeyActivity.ACTION_EDIT_KEY);
+// startActivityForResult(editIntent, 0);
+ startActivity(editIntent);
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/WizardActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/WizardActivity.java
index 20b47ed01..601fc09f9 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/WizardActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/WizardActivity.java
@@ -142,7 +142,7 @@ public class WizardActivity extends ActionBarActivity {
emailView.setThreshold(1); // Start working from first character
emailView.setAdapter(
new ArrayAdapter<String>
- (getActivity(), android.R.layout.simple_dropdown_item_1line,
+ (getActivity(), android.R.layout.simple_spinner_dropdown_item,
ContactHelper.getPossibleUserEmails(getActivity())
)
);
@@ -177,7 +177,7 @@ public class WizardActivity extends ActionBarActivity {
nameView.setThreshold(1); // Start working from first character
nameView.setAdapter(
new ArrayAdapter<String>
- (getActivity(), android.R.layout.simple_dropdown_item_1line,
+ (getActivity(), android.R.layout.simple_spinner_dropdown_item,
ContactHelper.getPossibleUserNames(getActivity())
)
);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java
index 6d8455589..02b1f31e2 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java
@@ -38,22 +38,11 @@ import java.util.Date;
public class SubkeysAdapter extends CursorAdapter {
private LayoutInflater mInflater;
- private int mIndexKeyId;
- private int mIndexAlgorithm;
- private int mIndexKeySize;
- private int mIndexRank;
- private int mIndexCanCertify;
- private int mIndexCanEncrypt;
- private int mIndexCanSign;
- private int mIndexHasSecret;
- private int mIndexRevokedKey;
- private int mIndexExpiry;
-
private boolean hasAnySecret;
private ColorStateList mDefaultTextColor;
- public static final String[] KEYS_PROJECTION = new String[] {
+ public static final String[] SUBKEYS_PROJECTION = new String[]{
Keys._ID,
Keys.KEY_ID,
Keys.RANK,
@@ -68,24 +57,32 @@ public class SubkeysAdapter extends CursorAdapter {
Keys.EXPIRY,
Keys.FINGERPRINT
};
+ private static final int INDEX_ID = 0;
+ private static final int INDEX_KEY_ID = 1;
+ private static final int INDEX_RANK = 2;
+ private static final int INDEX_ALGORITHM = 3;
+ private static final int INDEX_KEY_SIZE = 4;
+ private static final int INDEX_HAS_SECRET = 5;
+ private static final int INDEX_CAN_CERTIFY = 6;
+ private static final int INDEX_CAN_ENCRYPT = 7;
+ private static final int INDEX_CAN_SIGN = 8;
+ private static final int INDEX_IS_REVOKED = 9;
+ private static final int INDEX_CREATION = 10;
+ private static final int INDEX_EXPIRY = 11;
+ private static final int INDEX_FINGERPRINT = 12;
public SubkeysAdapter(Context context, Cursor c, int flags) {
super(context, c, flags);
mInflater = LayoutInflater.from(context);
-
- initIndex(c);
}
@Override
public Cursor swapCursor(Cursor newCursor) {
- initIndex(newCursor);
-
hasAnySecret = false;
- if (newCursor != null) {
- newCursor.moveToFirst();
+ if (newCursor != null && newCursor.moveToFirst()) {
do {
- if (newCursor.getInt(mIndexHasSecret) != 0) {
+ if (newCursor.getInt(INDEX_HAS_SECRET) != 0) {
hasAnySecret = true;
break;
}
@@ -95,27 +92,6 @@ public class SubkeysAdapter extends CursorAdapter {
return super.swapCursor(newCursor);
}
- /**
- * Get column indexes for performance reasons just once in constructor and swapCursor. For a
- * performance comparison see http://stackoverflow.com/a/17999582
- *
- * @param cursor
- */
- private void initIndex(Cursor cursor) {
- if (cursor != null) {
- mIndexKeyId = cursor.getColumnIndexOrThrow(Keys.KEY_ID);
- mIndexAlgorithm = cursor.getColumnIndexOrThrow(Keys.ALGORITHM);
- mIndexKeySize = cursor.getColumnIndexOrThrow(Keys.KEY_SIZE);
- mIndexRank = cursor.getColumnIndexOrThrow(Keys.RANK);
- mIndexCanCertify = cursor.getColumnIndexOrThrow(Keys.CAN_CERTIFY);
- mIndexCanEncrypt = cursor.getColumnIndexOrThrow(Keys.CAN_ENCRYPT);
- mIndexCanSign = cursor.getColumnIndexOrThrow(Keys.CAN_SIGN);
- mIndexHasSecret = cursor.getColumnIndexOrThrow(Keys.HAS_SECRET);
- mIndexRevokedKey = cursor.getColumnIndexOrThrow(Keys.IS_REVOKED);
- mIndexExpiry = cursor.getColumnIndexOrThrow(Keys.EXPIRY);
- }
- }
-
@Override
public void bindView(View view, Context context, Cursor cursor) {
TextView keyId = (TextView) view.findViewById(R.id.keyId);
@@ -127,16 +103,16 @@ public class SubkeysAdapter extends CursorAdapter {
ImageView signIcon = (ImageView) view.findViewById(R.id.ic_signKey);
ImageView revokedKeyIcon = (ImageView) view.findViewById(R.id.ic_revokedKey);
- String keyIdStr = PgpKeyHelper.convertKeyIdToHex(cursor.getLong(mIndexKeyId));
+ String keyIdStr = PgpKeyHelper.convertKeyIdToHex(cursor.getLong(INDEX_KEY_ID));
String algorithmStr = PgpKeyHelper.getAlgorithmInfo(
context,
- cursor.getInt(mIndexAlgorithm),
- cursor.getInt(mIndexKeySize)
+ cursor.getInt(INDEX_ALGORITHM),
+ cursor.getInt(INDEX_KEY_SIZE)
);
keyId.setText(keyIdStr);
// may be set with additional "stripped" later on
- if (hasAnySecret && cursor.getInt(mIndexHasSecret) == 0) {
+ if (hasAnySecret && cursor.getInt(INDEX_HAS_SECRET) == 0) {
keyDetails.setText(algorithmStr + ", " +
context.getString(R.string.key_stripped));
} else {
@@ -144,13 +120,13 @@ public class SubkeysAdapter extends CursorAdapter {
}
// Set icons according to properties
- masterKeyIcon.setVisibility(cursor.getInt(mIndexRank) == 0 ? View.VISIBLE : View.INVISIBLE);
- certifyIcon.setVisibility(cursor.getInt(mIndexCanCertify) != 0 ? View.VISIBLE : View.GONE);
- encryptIcon.setVisibility(cursor.getInt(mIndexCanEncrypt) != 0 ? View.VISIBLE : View.GONE);
- signIcon.setVisibility(cursor.getInt(mIndexCanSign) != 0 ? View.VISIBLE : View.GONE);
+ masterKeyIcon.setVisibility(cursor.getInt(INDEX_RANK) == 0 ? View.VISIBLE : View.INVISIBLE);
+ certifyIcon.setVisibility(cursor.getInt(INDEX_CAN_CERTIFY) != 0 ? View.VISIBLE : View.GONE);
+ encryptIcon.setVisibility(cursor.getInt(INDEX_CAN_ENCRYPT) != 0 ? View.VISIBLE : View.GONE);
+ signIcon.setVisibility(cursor.getInt(INDEX_CAN_SIGN) != 0 ? View.VISIBLE : View.GONE);
boolean valid = true;
- if (cursor.getInt(mIndexRevokedKey) > 0) {
+ if (cursor.getInt(INDEX_IS_REVOKED) > 0) {
revokedKeyIcon.setVisibility(View.VISIBLE);
valid = false;
@@ -162,17 +138,19 @@ public class SubkeysAdapter extends CursorAdapter {
revokedKeyIcon.setVisibility(View.GONE);
}
- if (!cursor.isNull(mIndexExpiry)) {
- Date expiryDate = new Date(cursor.getLong(mIndexExpiry) * 1000);
+ if (!cursor.isNull(INDEX_EXPIRY)) {
+ Date expiryDate = new Date(cursor.getLong(INDEX_EXPIRY) * 1000);
valid = valid && expiryDate.after(new Date());
keyExpiry.setText(
context.getString(R.string.label_expiry) + ": " +
- DateFormat.getDateFormat(context).format(expiryDate));
+ DateFormat.getDateFormat(context).format(expiryDate)
+ );
} else {
keyExpiry.setText(
context.getString(R.string.label_expiry) + ": " +
- context.getString(R.string.none));
+ context.getString(R.string.none)
+ );
}
// if key is expired or revoked, strike through text
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAddedAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAddedAdapter.java
new file mode 100644
index 000000000..25509fee5
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAddedAdapter.java
@@ -0,0 +1,361 @@
+/*
+ * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package org.sufficientlysecure.keychain.ui.adapter;
+
+import android.annotation.TargetApi;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.os.Build;
+import android.text.Editable;
+import android.text.TextUtils;
+import android.text.TextWatcher;
+import android.util.Patterns;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.AutoCompleteTextView;
+import android.widget.EditText;
+import android.widget.ImageButton;
+import android.widget.Spinner;
+import android.widget.TextView;
+
+import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.helper.ContactHelper;
+import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
+import org.sufficientlysecure.keychain.ui.dialog.CreateKeyDialogFragment;
+import org.sufficientlysecure.keychain.util.Choice;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.regex.Matcher;
+
+public class SubkeysAddedAdapter extends ArrayAdapter<SaveKeyringParcel.SubkeyAdd> {
+ private LayoutInflater mInflater;
+ private Activity mActivity;
+
+ public interface OnAlgorithmSelectedListener {
+ public void onAlgorithmSelected(Choice algorithmChoice, int keySize);
+ }
+
+ // hold a private reference to the underlying data List
+ private List<SaveKeyringParcel.SubkeyAdd> mData;
+
+ public SubkeysAddedAdapter(Activity activity, List<SaveKeyringParcel.SubkeyAdd> data) {
+ super(activity, -1, data);
+ mActivity = activity;
+ mInflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ mData = data;
+ }
+
+ static class ViewHolder {
+ public OnAlgorithmSelectedListener mAlgorithmSelectedListener;
+ public Spinner mAlgorithmSpinner;
+ public Spinner mKeySizeSpinner;
+ public TextView mCustomKeyTextView;
+ public EditText mCustomKeyEditText;
+ public TextView mCustomKeyInfoTextView;
+ public ImageButton vDelete;
+ // also hold a reference to the model item
+ public SaveKeyringParcel.SubkeyAdd mModel;
+ }
+
+ public View getView(final int position, View convertView, ViewGroup parent) {
+ if (convertView == null) {
+ // Not recycled, inflate a new view
+ convertView = mInflater.inflate(R.layout.edit_key_subkey_added_item, null);
+ final ViewHolder holder = new ViewHolder();
+ holder.mAlgorithmSpinner = (Spinner) convertView.findViewById(R.id.create_key_algorithm);
+ holder.mKeySizeSpinner = (Spinner) convertView.findViewById(R.id.create_key_size);
+ holder.mCustomKeyTextView = (TextView) convertView.findViewById(R.id.custom_key_size_label);
+ holder.mCustomKeyEditText = (EditText) convertView.findViewById(R.id.custom_key_size_input);
+ holder.mCustomKeyInfoTextView = (TextView) convertView.findViewById(R.id.custom_key_size_info);
+ holder.vDelete = (ImageButton) convertView.findViewById(R.id.subkey_added_item_delete);
+ convertView.setTag(holder);
+
+ holder.mAlgorithmSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+ Choice newKeyAlgorithmChoice = (Choice) holder.mAlgorithmSpinner.getSelectedItem();
+ // update referenced model item
+ holder.mModel.mAlgorithm = newKeyAlgorithmChoice.getId();
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> parent) {
+ }
+ });
+
+ holder.mKeySizeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+ Choice newKeyAlgorithmChoice = (Choice) holder.mAlgorithmSpinner.getSelectedItem();
+ int newKeySize = getProperKeyLength(newKeyAlgorithmChoice.getId(),
+ getSelectedKeyLength(holder.mKeySizeSpinner, holder.mCustomKeyEditText));
+ // update referenced model item
+ holder.mModel.mKeysize = newKeySize;
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> parent) {
+ }
+ });
+
+ holder.vDelete.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ // remove reference model item from adapter (data and notify about change)
+ SubkeysAddedAdapter.this.remove(holder.mModel);
+ }
+ });
+
+ }
+ final ViewHolder holder = (ViewHolder) convertView.getTag();
+
+ // save reference to model item
+ holder.mModel = getItem(position);
+
+ // TODO
+ boolean wouldBeMasterKey = false;
+// boolean wouldBeMasterKey = (childCount == 0);
+
+ ArrayList<Choice> choices = new ArrayList<Choice>();
+ choices.add(new Choice(Constants.choice.algorithm.dsa, mActivity.getResources().getString(
+ R.string.dsa)));
+ if (!wouldBeMasterKey) {
+ choices.add(new Choice(Constants.choice.algorithm.elgamal, mActivity.getResources().getString(
+ R.string.elgamal)));
+ }
+
+ choices.add(new Choice(Constants.choice.algorithm.rsa, mActivity.getResources().getString(
+ R.string.rsa)));
+
+ ArrayAdapter<Choice> adapter = new ArrayAdapter<Choice>(mActivity,
+ android.R.layout.simple_spinner_item, choices);
+ adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ holder.mAlgorithmSpinner.setAdapter(adapter);
+ // make RSA the default
+ for (int i = 0; i < choices.size(); ++i) {
+ if (choices.get(i).getId() == Constants.choice.algorithm.rsa) {
+ holder.mAlgorithmSpinner.setSelection(i);
+ break;
+ }
+ }
+
+ // dynamic ArrayAdapter must be created (instead of ArrayAdapter.getFromResource), because it's content may change
+ ArrayAdapter<CharSequence> keySizeAdapter = new ArrayAdapter<CharSequence>(mActivity, android.R.layout.simple_spinner_item,
+ new ArrayList<CharSequence>(Arrays.asList(mActivity.getResources().getStringArray(R.array.rsa_key_size_spinner_values))));
+ keySizeAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ holder.mKeySizeSpinner.setAdapter(keySizeAdapter);
+ holder.mKeySizeSpinner.setSelection(1); // Default to 4096 for the key length
+
+ holder.mCustomKeyEditText.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+// setOkButtonAvailability(alertDialog);
+ }
+ });
+
+ holder.mKeySizeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+ setCustomKeyVisibility(holder.mKeySizeSpinner, holder.mCustomKeyEditText,
+ holder.mCustomKeyTextView, holder.mCustomKeyInfoTextView);
+// setOkButtonAvailability(alertDialog);
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> parent) {
+ }
+ });
+
+ holder.mAlgorithmSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+ setKeyLengthSpinnerValuesForAlgorithm(((Choice) parent.getSelectedItem()).getId(),
+ holder.mKeySizeSpinner, holder.mCustomKeyInfoTextView);
+
+ setCustomKeyVisibility(holder.mKeySizeSpinner, holder.mCustomKeyEditText,
+ holder.mCustomKeyTextView, holder.mCustomKeyInfoTextView);
+// setOkButtonAvailability(alertDialog);
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> parent) {
+ }
+ });
+//
+// holder.vAddress.setText(holder.mModel.address);
+// holder.vAddress.setThreshold(1); // Start working from first character
+// holder.vAddress.setAdapter(mAutoCompleteEmailAdapter);
+//
+// holder.vName.setText(holder.mModel.name);
+// holder.vName.setThreshold(1); // Start working from first character
+// holder.vName.setAdapter(mAutoCompleteNameAdapter);
+//
+// holder.vComment.setText(holder.mModel.comment);
+
+ return convertView;
+ }
+
+
+ private int getSelectedKeyLength(Spinner keySizeSpinner, EditText customKeyEditText) {
+ final String selectedItemString = (String) keySizeSpinner.getSelectedItem();
+ final String customLengthString = mActivity.getResources().getString(R.string.key_size_custom);
+ final boolean customSelected = customLengthString.equals(selectedItemString);
+ String keyLengthString = customSelected ? customKeyEditText.getText().toString() : selectedItemString;
+ int keySize;
+ try {
+ keySize = Integer.parseInt(keyLengthString);
+ } catch (NumberFormatException e) {
+ keySize = 0;
+ }
+ return keySize;
+ }
+
+ /**
+ * <h3>RSA</h3>
+ * <p>for RSA algorithm, key length must be greater than 1024 (according to
+ * <a href="https://github.com/open-keychain/open-keychain/issues/102">#102</a>). Possibility to generate keys bigger
+ * than 8192 bits is currently disabled, because it's almost impossible to generate them on a mobile device (check
+ * <a href="http://www.javamex.com/tutorials/cryptography/rsa_key_length.shtml">RSA key length plot</a> and
+ * <a href="http://www.keylength.com/">Cryptographic Key Length Recommendation</a>). Also, key length must be a
+ * multiplicity of 8.</p>
+ * <h3>ElGamal</h3>
+ * <p>For ElGamal algorithm, supported key lengths are 1536, 2048, 3072, 4096 or 8192 bits.</p>
+ * <h3>DSA</h3>
+ * <p>For DSA algorithm key length must be between 512 and 1024. Also, it must me dividable by 64.</p>
+ *
+ * @return correct key length, according to SpongyCastle specification. Returns <code>-1</code>, if key length is
+ * inappropriate.
+ */
+ private int getProperKeyLength(int algorithmId, int currentKeyLength) {
+ final int[] elGamalSupportedLengths = {1536, 2048, 3072, 4096, 8192};
+ int properKeyLength = -1;
+ switch (algorithmId) {
+ case Constants.choice.algorithm.rsa:
+ if (currentKeyLength > 1024 && currentKeyLength <= 8192) {
+ properKeyLength = currentKeyLength + ((8 - (currentKeyLength % 8)) % 8);
+ }
+ break;
+ case Constants.choice.algorithm.elgamal:
+ int[] elGammalKeyDiff = new int[elGamalSupportedLengths.length];
+ for (int i = 0; i < elGamalSupportedLengths.length; i++) {
+ elGammalKeyDiff[i] = Math.abs(elGamalSupportedLengths[i] - currentKeyLength);
+ }
+ int minimalValue = Integer.MAX_VALUE;
+ int minimalIndex = -1;
+ for (int i = 0; i < elGammalKeyDiff.length; i++) {
+ if (elGammalKeyDiff[i] <= minimalValue) {
+ minimalValue = elGammalKeyDiff[i];
+ minimalIndex = i;
+ }
+ }
+ properKeyLength = elGamalSupportedLengths[minimalIndex];
+ break;
+ case Constants.choice.algorithm.dsa:
+ if (currentKeyLength >= 512 && currentKeyLength <= 1024) {
+ properKeyLength = currentKeyLength + ((64 - (currentKeyLength % 64)) % 64);
+ }
+ break;
+ }
+ return properKeyLength;
+ }
+
+ // TODO: make this an error message on the field
+// private boolean setOkButtonAvailability(AlertDialog alertDialog) {
+// final Choice selectedAlgorithm = (Choice) mAlgorithmSpinner.getSelectedItem();
+// final int selectedKeySize = getSelectedKeyLength(); //Integer.parseInt((String) mKeySizeSpinner.getSelectedItem());
+// final int properKeyLength = getProperKeyLength(selectedAlgorithm.getId(), selectedKeySize);
+// alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(properKeyLength > 0);
+// }
+
+ private void setCustomKeyVisibility(Spinner keySizeSpinner, EditText customkeyedittext, TextView customKeyTextView, TextView customKeyInfoTextView) {
+ final String selectedItemString = (String) keySizeSpinner.getSelectedItem();
+ final String customLengthString = mActivity.getResources().getString(R.string.key_size_custom);
+ final boolean customSelected = customLengthString.equals(selectedItemString);
+ final int visibility = customSelected ? View.VISIBLE : View.GONE;
+
+ customkeyedittext.setVisibility(visibility);
+ customKeyTextView.setVisibility(visibility);
+ customKeyInfoTextView.setVisibility(visibility);
+
+ // hide keyboard after setting visibility to gone
+ if (visibility == View.GONE) {
+ InputMethodManager imm = (InputMethodManager)
+ mActivity.getSystemService(mActivity.INPUT_METHOD_SERVICE);
+ imm.hideSoftInputFromWindow(customkeyedittext.getWindowToken(), 0);
+ }
+ }
+
+ private void setKeyLengthSpinnerValuesForAlgorithm(int algorithmId, Spinner keySizeSpinner, TextView customKeyInfoTextView) {
+ final ArrayAdapter<CharSequence> keySizeAdapter = (ArrayAdapter<CharSequence>) keySizeSpinner.getAdapter();
+ final Object selectedItem = keySizeSpinner.getSelectedItem();
+ keySizeAdapter.clear();
+ switch (algorithmId) {
+ case Constants.choice.algorithm.rsa:
+ replaceArrayAdapterContent(keySizeAdapter, R.array.rsa_key_size_spinner_values);
+ customKeyInfoTextView.setText(mActivity.getResources().getString(R.string.key_size_custom_info_rsa));
+ break;
+ case Constants.choice.algorithm.elgamal:
+ replaceArrayAdapterContent(keySizeAdapter, R.array.elgamal_key_size_spinner_values);
+ customKeyInfoTextView.setText(""); // ElGamal does not support custom key length
+ break;
+ case Constants.choice.algorithm.dsa:
+ replaceArrayAdapterContent(keySizeAdapter, R.array.dsa_key_size_spinner_values);
+ customKeyInfoTextView.setText(mActivity.getResources().getString(R.string.key_size_custom_info_dsa));
+ break;
+ }
+ keySizeAdapter.notifyDataSetChanged();
+
+ // when switching algorithm, try to select same key length as before
+ for (int i = 0; i < keySizeAdapter.getCount(); i++) {
+ if (selectedItem.equals(keySizeAdapter.getItem(i))) {
+ keySizeSpinner.setSelection(i);
+ break;
+ }
+ }
+ }
+
+ @TargetApi(Build.VERSION_CODES.HONEYCOMB)
+ private void replaceArrayAdapterContent(ArrayAdapter<CharSequence> arrayAdapter, int stringArrayResourceId) {
+ final String[] spinnerValuesStringArray = mActivity.getResources().getStringArray(stringArrayResourceId);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
+ arrayAdapter.addAll(spinnerValuesStringArray);
+ } else {
+ for (final String value : spinnerValuesStringArray) {
+ arrayAdapter.add(value);
+ }
+ }
+ }
+
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java
index 7fc78dc41..d729648e5 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java
@@ -41,9 +41,6 @@ import java.util.ArrayList;
public class UserIdsAdapter extends CursorAdapter implements AdapterView.OnItemClickListener {
private LayoutInflater mInflater;
- private int mIndexUserId, mIndexRank;
- private int mVerifiedId, mIsRevoked, mIsPrimary;
-
private final ArrayList<Boolean> mCheckStates;
private SaveKeyringParcel mSaveKeyringParcel;
@@ -56,6 +53,13 @@ public class UserIdsAdapter extends CursorAdapter implements AdapterView.OnItemC
UserIds.IS_PRIMARY,
UserIds.IS_REVOKED
};
+ private static final int INDEX_ID = 0;
+ private static final int INDEX_USER_ID = 1;
+ private static final int INDEX_RANK = 2;
+ private static final int INDEX_VERIFIED = 3;
+ private static final int INDEX_IS_PRIMARY = 4;
+ private static final int INDEX_IS_REVOKED = 5;
+
public UserIdsAdapter(Context context, Cursor c, int flags, boolean showCheckBoxes,
SaveKeyringParcel saveKeyringParcel) {
@@ -64,8 +68,6 @@ public class UserIdsAdapter extends CursorAdapter implements AdapterView.OnItemC
mCheckStates = showCheckBoxes ? new ArrayList<Boolean>() : null;
mSaveKeyringParcel = saveKeyringParcel;
-
- initIndex(c);
}
public UserIdsAdapter(Context context, Cursor c, int flags, boolean showCheckBoxes) {
@@ -82,7 +84,6 @@ public class UserIdsAdapter extends CursorAdapter implements AdapterView.OnItemC
@Override
public Cursor swapCursor(Cursor newCursor) {
- initIndex(newCursor);
if (mCheckStates != null) {
mCheckStates.clear();
if (newCursor != null) {
@@ -91,7 +92,7 @@ public class UserIdsAdapter extends CursorAdapter implements AdapterView.OnItemC
// initialize to true (use case knowledge: we usually want to sign all uids)
for (int i = 0; i < count; i++) {
newCursor.moveToPosition(i);
- int verified = newCursor.getInt(mVerifiedId);
+ int verified = newCursor.getInt(INDEX_VERIFIED);
mCheckStates.add(verified != Certs.VERIFIED_SECRET);
}
}
@@ -100,31 +101,15 @@ public class UserIdsAdapter extends CursorAdapter implements AdapterView.OnItemC
return super.swapCursor(newCursor);
}
- /**
- * Get column indexes for performance reasons just once in constructor and swapCursor. For a
- * performance comparison see http://stackoverflow.com/a/17999582
- *
- * @param cursor
- */
- private void initIndex(Cursor cursor) {
- if (cursor != null) {
- mIndexUserId = cursor.getColumnIndexOrThrow(UserIds.USER_ID);
- mIndexRank = cursor.getColumnIndexOrThrow(UserIds.RANK);
- mVerifiedId = cursor.getColumnIndexOrThrow(UserIds.VERIFIED);
- mIsRevoked = cursor.getColumnIndexOrThrow(UserIds.IS_REVOKED);
- mIsPrimary = cursor.getColumnIndexOrThrow(UserIds.IS_PRIMARY);
- }
- }
-
@Override
public void bindView(View view, Context context, Cursor cursor) {
TextView vName = (TextView) view.findViewById(R.id.userId);
TextView vAddress = (TextView) view.findViewById(R.id.address);
TextView vComment = (TextView) view.findViewById(R.id.comment);
ImageView vVerified = (ImageView) view.findViewById(R.id.certified);
- ImageView vHasChanges = (ImageView) view.findViewById(R.id.has_changes);
+ ImageView vEditImage = (ImageView) view.findViewById(R.id.edit_image);
- String userId = cursor.getString(mIndexUserId);
+ String userId = cursor.getString(INDEX_USER_ID);
String[] splitUserId = KeyRing.splitUserId(userId);
if (splitUserId[0] != null) {
vName.setText(splitUserId[0]);
@@ -144,31 +129,29 @@ public class UserIdsAdapter extends CursorAdapter implements AdapterView.OnItemC
vComment.setVisibility(View.GONE);
}
- boolean isPrimary = cursor.getInt(mIsPrimary) != 0;
- boolean isRevoked = cursor.getInt(mIsRevoked) > 0;
+ boolean isPrimary = cursor.getInt(INDEX_IS_PRIMARY) != 0;
+ boolean isRevoked = cursor.getInt(INDEX_IS_REVOKED) > 0;
// for edit key
if (mSaveKeyringParcel != null) {
- boolean changeUserId = (mSaveKeyringParcel.changePrimaryUserId != null
+ boolean changeAnyPrimaryUserId = (mSaveKeyringParcel.changePrimaryUserId != null);
+ boolean changeThisPrimaryUserId = (mSaveKeyringParcel.changePrimaryUserId != null
&& mSaveKeyringParcel.changePrimaryUserId.equals(userId));
- boolean revoke = (mSaveKeyringParcel.revokeUserIds.contains(userId));
+ boolean revokeThisUserId = (mSaveKeyringParcel.revokeUserIds.contains(userId));
- if (changeUserId) {
- isPrimary = !isPrimary;
+ if (changeAnyPrimaryUserId) {
+ // change all user ids, only this one should be primary
+ isPrimary = changeThisPrimaryUserId;
}
- if (revoke) {
+ if (revokeThisUserId) {
if (!isRevoked) {
isRevoked = true;
}
}
- if (changeUserId || revoke) {
- vHasChanges.setVisibility(View.VISIBLE);
- } else {
- vHasChanges.setVisibility(View.GONE);
- }
+ vEditImage.setVisibility(View.VISIBLE);
} else {
- vHasChanges.setVisibility(View.GONE);
+ vEditImage.setVisibility(View.GONE);
}
if (isRevoked) {
@@ -178,15 +161,18 @@ public class UserIdsAdapter extends CursorAdapter implements AdapterView.OnItemC
// disable and strike through text for revoked user ids
vName.setEnabled(false);
vAddress.setEnabled(false);
+ vComment.setEnabled(false);
vName.setText(OtherHelper.strikeOutText(vName.getText()));
vAddress.setText(OtherHelper.strikeOutText(vAddress.getText()));
+ vComment.setText(OtherHelper.strikeOutText(vComment.getText()));
} else {
vName.setEnabled(true);
vAddress.setEnabled(true);
+ vComment.setEnabled(true);
// verified: has been verified
// isPrimary: show small star icon for primary user ids
- int verified = cursor.getInt(mVerifiedId);
+ int verified = cursor.getInt(INDEX_VERIFIED);
switch (verified) {
case Certs.VERIFIED_SECRET:
vVerified.setImageResource(isPrimary
@@ -234,7 +220,7 @@ public class UserIdsAdapter extends CursorAdapter implements AdapterView.OnItemC
for (int i = 0; i < mCheckStates.size(); i++) {
if (mCheckStates.get(i)) {
mCursor.moveToPosition(i);
- result.add(mCursor.getString(mIndexUserId));
+ result.add(mCursor.getString(INDEX_USER_ID));
}
}
return result;
@@ -242,7 +228,7 @@ public class UserIdsAdapter extends CursorAdapter implements AdapterView.OnItemC
public String getUserId(int position) {
mCursor.moveToPosition(position);
- return mCursor.getString(mIndexUserId);
+ return mCursor.getString(INDEX_USER_ID);
}
@Override
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAddedAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAddedAdapter.java
new file mode 100644
index 000000000..3fe5574ee
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAddedAdapter.java
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package org.sufficientlysecure.keychain.ui.adapter;
+
+import android.app.Activity;
+import android.content.Context;
+import android.text.Editable;
+import android.text.TextUtils;
+import android.text.TextWatcher;
+import android.util.Patterns;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.AutoCompleteTextView;
+import android.widget.EditText;
+import android.widget.ImageButton;
+
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.helper.ContactHelper;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+
+public class UserIdsAddedAdapter extends ArrayAdapter<UserIdsAddedAdapter.UserIdModel> {
+ private LayoutInflater mInflater;
+ private Activity mActivity;
+
+ private ArrayAdapter<String> mAutoCompleteNameAdapter;
+ private ArrayAdapter<String> mAutoCompleteEmailAdapter;
+
+ // hold a private reference to the underlying data List
+ private List<UserIdModel> mData;
+
+ public static class UserIdModel {
+ String name = "";
+ String address = "";
+ String comment = "";
+
+ @Override
+ public String toString() {
+ String userId = name;
+ if (!TextUtils.isEmpty(comment)) {
+ userId += " (" + comment + ")";
+ }
+ if (!TextUtils.isEmpty(address)) {
+ userId += " <" + address + ">";
+ }
+ return userId;
+ }
+ }
+
+ public UserIdsAddedAdapter(Activity activity, List<UserIdModel> data) {
+ super(activity, -1, data);
+ mActivity = activity;
+ mInflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ mData = data;
+ mAutoCompleteNameAdapter = new ArrayAdapter<String>
+ (mActivity, android.R.layout.simple_spinner_dropdown_item,
+ ContactHelper.getPossibleUserNames(mActivity)
+ );
+ mAutoCompleteEmailAdapter = new ArrayAdapter<String>
+ (mActivity, android.R.layout.simple_spinner_dropdown_item,
+ ContactHelper.getPossibleUserEmails(mActivity)
+ );
+ }
+
+ public ArrayList<String> getDataAsStringList() {
+ ArrayList<String> out = new ArrayList<String>();
+ for (UserIdModel id : mData) {
+ // ignore empty user ids
+ if (!TextUtils.isEmpty(id.toString())) {
+ out.add(id.toString());
+ }
+ }
+
+ return out;
+ }
+
+ static class ViewHolder {
+ public AutoCompleteTextView vAddress;
+ public AutoCompleteTextView vName;
+ public EditText vComment;
+ public ImageButton vDelete;
+ // also hold a reference to the model item
+ public UserIdModel mModel;
+ }
+
+ public View getView(final int position, View convertView, ViewGroup parent) {
+ if (convertView == null) {
+ // Not recycled, inflate a new view
+ convertView = mInflater.inflate(R.layout.edit_key_user_id_added_item, null);
+ final ViewHolder holder = new ViewHolder();
+ holder.vAddress = (AutoCompleteTextView) convertView.findViewById(R.id.user_id_added_item_address);
+ holder.vName = (AutoCompleteTextView) convertView.findViewById(R.id.user_id_added_item_name);
+ holder.vComment = (EditText) convertView.findViewById(R.id.user_id_added_item_comment);
+ holder.vDelete = (ImageButton) convertView.findViewById(R.id.user_id_added_item_delete);
+ convertView.setTag(holder);
+
+ holder.vAddress.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ // update referenced item in view holder
+ holder.mModel.address = s.toString();
+
+ // show icon on valid email addresses
+ if (holder.mModel.address.length() > 0) {
+ Matcher emailMatcher = Patterns.EMAIL_ADDRESS.matcher(holder.mModel.address);
+ if (emailMatcher.matches()) {
+ holder.vAddress.setCompoundDrawablesWithIntrinsicBounds(0, 0,
+ R.drawable.uid_mail_ok, 0);
+ } else {
+ holder.vAddress.setCompoundDrawablesWithIntrinsicBounds(0, 0,
+ R.drawable.uid_mail_bad, 0);
+ }
+ } else {
+ // remove drawable if email is empty
+ holder.vAddress.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
+ }
+ }
+ });
+
+ holder.vName.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ // update referenced item in view holder
+ holder.mModel.name = s.toString();
+ }
+ });
+
+ holder.vComment.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ // update referenced item in view holder
+ holder.mModel.comment = s.toString();
+ }
+ });
+
+ holder.vDelete.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ // remove reference model item from adapter (data and notify about change)
+ UserIdsAddedAdapter.this.remove(holder.mModel);
+ }
+ });
+
+ }
+ final ViewHolder holder = (ViewHolder) convertView.getTag();
+
+ // save reference to model item
+ holder.mModel = getItem(position);
+
+ holder.vAddress.setText(holder.mModel.address);
+ holder.vAddress.setThreshold(1); // Start working from first character
+ holder.vAddress.setAdapter(mAutoCompleteEmailAdapter);
+
+ holder.vName.setText(holder.mModel.name);
+ holder.vName.setThreshold(1); // Start working from first character
+ holder.vName.setAdapter(mAutoCompleteNameAdapter);
+
+ holder.vComment.setText(holder.mModel.comment);
+
+ return convertView;
+ }
+
+}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsArrayAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsArrayAdapter.java
deleted file mode 100644
index e6445c074..000000000
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsArrayAdapter.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright (C) 2013-2014 Dominik Schürmann <dominik@dominikschuermann.de>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package org.sufficientlysecure.keychain.ui.adapter;
-
-import android.annotation.TargetApi;
-import android.app.Activity;
-import android.content.Context;
-import android.os.Build;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ArrayAdapter;
-import android.widget.CheckBox;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.pgp.KeyRing;
-
-import java.util.List;
-
-public class UserIdsArrayAdapter extends ArrayAdapter<String> {
- protected LayoutInflater mInflater;
- protected Activity mActivity;
-
- protected List<String> mData;
-
- static class ViewHolder {
- public TextView vName;
- public TextView vAddress;
- public TextView vComment;
- public ImageView vVerified;
- public ImageView vHasChanges;
- public CheckBox vCheckBox;
- }
-
- public UserIdsArrayAdapter(Activity activity) {
- super(activity, -1);
- mActivity = activity;
- mInflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- }
-
- @TargetApi(Build.VERSION_CODES.HONEYCOMB)
- public void setData(List<String> data) {
- clear();
- if (data != null) {
- this.mData = data;
-
- // add data to extended ArrayAdapter
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
- addAll(data);
- } else {
- for (String entry : data) {
- add(entry);
- }
- }
- }
- }
-
- public List<String> getData() {
- return mData;
- }
-
- @Override
- public boolean hasStableIds() {
- return true;
- }
-
- public View getView(int position, View convertView, ViewGroup parent) {
- String entry = mData.get(position);
- ViewHolder holder;
- if (convertView == null) {
- holder = new ViewHolder();
- convertView = mInflater.inflate(R.layout.view_key_userids_item, null);
- holder.vName = (TextView) convertView.findViewById(R.id.userId);
- holder.vAddress = (TextView) convertView.findViewById(R.id.address);
- holder.vComment = (TextView) convertView.findViewById(R.id.comment);
- holder.vVerified = (ImageView) convertView.findViewById(R.id.certified);
- holder.vHasChanges = (ImageView) convertView.findViewById(R.id.has_changes);
- holder.vCheckBox = (CheckBox) convertView.findViewById(R.id.checkBox);
- convertView.setTag(holder);
- } else {
- holder = (ViewHolder) convertView.getTag();
- }
-
- // user id
- String[] splitUserId = KeyRing.splitUserId(entry);
- if (splitUserId[0] != null) {
- holder.vName.setText(splitUserId[0]);
- } else {
- holder.vName.setText(R.string.user_id_no_name);
- }
- if (splitUserId[1] != null) {
- holder.vAddress.setText(splitUserId[1]);
- holder.vAddress.setVisibility(View.VISIBLE);
- } else {
- holder.vAddress.setVisibility(View.GONE);
- }
- if (splitUserId[2] != null) {
- holder.vComment.setText(splitUserId[2]);
- holder.vComment.setVisibility(View.VISIBLE);
- } else {
- holder.vComment.setVisibility(View.GONE);
- }
-
- holder.vCheckBox.setVisibility(View.GONE);
-
- holder.vVerified.setImageResource(R.drawable.key_certify_ok_depth0);
-
- // all items are "new"
- holder.vHasChanges.setVisibility(View.VISIBLE);
-
- return convertView;
- }
-
-}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddUserIdDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddUserIdDialogFragment.java
deleted file mode 100644
index c27266e3f..000000000
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddUserIdDialogFragment.java
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de>
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package org.sufficientlysecure.keychain.ui.dialog;
-
-import android.app.Dialog;
-import android.content.DialogInterface;
-import android.os.Bundle;
-import android.os.Message;
-import android.os.Messenger;
-import android.os.RemoteException;
-import android.support.v4.app.DialogFragment;
-import android.text.TextUtils;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.WindowManager;
-import android.view.inputmethod.EditorInfo;
-import android.widget.EditText;
-import android.widget.TextView;
-
-import org.sufficientlysecure.keychain.Constants;
-import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.util.Log;
-
-public class AddUserIdDialogFragment extends DialogFragment implements EditText.OnEditorActionListener {
- private static final String ARG_MESSENGER = "messenger";
-
- public static final int MESSAGE_OKAY = 1;
-
- public static final String MESSAGE_DATA_USER_ID = "user_id";
-
- private Messenger mMessenger;
-
- EditText mName;
- EditText mAddress;
- EditText mComment;
-
- /**
- * Creates new instance of this dialog fragment
- */
- public static AddUserIdDialogFragment newInstance(Messenger messenger) {
- AddUserIdDialogFragment frag = new AddUserIdDialogFragment();
- Bundle args = new Bundle();
- args.putParcelable(ARG_MESSENGER, messenger);
-
- frag.setArguments(args);
-
- return frag;
- }
-
- /**
- * Creates dialog
- */
- @Override
- public Dialog onCreateDialog(Bundle savedInstanceState) {
- mMessenger = getArguments().getParcelable(ARG_MESSENGER);
-
- CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(getActivity());
- LayoutInflater inflater = getActivity().getLayoutInflater();
- View view = inflater.inflate(R.layout.add_user_id_dialog, null);
- alert.setView(view);
- alert.setTitle("Add Identity");
-
- mName = (EditText) view.findViewById(R.id.name);
- mAddress = (EditText) view.findViewById(R.id.address);
- mComment = (EditText) view.findViewById(R.id.comment);
-
- alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
-
- @Override
- public void onClick(DialogInterface dialog, int id) {
- done();
- }
- });
-
- alert.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
-
- @Override
- public void onClick(DialogInterface dialog, int id) {
- dialog.cancel();
- }
- });
-
-
- return alert.show();
- }
-
- @Override
- public void onActivityCreated(Bundle arg0) {
- super.onActivityCreated(arg0);
- // Show soft keyboard automatically
- mName.requestFocus();
- getDialog().getWindow().setSoftInputMode(
- WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
- mComment.setOnEditorActionListener(this);
- }
-
- @Override
- public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
- if (EditorInfo.IME_ACTION_DONE == actionId) {
- done();
- return true;
- }
- return false;
- }
-
- private void done() {
- String name = mName.getText().toString();
- String email = mAddress.getText().toString();
- String comment = mComment.getText().toString();
-
- String userId = null;
- if (!TextUtils.isEmpty(name)) {
- userId = name;
- if (!TextUtils.isEmpty(comment)) {
- userId += " (" + comment + ")";
- }
- if (!TextUtils.isEmpty(email)) {
- userId += " <" + email + ">";
- }
- }
- Bundle data = new Bundle();
- data.putString(MESSAGE_DATA_USER_ID, userId);
- sendMessageToHandler(MESSAGE_OKAY, data);
-
- this.dismiss();
- }
-
- /**
- * Send message back to handler which is initialized in a activity
- *
- * @param what Message integer you want to send
- */
- private void sendMessageToHandler(Integer what, Bundle data) {
- Message msg = Message.obtain();
- msg.what = what;
- if (data != null) {
- msg.setData(data);
- }
-
- try {
- mMessenger.send(msg);
- } catch (RemoteException e) {
- Log.w(Constants.TAG, "Exception sending message, Is handler present?", e);
- } catch (NullPointerException e) {
- Log.w(Constants.TAG, "Messenger is null!", e);
- }
- }
-
-}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/CreateKeyDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/CreateKeyDialogFragment.java
index 6c012cb94..920743a9b 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/CreateKeyDialogFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/CreateKeyDialogFragment.java
@@ -51,8 +51,6 @@ public class CreateKeyDialogFragment extends DialogFragment {
private static final String ARG_EDITOR_CHILD_COUNT = "child_count";
- private int mNewKeySize;
- private Choice mNewKeyAlgorithmChoice;
private OnAlgorithmSelectedListener mAlgorithmSelectedListener;
private Spinner mAlgorithmSpinner;
private Spinner mKeySizeSpinner;
@@ -131,9 +129,9 @@ public class CreateKeyDialogFragment extends DialogFragment {
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface di, int id) {
di.dismiss();
- mNewKeyAlgorithmChoice = (Choice) mAlgorithmSpinner.getSelectedItem();
- mNewKeySize = getProperKeyLength(mNewKeyAlgorithmChoice.getId(), getSelectedKeyLength());
- mAlgorithmSelectedListener.onAlgorithmSelected(mNewKeyAlgorithmChoice, mNewKeySize);
+ Choice newKeyAlgorithmChoice = (Choice) mAlgorithmSpinner.getSelectedItem();
+ int newKeySize = getProperKeyLength(newKeyAlgorithmChoice.getId(), getSelectedKeyLength());
+ mAlgorithmSelectedListener.onAlgorithmSelected(newKeyAlgorithmChoice, newKeySize);
}
}
);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/EditUserIdDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/EditUserIdDialogFragment.java
index f0ca73f0d..5eba3a463 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/EditUserIdDialogFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/EditUserIdDialogFragment.java
@@ -26,6 +26,7 @@ import android.os.RemoteException;
import android.support.v4.app.DialogFragment;
import org.sufficientlysecure.keychain.Constants;
+import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.util.Log;
public class EditUserIdDialogFragment extends DialogFragment {
@@ -57,9 +58,9 @@ public class EditUserIdDialogFragment extends DialogFragment {
mMessenger = getArguments().getParcelable(ARG_MESSENGER);
CustomAlertDialogBuilder builder = new CustomAlertDialogBuilder(getActivity());
- CharSequence[] array = {"change to primary user id", "revoke"};
+ CharSequence[] array = getResources().getStringArray(R.array.edit_key_edit_user_id);
- builder.setTitle("select action!");
+ builder.setTitle(R.string.edit_key_edit_user_id_title);
builder.setItems(array, new DialogInterface.OnClickListener() {
@Override
@@ -76,7 +77,7 @@ public class EditUserIdDialogFragment extends DialogFragment {
}
}
});
- builder.setNegativeButton("cancel", new DialogInterface.OnClickListener() {
+ builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
dismiss();
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/SetPassphraseDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/SetPassphraseDialogFragment.java
index 04bec3282..93da48b75 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/SetPassphraseDialogFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/SetPassphraseDialogFragment.java
@@ -26,12 +26,15 @@ import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.support.v4.app.DialogFragment;
+import android.text.TextUtils;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager.LayoutParams;
import android.view.inputmethod.EditorInfo;
import android.widget.Button;
+import android.widget.CheckBox;
+import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
@@ -44,6 +47,7 @@ import org.sufficientlysecure.keychain.util.Log;
public class SetPassphraseDialogFragment extends DialogFragment implements OnEditorActionListener {
private static final String ARG_MESSENGER = "messenger";
private static final String ARG_TITLE = "title";
+ private static final String ARG_OLD_PASSPHRASE = "old_passphrase";
public static final int MESSAGE_OKAY = 1;
@@ -52,6 +56,7 @@ public class SetPassphraseDialogFragment extends DialogFragment implements OnEdi
private Messenger mMessenger;
private EditText mPassphraseEditText;
private EditText mPassphraseAgainEditText;
+ private CheckBox mNoPassphraseCheckBox;
/**
* Creates new instance of this dialog fragment
@@ -60,11 +65,12 @@ public class SetPassphraseDialogFragment extends DialogFragment implements OnEdi
* @param messenger to communicate back after setting the passphrase
* @return
*/
- public static SetPassphraseDialogFragment newInstance(Messenger messenger, int title) {
+ public static SetPassphraseDialogFragment newInstance(Messenger messenger, String oldPassphrase, int title) {
SetPassphraseDialogFragment frag = new SetPassphraseDialogFragment();
Bundle args = new Bundle();
args.putInt(ARG_TITLE, title);
args.putParcelable(ARG_MESSENGER, messenger);
+ args.putString(ARG_OLD_PASSPHRASE, oldPassphrase);
frag.setArguments(args);
@@ -80,6 +86,7 @@ public class SetPassphraseDialogFragment extends DialogFragment implements OnEdi
int title = getArguments().getInt(ARG_TITLE);
mMessenger = getArguments().getParcelable(ARG_MESSENGER);
+ String oldPassphrase = getArguments().getString(ARG_OLD_PASSPHRASE);
CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(activity);
@@ -92,6 +99,21 @@ public class SetPassphraseDialogFragment extends DialogFragment implements OnEdi
mPassphraseEditText = (EditText) view.findViewById(R.id.passphrase_passphrase);
mPassphraseAgainEditText = (EditText) view.findViewById(R.id.passphrase_passphrase_again);
+ mNoPassphraseCheckBox = (CheckBox) view.findViewById(R.id.passphrase_no_passphrase);
+
+ if (TextUtils.isEmpty(oldPassphrase)) {
+ mNoPassphraseCheckBox.setChecked(true);
+ mPassphraseEditText.setEnabled(false);
+ mPassphraseAgainEditText.setEnabled(false);
+ }
+
+ mNoPassphraseCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ mPassphraseEditText.setEnabled(!isChecked);
+ mPassphraseAgainEditText.setEnabled(!isChecked);
+ }
+ });
alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@@ -99,24 +121,31 @@ public class SetPassphraseDialogFragment extends DialogFragment implements OnEdi
public void onClick(DialogInterface dialog, int id) {
dismiss();
- String passphrase1 = mPassphraseEditText.getText().toString();
- String passphrase2 = mPassphraseAgainEditText.getText().toString();
- if (!passphrase1.equals(passphrase2)) {
- Toast.makeText(
- activity,
- getString(R.string.error_message,
- getString(R.string.passphrases_do_not_match)), Toast.LENGTH_SHORT)
- .show();
- return;
- }
-
- if (passphrase1.equals("")) {
- Toast.makeText(
- activity,
- getString(R.string.error_message,
- getString(R.string.passphrase_must_not_be_empty)),
- Toast.LENGTH_SHORT).show();
- return;
+ String passphrase1;
+ if (mNoPassphraseCheckBox.isChecked()) {
+ passphrase1 = "";
+ } else {
+ passphrase1 = mPassphraseEditText.getText().toString();
+ String passphrase2 = mPassphraseAgainEditText.getText().toString();
+ if (!passphrase1.equals(passphrase2)) {
+ Toast.makeText(
+ activity,
+ getString(R.string.error_message,
+ getString(R.string.passphrases_do_not_match)), Toast.LENGTH_SHORT
+ )
+ .show();
+ return;
+ }
+
+ if (passphrase1.equals("")) {
+ Toast.makeText(
+ activity,
+ getString(R.string.error_message,
+ getString(R.string.passphrase_must_not_be_empty)),
+ Toast.LENGTH_SHORT
+ ).show();
+ return;
+ }
}
// return resulting data back to activity
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/FixedListView.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/FixedListView.java
index da29f808a..294ff1500 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/FixedListView.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/FixedListView.java
@@ -25,9 +25,7 @@ import android.widget.ListView;
* Automatically calculate height of ListView based on contained items. This enables to put this
* ListView into a ScrollView without messing up.
* <p/>
- * from
- * http://stackoverflow.com/questions/2419246/how-do-i-create-a-listview-thats-not-in-a-scrollview-
- * or-has-the-scrollview-dis
+ * from http://stackoverflow.com/a/3580117
*/
public class FixedListView extends ListView {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SectionView.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SectionView.java
index 4ecc96cee..cd5671801 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SectionView.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SectionView.java
@@ -388,7 +388,7 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor
if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) {
// get new key from data bundle returned from service
- Bundle data = message.getData();
+ Bundle data = message.getDataAsStringList();
UncachedSecretKey newKey = PgpConversionHelper
.BytesToPGPSecretKey(data
.getByteArray(KeychainIntentService.RESULT_NEW_KEY));