diff options
author | Ashley Hughes <spirit.returned@gmail.com> | 2014-03-07 15:16:13 +0000 |
---|---|---|
committer | Ashley Hughes <spirit.returned@gmail.com> | 2014-03-07 15:16:13 +0000 |
commit | fba0e2af1d04fe95f82a60ed2acbb69d5be920d2 (patch) | |
tree | 2ec7978ddac4a3c3a2b99e165ddfdffea3835989 /OpenPGP-Keychain/src/main/java/org/sufficientlysecure | |
parent | 04fa0e9cc7fbfc117948d60a3ad8bfab0b0060ba (diff) | |
parent | 59067f9f8b0a12f875ba928b30f8f35fc284356c (diff) | |
download | open-keychain-fba0e2af1d04fe95f82a60ed2acbb69d5be920d2.tar.gz open-keychain-fba0e2af1d04fe95f82a60ed2acbb69d5be920d2.tar.bz2 open-keychain-fba0e2af1d04fe95f82a60ed2acbb69d5be920d2.zip |
keep up with master
Diffstat (limited to 'OpenPGP-Keychain/src/main/java/org/sufficientlysecure')
39 files changed, 1402 insertions, 770 deletions
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/Constants.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/Constants.java index c1809e4e1..4428c7133 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/Constants.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/Constants.java @@ -51,7 +51,7 @@ public final class Constants { public static final String DEFAULT_ASCII_ARMOUR = "defaultAsciiArmour"; public static final String DEFAULT_MESSAGE_COMPRESSION = "defaultMessageCompression"; public static final String DEFAULT_FILE_COMPRESSION = "defaultFileCompression"; - public static final String PASS_PHRASE_CACHE_TTL = "passPhraseCacheTtl"; + public static final String PASS_PHRASE_CACHE_TTL = "passphraseCacheTtl"; public static final String LANGUAGE = "language"; public static final String FORCE_V3_SIGNATURES = "forceV3Signatures"; public static final String KEY_SERVERS = "keyServers"; diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/Id.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/Id.java index a1571e491..1d79edd43 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/Id.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/Id.java @@ -30,7 +30,7 @@ public final class Id { public static final class menu { public static final class option { - public static final int new_pass_phrase = 0x21070001; + public static final int new_passphrase = 0x21070001; public static final int create = 0x21070002; public static final int about = 0x21070003; public static final int manage_public_keys = 0x21070004; @@ -85,12 +85,12 @@ public final class Id { } public static final class dialog { - public static final int pass_phrase = 0x21070001; + public static final int passphrase = 0x21070001; public static final int encrypting = 0x21070002; public static final int decrypting = 0x21070003; - public static final int new_pass_phrase = 0x21070004; - public static final int pass_phrases_do_not_match = 0x21070005; - public static final int no_pass_phrase = 0x21070006; + public static final int new_passphrase = 0x21070004; + public static final int passphrases_do_not_match = 0x21070005; + public static final int no_passphrase = 0x21070006; public static final int saving = 0x21070007; public static final int delete_key = 0x21070008; public static final int import_keys = 0x21070009; diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java index fb97f3a5c..ccd6ff8df 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java @@ -18,8 +18,8 @@ package org.sufficientlysecure.keychain.pgp; import android.content.Context; -import android.os.Bundle; +import org.openintents.openpgp.OpenPgpSignatureResult; import org.spongycastle.bcpg.ArmoredInputStream; import org.spongycastle.bcpg.SignatureSubpacketTags; import org.spongycastle.openpgp.PGPCompressedData; @@ -36,6 +36,7 @@ import org.spongycastle.openpgp.PGPPublicKey; import org.spongycastle.openpgp.PGPPublicKeyEncryptedData; import org.spongycastle.openpgp.PGPPublicKeyRing; import org.spongycastle.openpgp.PGPSecretKey; +import org.spongycastle.openpgp.PGPSecretKeyRing; import org.spongycastle.openpgp.PGPSignature; import org.spongycastle.openpgp.PGPSignatureList; import org.spongycastle.openpgp.PGPSignatureSubpacketVector; @@ -53,7 +54,7 @@ import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.service.KeychainIntentService; +import org.sufficientlysecure.keychain.service.PassphraseCacheService; import org.sufficientlysecure.keychain.util.InputData; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.ProgressDialogUpdater; @@ -75,9 +76,10 @@ public class PgpDecryptVerify { private InputData data; private OutputStream outStream; - private ProgressDialogUpdater progress; - boolean assumeSymmetric; - String passphrase; + private ProgressDialogUpdater progressDialogUpdater; + private boolean assumeSymmetric; + private String passphrase; + private long enforcedKeyId; private PgpDecryptVerify(Builder builder) { // private Constructor can only be called from Builder @@ -85,9 +87,10 @@ public class PgpDecryptVerify { this.data = builder.data; this.outStream = builder.outStream; - this.progress = builder.progress; + this.progressDialogUpdater = builder.progressDialogUpdater; this.assumeSymmetric = builder.assumeSymmetric; this.passphrase = builder.passphrase; + this.enforcedKeyId = builder.enforcedKeyId; } public static class Builder { @@ -97,9 +100,10 @@ public class PgpDecryptVerify { private OutputStream outStream; // optional - private ProgressDialogUpdater progress = null; + private ProgressDialogUpdater progressDialogUpdater = null; private boolean assumeSymmetric = false; private String passphrase = ""; + private long enforcedKeyId = 0; public Builder(Context context, InputData data, OutputStream outStream) { this.context = context; @@ -107,8 +111,8 @@ public class PgpDecryptVerify { this.outStream = outStream; } - public Builder progress(ProgressDialogUpdater progress) { - this.progress = progress; + public Builder progressDialogUpdater(ProgressDialogUpdater progressDialogUpdater) { + this.progressDialogUpdater = progressDialogUpdater; return this; } @@ -122,20 +126,32 @@ public class PgpDecryptVerify { return this; } + /** + * Allow this key id alone for decryption. + * This means only ciphertexts encrypted for this private key can be decrypted. + * + * @param enforcedKeyId + * @return + */ + public Builder enforcedKeyId(long enforcedKeyId) { + this.enforcedKeyId = enforcedKeyId; + return this; + } + public PgpDecryptVerify build() { return new PgpDecryptVerify(this); } } public void updateProgress(int message, int current, int total) { - if (progress != null) { - progress.setProgress(message, current, total); + if (progressDialogUpdater != null) { + progressDialogUpdater.setProgress(message, current, total); } } public void updateProgress(int current, int total) { - if (progress != null) { - progress.setProgress(current, total); + if (progressDialogUpdater != null) { + progressDialogUpdater.setProgress(current, total); } } @@ -177,9 +193,8 @@ public class PgpDecryptVerify { * @throws PGPException * @throws SignatureException */ - public Bundle execute() + public PgpDecryptVerifyResult execute() throws IOException, PgpGeneralException, PGPException, SignatureException { - // automatically works with ascii armor input and binary InputStream in = PGPUtil.getDecoderStream(data.getInputStream()); if (in instanceof ArmoredInputStream) { @@ -207,9 +222,9 @@ public class PgpDecryptVerify { * @throws PGPException * @throws SignatureException */ - private Bundle decryptVerify(InputStream in) + private PgpDecryptVerifyResult decryptVerify(InputStream in) throws IOException, PgpGeneralException, PGPException, SignatureException { - Bundle returnData = new Bundle(); + PgpDecryptVerifyResult returnData = new PgpDecryptVerifyResult(); PGPObjectFactory pgpF = new PGPObjectFactory(in); PGPEncryptedDataList enc; @@ -277,9 +292,40 @@ public class PgpDecryptVerify { PGPPublicKeyEncryptedData encData = (PGPPublicKeyEncryptedData) obj; secretKey = ProviderHelper.getPGPSecretKeyByKeyId(context, encData.getKeyID()); if (secretKey != null) { + // secret key exists in database + + // allow only a specific key for decryption? + if (enforcedKeyId != 0) { + // TODO: improve this code! get master key directly! + PGPSecretKeyRing secretKeyRing = ProviderHelper.getPGPSecretKeyRingByKeyId(context, encData.getKeyID()); + long masterKeyId = PgpKeyHelper.getMasterKey(secretKeyRing).getKeyID(); + Log.d(Constants.TAG, "encData.getKeyID():" + encData.getKeyID()); + Log.d(Constants.TAG, "enforcedKeyId: " + enforcedKeyId); + Log.d(Constants.TAG, "masterKeyId: " + masterKeyId); + + if (enforcedKeyId != masterKeyId) { + throw new PgpGeneralException(context.getString(R.string.error_no_secret_key_found)); + } + } + pbe = encData; + + // if no passphrase was explicitly set try to get it from the cache service + if (passphrase == null) { + // returns "" if key has no passphrase + passphrase = PassphraseCacheService.getCachedPassphrase(context, encData.getKeyID()); + + // if passphrase was not cached, return here indicating that a passphrase is missing! + if (passphrase == null) { + returnData.setKeyPassphraseNeeded(true); + return returnData; + } + } + break; } + + } } @@ -289,7 +335,7 @@ public class PgpDecryptVerify { currentProgress += 5; updateProgress(R.string.progress_extracting_key, currentProgress, 100); - PGPPrivateKey privateKey = null; + PGPPrivateKey privateKey; try { PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder() .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build( @@ -317,6 +363,7 @@ public class PgpDecryptVerify { PGPObjectFactory plainFact = new PGPObjectFactory(clear); Object dataChunk = plainFact.nextObject(); PGPOnePassSignature signature = null; + OpenPgpSignatureResult signatureResult = null; PGPPublicKey signatureKey = null; int signatureIndex = -1; @@ -334,7 +381,7 @@ public class PgpDecryptVerify { if (dataChunk instanceof PGPOnePassSignatureList) { updateProgress(R.string.progress_processing_signature, currentProgress, 100); - returnData.putBoolean(KeychainIntentService.RESULT_SIGNATURE, true); + signatureResult = new OpenPgpSignatureResult(); PGPOnePassSignatureList sigList = (PGPOnePassSignatureList) dataChunk; for (int i = 0; i < sigList.size(); ++i) { signature = sigList.get(i); @@ -354,12 +401,12 @@ public class PgpDecryptVerify { if (signKeyRing != null) { userId = PgpKeyHelper.getMainUserId(PgpKeyHelper.getMasterKey(signKeyRing)); } - returnData.putString(KeychainIntentService.RESULT_SIGNATURE_USER_ID, userId); + signatureResult.setUserId(userId); break; } } - returnData.putLong(KeychainIntentService.RESULT_SIGNATURE_KEY_ID, signatureKeyId); + signatureResult.setKeyId(signatureKeyId); if (signature != null) { JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = new JcaPGPContentVerifierBuilderProvider() @@ -367,7 +414,7 @@ public class PgpDecryptVerify { signature.init(contentVerifierBuilderProvider, signatureKey); } else { - returnData.putBoolean(KeychainIntentService.RESULT_SIGNATURE_UNKNOWN, true); + signatureResult.setStatus(OpenPgpSignatureResult.SIGNATURE_UNKNOWN_PUB_KEY); } dataChunk = plainFact.nextObject(); @@ -405,8 +452,7 @@ public class PgpDecryptVerify { try { signature.update(buffer, 0, n); } catch (SignatureException e) { - returnData - .putBoolean(KeychainIntentService.RESULT_SIGNATURE_SUCCESS, false); + signatureResult.setStatus(OpenPgpSignatureResult.SIGNATURE_ERROR); signature = null; } } @@ -430,17 +476,20 @@ public class PgpDecryptVerify { PGPSignature messageSignature = signatureList.get(signatureIndex); // these are not cleartext signatures! - returnData.putBoolean(KeychainIntentService.RESULT_CLEARTEXT_SIGNATURE_ONLY, false); + // TODO: what about binary signatures? + signatureResult.setSignatureOnly(false); //Now check binding signatures - boolean keyBinding_isok = verifyKeyBinding(context, messageSignature, signatureKey); - boolean sig_isok = signature.verify(messageSignature); + boolean validKeyBinding = verifyKeyBinding(context, messageSignature, signatureKey); + boolean validSignature = signature.verify(messageSignature); - returnData.putBoolean(KeychainIntentService.RESULT_SIGNATURE_SUCCESS, keyBinding_isok & sig_isok); + // TODO: implement CERTIFIED! + if (validKeyBinding & validSignature) { + signatureResult.setStatus(OpenPgpSignatureResult.SIGNATURE_SUCCESS_UNCERTIFIED); + } } } - // TODO: test if this integrity really check works! if (encryptedData.isIntegrityProtected()) { updateProgress(R.string.progress_verifying_integrity, 95, 100); @@ -455,9 +504,12 @@ public class PgpDecryptVerify { } else { // no integrity check Log.e(Constants.TAG, "Encrypted data was not integrity protected!"); + // TODO: inform user? } updateProgress(R.string.progress_done, 100, 100); + + returnData.setSignatureResult(signatureResult); return returnData; } @@ -474,11 +526,12 @@ public class PgpDecryptVerify { * @throws PGPException * @throws SignatureException */ - private Bundle verifyCleartextSignature(ArmoredInputStream aIn) + private PgpDecryptVerifyResult verifyCleartextSignature(ArmoredInputStream aIn) throws IOException, PgpGeneralException, PGPException, SignatureException { - Bundle returnData = new Bundle(); + PgpDecryptVerifyResult returnData = new PgpDecryptVerifyResult(); + OpenPgpSignatureResult signatureResult = new OpenPgpSignatureResult(); // cleartext signatures are never encrypted ;) - returnData.putBoolean(KeychainIntentService.RESULT_CLEARTEXT_SIGNATURE_ONLY, true); + signatureResult.setSignatureOnly(true); ByteArrayOutputStream out = new ByteArrayOutputStream(); @@ -504,8 +557,6 @@ public class PgpDecryptVerify { byte[] clearText = out.toByteArray(); outStream.write(clearText); - returnData.putBoolean(KeychainIntentService.RESULT_SIGNATURE, true); - updateProgress(R.string.progress_processing_signature, 60, 100); PGPObjectFactory pgpFact = new PGPObjectFactory(aIn); @@ -533,15 +584,17 @@ public class PgpDecryptVerify { if (signKeyRing != null) { userId = PgpKeyHelper.getMainUserId(PgpKeyHelper.getMasterKey(signKeyRing)); } - returnData.putString(KeychainIntentService.RESULT_SIGNATURE_USER_ID, userId); + signatureResult.setUserId(userId); break; } } - returnData.putLong(KeychainIntentService.RESULT_SIGNATURE_KEY_ID, signatureKeyId); + signatureResult.setKeyId(signatureKeyId); if (signature == null) { - returnData.putBoolean(KeychainIntentService.RESULT_SIGNATURE_UNKNOWN, true); + signatureResult.setStatus(OpenPgpSignatureResult.SIGNATURE_UNKNOWN_PUB_KEY); + returnData.setSignatureResult(signatureResult); + updateProgress(R.string.progress_done, 100, 100); return returnData; } @@ -569,12 +622,17 @@ public class PgpDecryptVerify { } while (lookAhead != -1); } - boolean sig_isok = signature.verify(); - //Now check binding signatures - boolean keyBinding_isok = verifyKeyBinding(context, signature, signatureKey); + boolean validKeyBinding = verifyKeyBinding(context, signature, signatureKey); + boolean validSignature = signature.verify(); + + if (validSignature & validKeyBinding) { + signatureResult.setStatus(OpenPgpSignatureResult.SIGNATURE_SUCCESS_UNCERTIFIED); + } + + // TODO: what about SIGNATURE_SUCCESS_CERTIFIED and SIGNATURE_ERROR???? - returnData.putBoolean(KeychainIntentService.RESULT_SIGNATURE_SUCCESS, sig_isok & keyBinding_isok); + returnData.setSignatureResult(signatureResult); updateProgress(R.string.progress_done, 100, 100); return returnData; @@ -582,34 +640,34 @@ public class PgpDecryptVerify { private static boolean verifyKeyBinding(Context context, PGPSignature signature, PGPPublicKey signatureKey) { long signatureKeyId = signature.getKeyID(); - boolean keyBinding_isok = false; - String userId = null; + boolean validKeyBinding = false; + PGPPublicKeyRing signKeyRing = ProviderHelper.getPGPPublicKeyRingByKeyId(context, signatureKeyId); PGPPublicKey mKey = null; if (signKeyRing != null) { mKey = PgpKeyHelper.getMasterKey(signKeyRing); } + if (signature.getKeyID() != mKey.getKeyID()) { - keyBinding_isok = verifyKeyBinding(mKey, signatureKey); + validKeyBinding = verifyKeyBinding(mKey, signatureKey); } else { //if the key used to make the signature was the master key, no need to check binding sigs - keyBinding_isok = true; + validKeyBinding = true; } - return keyBinding_isok; + return validKeyBinding; } private static boolean verifyKeyBinding(PGPPublicKey masterPublicKey, PGPPublicKey signingPublicKey) { - boolean subkeyBinding_isok = false; - boolean tmp_subkeyBinding_isok = false; - boolean primkeyBinding_isok = false; - JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = new JcaPGPContentVerifierBuilderProvider() - .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); + boolean validSubkeyBinding = false; + boolean validTempSubkeyBinding = false; + boolean validPrimaryKeyBinding = false; + + JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = + new JcaPGPContentVerifierBuilderProvider() + .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); Iterator<PGPSignature> itr = signingPublicKey.getSignatures(); - subkeyBinding_isok = false; - tmp_subkeyBinding_isok = false; - primkeyBinding_isok = false; while (itr.hasNext()) { //what does gpg do if the subkey binding is wrong? //gpg has an invalid subkey binding error on key import I think, but doesn't shout //about keys without subkey signing. Can't get it to import a slightly broken one @@ -619,32 +677,36 @@ public class PgpDecryptVerify { //check and if ok, check primary key binding. try { sig.init(contentVerifierBuilderProvider, masterPublicKey); - tmp_subkeyBinding_isok = sig.verifyCertification(masterPublicKey, signingPublicKey); + validTempSubkeyBinding = sig.verifyCertification(masterPublicKey, signingPublicKey); } catch (PGPException e) { continue; } catch (SignatureException e) { continue; } - if (tmp_subkeyBinding_isok) - subkeyBinding_isok = true; - if (tmp_subkeyBinding_isok) { - primkeyBinding_isok = verifyPrimaryBinding(sig.getUnhashedSubPackets(), masterPublicKey, signingPublicKey); - if (primkeyBinding_isok) + if (validTempSubkeyBinding) + validSubkeyBinding = true; + if (validTempSubkeyBinding) { + validPrimaryKeyBinding = verifyPrimaryKeyBinding(sig.getUnhashedSubPackets(), + masterPublicKey, signingPublicKey); + if (validPrimaryKeyBinding) break; - primkeyBinding_isok = verifyPrimaryBinding(sig.getHashedSubPackets(), masterPublicKey, signingPublicKey); - if (primkeyBinding_isok) + validPrimaryKeyBinding = verifyPrimaryKeyBinding(sig.getHashedSubPackets(), + masterPublicKey, signingPublicKey); + if (validPrimaryKeyBinding) break; } } } - return (subkeyBinding_isok & primkeyBinding_isok); + return (validSubkeyBinding & validPrimaryKeyBinding); } - private static boolean verifyPrimaryBinding(PGPSignatureSubpacketVector Pkts, PGPPublicKey masterPublicKey, PGPPublicKey signingPublicKey) { - boolean primkeyBinding_isok = false; - JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = new JcaPGPContentVerifierBuilderProvider() - .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); + private static boolean verifyPrimaryKeyBinding(PGPSignatureSubpacketVector Pkts, + PGPPublicKey masterPublicKey, PGPPublicKey signingPublicKey) { + boolean validPrimaryKeyBinding = false; + JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = + new JcaPGPContentVerifierBuilderProvider() + .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); PGPSignatureList eSigList; if (Pkts.hasSubpacket(SignatureSubpacketTags.EMBEDDED_SIGNATURE)) { @@ -660,8 +722,8 @@ public class PgpDecryptVerify { if (emSig.getSignatureType() == PGPSignature.PRIMARYKEY_BINDING) { try { emSig.init(contentVerifierBuilderProvider, signingPublicKey); - primkeyBinding_isok = emSig.verifyCertification(masterPublicKey, signingPublicKey); - if (primkeyBinding_isok) + validPrimaryKeyBinding = emSig.verifyCertification(masterPublicKey, signingPublicKey); + if (validPrimaryKeyBinding) break; } catch (PGPException e) { continue; @@ -671,7 +733,8 @@ public class PgpDecryptVerify { } } } - return primkeyBinding_isok; + + return validPrimaryKeyBinding; } /** diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyResult.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyResult.java new file mode 100644 index 000000000..0477c4fdf --- /dev/null +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerifyResult.java @@ -0,0 +1,88 @@ +/* + * 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.pgp; + +import android.os.Parcel; +import android.os.Parcelable; + +import org.openintents.openpgp.OpenPgpSignatureResult; + +public class PgpDecryptVerifyResult implements Parcelable { + boolean symmetricPassphraseNeeded; + boolean keyPassphraseNeeded; + OpenPgpSignatureResult signatureResult; + + public boolean isSymmetricPassphraseNeeded() { + return symmetricPassphraseNeeded; + } + + public void setSymmetricPassphraseNeeded(boolean symmetricPassphraseNeeded) { + this.symmetricPassphraseNeeded = symmetricPassphraseNeeded; + } + + public boolean isKeyPassphraseNeeded() { + return keyPassphraseNeeded; + } + + public void setKeyPassphraseNeeded(boolean keyPassphraseNeeded) { + this.keyPassphraseNeeded = keyPassphraseNeeded; + } + + public OpenPgpSignatureResult getSignatureResult() { + return signatureResult; + } + + public void setSignatureResult(OpenPgpSignatureResult signatureResult) { + this.signatureResult = signatureResult; + } + + public PgpDecryptVerifyResult() { + + } + + public PgpDecryptVerifyResult(PgpDecryptVerifyResult b) { + this.symmetricPassphraseNeeded = b.symmetricPassphraseNeeded; + this.keyPassphraseNeeded = b.keyPassphraseNeeded; + this.signatureResult = b.signatureResult; + } + + + public int describeContents() { + return 0; + } + + public void writeToParcel(Parcel dest, int flags) { + dest.writeByte((byte) (symmetricPassphraseNeeded ? 1 : 0)); + dest.writeByte((byte) (keyPassphraseNeeded ? 1 : 0)); + dest.writeParcelable(signatureResult, 0); + } + + public static final Creator<PgpDecryptVerifyResult> CREATOR = new Creator<PgpDecryptVerifyResult>() { + public PgpDecryptVerifyResult createFromParcel(final Parcel source) { + PgpDecryptVerifyResult vr = new PgpDecryptVerifyResult(); + vr.symmetricPassphraseNeeded = source.readByte() == 1; + vr.keyPassphraseNeeded = source.readByte() == 1; + vr.signatureResult = source.readParcelable(OpenPgpSignatureResult.class.getClassLoader()); + return vr; + } + + public PgpDecryptVerifyResult[] newArray(final int size) { + return new PgpDecryptVerifyResult[size]; + } + }; +} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java index a7a574ee7..2495a212c 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java @@ -90,8 +90,8 @@ public class PgpImportExport { aos.write(keyring.getEncoded()); aos.close(); - String armouredKey = bos.toString("UTF-8"); - server.add(armouredKey); + String armoredKey = bos.toString("UTF-8"); + server.add(armoredKey); return true; } catch (IOException e) { diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java index 0073107a0..f744fbcec 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java @@ -105,7 +105,7 @@ public class PgpKeyOperation { } } - public PGPSecretKey createKey(int algorithmChoice, int keySize, String passPhrase, + public PGPSecretKey createKey(int algorithmChoice, int keySize, String passphrase, boolean isMasterKey) throws NoSuchAlgorithmException, PGPException, NoSuchProviderException, PgpGeneralException, InvalidAlgorithmParameterException { @@ -113,8 +113,8 @@ public class PgpKeyOperation { throw new PgpGeneralException(mContext.getString(R.string.error_key_size_minimum512bit)); } - if (passPhrase == null) { - passPhrase = ""; + if (passphrase == null) { + passphrase = ""; } int algorithm; @@ -168,7 +168,7 @@ public class PgpKeyOperation { // Build key encrypter and decrypter based on passphrase PBESecretKeyEncryptor keyEncryptor = new JcePBESecretKeyEncryptorBuilder( PGPEncryptedData.CAST5, sha1Calc) - .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passPhrase.toCharArray()); + .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(passphrase.toCharArray()); return new PGPSecretKey(keyPair.getPrivateKey(), keyPair.getPublicKey(), sha1Calc, isMasterKey, keyEncryptor); diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java index ba931c61a..fef3d391b 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java @@ -626,7 +626,7 @@ public class ProviderHelper { String armoredKey = bos.toString("UTF-8"); - Log.d(Constants.TAG, "armouredKey:" + armoredKey); + Log.d(Constants.TAG, "armoredKey:" + armoredKey); output.add(armoredKey); } catch (IOException e) { diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java index 24bce8eeb..d796ccf31 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -44,6 +44,7 @@ import org.sufficientlysecure.keychain.helper.OtherHelper; import org.sufficientlysecure.keychain.helper.Preferences; import org.sufficientlysecure.keychain.pgp.PgpConversionHelper; import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify; +import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyResult; import org.sufficientlysecure.keychain.pgp.PgpHelper; import org.sufficientlysecure.keychain.pgp.PgpImportExport; import org.sufficientlysecure.keychain.pgp.PgpKeyOperation; @@ -176,13 +177,7 @@ public class KeychainIntentService extends IntentService implements ProgressDial // decrypt/verify public static final String RESULT_DECRYPTED_STRING = "decrypted_message"; public static final String RESULT_DECRYPTED_BYTES = "decrypted_data"; - public static final String RESULT_SIGNATURE = "signature"; - public static final String RESULT_SIGNATURE_KEY_ID = "signature_key_id"; - public static final String RESULT_SIGNATURE_USER_ID = "signature_user_id"; - public static final String RESULT_CLEARTEXT_SIGNATURE_ONLY = "signature_only"; - - public static final String RESULT_SIGNATURE_SUCCESS = "signature_success"; - public static final String RESULT_SIGNATURE_UNKNOWN = "signature_unknown"; + public static final String RESULT_DECRYPT_VERIFY_RESULT = "signature"; // import public static final String RESULT_IMPORT_ADDED = "added"; @@ -198,8 +193,16 @@ public class KeychainIntentService extends IntentService implements ProgressDial Messenger mMessenger; + private boolean mIsCanceled; + public KeychainIntentService() { - super("ApgService"); + super("KeychainIntentService"); + } + + @Override + public void onDestroy() { + super.onDestroy(); + this.mIsCanceled = true; } /** @@ -476,15 +479,17 @@ public class KeychainIntentService extends IntentService implements ProgressDial // verifyText and decrypt returning additional resultData values for the // verification of signatures PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder(this, inputData, outStream); - builder.progress(this); + builder.progressDialogUpdater(this); builder.assumeSymmetric(assumeSymmetricEncryption) .passphrase(PassphraseCacheService.getCachedPassphrase(this, secretKeyId)); - resultData = builder.build().execute(); + PgpDecryptVerifyResult decryptVerifyResult = builder.build().execute(); outStream.close(); + resultData.putParcelable(RESULT_DECRYPT_VERIFY_RESULT, decryptVerifyResult); + /* Output */ switch (target) { @@ -733,7 +738,7 @@ public class KeychainIntentService extends IntentService implements ProgressDial */ // need to have access to the bufferedInput, so we can reuse it for the possible // PGPObject chunks after the first one, e.g. files with several consecutive ASCII - // armour blocks + // armor blocks BufferedInputStream bufferedInput = new BufferedInputStream(new ByteArrayInputStream(downloadedKey)); try { @@ -805,6 +810,10 @@ public class KeychainIntentService extends IntentService implements ProgressDial } private void sendErrorToHandler(Exception e) { + // Service was canceled. Do not send error to handler. + if (this.mIsCanceled) + return; + Log.e(Constants.TAG, "ApgService Exception: ", e); e.printStackTrace(); @@ -814,6 +823,10 @@ public class KeychainIntentService extends IntentService implements ProgressDial } private void sendMessageToHandler(Integer arg1, Integer arg2, Bundle data) { + // Service was canceled. Do not send message to handler. + if (this.mIsCanceled) + return; + Message msg = Message.obtain(); msg.arg1 = arg1; if (arg2 != null) { @@ -841,10 +854,10 @@ public class KeychainIntentService extends IntentService implements ProgressDial } /** - * Set progress of ProgressDialog by sending message to handler on UI thread + * Set progressDialogUpdater of ProgressDialog by sending message to handler on UI thread */ public void setProgress(String message, int progress, int max) { - Log.d(Constants.TAG, "Send message by setProgress with progress=" + progress + ", max=" + Log.d(Constants.TAG, "Send message by setProgress with progressDialogUpdater=" + progress + ", max=" + max); Bundle data = new Bundle(); diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java index dfea7eb04..6eba9cc83 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java @@ -21,6 +21,8 @@ import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment; import org.sufficientlysecure.keychain.R; import android.app.Activity; +import android.content.DialogInterface; +import android.content.DialogInterface.OnCancelListener; import android.os.Bundle; import android.os.Handler; import android.os.Message; @@ -55,9 +57,15 @@ public class KeychainIntentServiceHandler extends Handler { } public KeychainIntentServiceHandler(Activity activity, int progressDialogMessageId, int progressDialogStyle) { + this(activity, progressDialogMessageId, progressDialogStyle, false, null); + } + + public KeychainIntentServiceHandler(Activity activity, int progressDialogMessageId, + int progressDialogStyle, boolean cancelable, + OnCancelListener onCancelListener) { this.mActivity = activity; this.mProgressDialogFragment = ProgressDialogFragment.newInstance(progressDialogMessageId, - progressDialogStyle); + progressDialogStyle, cancelable, onCancelListener); } public void showProgressDialog(FragmentActivity activity) { diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/OpenPgpService.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/OpenPgpService.java index 34213bd3b..f697faa6e 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/OpenPgpService.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/OpenPgpService.java @@ -21,21 +21,22 @@ import android.app.PendingIntent; import android.content.Intent; import android.database.Cursor; import android.net.Uri; -import android.os.Bundle; import android.os.IBinder; import android.os.ParcelFileDescriptor; import org.openintents.openpgp.IOpenPgpService; import org.openintents.openpgp.OpenPgpError; import org.openintents.openpgp.OpenPgpSignatureResult; -import org.openintents.openpgp.util.OpenPgpConstants; +import org.openintents.openpgp.util.OpenPgpApi; import org.spongycastle.util.Arrays; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Id; import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify; +import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyResult; import org.sufficientlysecure.keychain.pgp.PgpSignEncrypt; +import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.provider.KeychainContract; -import org.sufficientlysecure.keychain.service.KeychainIntentService; +import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.service.PassphraseCacheService; import org.sufficientlysecure.keychain.util.InputData; import org.sufficientlysecure.keychain.util.Log; @@ -48,7 +49,7 @@ public class OpenPgpService extends RemoteService { private static final int PRIVATE_REQUEST_CODE_PASSPHRASE = 551; private static final int PRIVATE_REQUEST_CODE_USER_IDS = 552; - + private static final int PRIVATE_REQUEST_CODE_GET_KEYS = 553; /** * Search database for key ids based on emails. @@ -56,7 +57,7 @@ public class OpenPgpService extends RemoteService { * @param encryptionUserIds * @return */ - private Bundle getKeyIdsFromEmails(Bundle params, String[] encryptionUserIds) { + private Intent getKeyIdsFromEmails(Intent data, String[] encryptionUserIds) { // find key ids to given emails in database ArrayList<Long> keyIds = new ArrayList<Long>(); @@ -91,21 +92,20 @@ public class OpenPgpService extends RemoteService { // allow the user to verify pub key selection if (missingUserIdsCheck || dublicateUserIdsCheck) { - // build PendingIntent for passphrase input + // build PendingIntent Intent intent = new Intent(getBaseContext(), RemoteServiceActivity.class); intent.setAction(RemoteServiceActivity.ACTION_SELECT_PUB_KEYS); intent.putExtra(RemoteServiceActivity.EXTRA_SELECTED_MASTER_KEY_IDS, keyIdsArray); intent.putExtra(RemoteServiceActivity.EXTRA_MISSING_USER_IDS, missingUserIds); intent.putExtra(RemoteServiceActivity.EXTRA_DUBLICATE_USER_IDS, dublicateUserIds); - intent.putExtra(OpenPgpConstants.PI_RESULT_PARAMS, params); + intent.putExtra(RemoteServiceActivity.EXTRA_DATA, data); PendingIntent pi = PendingIntent.getActivity(getBaseContext(), PRIVATE_REQUEST_CODE_USER_IDS, intent, 0); // return PendingIntent to be executed by client - Bundle result = new Bundle(); - result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_USER_INTERACTION_REQUIRED); - result.putParcelable(OpenPgpConstants.RESULT_INTENT, pi); - + Intent result = new Intent(); + result.putExtra(OpenPgpApi.RESULT_INTENT, pi); + result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED); return result; } @@ -113,44 +113,43 @@ public class OpenPgpService extends RemoteService { return null; } - Bundle result = new Bundle(); - result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_SUCCESS); - result.putLongArray(OpenPgpConstants.PARAMS_KEY_IDS, keyIdsArray); + Intent result = new Intent(); + result.putExtra(OpenPgpApi.EXTRA_KEY_IDS, keyIdsArray); + result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS); return result; } - private Bundle getPassphraseBundleIntent(Bundle params, long keyId) { + private Intent getPassphraseBundleIntent(Intent data, long keyId) { // build PendingIntent for passphrase input Intent intent = new Intent(getBaseContext(), RemoteServiceActivity.class); intent.setAction(RemoteServiceActivity.ACTION_CACHE_PASSPHRASE); intent.putExtra(RemoteServiceActivity.EXTRA_SECRET_KEY_ID, keyId); // pass params through to activity that it can be returned again later to repeat pgp operation - intent.putExtra(OpenPgpConstants.PI_RESULT_PARAMS, params); + intent.putExtra(RemoteServiceActivity.EXTRA_DATA, data); PendingIntent pi = PendingIntent.getActivity(getBaseContext(), PRIVATE_REQUEST_CODE_PASSPHRASE, intent, 0); // return PendingIntent to be executed by client - Bundle result = new Bundle(); - result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_USER_INTERACTION_REQUIRED); - result.putParcelable(OpenPgpConstants.RESULT_INTENT, pi); - + Intent result = new Intent(); + result.putExtra(OpenPgpApi.RESULT_INTENT, pi); + result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED); return result; } - private Bundle signImpl(Bundle params, ParcelFileDescriptor input, ParcelFileDescriptor output, - AppSettings appSettings) { + private Intent signImpl(Intent data, ParcelFileDescriptor input, + ParcelFileDescriptor output, AppSettings appSettings) { try { - boolean asciiArmor = params.getBoolean(OpenPgpConstants.PARAMS_REQUEST_ASCII_ARMOR, true); + boolean asciiArmor = data.getBooleanExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true); // get passphrase from cache, if key has "no" passphrase, this returns an empty String String passphrase; - if (params.containsKey(OpenPgpConstants.PARAMS_PASSPHRASE)) { - passphrase = params.getString(OpenPgpConstants.PARAMS_PASSPHRASE); + if (data.hasExtra(OpenPgpApi.EXTRA_PASSPHRASE)) { + passphrase = data.getStringExtra(OpenPgpApi.EXTRA_PASSPHRASE); } else { passphrase = PassphraseCacheService.getCachedPassphrase(getContext(), appSettings.getKeyId()); } if (passphrase == null) { // get PendingIntent for passphrase input, add it to given params and return to client - Bundle passphraseBundle = getPassphraseBundleIntent(params, appSettings.getKeyId()); + Intent passphraseBundle = getPassphraseBundleIntent(data, appSettings.getKeyId()); return passphraseBundle; } @@ -174,44 +173,43 @@ public class OpenPgpService extends RemoteService { os.close(); } - Bundle result = new Bundle(); - result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_SUCCESS); + Intent result = new Intent(); + result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS); return result; } catch (Exception e) { - Bundle result = new Bundle(); - result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_ERROR); - result.putParcelable(OpenPgpConstants.RESULT_ERRORS, + Intent result = new Intent(); + result.putExtra(OpenPgpApi.RESULT_ERROR, new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage())); + result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR); return result; } } - private Bundle encryptAndSignImpl(Bundle params, ParcelFileDescriptor input, - ParcelFileDescriptor output, AppSettings appSettings, - boolean sign) { + private Intent encryptAndSignImpl(Intent data, ParcelFileDescriptor input, + ParcelFileDescriptor output, AppSettings appSettings, boolean sign) { try { - boolean asciiArmor = params.getBoolean(OpenPgpConstants.PARAMS_REQUEST_ASCII_ARMOR, true); + boolean asciiArmor = data.getBooleanExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true); long[] keyIds; - if (params.containsKey(OpenPgpConstants.PARAMS_KEY_IDS)) { - keyIds = params.getLongArray(OpenPgpConstants.PARAMS_KEY_IDS); - } else if (params.containsKey(OpenPgpConstants.PARAMS_USER_IDS)) { + if (data.hasExtra(OpenPgpApi.EXTRA_KEY_IDS)) { + keyIds = data.getLongArrayExtra(OpenPgpApi.EXTRA_KEY_IDS); + } else if (data.hasExtra(OpenPgpApi.EXTRA_USER_IDS)) { // get key ids based on given user ids - String[] userIds = params.getStringArray(OpenPgpConstants.PARAMS_USER_IDS); + String[] userIds = data.getStringArrayExtra(OpenPgpApi.EXTRA_USER_IDS); // give params through to activity... - Bundle result = getKeyIdsFromEmails(params, userIds); + Intent result = getKeyIdsFromEmails(data, userIds); - if (result.getInt(OpenPgpConstants.RESULT_CODE, 0) == OpenPgpConstants.RESULT_CODE_SUCCESS) { - keyIds = result.getLongArray(OpenPgpConstants.PARAMS_KEY_IDS); + if (result.getIntExtra(OpenPgpApi.RESULT_CODE, 0) == OpenPgpApi.RESULT_CODE_SUCCESS) { + keyIds = result.getLongArrayExtra(OpenPgpApi.EXTRA_KEY_IDS); } else { // if not success -> result contains a PendingIntent for user interaction return result; } } else { - Bundle result = new Bundle(); - result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_ERROR); - result.putParcelable(OpenPgpConstants.RESULT_ERRORS, + Intent result = new Intent(); + result.putExtra(OpenPgpApi.RESULT_ERROR, new OpenPgpError(OpenPgpError.GENERIC_ERROR, "Missing parameter user_ids or key_ids!")); + result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR); return result; } @@ -235,15 +233,15 @@ public class OpenPgpService extends RemoteService { if (sign) { String passphrase; - if (params.containsKey(OpenPgpConstants.PARAMS_PASSPHRASE)) { - passphrase = params.getString(OpenPgpConstants.PARAMS_PASSPHRASE); + if (data.hasExtra(OpenPgpApi.EXTRA_PASSPHRASE)) { + passphrase = data.getStringExtra(OpenPgpApi.EXTRA_PASSPHRASE); } else { passphrase = PassphraseCacheService.getCachedPassphrase(getContext(), appSettings.getKeyId()); } if (passphrase == null) { // get PendingIntent for passphrase input, add it to given params and return to client - Bundle passphraseBundle = getPassphraseBundleIntent(params, appSettings.getKeyId()); + Intent passphraseBundle = getPassphraseBundleIntent(data, appSettings.getKeyId()); return passphraseBundle; } @@ -263,193 +261,123 @@ public class OpenPgpService extends RemoteService { os.close(); } - Bundle result = new Bundle(); - result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_SUCCESS); + Intent result = new Intent(); + result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS); return result; } catch (Exception e) { - Bundle result = new Bundle(); - result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_ERROR); - result.putParcelable(OpenPgpConstants.RESULT_ERRORS, + Intent result = new Intent(); + result.putExtra(OpenPgpApi.RESULT_ERROR, new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage())); + result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR); return result; } } - private Bundle decryptAndVerifyImpl(Bundle params, ParcelFileDescriptor input, + private Intent decryptAndVerifyImpl(Intent data, ParcelFileDescriptor input, ParcelFileDescriptor output, AppSettings appSettings) { try { // Get Input- and OutputStream from ParcelFileDescriptor InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(input); OutputStream os = new ParcelFileDescriptor.AutoCloseOutputStream(output); - OpenPgpSignatureResult sigResult = null; - try { -// PGPUtil.getDecoderStream(is) - // TODOs API 2.0: - // implement verify-only! - // fix the mess: http://stackoverflow.com/questions/148130/how-do-i-peek-at-the-first-two-bytes-in-an-inputstream - // should we allow to decrypt everything under every key id or only the one set? - // TODO: instead of trying to get the passphrase before - // pause stream when passphrase is missing and then resume - - - // TODO: this is not really needed - // checked if it is text with BEGIN and END tags -// String message = new String(inputBytes); -// Log.d(Constants.TAG, "in: " + message); -// boolean signedOnly = false; -// Matcher matcher = PgpHelper.PGP_MESSAGE.matcher(message); -// if (matcher.matches()) { -// Log.d(Constants.TAG, "PGP_MESSAGE matched"); -// message = matcher.group(1); -// // replace non breakable spaces -// message = message.replaceAll("\\xa0", " "); -// -// // overwrite inputBytes -// inputBytes = message.getBytes(); -// } else { -// matcher = PgpHelper.PGP_SIGNED_MESSAGE.matcher(message); -// if (matcher.matches()) { -// signedOnly = true; -// Log.d(Constants.TAG, "PGP_SIGNED_MESSAGE matched"); -// message = matcher.group(1); -// // replace non breakable spaces -// message = message.replaceAll("\\xa0", " "); -// -// // overwrite inputBytes -// inputBytes = message.getBytes(); -// } else { -// Log.d(Constants.TAG, "Nothing matched! Binary?"); -// } -// } - // END TODO - -// Log.d(Constants.TAG, "in: " + new String(inputBytes)); - - // TODO: This allows to decrypt messages with ALL secret keys, not only the one for the - // app, Fix this? - -// String passphrase = null; -// if (!signedOnly) { -// // BEGIN Get key -// // TODO: this input stream is consumed after PgpMain.getDecryptionKeyId()... do it -// // better! -// InputStream inputStream2 = new ByteArrayInputStream(inputBytes); -// -// // TODO: duplicates functions from DecryptActivity! -// long secretKeyId; -// try { -// if (inputStream2.markSupported()) { -// // should probably set this to the max size of two -// // pgpF objects, if it even needs to be anything other -// // than 0. -// inputStream2.mark(200); -// } -// secretKeyId = PgpHelper.getDecryptionKeyId(this, inputStream2); -// if (secretKeyId == Id.key.none) { -// throw new PgpGeneralException(getString(R.string.error_no_secret_key_found)); -// } -// } catch (NoAsymmetricEncryptionException e) { -// if (inputStream2.markSupported()) { -// inputStream2.reset(); -// } -// secretKeyId = Id.key.symmetric; -// if (!PgpDecryptVerify.hasSymmetricEncryption(this, inputStream2)) { -// throw new PgpGeneralException( -// getString(R.string.error_no_known_encryption_found)); -// } -// // we do not support symmetric decryption from the API! -// throw new Exception("Symmetric decryption is not supported!"); -// } -// -// Log.d(Constants.TAG, "secretKeyId " + secretKeyId); - - // NOTE: currently this only gets the passphrase for the key set for this client - String passphrase; - if (params.containsKey(OpenPgpConstants.PARAMS_PASSPHRASE)) { - passphrase = params.getString(OpenPgpConstants.PARAMS_PASSPHRASE); - } else { - passphrase = PassphraseCacheService.getCachedPassphrase(getContext(), appSettings.getKeyId()); - } - if (passphrase == null) { - // get PendingIntent for passphrase input, add it to given params and return to client - Bundle passphraseBundle = getPassphraseBundleIntent(params, appSettings.getKeyId()); - return passphraseBundle; - } -// } + Intent result = new Intent(); + try { - // build InputData and write into OutputStream + String passphrase = data.getStringExtra(OpenPgpApi.EXTRA_PASSPHRASE); long inputLength = is.available(); InputData inputData = new InputData(is, inputLength); - - Bundle outputBundle; PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder(this, inputData, os); - -// if (signedOnly) { -// outputBundle = builder.build().verifyText(); -// } else { - builder.assumeSymmetric(false) + builder.assumeSymmetric(false) // no support for symmetric encryption + .enforcedKeyId(appSettings.getKeyId()) // allow only the private key for this app for decryption .passphrase(passphrase); - // Do we want to do this: instead of trying to get the passphrase before - // pause stream when passphrase is missing and then resume??? - - // TODO: this also decrypts with other secret keys without passphrase!!! - outputBundle = builder.build().execute(); -// } - -// outputStream.close(); - -// byte[] outputBytes = ((ByteArrayOutputStream) outputStream).toByteArray(); - - // get signature informations from bundle - boolean signature = outputBundle.getBoolean(KeychainIntentService.RESULT_SIGNATURE, false); - - if (signature) { - long signatureKeyId = outputBundle - .getLong(KeychainIntentService.RESULT_SIGNATURE_KEY_ID, 0); - String signatureUserId = outputBundle - .getString(KeychainIntentService.RESULT_SIGNATURE_USER_ID); - boolean signatureSuccess = outputBundle - .getBoolean(KeychainIntentService.RESULT_SIGNATURE_SUCCESS, false); - boolean signatureUnknown = outputBundle - .getBoolean(KeychainIntentService.RESULT_SIGNATURE_UNKNOWN, false); - boolean signatureOnly = outputBundle - .getBoolean(KeychainIntentService.RESULT_CLEARTEXT_SIGNATURE_ONLY, false); - - int signatureStatus = OpenPgpSignatureResult.SIGNATURE_ERROR; - if (signatureSuccess) { - signatureStatus = OpenPgpSignatureResult.SIGNATURE_SUCCESS_CERTIFIED; - } else if (signatureUnknown) { - signatureStatus = OpenPgpSignatureResult.SIGNATURE_UNKNOWN_PUB_KEY; + // TODO: currently does not support binary signed-only content + PgpDecryptVerifyResult decryptVerifyResult = builder.build().execute(); + + if (decryptVerifyResult.isKeyPassphraseNeeded()) { + // get PendingIntent for passphrase input, add it to given params and return to client + Intent passphraseBundle = getPassphraseBundleIntent(data, appSettings.getKeyId()); + return passphraseBundle; + } else if (decryptVerifyResult.isSymmetricPassphraseNeeded()) { + throw new PgpGeneralException("Decryption of symmetric content not supported by API!"); + } + + OpenPgpSignatureResult signatureResult = decryptVerifyResult.getSignatureResult(); + if (signatureResult != null) { + if (signatureResult.getStatus() == OpenPgpSignatureResult.SIGNATURE_UNKNOWN_PUB_KEY) { + // If signature is unknown we return an _additional_ PendingIntent + // to retrieve the missing key + // TODO!!! + Intent intent = new Intent(getBaseContext(), RemoteServiceActivity.class); + intent.setAction(RemoteServiceActivity.ACTION_ERROR_MESSAGE); + intent.putExtra(RemoteServiceActivity.EXTRA_ERROR_MESSAGE, "todo"); + intent.putExtra(RemoteServiceActivity.EXTRA_DATA, data); + + PendingIntent pi = PendingIntent.getActivity(getBaseContext(), + PRIVATE_REQUEST_CODE_GET_KEYS, intent, 0); + + result.putExtra(OpenPgpApi.RESULT_INTENT, pi); } - sigResult = new OpenPgpSignatureResult(signatureStatus, signatureUserId, - signatureOnly, signatureKeyId); + result.putExtra(OpenPgpApi.RESULT_SIGNATURE, signatureResult); } + } finally { is.close(); os.close(); } - Bundle result = new Bundle(); - result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_SUCCESS); - result.putParcelable(OpenPgpConstants.RESULT_SIGNATURE, sigResult); + result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS); return result; } catch (Exception e) { - Bundle result = new Bundle(); - result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_ERROR); - result.putParcelable(OpenPgpConstants.RESULT_ERRORS, + Intent result = new Intent(); + result.putExtra(OpenPgpApi.RESULT_ERROR, new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage())); + result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR); return result; } } - private Bundle getKeyIdsImpl(Bundle params) { + private Intent getKeyImpl(Intent data) { + try { + long keyId = data.getLongExtra(OpenPgpApi.EXTRA_KEY_ID, 0); + + if (ProviderHelper.getPGPPublicKeyByKeyId(this, keyId) == null) { + Intent result = new Intent(); + + // If keys are not in db we return an additional PendingIntent + // to retrieve the missing key + // TODO!!! + Intent intent = new Intent(getBaseContext(), RemoteServiceActivity.class); + intent.setAction(RemoteServiceActivity.ACTION_ERROR_MESSAGE); + intent.putExtra(RemoteServiceActivity.EXTRA_ERROR_MESSAGE, "todo"); + intent.putExtra(RemoteServiceActivity.EXTRA_DATA, data); + + PendingIntent pi = PendingIntent.getActivity(getBaseContext(), + PRIVATE_REQUEST_CODE_GET_KEYS, intent, 0); + + result.putExtra(OpenPgpApi.RESULT_INTENT, pi); + result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED); + return result; + } else { + Intent result = new Intent(); + result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS); + return result; + } + } catch (Exception e) { + Intent result = new Intent(); + result.putExtra(OpenPgpApi.RESULT_ERROR, + new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage())); + result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR); + return result; + } + } + + private Intent getKeyIdsImpl(Intent data) { // get key ids based on given user ids - String[] userIds = params.getStringArray(OpenPgpConstants.PARAMS_USER_IDS); - Bundle result = getKeyIdsFromEmails(params, userIds); + String[] userIds = data.getStringArrayExtra(OpenPgpApi.EXTRA_USER_IDS); + Intent result = getKeyIdsFromEmails(data, userIds); return result; } @@ -459,30 +387,30 @@ public class OpenPgpService extends RemoteService { * - has supported API version * - is allowed to call the service (access has been granted) * - * @param params + * @param data * @return null if everything is okay, or a Bundle with an error/PendingIntent */ - private Bundle checkRequirements(Bundle params) { + private Intent checkRequirements(Intent data) { // params Bundle is required! - if (params == null) { - Bundle result = new Bundle(); + if (data == null) { + Intent result = new Intent(); OpenPgpError error = new OpenPgpError(OpenPgpError.GENERIC_ERROR, "params Bundle required!"); - result.putParcelable(OpenPgpConstants.RESULT_ERRORS, error); - result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_ERROR); + result.putExtra(OpenPgpApi.RESULT_ERROR, error); + result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR); return result; } // version code is required and needs to correspond to version code of service! - if (params.getInt(OpenPgpConstants.PARAMS_API_VERSION) != OpenPgpConstants.API_VERSION) { - Bundle result = new Bundle(); + if (data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) != OpenPgpApi.API_VERSION) { + Intent result = new Intent(); OpenPgpError error = new OpenPgpError(OpenPgpError.INCOMPATIBLE_API_VERSIONS, "Incompatible API versions!"); - result.putParcelable(OpenPgpConstants.RESULT_ERRORS, error); - result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_ERROR); + result.putExtra(OpenPgpApi.RESULT_ERROR, error); + result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR); return result; } // check if caller is allowed to access openpgp keychain - Bundle result = isAllowed(params); + Intent result = isAllowed(data); if (result != null) { return result; } @@ -494,61 +422,30 @@ public class OpenPgpService extends RemoteService { private final IOpenPgpService.Stub mBinder = new IOpenPgpService.Stub() { @Override - public Bundle sign(Bundle params, final ParcelFileDescriptor input, final ParcelFileDescriptor output) { - final AppSettings appSettings = getAppSettings(); - - Bundle errorResult = checkRequirements(params); + public Intent execute(Intent data, ParcelFileDescriptor input, ParcelFileDescriptor output) { + Intent errorResult = checkRequirements(data); if (errorResult != null) { return errorResult; } - return signImpl(params, input, output, appSettings); - } - - @Override - public Bundle encrypt(Bundle params, ParcelFileDescriptor input, ParcelFileDescriptor output) { final AppSettings appSettings = getAppSettings(); - Bundle errorResult = checkRequirements(params); - if (errorResult != null) { - return errorResult; - } - - return encryptAndSignImpl(params, input, output, appSettings, false); - } - - @Override - public Bundle signAndEncrypt(Bundle params, ParcelFileDescriptor input, ParcelFileDescriptor output) { - final AppSettings appSettings = getAppSettings(); - - Bundle errorResult = checkRequirements(params); - if (errorResult != null) { - return errorResult; - } - - return encryptAndSignImpl(params, input, output, appSettings, true); - } - - @Override - public Bundle decryptAndVerify(Bundle params, ParcelFileDescriptor input, ParcelFileDescriptor output) { - final AppSettings appSettings = getAppSettings(); - - Bundle errorResult = checkRequirements(params); - if (errorResult != null) { - return errorResult; - } - - return decryptAndVerifyImpl(params, input, output, appSettings); - } - - @Override - public Bundle getKeyIds(Bundle params) { - Bundle errorResult = checkRequirements(params); - if (errorResult != null) { - return errorResult; + String action = data.getAction(); + if (OpenPgpApi.ACTION_SIGN.equals(action)) { + return signImpl(data, input, output, appSettings); + } else if (OpenPgpApi.ACTION_ENCRYPT.equals(action)) { + return encryptAndSignImpl(data, input, output, appSettings, false); + } else if (OpenPgpApi.ACTION_SIGN_AND_ENCRYPT.equals(action)) { + return encryptAndSignImpl(data, input, output, appSettings, true); + } else if (OpenPgpApi.ACTION_DECRYPT_VERIFY.equals(action)) { + return decryptAndVerifyImpl(data, input, output, appSettings); + } else if (OpenPgpApi.ACTION_GET_KEY.equals(action)) { + return getKeyImpl(data); + } else if (OpenPgpApi.ACTION_GET_KEY_IDS.equals(action)) { + return getKeyIdsImpl(data); + } else { + return null; } - - return getKeyIdsImpl(params); } }; diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RemoteService.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RemoteService.java index cfd2b9ec3..cb556be39 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RemoteService.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RemoteService.java @@ -21,7 +21,7 @@ import java.util.ArrayList; import java.util.Arrays; import org.openintents.openpgp.OpenPgpError; -import org.openintents.openpgp.util.OpenPgpConstants; +import org.openintents.openpgp.util.OpenPgpApi; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.provider.KeychainContract; @@ -38,10 +38,6 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.Signature; import android.net.Uri; import android.os.Binder; -import android.os.Bundle; -import android.os.Handler; -import android.os.Message; -import android.os.Messenger; /** * Abstract service class for remote APIs that handle app registration and user input. @@ -57,7 +53,7 @@ public abstract class RemoteService extends Service { return mContext; } - protected Bundle isAllowed(Bundle params) { + protected Intent isAllowed(Intent data) { try { if (isCallerAllowed(false)) { @@ -74,9 +70,9 @@ public abstract class RemoteService extends Service { } catch (NameNotFoundException e) { Log.e(Constants.TAG, "Should not happen, returning!", e); // return error - Bundle result = new Bundle(); - result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_ERROR); - result.putParcelable(OpenPgpConstants.RESULT_ERRORS, + Intent result = new Intent(); + result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR); + result.putExtra(OpenPgpApi.RESULT_ERROR, new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage())); return result; } @@ -86,14 +82,14 @@ public abstract class RemoteService extends Service { intent.setAction(RemoteServiceActivity.ACTION_REGISTER); intent.putExtra(RemoteServiceActivity.EXTRA_PACKAGE_NAME, packageName); intent.putExtra(RemoteServiceActivity.EXTRA_PACKAGE_SIGNATURE, packageSignature); - intent.putExtra(OpenPgpConstants.PI_RESULT_PARAMS, params); + intent.putExtra(RemoteServiceActivity.EXTRA_DATA, data); PendingIntent pi = PendingIntent.getActivity(getBaseContext(), PRIVATE_REQUEST_CODE_REGISTER, intent, 0); // return PendingIntent to be executed by client - Bundle result = new Bundle(); - result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_USER_INTERACTION_REQUIRED); - result.putParcelable(OpenPgpConstants.RESULT_INTENT, pi); + Intent result = new Intent(); + result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED); + result.putExtra(OpenPgpApi.RESULT_INTENT, pi); return result; } @@ -103,14 +99,14 @@ public abstract class RemoteService extends Service { Intent intent = new Intent(getBaseContext(), RemoteServiceActivity.class); intent.setAction(RemoteServiceActivity.ACTION_ERROR_MESSAGE); intent.putExtra(RemoteServiceActivity.EXTRA_ERROR_MESSAGE, getString(R.string.api_error_wrong_signature)); - intent.putExtra(OpenPgpConstants.PI_RESULT_PARAMS, params); + intent.putExtra(RemoteServiceActivity.EXTRA_DATA, data); PendingIntent pi = PendingIntent.getActivity(getBaseContext(), PRIVATE_REQUEST_CODE_ERROR, intent, 0); // return PendingIntent to be executed by client - Bundle result = new Bundle(); - result.putInt(OpenPgpConstants.RESULT_CODE, OpenPgpConstants.RESULT_CODE_USER_INTERACTION_REQUIRED); - result.putParcelable(OpenPgpConstants.RESULT_INTENT, pi); + Intent result = new Intent(); + result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED); + result.putExtra(OpenPgpApi.RESULT_INTENT, pi); return result; } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RemoteServiceActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RemoteServiceActivity.java index af8e3ade8..11b3ee217 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RemoteServiceActivity.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/service/remote/RemoteServiceActivity.java @@ -25,7 +25,7 @@ import android.os.Messenger; import android.support.v7.app.ActionBarActivity; import android.view.View; -import org.openintents.openpgp.util.OpenPgpConstants; +import org.openintents.openpgp.util.OpenPgpApi; import org.sufficientlysecure.htmltextview.HtmlTextView; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Id; @@ -51,6 +51,8 @@ public class RemoteServiceActivity extends ActionBarActivity { public static final String EXTRA_MESSENGER = "messenger"; + public static final String EXTRA_DATA = "data"; + // passphrase action public static final String EXTRA_SECRET_KEY_ID = "secret_key_id"; // register action @@ -100,12 +102,9 @@ public class RemoteServiceActivity extends ActionBarActivity { ProviderHelper.insertApiApp(RemoteServiceActivity.this, mSettingsFragment.getAppSettings()); - // give params through for new service call - Bundle oldParams = extras.getBundle(OpenPgpConstants.PI_RESULT_PARAMS); - - Intent finishIntent = new Intent(); - finishIntent.putExtra(OpenPgpConstants.PI_RESULT_PARAMS, oldParams); - RemoteServiceActivity.this.setResult(RESULT_OK, finishIntent); + // give data through for new service call + Intent resultData = extras.getParcelable(EXTRA_DATA); + RemoteServiceActivity.this.setResult(RESULT_OK, resultData); RemoteServiceActivity.this.finish(); } } @@ -128,9 +127,9 @@ public class RemoteServiceActivity extends ActionBarActivity { mSettingsFragment.setAppSettings(settings); } else if (ACTION_CACHE_PASSPHRASE.equals(action)) { long secretKeyId = extras.getLong(EXTRA_SECRET_KEY_ID); - Bundle oldParams = extras.getBundle(OpenPgpConstants.PI_RESULT_PARAMS); + Intent resultData = extras.getParcelable(EXTRA_DATA); - showPassphraseDialog(oldParams, secretKeyId); + showPassphraseDialog(resultData, secretKeyId); } else if (ACTION_SELECT_PUB_KEYS.equals(action)) { long[] selectedMasterKeyIds = intent.getLongArrayExtra(EXTRA_SELECTED_MASTER_KEY_IDS); ArrayList<String> missingUserIds = intent @@ -167,13 +166,11 @@ public class RemoteServiceActivity extends ActionBarActivity { @Override public void onClick(View v) { // add key ids to params Bundle for new request - Bundle params = extras.getBundle(OpenPgpConstants.PI_RESULT_PARAMS); - params.putLongArray(OpenPgpConstants.PARAMS_KEY_IDS, + Intent resultData = extras.getParcelable(EXTRA_DATA); + resultData.putExtra(OpenPgpApi.EXTRA_KEY_IDS, mSelectFragment.getSelectedMasterKeyIds()); - Intent finishIntent = new Intent(); - finishIntent.putExtra(OpenPgpConstants.PI_RESULT_PARAMS, params); - RemoteServiceActivity.this.setResult(RESULT_OK, finishIntent); + RemoteServiceActivity.this.setResult(RESULT_OK, resultData); RemoteServiceActivity.this.finish(); } }, R.string.btn_do_not_save, new View.OnClickListener() { @@ -222,7 +219,7 @@ public class RemoteServiceActivity extends ActionBarActivity { @Override public void onClick(View v) { - RemoteServiceActivity.this.setResult(RESULT_OK); + RemoteServiceActivity.this.setResult(RESULT_CANCELED); RemoteServiceActivity.this.finish(); } }); @@ -244,16 +241,14 @@ public class RemoteServiceActivity extends ActionBarActivity { * encryption. Based on mSecretKeyId it asks for a passphrase to open a private key or it asks * for a symmetric passphrase */ - private void showPassphraseDialog(final Bundle params, long secretKeyId) { + private void showPassphraseDialog(final Intent data, long secretKeyId) { // Message is received after passphrase is cached Handler returnHandler = new Handler() { @Override public void handleMessage(Message message) { if (message.what == PassphraseDialogFragment.MESSAGE_OKAY) { // return given params again, for calling the service method again - Intent finishIntent = new Intent(); - finishIntent.putExtra(OpenPgpConstants.PI_RESULT_PARAMS, params); - RemoteServiceActivity.this.setResult(RESULT_OK, finishIntent); + RemoteServiceActivity.this.setResult(RESULT_OK, data); } else { RemoteServiceActivity.this.setResult(RESULT_CANCELED); } @@ -273,9 +268,7 @@ public class RemoteServiceActivity extends ActionBarActivity { } catch (PgpGeneralException e) { Log.d(Constants.TAG, "No passphrase for this secret key, do pgp operation directly!"); // return given params again, for calling the service method again - Intent finishIntent = new Intent(); - finishIntent.putExtra(OpenPgpConstants.PI_RESULT_PARAMS, params); - setResult(RESULT_OK, finishIntent); + setResult(RESULT_OK, data); finish(); } } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java index 652310cd2..42288ca37 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java @@ -25,6 +25,7 @@ import java.io.FileNotFoundException; import java.io.InputStream; import java.util.regex.Matcher; +import org.openintents.openpgp.OpenPgpSignatureResult; import org.spongycastle.openpgp.PGPPublicKeyRing; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.Id; @@ -32,6 +33,7 @@ import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.compatibility.ClipboardReflection; import org.sufficientlysecure.keychain.helper.ActionBarHelper; import org.sufficientlysecure.keychain.helper.FileHelper; +import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyResult; import org.sufficientlysecure.keychain.pgp.PgpHelper; import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify; @@ -66,6 +68,7 @@ import android.widget.Toast; import android.widget.ViewFlipper; import com.beardedhen.androidbootstrap.BootstrapButton; +import com.devspark.appmsg.AppMsg; @SuppressLint("NewApi") public class DecryptActivity extends DrawerActivity { @@ -233,7 +236,7 @@ public class DecryptActivity extends DrawerActivity { if (matcher.matches()) { data = matcher.group(1); mMessage.setText(data); - Toast.makeText(this, R.string.using_clipboard_content, Toast.LENGTH_SHORT) + AppMsg.makeText(this, R.string.using_clipboard_content, AppMsg.STYLE_INFO) .show(); } } @@ -420,17 +423,17 @@ public class DecryptActivity extends DrawerActivity { } if (mInputFilename.equals("")) { - Toast.makeText(this, R.string.no_file_selected, Toast.LENGTH_SHORT).show(); + AppMsg.makeText(this, R.string.no_file_selected, AppMsg.STYLE_ALERT).show(); return; } if (mInputFilename.startsWith("file")) { File file = new File(mInputFilename); if (!file.exists() || !file.isFile()) { - Toast.makeText( + AppMsg.makeText( this, getString(R.string.error_message, - getString(R.string.error_file_not_found)), Toast.LENGTH_SHORT) + getString(R.string.error_file_not_found)), AppMsg.STYLE_ALERT) .show(); return; } @@ -510,14 +513,14 @@ public class DecryptActivity extends DrawerActivity { inStream = getContentResolver().openInputStream(mContentUri); } catch (FileNotFoundException e) { Log.e(Constants.TAG, "File not found!", e); - Toast.makeText(this, getString(R.string.error_file_not_found, e.getMessage()), - Toast.LENGTH_SHORT).show(); + AppMsg.makeText(this, getString(R.string.error_file_not_found, e.getMessage()), + AppMsg.STYLE_ALERT).show(); } } else if (mDecryptTarget == Id.target.file) { // check if storage is ready if (!FileHelper.isStorageMounted(mInputFilename)) { - Toast.makeText(this, getString(R.string.error_external_storage_not_ready), - Toast.LENGTH_SHORT).show(); + AppMsg.makeText(this, getString(R.string.error_external_storage_not_ready), + AppMsg.STYLE_ALERT).show(); return; } @@ -525,8 +528,8 @@ public class DecryptActivity extends DrawerActivity { inStream = new BufferedInputStream(new FileInputStream(mInputFilename)); } catch (FileNotFoundException e) { Log.e(Constants.TAG, "File not found!", e); - Toast.makeText(this, getString(R.string.error_file_not_found, e.getMessage()), - Toast.LENGTH_SHORT).show(); + AppMsg.makeText(this, getString(R.string.error_file_not_found, e.getMessage()), + AppMsg.STYLE_ALERT).show(); } } else { inStream = new ByteArrayInputStream(mMessage.getText().toString().getBytes()); @@ -556,8 +559,8 @@ public class DecryptActivity extends DrawerActivity { mAssumeSymmetricEncryption = true; } } catch (Exception e) { - Toast.makeText(this, getString(R.string.error_message, e.getMessage()), - Toast.LENGTH_SHORT).show(); + AppMsg.makeText(this, getString(R.string.error_message, e.getMessage()), + AppMsg.STYLE_ALERT).show(); } } @@ -655,8 +658,8 @@ public class DecryptActivity extends DrawerActivity { mSignatureKeyId = 0; mSignatureLayout.setVisibility(View.GONE); - Toast.makeText(DecryptActivity.this, R.string.decryption_successful, - Toast.LENGTH_SHORT).show(); + AppMsg.makeText(DecryptActivity.this, R.string.decryption_successful, + AppMsg.STYLE_INFO).show(); if (mReturnResult) { Intent intent = new Intent(); intent.putExtras(returnData); @@ -689,11 +692,15 @@ public class DecryptActivity extends DrawerActivity { } - if (returnData.getBoolean(KeychainIntentService.RESULT_SIGNATURE)) { - String userId = returnData - .getString(KeychainIntentService.RESULT_SIGNATURE_USER_ID); - mSignatureKeyId = returnData - .getLong(KeychainIntentService.RESULT_SIGNATURE_KEY_ID); + PgpDecryptVerifyResult decryptVerifyResult = + returnData.getParcelable(KeychainIntentService.RESULT_DECRYPT_VERIFY_RESULT); + + OpenPgpSignatureResult signatureResult = decryptVerifyResult.getSignatureResult(); + + if (signatureResult != null) { + + String userId = signatureResult.getUserId(); + mSignatureKeyId = signatureResult.getKeyId(); mUserIdRest.setText("id: " + PgpKeyHelper.convertKeyIdToHex(mSignatureKeyId)); if (userId == null) { @@ -706,19 +713,32 @@ public class DecryptActivity extends DrawerActivity { } mUserId.setText(userId); - if (returnData.getBoolean(KeychainIntentService.RESULT_SIGNATURE_SUCCESS)) { - mSignatureStatusImage.setImageResource(R.drawable.overlay_ok); - mLookupKey.setVisibility(View.GONE); - } else if (returnData - .getBoolean(KeychainIntentService.RESULT_SIGNATURE_UNKNOWN)) { - mSignatureStatusImage.setImageResource(R.drawable.overlay_error); - mLookupKey.setVisibility(View.VISIBLE); - Toast.makeText(DecryptActivity.this, - R.string.unknown_signature, - Toast.LENGTH_LONG).show(); - } else { - mSignatureStatusImage.setImageResource(R.drawable.overlay_error); - mLookupKey.setVisibility(View.GONE); + switch (signatureResult.getStatus()) { + case OpenPgpSignatureResult.SIGNATURE_SUCCESS_UNCERTIFIED: { + mSignatureStatusImage.setImageResource(R.drawable.overlay_ok); + mLookupKey.setVisibility(View.GONE); + break; + } + + // TODO! +// case OpenPgpSignatureResult.SIGNATURE_SUCCESS_CERTIFIED: { +// break; +// } + + case OpenPgpSignatureResult.SIGNATURE_UNKNOWN_PUB_KEY: { + mSignatureStatusImage.setImageResource(R.drawable.overlay_error); + mLookupKey.setVisibility(View.VISIBLE); + AppMsg.makeText(DecryptActivity.this, + R.string.unknown_signature, + AppMsg.STYLE_ALERT).show(); + break; + } + + default: { + mSignatureStatusImage.setImageResource(R.drawable.overlay_error); + mLookupKey.setVisibility(View.GONE); + break; + } } mSignatureLayout.setVisibility(View.VISIBLE); } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/DrawerActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/DrawerActivity.java index 53a57c4cd..08ca262c3 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/DrawerActivity.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/DrawerActivity.java @@ -19,6 +19,7 @@ package org.sufficientlysecure.keychain.ui; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.service.remote.RegisteredAppsListActivity; +import org.sufficientlysecure.keychain.util.Log; import android.app.Activity; import android.content.Context; @@ -52,6 +53,7 @@ public class DrawerActivity extends ActionBarActivity { private static Class[] mItemsClass = new Class[] { KeyListPublicActivity.class, EncryptActivity.class, DecryptActivity.class, ImportKeysActivity.class, KeyListSecretActivity.class, RegisteredAppsListActivity.class }; + private Class mSelectedItem; private static final int MENU_ID_PREFERENCE = 222; private static final int MENU_ID_HELP = 223; @@ -94,6 +96,17 @@ public class DrawerActivity extends ActionBarActivity { getSupportActionBar().setTitle(mTitle); // creates call to onPrepareOptionsMenu() supportInvalidateOptionsMenu(); + + // call intent activity if selected + if(mSelectedItem != null) { + finish(); + overridePendingTransition(0, 0); + + Intent intent = new Intent(DrawerActivity.this, mSelectedItem); + startActivity(intent); + // disable animation of activity start + overridePendingTransition(0, 0); + } } public void onDrawerOpened(View drawerView) { @@ -182,14 +195,8 @@ public class DrawerActivity extends ActionBarActivity { mDrawerList.setItemChecked(position, true); // setTitle(mDrawerTitles[position]); mDrawerLayout.closeDrawer(mDrawerList); - - finish(); - overridePendingTransition(0, 0); - - Intent intent = new Intent(this, mItemsClass[position]); - startActivity(intent); - // disable animation of activity start - overridePendingTransition(0, 0); + // set selected class + mSelectedItem = mItemsClass[position]; } /** diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java index 6ce2a8f6b..716140655 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java @@ -49,6 +49,7 @@ import org.sufficientlysecure.keychain.util.IterableIterator; import org.sufficientlysecure.keychain.util.Log; import android.app.AlertDialog; +import android.app.Activity; import android.app.ProgressDialog; import android.content.Context; import android.content.DialogInterface; @@ -97,7 +98,7 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener private SectionView mUserIdsView; private SectionView mKeysView; - private String mCurrentPassPhrase = null; + private String mCurrentPassphrase = null; private String mNewPassPhrase = null; private String mSavedNewPassPhrase = null; private boolean mIsPassPhraseSet; @@ -105,7 +106,7 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener private boolean mIsBrandNewKeyring = false; private MenuItem mSaveButton; - private BootstrapButton mChangePassPhrase; + private BootstrapButton mChangePassphrase; private CheckBox mNoPassphrase; @@ -174,7 +175,7 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener private void handleActionCreateKey(Intent intent) { Bundle extras = intent.getExtras(); - mCurrentPassPhrase = ""; + mCurrentPassphrase = ""; mIsBrandNewKeyring = true; if (extras != null) { @@ -190,7 +191,7 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener if (noPassphrase) { // check "no passphrase" checkbox and remove button mNoPassphrase.setChecked(true); - mChangePassPhrase.setVisibility(View.GONE); + mChangePassphrase.setVisibility(View.GONE); } } @@ -200,19 +201,31 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener if (generateDefaultKeys) { // Send all information needed to service generate keys in other thread - Intent serviceIntent = new Intent(this, KeychainIntentService.class); + final Intent serviceIntent = new Intent(this, KeychainIntentService.class); serviceIntent.setAction(KeychainIntentService.ACTION_GENERATE_DEFAULT_RSA_KEYS); // fill values for this action Bundle data = new Bundle(); data.putString(KeychainIntentService.GENERATE_KEY_SYMMETRIC_PASSPHRASE, - mCurrentPassPhrase); + mCurrentPassphrase); serviceIntent.putExtra(KeychainIntentService.EXTRA_DATA, data); // Message is received after generating is done in ApgService KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler( - this, R.string.progress_generating, ProgressDialog.STYLE_SPINNER) { + this, R.string.progress_generating, ProgressDialog.STYLE_SPINNER, 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 ApgHandler first super.handleMessage(message); @@ -286,7 +299,7 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener @Override public void handleMessage(Message message) { if (message.what == PassphraseDialogFragment.MESSAGE_OKAY) { - mCurrentPassPhrase = PassphraseCacheService.getCachedPassphrase( + mCurrentPassphrase = PassphraseCacheService.getCachedPassphrase( EditKeyActivity.this, masterKeyId); finallySaveClicked(); } @@ -393,14 +406,14 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener } } - mCurrentPassPhrase = ""; + mCurrentPassphrase = ""; buildLayout(false); mIsPassPhraseSet = PassphraseCacheService.hasPassphrase(this, masterKeyId); if (!mIsPassPhraseSet) { // check "no passphrase" checkbox and remove button mNoPassphrase.setChecked(true); - mChangePassPhrase.setVisibility(View.GONE); + mChangePassphrase.setVisibility(View.GONE); } } @@ -431,7 +444,7 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener // set title based on isPassphraseSet() int title; if (isPassphraseSet()) { - title = R.string.title_change_pass_phrase; + title = R.string.title_change_passphrase; } else { title = R.string.title_set_passphrase; } @@ -451,7 +464,7 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener setContentView(R.layout.edit_key_activity); // find views - mChangePassPhrase = (BootstrapButton) findViewById(R.id.edit_key_btn_change_pass_phrase); + mChangePassphrase = (BootstrapButton) 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 @@ -473,7 +486,7 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener updatePassPhraseButtonText(); - mChangePassPhrase.setOnClickListener(new OnClickListener() { + mChangePassphrase.setOnClickListener(new OnClickListener() { public void onClick(View v) { showSetPassphraseDialog(); } @@ -488,10 +501,10 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener // remove passphrase mSavedNewPassPhrase = mNewPassPhrase; mNewPassPhrase = ""; - mChangePassPhrase.setVisibility(View.GONE); + mChangePassphrase.setVisibility(View.GONE); } else { mNewPassPhrase = mSavedNewPassPhrase; - mChangePassPhrase.setVisibility(View.VISIBLE); + mChangePassphrase.setVisibility(View.VISIBLE); } somethingChanged(); } @@ -545,7 +558,7 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener if (passphrase == null) { showPassphraseDialog(masterKeyId); } else { - mCurrentPassPhrase = passphrase; + mCurrentPassphrase = passphrase; finallySaveClicked(); } } catch (PgpGeneralException e) { @@ -581,13 +594,14 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener saveParams.keysExpiryDates = getKeysExpiryDates(mKeysView); saveParams.keysUsages = getKeysUsages(mKeysView); saveParams.newPassPhrase = mNewPassPhrase; - saveParams.oldPassPhrase = mCurrentPassPhrase; + saveParams.oldPassPhrase = mCurrentPassphrase; saveParams.newKeys = toPrimitiveArray(mKeysView.getNewKeysArray()); saveParams.keys = getKeys(mKeysView); // fill values for this action Bundle data = new Bundle(); + data.putBoolean(KeychainIntentService.SAVE_KEYRING_CAN_SIGN, masterCanSign); data.putParcelable(KeychainIntentService.SAVE_KEYRING_PARCEL, saveParams); @@ -766,7 +780,7 @@ public class EditKeyActivity extends ActionBarActivity implements EditorListener } private void updatePassPhraseButtonText() { - mChangePassPhrase.setText(isPassphraseSet() ? getString(R.string.btn_change_passphrase) + mChangePassphrase.setText(isPassphraseSet() ? getString(R.string.btn_change_passphrase) : getString(R.string.btn_set_passphrase)); } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java index 85bfba224..faac9b157 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java @@ -63,6 +63,7 @@ import android.widget.Toast; import android.widget.ViewFlipper; import com.beardedhen.androidbootstrap.BootstrapButton; +import com.devspark.appmsg.AppMsg; public class EncryptActivity extends DrawerActivity { @@ -100,8 +101,8 @@ public class EncryptActivity extends DrawerActivity { private int mEncryptTarget; - private EditText mPassPhrase = null; - private EditText mPassPhraseAgain = null; + private EditText mPassphrase = null; + private EditText mPassphraseAgain = null; private CheckBox mAsciiArmor = null; private Spinner mFileCompression = null; @@ -415,17 +416,17 @@ public class EncryptActivity extends DrawerActivity { mOutputFilename = guessOutputFilename(mInputFilename); if (mInputFilename.equals("")) { - Toast.makeText(this, R.string.no_file_selected, Toast.LENGTH_SHORT).show(); + AppMsg.makeText(this, R.string.no_file_selected, AppMsg.STYLE_ALERT).show(); return; } if (!mInputFilename.startsWith("content")) { File file = new File(mInputFilename); if (!file.exists() || !file.isFile()) { - Toast.makeText( + AppMsg.makeText( this, getString(R.string.error_message, - getString(R.string.error_file_not_found)), Toast.LENGTH_SHORT) + getString(R.string.error_file_not_found)), AppMsg.STYLE_ALERT) .show(); return; } @@ -435,16 +436,16 @@ public class EncryptActivity extends DrawerActivity { // symmetric encryption if (mMode.getCurrentView().getId() == R.id.modeSymmetric) { boolean gotPassPhrase = false; - String passPhrase = mPassPhrase.getText().toString(); - String passPhraseAgain = mPassPhraseAgain.getText().toString(); - if (!passPhrase.equals(passPhraseAgain)) { - Toast.makeText(this, R.string.passphrases_do_not_match, Toast.LENGTH_SHORT).show(); + String passphrase = mPassphrase.getText().toString(); + String passphraseAgain = mPassphraseAgain.getText().toString(); + if (!passphrase.equals(passphraseAgain)) { + AppMsg.makeText(this, R.string.passphrases_do_not_match, AppMsg.STYLE_ALERT).show(); return; } - gotPassPhrase = (passPhrase.length() != 0); + gotPassPhrase = (passphrase.length() != 0); if (!gotPassPhrase) { - Toast.makeText(this, R.string.passphrase_must_not_be_empty, Toast.LENGTH_SHORT) + AppMsg.makeText(this, R.string.passphrase_must_not_be_empty, AppMsg.STYLE_ALERT) .show(); return; } @@ -452,13 +453,13 @@ public class EncryptActivity extends DrawerActivity { boolean encryptIt = (mEncryptionKeyIds != null && mEncryptionKeyIds.length > 0); // for now require at least one form of encryption for files if (!encryptIt && mEncryptTarget == Id.target.file) { - Toast.makeText(this, R.string.select_encryption_key, Toast.LENGTH_SHORT).show(); + AppMsg.makeText(this, R.string.select_encryption_key, AppMsg.STYLE_ALERT).show(); return; } if (!encryptIt && mSecretKeyId == 0) { - Toast.makeText(this, R.string.select_encryption_or_signature_key, - Toast.LENGTH_SHORT).show(); + AppMsg.makeText(this, R.string.select_encryption_or_signature_key, + AppMsg.STYLE_ALERT).show(); return; } @@ -549,11 +550,11 @@ public class EncryptActivity extends DrawerActivity { if (mMode.getCurrentView().getId() == R.id.modeSymmetric) { Log.d(Constants.TAG, "Symmetric encryption enabled!"); - String passPhrase = mPassPhrase.getText().toString(); - if (passPhrase.length() == 0) { - passPhrase = null; + String passphrase = mPassphrase.getText().toString(); + if (passphrase.length() == 0) { + passphrase = null; } - data.putString(KeychainIntentService.GENERATE_KEY_SYMMETRIC_PASSPHRASE, passPhrase); + data.putString(KeychainIntentService.GENERATE_KEY_SYMMETRIC_PASSPHRASE, passphrase); } else { mSecretKeyIdToPass = mSecretKeyId; encryptionKeyIds = mEncryptionKeyIds; @@ -618,8 +619,8 @@ public class EncryptActivity extends DrawerActivity { output = data.getString(KeychainIntentService.RESULT_ENCRYPTED_STRING); Log.d(Constants.TAG, "output: " + output); ClipboardReflection.copyToClipboard(EncryptActivity.this, output); - Toast.makeText(EncryptActivity.this, - R.string.encryption_to_clipboard_successful, Toast.LENGTH_SHORT) + AppMsg.makeText(EncryptActivity.this, + R.string.encryption_to_clipboard_successful, AppMsg.STYLE_INFO) .show(); break; @@ -640,8 +641,8 @@ public class EncryptActivity extends DrawerActivity { break; case Id.target.file: - Toast.makeText(EncryptActivity.this, R.string.encryption_successful, - Toast.LENGTH_SHORT).show(); + AppMsg.makeText(EncryptActivity.this, R.string.encryption_successful, + AppMsg.STYLE_INFO).show(); if (mDeleteAfter.isChecked()) { // Create and show dialog to delete original file @@ -765,8 +766,8 @@ public class EncryptActivity extends DrawerActivity { mMainUserId = (TextView) findViewById(R.id.mainUserId); mMainUserIdRest = (TextView) findViewById(R.id.mainUserIdRest); - mPassPhrase = (EditText) findViewById(R.id.passPhrase); - mPassPhraseAgain = (EditText) findViewById(R.id.passPhraseAgain); + mPassphrase = (EditText) findViewById(R.id.passphrase); + mPassphraseAgain = (EditText) findViewById(R.id.passphraseAgain); // measure the height of the source_file view and set the message view's min height to that, // so it fills mSource fully... bit of a hack. diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java index a5027ac1c..5ac421a44 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java @@ -17,22 +17,9 @@ package org.sufficientlysecure.keychain.ui; -import java.util.ArrayList; -import java.util.Locale; - -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; -import org.sufficientlysecure.keychain.service.KeychainIntentService; -import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; -import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry; -import org.sufficientlysecure.keychain.util.Log; - import android.annotation.SuppressLint; -import android.app.AlertDialog; import android.app.ProgressDialog; import android.content.Context; -import android.content.DialogInterface; import android.content.Intent; import android.net.Uri; import android.nfc.NdefMessage; @@ -51,6 +38,18 @@ import android.widget.ArrayAdapter; import com.beardedhen.androidbootstrap.BootstrapButton; import com.devspark.appmsg.AppMsg; +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; +import org.sufficientlysecure.keychain.service.KeychainIntentService; +import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; +import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry; +import org.sufficientlysecure.keychain.ui.dialog.BadImportKeyDialogFragment; +import org.sufficientlysecure.keychain.util.Log; + +import java.util.ArrayList; +import java.util.Locale; + public class ImportKeysActivity extends DrawerActivity implements ActionBar.OnNavigationListener { public static final String ACTION_IMPORT_KEY = Constants.INTENT_PREFIX + "IMPORT_KEY"; public static final String ACTION_IMPORT_KEY_FROM_QR_CODE = Constants.INTENT_PREFIX @@ -236,10 +235,10 @@ public class ImportKeysActivity extends DrawerActivity implements ActionBar.OnNa * inside your Activity." * <p/> * from http://stackoverflow.com/questions/10983396/fragment-oncreateview-and-onactivitycreated-called-twice/14295474#14295474 - * + * <p/> * In our case, if we start ImportKeysActivity with parameters to directly search using a fingerprint, * the fragment would be loaded twice resulting in the query being empty after the second load. - * + * <p/> * Our solution: * To prevent that a fragment will be loaded again even if it was already loaded loadNavFragment * checks against mCurrentNavPostition. @@ -395,23 +394,8 @@ public class ImportKeysActivity extends DrawerActivity implements ActionBar.OnNa AppMsg.makeText(ImportKeysActivity.this, toastMessage, AppMsg.STYLE_INFO) .show(); if (bad > 0) { - AlertDialog.Builder alert = new AlertDialog.Builder( - ImportKeysActivity.this); - - alert.setIcon(android.R.drawable.ic_dialog_alert); - alert.setTitle(R.string.warning); - - alert.setMessage(ImportKeysActivity.this.getResources() - .getQuantityString(R.plurals.bad_keys_encountered, bad, bad)); - - alert.setPositiveButton(android.R.string.ok, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - dialog.cancel(); - } - }); - alert.setCancelable(true); - alert.create().show(); + BadImportKeyDialogFragment badImportKeyDialogFragment = BadImportKeyDialogFragment.newInstance(bad); + badImportKeyDialogFragment.show(getSupportFragmentManager(), "badKeyDialog"); } } } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java index b52de5bc9..1118f0264 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java @@ -27,11 +27,13 @@ import java.util.List; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.helper.Preferences; +import org.sufficientlysecure.keychain.ui.adapter.AsyncTaskResultWrapper; import org.sufficientlysecure.keychain.ui.adapter.ImportKeysAdapter; import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry; import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListLoader; import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListServerLoader; import org.sufficientlysecure.keychain.util.InputData; +import org.sufficientlysecure.keychain.util.KeyServer; import org.sufficientlysecure.keychain.util.Log; import android.app.Activity; @@ -42,10 +44,11 @@ import android.support.v4.app.LoaderManager; import android.support.v4.content.Loader; import android.view.View; import android.widget.ListView; -import android.widget.Toast; + +import com.devspark.appmsg.AppMsg; public class ImportKeysListFragment extends ListFragment implements - LoaderManager.LoaderCallbacks<List<ImportKeysListEntry>> { + LoaderManager.LoaderCallbacks<AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>> { private static final String ARG_DATA_URI = "uri"; private static final String ARG_BYTES = "bytes"; private static final String ARG_SERVER_QUERY = "query"; @@ -181,11 +184,10 @@ public class ImportKeysListFragment extends ListFragment implements } @Override - public Loader<List<ImportKeysListEntry>> onCreateLoader(int id, Bundle args) { + public Loader<AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>> onCreateLoader(int id, Bundle args) { switch (id) { case LOADER_ID_BYTES: { InputData inputData = getInputData(mKeyBytes, mDataUri); - return new ImportKeysListLoader(mActivity, inputData); } case LOADER_ID_SERVER_QUERY: { @@ -198,15 +200,15 @@ public class ImportKeysListFragment extends ListFragment implements } @Override - public void onLoadFinished(Loader<List<ImportKeysListEntry>> loader, - List<ImportKeysListEntry> data) { + public void onLoadFinished(Loader<AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>> loader, + AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> data) { // Swap the new cursor in. (The framework will take care of closing the // old cursor once we return.) - Log.d(Constants.TAG, "data: " + data); + Log.d(Constants.TAG, "data: " + data.getResult()); // swap in the real data! - mAdapter.setData(data); + mAdapter.setData(data.getResult()); mAdapter.notifyDataSetChanged(); setListAdapter(mAdapter); @@ -222,11 +224,25 @@ public class ImportKeysListFragment extends ListFragment implements break; case LOADER_ID_SERVER_QUERY: - Toast.makeText( - getActivity(), getResources().getQuantityString(R.plurals.keys_found, - mAdapter.getCount(), mAdapter.getCount()), - Toast.LENGTH_SHORT - ).show(); + + Exception error = data.getError(); + + if(error == null){ + AppMsg.makeText( + getActivity(), getResources().getQuantityString(R.plurals.keys_found, + mAdapter.getCount(), mAdapter.getCount()), + AppMsg.STYLE_INFO + ).show(); + } else if(error instanceof KeyServer.InsufficientQuery){ + AppMsg.makeText(getActivity(), R.string.error_keyserver_insufficient_query, + AppMsg.STYLE_ALERT).show(); + }else if(error instanceof KeyServer.QueryException){ + AppMsg.makeText(getActivity(), R.string.error_keyserver_query, + AppMsg.STYLE_ALERT).show(); + }else if(error instanceof KeyServer.TooManyResponses){ + AppMsg.makeText(getActivity(), R.string.error_keyserver_too_many_responses, + AppMsg.STYLE_ALERT).show(); + } break; default: @@ -235,7 +251,7 @@ public class ImportKeysListFragment extends ListFragment implements } @Override - public void onLoaderReset(Loader<List<ImportKeysListEntry>> loader) { + public void onLoaderReset(Loader<AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>> loader) { switch (loader.getId()) { case LOADER_ID_BYTES: // Clear the data in the adapter. diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java index c28d57627..f2cb8a265 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListPublicFragment.java @@ -33,6 +33,7 @@ import se.emilsjolander.stickylistheaders.ApiLevelTooLowException; import se.emilsjolander.stickylistheaders.StickyListHeadersListView; import android.annotation.SuppressLint; +import android.annotation.TargetApi; import android.content.Intent; import android.database.Cursor; import android.net.Uri; @@ -45,9 +46,13 @@ import android.support.v4.app.Fragment; import android.support.v4.app.LoaderManager; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; +import android.support.v4.view.MenuItemCompat; +import android.support.v7.widget.SearchView; +import android.text.TextUtils; import android.view.ActionMode; import android.view.LayoutInflater; import android.view.Menu; +import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; @@ -63,23 +68,25 @@ import com.beardedhen.androidbootstrap.BootstrapButton; * Public key list with sticky list headers. It does _not_ extend ListFragment because it uses * StickyListHeaders library which does not extend upon ListView. */ -public class KeyListPublicFragment extends Fragment implements AdapterView.OnItemClickListener, +public class KeyListPublicFragment extends Fragment implements SearchView.OnQueryTextListener, AdapterView.OnItemClickListener, LoaderManager.LoaderCallbacks<Cursor> { private KeyListPublicAdapter mAdapter; private StickyListHeadersListView mStickyList; - + private String mCurQuery; + private SearchView mSearchView; // empty list layout private BootstrapButton mButtonEmptyCreate; private BootstrapButton mButtonEmptyImport; + /** * Load custom layout with StickyListView from library */ @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.key_list_public_fragment, container, false); - + setHasOptionsMenu(true); mButtonEmptyCreate = (BootstrapButton) view.findViewById(R.id.key_list_empty_button_create); mButtonEmptyCreate.setOnClickListener(new OnClickListener() { @@ -137,8 +144,6 @@ public class KeyListPublicFragment extends Fragment implements AdapterView.OnIte mStickyList.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL); mStickyList.getWrappedList().setMultiChoiceModeListener(new MultiChoiceModeListener() { - private int count = 0; - @Override public boolean onCreateActionMode(ActionMode mode, Menu menu) { android.view.MenuInflater inflater = getActivity().getMenuInflater(); @@ -172,13 +177,20 @@ public class KeyListPublicFragment extends Fragment implements AdapterView.OnIte showDeleteKeyDialog(mode, ids); break; } + case R.id.menu_key_list_public_multi_select_all: { + //Select all + int localCount = mStickyList.getCount(); + for(int k = 0; k < localCount; k++) { + mStickyList.setItemChecked(k, true); + } + break; + } } return true; } @Override public void onDestroyActionMode(ActionMode mode) { - count = 0; mAdapter.clearSelection(); } @@ -186,13 +198,11 @@ public class KeyListPublicFragment extends Fragment implements AdapterView.OnIte public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) { if (checked) { - count++; mAdapter.setNewSelection(position, checked); } else { - count--; mAdapter.removeSelection(position); } - + int count = mAdapter.getCurrentCheckedPosition().size(); String keysSelected = getResources().getQuantityString( R.plurals.key_list_selected_keys, count, count); mode.setTitle(keysSelected); @@ -231,10 +241,15 @@ public class KeyListPublicFragment extends Fragment implements AdapterView.OnIte // This is called when a new Loader needs to be created. This // sample only has one Loader, so we don't care about the ID. Uri baseUri = KeyRings.buildPublicKeyRingsUri(); - + String where = null; + String whereArgs[] = null; + if(mCurQuery != null){ + where = KeychainContract.UserIds.USER_ID + " LIKE ?"; + whereArgs = new String[]{mCurQuery+"%"}; + } // Now create and return a CursorLoader that will take care of // creating a Cursor for the data being displayed. - return new CursorLoader(getActivity(), baseUri, PROJECTION, null, null, SORT_ORDER); + return new CursorLoader(getActivity(), baseUri, PROJECTION, where, whereArgs, SORT_ORDER); } @Override @@ -276,7 +291,8 @@ public class KeyListPublicFragment extends Fragment implements AdapterView.OnIte viewIntent.setData(KeychainContract.KeyRings.buildPublicKeyRingsUri(Long.toString(id))); startActivity(viewIntent); } - + + @TargetApi(11) public void encrypt(ActionMode mode, long[] keyRingRowIds) { // get master key ids from row ids long[] keyRingIds = new long[keyRingRowIds.length]; @@ -298,6 +314,7 @@ public class KeyListPublicFragment extends Fragment implements AdapterView.OnIte * * @param keyRingRowIds */ + @TargetApi(11) public void showDeleteKeyDialog(final ActionMode mode, long[] keyRingRowIds) { // Message is received after key is deleted Handler returnHandler = new Handler() { @@ -332,4 +349,34 @@ public class KeyListPublicFragment extends Fragment implements AdapterView.OnIte deleteKeyDialog.show(getActivity().getSupportFragmentManager(), "deleteKeyDialog"); } -}
\ No newline at end of file + + @Override + public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) { + + // Get the searchview + MenuItem searchItem = menu.findItem(R.id.menu_key_list_public_search); + mSearchView = (SearchView) MenuItemCompat.getActionView(searchItem); + + // Execute this when searching + mSearchView.setOnQueryTextListener(this); + + super.onCreateOptionsMenu(menu, inflater); + + } + + @Override + public boolean onQueryTextSubmit(String s) { + return true; + } + + @Override + public boolean onQueryTextChange(String s) { + // Called when the action bar search text has changed. Update + // the search filter, and restart the loader to do a new query + // with this filter. + String newQuery = !TextUtils.isEmpty(s) ? s : null; + mCurQuery = newQuery; + getLoaderManager().restartLoader(0, null, this); + return true; + } +} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListSecretFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListSecretFragment.java index f9d267f27..eaac6d8b1 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListSecretFragment.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListSecretFragment.java @@ -29,6 +29,7 @@ import org.sufficientlysecure.keychain.ui.adapter.KeyListSecretAdapter; import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment; import android.annotation.SuppressLint; +import android.annotation.TargetApi; import android.content.Intent; import android.database.Cursor; import android.net.Uri; @@ -81,8 +82,6 @@ public class KeyListSecretFragment extends ListFragment implements getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL); getListView().setMultiChoiceModeListener(new MultiChoiceModeListener() { - private int count = 0; - @Override public boolean onCreateActionMode(ActionMode mode, Menu menu) { android.view.MenuInflater inflater = getActivity().getMenuInflater(); @@ -112,13 +111,20 @@ public class KeyListSecretFragment extends ListFragment implements showDeleteKeyDialog(mode, ids); break; } + case R.id.menu_key_list_public_multi_select_all: { + //Select all + int localCount = getListView().getCount(); + for(int k = 0; k < localCount; k++) { + getListView().setItemChecked(k, true); + } + break; + } } return true; } @Override public void onDestroyActionMode(ActionMode mode) { - count = 0; mAdapter.clearSelection(); } @@ -126,13 +132,12 @@ public class KeyListSecretFragment extends ListFragment implements public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) { if (checked) { - count++; mAdapter.setNewSelection(position, checked); } else { - count--; mAdapter.removeSelection(position); } + int count = getListView().getCheckedItemCount(); String keysSelected = getResources().getQuantityString( R.plurals.key_list_selected_keys, count, count); mode.setTitle(keysSelected); @@ -209,6 +214,7 @@ public class KeyListSecretFragment extends ListFragment implements * * @param keyRingRowIds */ + @TargetApi(11) public void showDeleteKeyDialog(final ActionMode mode, long[] keyRingRowIds) { // Message is received after key is deleted Handler returnHandler = new Handler() { diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesActivity.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesActivity.java index b38beebd1..af20b499b 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesActivity.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesActivity.java @@ -24,24 +24,28 @@ import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.helper.Preferences; import org.sufficientlysecure.keychain.ui.widget.IntegerListPreference; +import android.annotation.SuppressLint; +import android.content.Context; import android.content.Intent; +import android.os.Build; import android.os.Bundle; import android.preference.CheckBoxPreference; import android.preference.Preference; import android.preference.PreferenceActivity; +import android.preference.PreferenceFragment; import android.preference.PreferenceScreen; import android.support.v7.app.ActionBarActivity; +import java.util.List; + +@SuppressLint("NewApi") public class PreferencesActivity extends PreferenceActivity { - private IntegerListPreference mPassPhraseCacheTtl = null; - private IntegerListPreference mEncryptionAlgorithm = null; - private IntegerListPreference mHashAlgorithm = null; - private IntegerListPreference mMessageCompression = null; - private IntegerListPreference mFileCompression = null; - private CheckBoxPreference mAsciiArmour = null; - private CheckBoxPreference mForceV3Signatures = null; + + public final static String ACTION_PREFS_GEN = "org.sufficientlysecure.keychain.ui.PREFS_GEN"; + public final static String ACTION_PREFS_ADV = "org.sufficientlysecure.keychain.ui.PREFS_ADV"; + private PreferenceScreen mKeyServerPreference = null; - private Preferences mPreferences; + private static Preferences mPreferences; @Override protected void onCreate(Bundle savedInstanceState) { @@ -53,22 +57,219 @@ public class PreferencesActivity extends PreferenceActivity { // actionBar.setDisplayHomeAsUpEnabled(false); // actionBar.setHomeButtonEnabled(false); - addPreferencesFromResource(R.xml.preferences); + //addPreferencesFromResource(R.xml.preferences); + String action = getIntent().getAction(); + + if (action != null && action.equals(ACTION_PREFS_GEN)) { + addPreferencesFromResource(R.xml.gen_preferences); + + initializePassPassPhraceCacheTtl( + (IntegerListPreference) findPreference(Constants.pref.PASS_PHRASE_CACHE_TTL)); + + mKeyServerPreference = (PreferenceScreen) findPreference(Constants.pref.KEY_SERVERS); + String servers[] = mPreferences.getKeyServers(); + mKeyServerPreference.setSummary(getResources().getQuantityString(R.plurals.n_key_servers, + servers.length, servers.length)); + mKeyServerPreference + .setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { + public boolean onPreferenceClick(Preference preference) { + Intent intent = new Intent(PreferencesActivity.this, + PreferencesKeyServerActivity.class); + intent.putExtra(PreferencesKeyServerActivity.EXTRA_KEY_SERVERS, + mPreferences.getKeyServers()); + startActivityForResult(intent, Id.request.key_server_preference); + return false; + } + }); + + } else if (action != null && action.equals(ACTION_PREFS_ADV)) { + addPreferencesFromResource(R.xml.adv_preferences); + + initializeEncryptionAlgorithm( + (IntegerListPreference) findPreference(Constants.pref.DEFAULT_ENCRYPTION_ALGORITHM)); + + int[] valueIds = new int[] { Id.choice.compression.none, Id.choice.compression.zip, + Id.choice.compression.zlib, Id.choice.compression.bzip2, }; + String[] entries = new String[] { + getString(R.string.choice_none) + " (" + getString(R.string.compression_fast) + ")", + "ZIP (" + getString(R.string.compression_fast) + ")", + "ZLIB (" + getString(R.string.compression_fast) + ")", + "BZIP2 (" + getString(R.string.compression_very_slow) + ")", }; + String[] values = new String[valueIds.length]; + for (int i = 0; i < values.length; ++i) { + values[i] = "" + valueIds[i]; + } + + initializeHashAlgorithm( + (IntegerListPreference) findPreference(Constants.pref.DEFAULT_HASH_ALGORITHM), + valueIds, entries, values); + + initializeMessageCompression( + (IntegerListPreference) findPreference(Constants.pref.DEFAULT_MESSAGE_COMPRESSION), + valueIds, entries, values); + + initializeFileCompression( + (IntegerListPreference) findPreference(Constants.pref.DEFAULT_FILE_COMPRESSION), + entries, values); + + initializeAsciiArmour((CheckBoxPreference) findPreference(Constants.pref.DEFAULT_ASCII_ARMOUR)); + + initializeForceV3Signatures((CheckBoxPreference) findPreference(Constants.pref.FORCE_V3_SIGNATURES)); + + } else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { + // Load the legacy preferences headers + addPreferencesFromResource(R.xml.preference_headers_legacy); + } + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + switch (requestCode) { + case Id.request.key_server_preference: { + if (resultCode == RESULT_CANCELED || data == null) { + return; + } + String servers[] = data + .getStringArrayExtra(PreferencesKeyServerActivity.EXTRA_KEY_SERVERS); + mPreferences.setKeyServers(servers); + mKeyServerPreference.setSummary(getResources().getQuantityString( + R.plurals.n_key_servers, servers.length, servers.length)); + break; + } + + default: { + super.onActivityResult(requestCode, resultCode, data); + break; + } + } + } + + /* Called only on Honeycomb and later */ + @Override + public void onBuildHeaders(List<Header> target) { + super.onBuildHeaders(target); + loadHeadersFromResource(R.xml.preference_headers, target); + } + + /** This fragment shows the general preferences in android 3.0+ */ + public static class GeneralPrefsFragment extends PreferenceFragment { + + private PreferenceScreen mKeyServerPreference = null; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + // Load the preferences from an XML resource + addPreferencesFromResource(R.xml.gen_preferences); + + initializePassPassPhraceCacheTtl( + (IntegerListPreference) findPreference(Constants.pref.PASS_PHRASE_CACHE_TTL)); + + mKeyServerPreference = (PreferenceScreen) findPreference(Constants.pref.KEY_SERVERS); + String servers[] = mPreferences.getKeyServers(); + mKeyServerPreference.setSummary(getResources().getQuantityString(R.plurals.n_key_servers, + servers.length, servers.length)); + mKeyServerPreference + .setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { + public boolean onPreferenceClick(Preference preference) { + Intent intent = new Intent(getActivity(), + PreferencesKeyServerActivity.class); + intent.putExtra(PreferencesKeyServerActivity.EXTRA_KEY_SERVERS, + mPreferences.getKeyServers()); + startActivityForResult(intent, Id.request.key_server_preference); + return false; + } + }); + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + switch (requestCode) { + case Id.request.key_server_preference: { + if (resultCode == RESULT_CANCELED || data == null) { + return; + } + String servers[] = data + .getStringArrayExtra(PreferencesKeyServerActivity.EXTRA_KEY_SERVERS); + mPreferences.setKeyServers(servers); + mKeyServerPreference.setSummary(getResources().getQuantityString( + R.plurals.n_key_servers, servers.length, servers.length)); + break; + } + + default: { + super.onActivityResult(requestCode, resultCode, data); + break; + } + } + } + } + + /** This fragment shows the advanced preferences in android 3.0+ */ + public static class AdvancedPrefsFragment extends PreferenceFragment { + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + // Load the preferences from an XML resource + addPreferencesFromResource(R.xml.adv_preferences); + + initializeEncryptionAlgorithm( + (IntegerListPreference) findPreference(Constants.pref.DEFAULT_ENCRYPTION_ALGORITHM)); + + int[] valueIds = new int[] { Id.choice.compression.none, Id.choice.compression.zip, + Id.choice.compression.zlib, Id.choice.compression.bzip2, }; + String[] entries = new String[] { + getString(R.string.choice_none) + " (" + getString(R.string.compression_fast) + ")", + "ZIP (" + getString(R.string.compression_fast) + ")", + "ZLIB (" + getString(R.string.compression_fast) + ")", + "BZIP2 (" + getString(R.string.compression_very_slow) + ")", }; + String[] values = new String[valueIds.length]; + for (int i = 0; i < values.length; ++i) { + values[i] = "" + valueIds[i]; + } + + initializeHashAlgorithm( + (IntegerListPreference) findPreference(Constants.pref.DEFAULT_HASH_ALGORITHM), + valueIds, entries, values); + + initializeMessageCompression( + (IntegerListPreference) findPreference(Constants.pref.DEFAULT_MESSAGE_COMPRESSION), + valueIds, entries, values); + + initializeFileCompression( + (IntegerListPreference) findPreference(Constants.pref.DEFAULT_FILE_COMPRESSION), + entries, values); - mPassPhraseCacheTtl = (IntegerListPreference) findPreference(Constants.pref.PASS_PHRASE_CACHE_TTL); - mPassPhraseCacheTtl.setValue("" + mPreferences.getPassPhraseCacheTtl()); - mPassPhraseCacheTtl.setSummary(mPassPhraseCacheTtl.getEntry()); - mPassPhraseCacheTtl + initializeAsciiArmour((CheckBoxPreference) findPreference(Constants.pref.DEFAULT_ASCII_ARMOUR)); + + initializeForceV3Signatures((CheckBoxPreference) findPreference(Constants.pref.FORCE_V3_SIGNATURES)); + } + } + + protected boolean isValidFragment (String fragmentName) { + return AdvancedPrefsFragment.class.getName().equals(fragmentName) + || GeneralPrefsFragment.class.getName().equals(fragmentName) + || super.isValidFragment(fragmentName); + } + + private static void initializePassPassPhraceCacheTtl(final IntegerListPreference mPassphraseCacheTtl) { + mPassphraseCacheTtl.setValue("" + mPreferences.getPassPhraseCacheTtl()); + mPassphraseCacheTtl.setSummary(mPassphraseCacheTtl.getEntry()); + mPassphraseCacheTtl .setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { public boolean onPreferenceChange(Preference preference, Object newValue) { - mPassPhraseCacheTtl.setValue(newValue.toString()); - mPassPhraseCacheTtl.setSummary(mPassPhraseCacheTtl.getEntry()); + mPassphraseCacheTtl.setValue(newValue.toString()); + mPassphraseCacheTtl.setSummary(mPassphraseCacheTtl.getEntry()); mPreferences.setPassPhraseCacheTtl(Integer.parseInt(newValue.toString())); return false; } }); + } - mEncryptionAlgorithm = (IntegerListPreference) findPreference(Constants.pref.DEFAULT_ENCRYPTION_ALGORITHM); + private static void initializeEncryptionAlgorithm(final IntegerListPreference mEncryptionAlgorithm) { int valueIds[] = { PGPEncryptedData.AES_128, PGPEncryptedData.AES_192, PGPEncryptedData.AES_256, PGPEncryptedData.BLOWFISH, PGPEncryptedData.TWOFISH, PGPEncryptedData.CAST5, PGPEncryptedData.DES, PGPEncryptedData.TRIPLE_DES, @@ -93,8 +294,10 @@ public class PreferencesActivity extends PreferenceActivity { return false; } }); + } - mHashAlgorithm = (IntegerListPreference) findPreference(Constants.pref.DEFAULT_HASH_ALGORITHM); + private static void initializeHashAlgorithm + (final IntegerListPreference mHashAlgorithm, int[] valueIds, String[] entries, String[] values) { valueIds = new int[] { HashAlgorithmTags.MD5, HashAlgorithmTags.RIPEMD160, HashAlgorithmTags.SHA1, HashAlgorithmTags.SHA224, HashAlgorithmTags.SHA256, HashAlgorithmTags.SHA384, HashAlgorithmTags.SHA512, }; @@ -116,19 +319,10 @@ public class PreferencesActivity extends PreferenceActivity { return false; } }); + } - mMessageCompression = (IntegerListPreference) findPreference(Constants.pref.DEFAULT_MESSAGE_COMPRESSION); - valueIds = new int[] { Id.choice.compression.none, Id.choice.compression.zip, - Id.choice.compression.zlib, Id.choice.compression.bzip2, }; - entries = new String[] { - getString(R.string.choice_none) + " (" + getString(R.string.compression_fast) + ")", - "ZIP (" + getString(R.string.compression_fast) + ")", - "ZLIB (" + getString(R.string.compression_fast) + ")", - "BZIP2 (" + getString(R.string.compression_very_slow) + ")", }; - values = new String[valueIds.length]; - for (int i = 0; i < values.length; ++i) { - values[i] = "" + valueIds[i]; - } + private static void initializeMessageCompression + (final IntegerListPreference mMessageCompression, int[] valueIds, String[] entries, String[] values) { mMessageCompression.setEntries(entries); mMessageCompression.setEntryValues(values); mMessageCompression.setValue("" + mPreferences.getDefaultMessageCompression()); @@ -143,8 +337,10 @@ public class PreferencesActivity extends PreferenceActivity { return false; } }); + } - mFileCompression = (IntegerListPreference) findPreference(Constants.pref.DEFAULT_FILE_COMPRESSION); + private static void initializeFileCompression + (final IntegerListPreference mFileCompression, String[] entries, String[] values) { mFileCompression.setEntries(entries); mFileCompression.setEntryValues(values); mFileCompression.setValue("" + mPreferences.getDefaultFileCompression()); @@ -157,8 +353,9 @@ public class PreferencesActivity extends PreferenceActivity { return false; } }); + } - mAsciiArmour = (CheckBoxPreference) findPreference(Constants.pref.DEFAULT_ASCII_ARMOUR); + private static void initializeAsciiArmour(final CheckBoxPreference mAsciiArmour) { mAsciiArmour.setChecked(mPreferences.getDefaultAsciiArmour()); mAsciiArmour.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { public boolean onPreferenceChange(Preference preference, Object newValue) { @@ -167,8 +364,9 @@ public class PreferencesActivity extends PreferenceActivity { return false; } }); + } - mForceV3Signatures = (CheckBoxPreference) findPreference(Constants.pref.FORCE_V3_SIGNATURES); + private static void initializeForceV3Signatures(final CheckBoxPreference mForceV3Signatures) { mForceV3Signatures.setChecked(mPreferences.getForceV3Signatures()); mForceV3Signatures .setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { @@ -178,43 +376,5 @@ public class PreferencesActivity extends PreferenceActivity { return false; } }); - - mKeyServerPreference = (PreferenceScreen) findPreference(Constants.pref.KEY_SERVERS); - String servers[] = mPreferences.getKeyServers(); - mKeyServerPreference.setSummary(getResources().getQuantityString(R.plurals.n_key_servers, - servers.length, servers.length)); - mKeyServerPreference - .setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { - public boolean onPreferenceClick(Preference preference) { - Intent intent = new Intent(PreferencesActivity.this, - PreferencesKeyServerActivity.class); - intent.putExtra(PreferencesKeyServerActivity.EXTRA_KEY_SERVERS, - mPreferences.getKeyServers()); - startActivityForResult(intent, Id.request.key_server_preference); - return false; - } - }); - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - switch (requestCode) { - case Id.request.key_server_preference: { - if (resultCode == RESULT_CANCELED || data == null) { - return; - } - String servers[] = data - .getStringArrayExtra(PreferencesKeyServerActivity.EXTRA_KEY_SERVERS); - mPreferences.setKeyServers(servers); - mKeyServerPreference.setSummary(getResources().getQuantityString( - R.plurals.n_key_servers, servers.length, servers.length)); - break; - } - - default: { - super.onActivityResult(requestCode, resultCode, data); - break; - } - } } -} +}
\ No newline at end of file diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyFragment.java index 59b46dd00..a43c84cf4 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyFragment.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyFragment.java @@ -38,17 +38,22 @@ import android.os.Bundle; import android.support.v4.app.LoaderManager; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; +import android.text.Editable; +import android.text.TextUtils; +import android.text.TextWatcher; +import android.widget.EditText; import android.widget.ListView; -public class SelectPublicKeyFragment extends ListFragmentWorkaround implements +public class SelectPublicKeyFragment extends ListFragmentWorkaround implements TextWatcher, LoaderManager.LoaderCallbacks<Cursor> { public static final String ARG_PRESELECTED_KEY_IDS = "preselected_key_ids"; private Activity mActivity; private SelectKeyCursorAdapter mAdapter; private ListView mListView; - + private EditText mSearchView; private long mSelectedMasterKeyIds[]; + private String mCurQuery; /** * Creates new instance of this fragment @@ -67,7 +72,8 @@ public class SelectPublicKeyFragment extends ListFragmentWorkaround implements @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - + mSearchView = (EditText)getActivity().findViewById(R.id.select_public_key_search); + mSearchView.addTextChangedListener(this); mSelectedMasterKeyIds = getArguments().getLongArray(ARG_PRESELECTED_KEY_IDS); } @@ -82,7 +88,6 @@ public class SelectPublicKeyFragment extends ListFragmentWorkaround implements mListView = getListView(); mListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE); - // Give some text to display if there is no data. In a real // application this would come from a resource. setEmptyText(getString(R.string.list_empty)); @@ -220,10 +225,16 @@ public class SelectPublicKeyFragment extends ListFragmentWorkaround implements // sort by selected master keys orderBy = inMasterKeyList + " DESC, " + orderBy; } + String where = null; + String whereArgs[] = null; + if(mCurQuery != null){ + where = UserIds.USER_ID + " LIKE ?"; + whereArgs = new String[]{mCurQuery+"%"}; + } // Now create and return a CursorLoader that will take care of // creating a Cursor for the data being displayed. - return new CursorLoader(getActivity(), baseUri, projection, null, null, orderBy); + return new CursorLoader(getActivity(), baseUri, projection, where, whereArgs, orderBy); } @Override @@ -250,4 +261,21 @@ public class SelectPublicKeyFragment extends ListFragmentWorkaround implements // longer using it. mAdapter.swapCursor(null); } + + @Override + public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) { + + } + + @Override + public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) { + + } + + @Override + public void afterTextChanged(Editable editable) { + String newQuery = !TextUtils.isEmpty(editable.toString()) ? editable.toString() : null; + mCurQuery = newQuery; + getLoaderManager().restartLoader(0, null, this); + } } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/AsyncTaskResultWrapper.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/AsyncTaskResultWrapper.java new file mode 100644 index 000000000..2ac19c1d9 --- /dev/null +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/AsyncTaskResultWrapper.java @@ -0,0 +1,45 @@ +/* + * 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; + +/** + * The AsyncTaskResultWrapper is used to wrap a result from a AsyncTask (for example: Loader). + * You can pass the result and an exception in it if an error occurred. + * Concept found at: + * https://stackoverflow.com/questions/19593577/how-to-handle-errors-in-custom-asynctaskloader + * @param <T> - Typ of the result which is wrapped + */ +public class AsyncTaskResultWrapper <T>{ + + private final T result; + private final Exception error; + + public AsyncTaskResultWrapper(T result, Exception error){ + this.result = result; + this.error = error; + } + + public T getResult() { + return result; + } + + public Exception getError() { + return error; + } + +} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java index 00ad8c957..76649b27b 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java @@ -33,12 +33,13 @@ import org.sufficientlysecure.keychain.util.PositionAwareInputStream; import android.content.Context; import android.support.v4.content.AsyncTaskLoader; -public class ImportKeysListLoader extends AsyncTaskLoader<List<ImportKeysListEntry>> { +public class ImportKeysListLoader extends AsyncTaskLoader<AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>> { Context mContext; InputData mInputData; ArrayList<ImportKeysListEntry> data = new ArrayList<ImportKeysListEntry>(); + AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> entryListWrapper; public ImportKeysListLoader(Context context, InputData inputData) { super(context); @@ -47,15 +48,18 @@ public class ImportKeysListLoader extends AsyncTaskLoader<List<ImportKeysListEnt } @Override - public List<ImportKeysListEntry> loadInBackground() { + public AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> loadInBackground() { + + entryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(data, null); + if (mInputData == null) { Log.e(Constants.TAG, "Input data is null!"); - return data; + return entryListWrapper; } generateListOfKeyrings(mInputData); - return data; + return entryListWrapper; } @Override @@ -77,7 +81,7 @@ public class ImportKeysListLoader extends AsyncTaskLoader<List<ImportKeysListEnt } @Override - public void deliverResult(List<ImportKeysListEntry> data) { + public void deliverResult(AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> data) { super.deliverResult(data); } @@ -93,7 +97,7 @@ public class ImportKeysListLoader extends AsyncTaskLoader<List<ImportKeysListEnt // need to have access to the bufferedInput, so we can reuse it for the possible // PGPObject chunks after the first one, e.g. files with several consecutive ASCII - // armour blocks + // armor blocks BufferedInputStream bufferedInput = new BufferedInputStream(progressIn); try { diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListServerLoader.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListServerLoader.java index b3bc39127..3a3b6e58b 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListServerLoader.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListServerLoader.java @@ -26,15 +26,15 @@ import org.sufficientlysecure.keychain.util.KeyServer; import org.sufficientlysecure.keychain.util.Log; import java.util.ArrayList; -import java.util.List; -public class ImportKeysListServerLoader extends AsyncTaskLoader<List<ImportKeysListEntry>> { +public class ImportKeysListServerLoader extends AsyncTaskLoader<AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>> { Context mContext; String mServerQuery; String mKeyServer; - ArrayList<ImportKeysListEntry> data = new ArrayList<ImportKeysListEntry>(); + private ArrayList<ImportKeysListEntry> entryList = new ArrayList<ImportKeysListEntry>(); + private AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> entryListWrapper; public ImportKeysListServerLoader(Context context, String serverQuery, String keyServer) { super(context); @@ -44,15 +44,18 @@ public class ImportKeysListServerLoader extends AsyncTaskLoader<List<ImportKeysL } @Override - public List<ImportKeysListEntry> loadInBackground() { + public AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> loadInBackground() { + + entryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(entryList, null); + if (mServerQuery == null) { Log.e(Constants.TAG, "mServerQuery is null!"); - return data; + return entryListWrapper; } queryServer(mServerQuery, mKeyServer); - return data; + return entryListWrapper; } @Override @@ -74,7 +77,7 @@ public class ImportKeysListServerLoader extends AsyncTaskLoader<List<ImportKeysL } @Override - public void deliverResult(List<ImportKeysListEntry> data) { + public void deliverResult(AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>> data) { super.deliverResult(data); } @@ -87,13 +90,17 @@ public class ImportKeysListServerLoader extends AsyncTaskLoader<List<ImportKeysL ArrayList<ImportKeysListEntry> searchResult = server.search(query); // add result to data - data.addAll(searchResult); + entryList.addAll(searchResult); + entryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(entryList, null); } catch (KeyServer.InsufficientQuery e) { Log.e(Constants.TAG, "InsufficientQuery", e); + entryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(entryList, e); } catch (KeyServer.QueryException e) { Log.e(Constants.TAG, "QueryException", e); + entryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(entryList, e); } catch (KeyServer.TooManyResponses e) { Log.e(Constants.TAG, "TooManyResponses", e); + entryListWrapper = new AsyncTaskResultWrapper<ArrayList<ImportKeysListEntry>>(entryList, e); } } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyListPublicAdapter.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyListPublicAdapter.java index 257136cbd..ac505adfb 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyListPublicAdapter.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyListPublicAdapter.java @@ -223,7 +223,7 @@ public class KeyListPublicAdapter extends CursorAdapter implements StickyListHea */ // default color v.setBackgroundColor(Color.TRANSPARENT); - if (mSelection.get(position) != null) { + if (mSelection.get(position) != null && mSelection.get(position).booleanValue()) { // this is a selected position, change color! v.setBackgroundColor(parent.getResources().getColor(R.color.emphasis)); } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/BadImportKeyDialogFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/BadImportKeyDialogFragment.java new file mode 100644 index 000000000..2b8cba857 --- /dev/null +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/BadImportKeyDialogFragment.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2012-2013 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.AlertDialog; +import android.app.Dialog; +import android.content.DialogInterface; +import android.os.Bundle; +import android.support.v4.app.DialogFragment; +import android.support.v4.app.FragmentActivity; + +import org.sufficientlysecure.keychain.R; + +public class BadImportKeyDialogFragment extends DialogFragment { + private static final String ARG_BAD_IMPORT = "bad_import"; + + /** + * Creates a new instance of this Bad Import Key DialogFragment + * + * @param bad + * @return + */ + public static BadImportKeyDialogFragment newInstance(int bad) { + BadImportKeyDialogFragment frag = new BadImportKeyDialogFragment(); + Bundle args = new Bundle(); + + args.putInt(ARG_BAD_IMPORT, bad); + frag.setArguments(args); + + return frag; + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + final FragmentActivity activity = getActivity(); + final int badImport = getArguments().getInt(ARG_BAD_IMPORT); + + AlertDialog.Builder alert = new AlertDialog.Builder(activity); + alert.setIcon(R.drawable.ic_dialog_alert_holo_light); + alert.setTitle(R.string.warning); + alert.setMessage(activity.getResources() + .getQuantityString(R.plurals.bad_keys_encountered, badImport, badImport)); + alert.setPositiveButton(android.R.string.ok, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + dialog.cancel(); + } + }); + alert.setCancelable(true); + + return alert.create(); + } +} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/CreateKeyDialogFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/CreateKeyDialogFragment.java new file mode 100644 index 000000000..98b677511 --- /dev/null +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/CreateKeyDialogFragment.java @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2012-2013 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.AlertDialog; +import android.app.Dialog; +import android.content.DialogInterface; +import android.os.Bundle; +import android.support.v4.app.DialogFragment; +import android.support.v4.app.FragmentActivity; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.ArrayAdapter; +import android.widget.Spinner; + +import org.sufficientlysecure.keychain.Id; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.util.Choice; + +import java.util.Vector; + +public class CreateKeyDialogFragment extends DialogFragment { + + public interface OnAlgorithmSelectedListener { + public void onAlgorithmSelected(Choice algorithmChoice, int keySize); + } + + private static final String ARG_EDITOR_CHILD_COUNT = "child_count"; + + private int mNewKeySize; + private Choice mNewKeyAlgorithmChoice; + private OnAlgorithmSelectedListener mAlgorithmSelectedListener; + + public void setOnAlgorithmSelectedListener(OnAlgorithmSelectedListener listener) { + mAlgorithmSelectedListener = listener; + } + + public static CreateKeyDialogFragment newInstance(int mEditorChildCount) { + CreateKeyDialogFragment frag = new CreateKeyDialogFragment(); + Bundle args = new Bundle(); + + args.putInt(ARG_EDITOR_CHILD_COUNT, mEditorChildCount); + + frag.setArguments(args); + + return frag; + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + final FragmentActivity context = getActivity(); + final LayoutInflater mInflater; + + final int childCount = getArguments().getInt(ARG_EDITOR_CHILD_COUNT); + mInflater = context.getLayoutInflater(); + + AlertDialog.Builder dialog = new AlertDialog.Builder(context); + + View view = mInflater.inflate(R.layout.create_key_dialog, null); + dialog.setView(view); + dialog.setTitle(R.string.title_create_key); + + boolean wouldBeMasterKey = (childCount == 0); + + final Spinner algorithm = (Spinner) view.findViewById(R.id.create_key_algorithm); + Vector<Choice> choices = new Vector<Choice>(); + choices.add(new Choice(Id.choice.algorithm.dsa, getResources().getString( + R.string.dsa))); + if (!wouldBeMasterKey) { + choices.add(new Choice(Id.choice.algorithm.elgamal, getResources().getString( + R.string.elgamal))); + } + + choices.add(new Choice(Id.choice.algorithm.rsa, getResources().getString( + R.string.rsa))); + + ArrayAdapter<Choice> adapter = new ArrayAdapter<Choice>(context, + android.R.layout.simple_spinner_item, choices); + adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + algorithm.setAdapter(adapter); + // make RSA the default + for (int i = 0; i < choices.size(); ++i) { + if (choices.get(i).getId() == Id.choice.algorithm.rsa) { + algorithm.setSelection(i); + break; + } + } + + final Spinner keySize = (Spinner) view.findViewById(R.id.create_key_size); + ArrayAdapter<CharSequence> keySizeAdapter = ArrayAdapter.createFromResource( + context, R.array.key_size_spinner_values, + android.R.layout.simple_spinner_item); + keySizeAdapter + .setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + keySize.setAdapter(keySizeAdapter); + keySize.setSelection(3); // Default to 4096 for the key length + dialog.setPositiveButton(android.R.string.ok, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface di, int id) { + di.dismiss(); + try { + int nKeyIndex = keySize.getSelectedItemPosition(); + switch (nKeyIndex) { + case 0: + mNewKeySize = 512; + break; + case 1: + mNewKeySize = 1024; + break; + case 2: + mNewKeySize = 2048; + break; + case 3: + mNewKeySize = 4096; + break; + } + } catch (NumberFormatException e) { + mNewKeySize = 0; + } + + mNewKeyAlgorithmChoice = (Choice) algorithm.getSelectedItem(); + mAlgorithmSelectedListener.onAlgorithmSelected(mNewKeyAlgorithmChoice, mNewKeySize); + } + }); + + dialog.setCancelable(true); + dialog.setNegativeButton(android.R.string.cancel, + new DialogInterface.OnClickListener() { + public void onClick(DialogInterface di, int id) { + di.dismiss(); + } + }); + + return dialog.create(); + } + +}
\ No newline at end of file diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteFileDialogFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteFileDialogFragment.java index f7e41daf7..cd8bc79a9 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteFileDialogFragment.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteFileDialogFragment.java @@ -61,7 +61,8 @@ public class DeleteFileDialogFragment extends DialogFragment { AlertDialog.Builder alert = new AlertDialog.Builder(activity); - alert.setIcon(android.R.drawable.ic_dialog_alert); + + alert.setIcon(R.drawable.ic_dialog_alert_holo_light); alert.setTitle(R.string.warning); alert.setMessage(this.getString(R.string.file_delete_confirmation, deleteFile)); @@ -82,7 +83,7 @@ public class DeleteFileDialogFragment extends DialogFragment { intent.putExtra(KeychainIntentService.EXTRA_DATA, data); ProgressDialogFragment deletingDialog = ProgressDialogFragment.newInstance( - R.string.progress_deleting_securely, ProgressDialog.STYLE_HORIZONTAL); + R.string.progress_deleting_securely, ProgressDialog.STYLE_HORIZONTAL, false, null); // Message is received after deleting is done in ApgService KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(activity, deletingDialog) { diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java index 3c44bff81..dc40bab2a 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java @@ -17,17 +17,6 @@ package org.sufficientlysecure.keychain.ui.dialog; -import org.spongycastle.openpgp.PGPPublicKeyRing; -import org.spongycastle.openpgp.PGPSecretKeyRing; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.Id; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; -import org.sufficientlysecure.keychain.provider.KeychainContract; -import org.sufficientlysecure.keychain.provider.KeychainDatabase; -import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.util.Log; - import android.app.AlertDialog; import android.app.Dialog; import android.content.DialogInterface; @@ -40,6 +29,14 @@ import android.os.RemoteException; import android.support.v4.app.DialogFragment; import android.support.v4.app.FragmentActivity; +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.Id; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.provider.KeychainContract; +import org.sufficientlysecure.keychain.provider.KeychainDatabase; +import org.sufficientlysecure.keychain.provider.ProviderHelper; +import org.sufficientlysecure.keychain.util.Log; + import java.util.ArrayList; public class DeleteKeyDialogFragment extends DialogFragment { @@ -100,7 +97,7 @@ public class DeleteKeyDialogFragment extends DialogFragment { builder.setMessage(R.string.key_deletion_confirmation_multi); } - builder.setIcon(android.R.drawable.ic_dialog_alert); + builder.setIcon(R.drawable.ic_dialog_alert_holo_light); builder.setPositiveButton(R.string.btn_delete, new DialogInterface.OnClickListener() { @Override diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/PassphraseDialogFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/PassphraseDialogFragment.java index e88271240..c00232fd1 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/PassphraseDialogFragment.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/PassphraseDialogFragment.java @@ -153,7 +153,7 @@ public class PassphraseDialogFragment extends DialogFragment implements OnEditor dismiss(); long curKeyIndex = 1; boolean keyOK = true; - String passPhrase = mPassphraseEditText.getText().toString(); + String passphrase = mPassphraseEditText.getText().toString(); long keyId; PGPSecretKey clickSecretKey = secretKey; @@ -163,7 +163,7 @@ public class PassphraseDialogFragment extends DialogFragment implements OnEditor try { PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder() .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME).build( - passPhrase.toCharArray()); + passphrase.toCharArray()); PGPPrivateKey testKey = clickSecretKey .extractPrivateKey(keyDecryptor); if (testKey == null) { @@ -206,10 +206,10 @@ public class PassphraseDialogFragment extends DialogFragment implements OnEditor // cache the new passphrase Log.d(Constants.TAG, "Everything okay! Caching entered passphrase"); - PassphraseCacheService.addCachedPassphrase(activity, keyId, passPhrase); + PassphraseCacheService.addCachedPassphrase(activity, keyId, passphrase); if (keyOK == false && clickSecretKey.getKeyID() != keyId) { PassphraseCacheService.addCachedPassphrase(activity, clickSecretKey.getKeyID(), - passPhrase); + passphrase); } sendMessageToHandler(MESSAGE_OKAY); diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ProgressDialogFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ProgressDialogFragment.java index 9b5d233e8..6c62d14e0 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ProgressDialogFragment.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ProgressDialogFragment.java @@ -21,28 +21,40 @@ import android.app.Activity; import android.app.Dialog; import android.app.ProgressDialog; import android.content.DialogInterface; +import android.content.DialogInterface.OnCancelListener; import android.content.DialogInterface.OnKeyListener; import android.os.Bundle; import android.support.v4.app.DialogFragment; import android.view.KeyEvent; +import org.sufficientlysecure.keychain.R; + public class ProgressDialogFragment extends DialogFragment { private static final String ARG_MESSAGE_ID = "message_id"; private static final String ARG_STYLE = "style"; + private static final String ARG_CANCELABLE = "cancelable"; + + private OnCancelListener mOnCancelListener; /** * Creates new instance of this fragment * - * @param id + * @param messageId + * @param style + * @param cancelable * @return */ - public static ProgressDialogFragment newInstance(int messageId, int style) { + public static ProgressDialogFragment newInstance(int messageId, int style, boolean cancelable, + OnCancelListener onCancelListener) { ProgressDialogFragment frag = new ProgressDialogFragment(); Bundle args = new Bundle(); args.putInt(ARG_MESSAGE_ID, messageId); args.putInt(ARG_STYLE, style); + args.putBoolean(ARG_CANCELABLE, cancelable); frag.setArguments(args); + frag.mOnCancelListener = onCancelListener; + return frag; } @@ -60,7 +72,6 @@ public class ProgressDialogFragment extends DialogFragment { /** * Updates progress of dialog * - * @param messageId * @param progress * @param max */ @@ -74,7 +85,7 @@ public class ProgressDialogFragment extends DialogFragment { /** * Updates progress of dialog * - * @param messageId + * @param message * @param progress * @param max */ @@ -86,12 +97,20 @@ public class ProgressDialogFragment extends DialogFragment { dialog.setMax(max); } + @Override + public void onCancel(DialogInterface dialog) { + super.onCancel(dialog); + + if (this.mOnCancelListener != null) + this.mOnCancelListener.onCancel(dialog); + } + /** * Creates dialog */ @Override public Dialog onCreateDialog(Bundle savedInstanceState) { - Activity activity = getActivity(); + final Activity activity = getActivity(); ProgressDialog dialog = new ProgressDialog(activity); dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); @@ -100,10 +119,22 @@ public class ProgressDialogFragment extends DialogFragment { int messageId = getArguments().getInt(ARG_MESSAGE_ID); int style = getArguments().getInt(ARG_STYLE); + boolean cancelable = getArguments().getBoolean(ARG_CANCELABLE); dialog.setMessage(getString(messageId)); dialog.setProgressStyle(style); + if (cancelable) { + dialog.setButton(DialogInterface.BUTTON_NEGATIVE, + activity.getString(R.string.progress_cancel), + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + dialog.cancel(); + } + }); + } + // Disable the back button OnKeyListener keyListener = new OnKeyListener() { diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/SetPassphraseDialogFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/SetPassphraseDialogFragment.java index 50e72dfba..e406547b3 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/SetPassphraseDialogFragment.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/SetPassphraseDialogFragment.java @@ -101,9 +101,9 @@ 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)) { + String passphrase1 = mPassphraseEditText.getText().toString(); + String passphrase2 = mPassphraseAgainEditText.getText().toString(); + if (!passphrase1.equals(passphrase2)) { Toast.makeText( activity, getString(R.string.error_message, @@ -112,7 +112,7 @@ public class SetPassphraseDialogFragment extends DialogFragment implements OnEdi return; } - if (passPhrase1.equals("")) { + if (passphrase1.equals("")) { Toast.makeText( activity, getString(R.string.error_message, @@ -123,7 +123,7 @@ public class SetPassphraseDialogFragment extends DialogFragment implements OnEdi // return resulting data back to activity Bundle data = new Bundle(); - data.putString(MESSAGE_NEW_PASSPHRASE, passPhrase1); + data.putString(MESSAGE_NEW_PASSPHRASE, passphrase1); sendMessageToHandler(MESSAGE_OKAY, data); } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareNfcDialogFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareNfcDialogFragment.java index 03e09cdcb..b850638a6 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareNfcDialogFragment.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareNfcDialogFragment.java @@ -53,7 +53,6 @@ public class ShareNfcDialogFragment extends DialogFragment { AlertDialog.Builder alert = new AlertDialog.Builder(activity); - alert.setIcon(android.R.drawable.ic_dialog_info); alert.setTitle(R.string.share_nfc_dialog); alert.setCancelable(true); diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareQrCodeDialogFragment.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareQrCodeDialogFragment.java index 9f3270250..f26cd35c0 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareQrCodeDialogFragment.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareQrCodeDialogFragment.java @@ -17,28 +17,26 @@ package org.sufficientlysecure.keychain.ui.dialog; -import java.util.ArrayList; - -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; -import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.util.Log; -import org.sufficientlysecure.keychain.util.QrCodeUtils; - import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; import android.net.Uri; import android.os.Bundle; import android.support.v4.app.DialogFragment; -import android.view.ContextThemeWrapper; import android.view.LayoutInflater; import android.view.View; import android.widget.Button; import android.widget.ImageView; import android.widget.TextView; +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.pgp.PgpKeyHelper; +import org.sufficientlysecure.keychain.provider.ProviderHelper; +import org.sufficientlysecure.keychain.util.QrCodeUtils; + +import java.util.ArrayList; + public class ShareQrCodeDialogFragment extends DialogFragment { private static final String ARG_KEY_URI = "uri"; private static final String ARG_FINGERPRINT_ONLY = "fingerprint_only"; diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeyEditor.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeyEditor.java index 68bfc573e..b1f97babf 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeyEditor.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeyEditor.java @@ -35,6 +35,7 @@ import android.app.DatePickerDialog; import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; +import android.text.format.DateUtils; import android.util.AttributeSet; import android.view.View; import android.view.View.OnClickListener; @@ -60,6 +61,7 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener { TextView mKeyId; TextView mCreationDate; BootstrapButton mExpiryDateButton; + GregorianCalendar mCreatedDate; GregorianCalendar mExpiryDate; GregorianCalendar mOriginalExpiryDate = null; CheckBox mChkCertify; @@ -142,8 +144,12 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener { if (date == null) { date = new GregorianCalendar(TimeZone.getTimeZone("UTC")); } - - DatePickerDialog dialog = new DatePickerDialog(getContext(), + /* + * Using custom DatePickerDialog which overrides the setTitle because + * the DatePickerDialog title is buggy (unix warparound bug). + * See: https://code.google.com/p/android/issues/detail?id=49066 + */ + DatePickerDialog dialog = new ExpiryDatePickerDialog(getContext(), mExpiryDateSetListener, date.get(Calendar.YEAR), date.get(Calendar.MONTH), date.get(Calendar.DAY_OF_MONTH)); mDatePickerResultCount = 0; @@ -161,6 +167,21 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener { } } }); + + // setCalendarViewShown() is supported from API 11 onwards. + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) + // Hide calendarView in tablets because of the unix warparound bug. + dialog.getDatePicker().setCalendarViewShown(false); + + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) { + if ( dialog != null && mCreatedDate != null ) { + dialog.getDatePicker().setMinDate(mCreatedDate.getTime().getTime()+ DateUtils.DAY_IN_MILLIS); + } else { + //When created date isn't available + dialog.getDatePicker().setMinDate(date.getTime().getTime()+ DateUtils.DAY_IN_MILLIS); + } + } + dialog.show(); } }); @@ -237,7 +258,7 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener { GregorianCalendar cal = new GregorianCalendar(TimeZone.getTimeZone("UTC")); cal.setTime(PgpKeyHelper.getCreationDate(key)); - mCreationDate.setText(DateFormat.getDateInstance().format(cal.getTime())); + setCreatedDate(cal); cal = new GregorianCalendar(TimeZone.getTimeZone("UTC")); Date expiryDate = PgpKeyHelper.getExpiryDate(key); if (expiryDate == null) { @@ -268,6 +289,15 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener { mEditorListener = listener; } + private void setCreatedDate(GregorianCalendar date) { + mCreatedDate = date; + if (date == null) { + mCreationDate.setText(getContext().getString(R.string.none)); + } else { + mCreationDate.setText(DateFormat.getDateInstance().format(date.getTime())); + } + } + private void setExpiryDate(GregorianCalendar date) { mExpiryDate = date; if (date == null) { @@ -320,3 +350,14 @@ public class KeyEditor extends LinearLayout implements Editor, OnClickListener { } } + +class ExpiryDatePickerDialog extends DatePickerDialog { + + public ExpiryDatePickerDialog(Context context, OnDateSetListener callBack, int year, int monthOfYear, int dayOfMonth) { + super(context, callBack, year, monthOfYear, dayOfMonth); + } + //Set permanent title. + public void setTitle(CharSequence title) { + super.setTitle(getContext().getString(R.string.expiry_date_dialog_title)); + } +} diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SectionView.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SectionView.java index 93c10a2b0..6ab422d69 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SectionView.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SectionView.java @@ -46,13 +46,25 @@ import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; -import android.widget.ArrayAdapter; import android.widget.LinearLayout; -import android.widget.Spinner; import android.widget.TextView; import com.beardedhen.androidbootstrap.BootstrapButton; +import org.spongycastle.openpgp.PGPSecretKey; +import org.sufficientlysecure.keychain.Id; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.pgp.PgpConversionHelper; +import org.sufficientlysecure.keychain.service.KeychainIntentService; +import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; +import org.sufficientlysecure.keychain.service.PassphraseCacheService; +import org.sufficientlysecure.keychain.ui.dialog.CreateKeyDialogFragment; +import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment; +import org.sufficientlysecure.keychain.ui.widget.Editor.EditorListener; +import org.sufficientlysecure.keychain.util.Choice; + + + public class SectionView extends LinearLayout implements OnClickListener, EditorListener, Editor { private LayoutInflater mInflater; private BootstrapButton mPlusButton; @@ -252,84 +264,16 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor } case Id.type.key: { - AlertDialog.Builder dialog = new AlertDialog.Builder(getContext()); - - View view = mInflater.inflate(R.layout.create_key_dialog, null); - dialog.setView(view); - dialog.setTitle(R.string.title_create_key); - - boolean wouldBeMasterKey = (mEditors.getChildCount() == 0); - - final Spinner algorithm = (Spinner) view.findViewById(R.id.create_key_algorithm); - Vector<Choice> choices = new Vector<Choice>(); - choices.add(new Choice(Id.choice.algorithm.dsa, getResources().getString( - R.string.dsa))); - if (!wouldBeMasterKey) { - choices.add(new Choice(Id.choice.algorithm.elgamal, getResources().getString( - R.string.elgamal))); - } - - choices.add(new Choice(Id.choice.algorithm.rsa, getResources().getString( - R.string.rsa))); - - ArrayAdapter<Choice> adapter = new ArrayAdapter<Choice>(getContext(), - android.R.layout.simple_spinner_item, choices); - adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); - algorithm.setAdapter(adapter); - // make RSA the default - for (int i = 0; i < choices.size(); ++i) { - if (choices.get(i).getId() == Id.choice.algorithm.rsa) { - algorithm.setSelection(i); - break; + CreateKeyDialogFragment mCreateKeyDialogFragment = CreateKeyDialogFragment.newInstance(mEditors.getChildCount()); + mCreateKeyDialogFragment.setOnAlgorithmSelectedListener(new CreateKeyDialogFragment.OnAlgorithmSelectedListener() { + @Override + public void onAlgorithmSelected(Choice algorithmChoice, int keySize) { + mNewKeyAlgorithmChoice = algorithmChoice; + mNewKeySize = keySize; + createKey(); } - } - - final Spinner keySize = (Spinner) view.findViewById(R.id.create_key_size); - ArrayAdapter<CharSequence> keySizeAdapter = ArrayAdapter.createFromResource( - getContext(), R.array.key_size_spinner_values, - android.R.layout.simple_spinner_item); - keySizeAdapter - .setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); - keySize.setAdapter(keySizeAdapter); - keySize.setSelection(3); // Default to 4096 for the key length - dialog.setPositiveButton(android.R.string.ok, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface di, int id) { - di.dismiss(); - try { - int nKeyIndex = keySize.getSelectedItemPosition(); - switch (nKeyIndex) { - case 0: - mNewKeySize = 512; - break; - case 1: - mNewKeySize = 1024; - break; - case 2: - mNewKeySize = 2048; - break; - case 3: - mNewKeySize = 4096; - break; - } - } catch (NumberFormatException e) { - mNewKeySize = 0; - } - - mNewKeyAlgorithmChoice = (Choice) algorithm.getSelectedItem(); - createKey(); - } - }); - - dialog.setCancelable(true); - dialog.setNegativeButton(android.R.string.cancel, - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface di, int id) { - di.dismiss(); - } - }); - - dialog.create().show(); + }); + mCreateKeyDialogFragment.show(mActivity.getSupportFragmentManager(), "createKeyDialog"); break; } @@ -382,7 +326,7 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor private void createKey() { // Send all information needed to service to edit key in other thread - Intent intent = new Intent(mActivity, KeychainIntentService.class); + final Intent intent = new Intent(mActivity, KeychainIntentService.class); intent.setAction(KeychainIntentService.ACTION_GENERATE_KEY); @@ -390,18 +334,18 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor Bundle data = new Bundle(); Boolean isMasterKey; - String passPhrase; + String passphrase; if (mEditors.getChildCount() > 0) { PGPSecretKey masterKey = ((KeyEditor) mEditors.getChildAt(0)).getValue(); - passPhrase = PassphraseCacheService + passphrase = PassphraseCacheService .getCachedPassphrase(mActivity, masterKey.getKeyID()); isMasterKey = false; } else { - passPhrase = ""; + passphrase = ""; isMasterKey = true; } data.putBoolean(KeychainIntentService.GENERATE_KEY_MASTER_KEY, isMasterKey); - data.putString(KeychainIntentService.GENERATE_KEY_SYMMETRIC_PASSPHRASE, passPhrase); + data.putString(KeychainIntentService.GENERATE_KEY_SYMMETRIC_PASSPHRASE, passphrase); data.putInt(KeychainIntentService.GENERATE_KEY_ALGORITHM, mNewKeyAlgorithmChoice.getId()); data.putInt(KeychainIntentService.GENERATE_KEY_KEY_SIZE, mNewKeySize); @@ -409,7 +353,12 @@ public class SectionView extends LinearLayout implements OnClickListener, Editor // show progress dialog mGeneratingDialog = ProgressDialogFragment.newInstance(R.string.progress_generating, - ProgressDialog.STYLE_SPINNER); + ProgressDialog.STYLE_SPINNER, true, new DialogInterface.OnCancelListener() { + @Override + public void onCancel(DialogInterface dialog) { + mActivity.stopService(intent); + } + }); // Message is received after generating is done in ApgService KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(mActivity, diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/HkpKeyServer.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/HkpKeyServer.java index 61fe13ffb..921d22f21 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/HkpKeyServer.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/HkpKeyServer.java @@ -1,6 +1,8 @@ /* + * Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de> + * Copyright (C) 2011 Thialfihar <thi@thialfihar.org> * Copyright (C) 2011 Senecaso - * + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -32,6 +34,7 @@ import java.util.List; import java.util.TimeZone; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.Locale; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; @@ -172,11 +175,11 @@ public class HkpKeyServer extends KeyServer { if (e.getCode() == 404) { return results; } else { - if (e.getData().toLowerCase().contains("no keys found")) { + if (e.getData().toLowerCase(Locale.US).contains("no keys found")) { return results; - } else if (e.getData().toLowerCase().contains("too many")) { + } else if (e.getData().toLowerCase(Locale.US).contains("too many")) { throw new TooManyResponses(); - } else if (e.getData().toLowerCase().contains("insufficient")) { + } else if (e.getData().toLowerCase(Locale.US).contains("insufficient")) { throw new InsufficientQuery(); } } diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/KeyServer.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/KeyServer.java index 072affb1f..7049820e8 100644 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/KeyServer.java +++ b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/util/KeyServer.java @@ -1,6 +1,8 @@ /* + * Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de> + * Copyright (C) 2011 Thialfihar <thi@thialfihar.org> * Copyright (C) 2011 Senecaso - * + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -16,14 +18,8 @@ package org.sufficientlysecure.keychain.util; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Date; import java.util.List; -import android.os.Parcel; -import android.os.Parcelable; - import org.sufficientlysecure.keychain.ui.adapter.ImportKeysListEntry; public abstract class KeyServer { @@ -52,5 +48,5 @@ public abstract class KeyServer { abstract String get(long keyId) throws QueryException; - abstract void add(String armouredText) throws AddKeyException; + abstract void add(String armoredText) throws AddKeyException; } |