From c05441667e151dceb6f5874b290d70a53258061b Mon Sep 17 00:00:00 2001 From: Tim Bray Date: Fri, 7 Nov 2014 12:28:27 -0800 Subject: Moved from WebView to Spannables, some proof cleanup too --- .../operations/results/OperationResult.java | 9 + .../keychain/pgp/PgpDecryptVerify.java | 162 +++++++- .../keychain/service/KeychainIntentService.java | 133 ++++++- .../keychain/ui/ViewKeyActivity.java | 6 + .../keychain/ui/ViewKeyTrustFragment.java | 443 +++++++++++++++++++++ 5 files changed, 732 insertions(+), 21 deletions(-) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyTrustFragment.java (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java index dc45fabc3..70d999242 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java @@ -545,6 +545,15 @@ public abstract class OperationResult implements Parcelable { MSG_DC_TRAIL_UNKNOWN (LogLevel.DEBUG, R.string.msg_dc_trail_unknown), MSG_DC_UNLOCKING (LogLevel.INFO, R.string.msg_dc_unlocking), + // verify signed literal data + MSG_VL (LogLevel.INFO, R.string.msg_vl), + MSG_VL_ERROR_MISSING_SIGLIST (LogLevel.ERROR, R.string.msg_vl_error_no_siglist), + MSG_VL_ERROR_MISSING_LITERAL (LogLevel.ERROR, R.string.msg_vl_error_missing_literal), + MSG_VL_ERROR_MISSING_KEY (LogLevel.ERROR, R.string.msg_vl_error_wrong_key), + MSG_VL_CLEAR_SIGNATURE_CHECK (LogLevel.DEBUG, R.string.msg_vl_clear_signature_check), + MSG_VL_ERROR_INTEGRITY_CHECK (LogLevel.ERROR, R.string.msg_vl_error_integrity_check), + MSG_VL_OK (LogLevel.OK, R.string.msg_vl_ok), + // signencrypt MSG_SE_ASYMMETRIC (LogLevel.INFO, R.string.msg_se_asymmetric), MSG_SE_CLEARSIGN_ONLY (LogLevel.DEBUG, R.string.msg_se_clearsign_only), diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java index 4f086c2a6..4161f2928 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java @@ -48,6 +48,7 @@ import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.operations.BaseOperation; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; +import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult; @@ -83,6 +84,8 @@ public class PgpDecryptVerify extends BaseOperation { private Set mAllowedKeyIds; private boolean mDecryptMetadataOnly; private byte[] mDecryptedSessionKey; + private String mRequiredSignerFingerprint; + private boolean mSignedLiteralData; private PgpDecryptVerify(Builder builder) { super(builder.mContext, builder.mProviderHelper, builder.mProgressable); @@ -96,6 +99,8 @@ public class PgpDecryptVerify extends BaseOperation { this.mAllowedKeyIds = builder.mAllowedKeyIds; this.mDecryptMetadataOnly = builder.mDecryptMetadataOnly; this.mDecryptedSessionKey = builder.mDecryptedSessionKey; + this.mSignedLiteralData = builder.mSignedLiteralData; + this.mRequiredSignerFingerprint = builder.mRequiredSignerFingerprint; } public static class Builder { @@ -112,6 +117,8 @@ public class PgpDecryptVerify extends BaseOperation { private Set mAllowedKeyIds = null; private boolean mDecryptMetadataOnly = false; private byte[] mDecryptedSessionKey = null; + private String mRequiredSignerFingerprint = null; + private boolean mSignedLiteralData = false; public Builder(Context context, ProviderHelper providerHelper, Progressable progressable, @@ -123,6 +130,24 @@ public class PgpDecryptVerify extends BaseOperation { mOutStream = outStream; } + /** + * This is used when verifying signed literals to check that they are signed with + * the required key + */ + public Builder setRequiredSignerFingerprint(String fingerprint) { + mRequiredSignerFingerprint = fingerprint; + return this; + } + + /** + * This is to force a mode where the message is just the signature key id and + * then a literal data packet; used in Keybase.io proofs + */ + public Builder setSignedLiteralData(boolean signedLiteralData) { + mSignedLiteralData = signedLiteralData; + return this; + } + public Builder setAllowSymmetricDecryption(boolean allowSymmetricDecryption) { mAllowSymmetricDecryption = allowSymmetricDecryption; return this; @@ -174,7 +199,9 @@ public class PgpDecryptVerify extends BaseOperation { // it is ascii armored Log.d(Constants.TAG, "ASCII Armor Header Line: " + aIn.getArmorHeaderLine()); - if (aIn.isClearText()) { + if (mSignedLiteralData) { + return verifySignedLiteralData(aIn, 0); + } else if (aIn.isClearText()) { // a cleartext signature, verify it with the other method return verifyCleartextSignature(aIn, 0); } @@ -195,6 +222,139 @@ public class PgpDecryptVerify extends BaseOperation { } } + /** + * Verify Keybase.io style signed literal data + */ + private DecryptVerifyResult verifySignedLiteralData(InputStream in, int indent) throws IOException, PGPException { + OperationLog log = new OperationLog(); + log.add(LogType.MSG_VL, indent); + + // thinking that the proof-fetching operation is going to take most of the time + updateProgress(R.string.progress_reading_data, 75, 100); + + PGPObjectFactory pgpF = new PGPObjectFactory(in, new JcaKeyFingerprintCalculator()); + Object o = pgpF.nextObject(); + if (o instanceof PGPCompressedData) { + log.add(LogType.MSG_DC_CLEAR_DECOMPRESS, indent + 1); + + pgpF = new PGPObjectFactory(((PGPCompressedData) o).getDataStream(), new JcaKeyFingerprintCalculator()); + o = pgpF.nextObject(); + updateProgress(R.string.progress_decompressing_data, 80, 100); + } + + // all we want to see is a OnePassSignatureList followed by LiteralData + if (!(o instanceof PGPOnePassSignatureList)) { + log.add(LogType.MSG_VL_ERROR_MISSING_SIGLIST, indent); + return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log); + } + PGPOnePassSignatureList sigList = (PGPOnePassSignatureList) o; + + // go through all signatures (should be just one), make sure we have + // the key and it matches the one we’re looking for + CanonicalizedPublicKeyRing signingRing = null; + CanonicalizedPublicKey signingKey = null; + int signatureIndex = -1; + for (int i = 0; i < sigList.size(); ++i) { + try { + long sigKeyId = sigList.get(i).getKeyID(); + signingRing = mProviderHelper.getCanonicalizedPublicKeyRing( + KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(sigKeyId) + ); + signingKey = signingRing.getPublicKey(sigKeyId); + signatureIndex = i; + } catch (ProviderHelper.NotFoundException e) { + Log.d(Constants.TAG, "key not found, trying next signature..."); + } + } + + // there has to be a key, and it has to be the right one + if (signingKey == null) { + log.add(LogType.MSG_VL_ERROR_MISSING_KEY, indent); + Log.d(Constants.TAG, "Failed to find key in signed-literal message"); + return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log); + } + + CanonicalizedPublicKey encryptKey = signingKey; + try { + encryptKey = signingRing.getEncryptionSubKey(); + } catch (PgpKeyNotFoundException e) { + } + String fingerprint = KeyFormattingUtils.convertFingerprintToHex(signingKey.getFingerprint()); + String cryptFingerprint = KeyFormattingUtils.convertFingerprintToHex(encryptKey.getFingerprint()); + if (!(mRequiredSignerFingerprint.equals(fingerprint) || mRequiredSignerFingerprint.equals(cryptFingerprint))) { + log.add(LogType.MSG_VL_ERROR_MISSING_KEY, indent); + Log.d(Constants.TAG, "Key mismatch; wanted " + mRequiredSignerFingerprint + + " got " + fingerprint + "/" + cryptFingerprint); + return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log); + } + + OpenPgpSignatureResultBuilder signatureResultBuilder = new OpenPgpSignatureResultBuilder(); + + PGPOnePassSignature signature = sigList.get(signatureIndex); + signatureResultBuilder.initValid(signingRing, signingKey); + + JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = + new JcaPGPContentVerifierBuilderProvider() + .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); + signature.init(contentVerifierBuilderProvider, signingKey.getPublicKey()); + + o = pgpF.nextObject(); + + if (!(o instanceof PGPLiteralData)) { + log.add(LogType.MSG_VL_ERROR_MISSING_LITERAL, indent); + return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log); + } + + PGPLiteralData literalData = (PGPLiteralData) o; + + log.add(LogType.MSG_DC_CLEAR_DATA, indent + 1); + updateProgress(R.string.progress_decrypting, 85, 100); + + InputStream dataIn = literalData.getInputStream(); + + int length; + byte[] buffer = new byte[1 << 16]; + while ((length = dataIn.read(buffer)) > 0) { + mOutStream.write(buffer, 0, length); + signature.update(buffer, 0, length); + } + + updateProgress(R.string.progress_verifying_signature, 95, 100); + log.add(LogType.MSG_VL_CLEAR_SIGNATURE_CHECK, indent + 1); + + PGPSignatureList signatureList = (PGPSignatureList) pgpF.nextObject(); + PGPSignature messageSignature = signatureList.get(signatureIndex); + + // these are not cleartext signatures! + // TODO: what about binary signatures? + signatureResultBuilder.setSignatureOnly(false); + + // Verify signature and check binding signatures + boolean validSignature = signature.verify(messageSignature); + if (validSignature) { + log.add(LogType.MSG_DC_CLEAR_SIGNATURE_OK, indent + 1); + } else { + log.add(LogType.MSG_DC_CLEAR_SIGNATURE_BAD, indent + 1); + } + signatureResultBuilder.setValidSignature(validSignature); + + if (!signatureResultBuilder.isValidSignature()) { + log.add(LogType.MSG_VL_ERROR_INTEGRITY_CHECK, indent); + return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log); + } + + updateProgress(R.string.progress_done, 100, 100); + + log.add(LogType.MSG_VL_OK, indent); + + // Return a positive result, with metadata and verification info + DecryptVerifyResult result = + new DecryptVerifyResult(DecryptVerifyResult.RESULT_OK, log); + result.setSignatureResult(signatureResultBuilder.build()); + return result; + } + + /** * Decrypt and/or verifies binary or ascii armored pgp */ diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java index a2988f2b2..42e0c7cc9 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -26,55 +26,62 @@ import android.os.Message; import android.os.Messenger; import android.os.RemoteException; +import com.textuality.keybase.lib.Proof; +import com.textuality.keybase.lib.prover.Prover; + +import org.json.JSONObject; +import org.spongycastle.openpgp.PGPUtil; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.keyimport.HkpKeyserver; +import org.sufficientlysecure.keychain.keyimport.Keyserver; +import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing; import org.sufficientlysecure.keychain.operations.CertifyOperation; import org.sufficientlysecure.keychain.operations.DeleteOperation; +import org.sufficientlysecure.keychain.operations.ImportExportOperation; +import org.sufficientlysecure.keychain.operations.results.CertifyResult; +import org.sufficientlysecure.keychain.operations.results.ConsolidateResult; +import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult; import org.sufficientlysecure.keychain.operations.results.DeleteResult; +import org.sufficientlysecure.keychain.operations.results.EditKeyResult; import org.sufficientlysecure.keychain.operations.results.ExportResult; -import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; -import org.sufficientlysecure.keychain.operations.results.CertifyResult; -import org.sufficientlysecure.keychain.util.FileHelper; -import org.sufficientlysecure.keychain.util.ParcelableFileCache.IteratorWithSize; -import org.sufficientlysecure.keychain.util.Preferences; -import org.sufficientlysecure.keychain.keyimport.HkpKeyserver; -import org.sufficientlysecure.keychain.keyimport.Keyserver; -import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing; +import org.sufficientlysecure.keychain.operations.results.ImportKeyResult; +import org.sufficientlysecure.keychain.operations.results.OperationResult; +import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; +import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; +import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult; +import org.sufficientlysecure.keychain.operations.results.SignEncryptResult; import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing; import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKeyRing; import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify; -import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult; import org.sufficientlysecure.keychain.pgp.PgpHelper; -import org.sufficientlysecure.keychain.operations.ImportExportOperation; import org.sufficientlysecure.keychain.pgp.PgpKeyOperation; import org.sufficientlysecure.keychain.pgp.PgpSignEncrypt; import org.sufficientlysecure.keychain.pgp.Progressable; import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralMsgIdException; +import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing; import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.operations.results.OperationResult; -import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; -import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; -import org.sufficientlysecure.keychain.operations.results.ConsolidateResult; -import org.sufficientlysecure.keychain.operations.results.EditKeyResult; -import org.sufficientlysecure.keychain.operations.results.ImportKeyResult; -import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult; -import org.sufficientlysecure.keychain.operations.results.SignEncryptResult; -import org.sufficientlysecure.keychain.util.ParcelableFileCache; +import org.sufficientlysecure.keychain.util.FileHelper; import org.sufficientlysecure.keychain.util.InputData; import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.ParcelableFileCache; +import org.sufficientlysecure.keychain.util.ParcelableFileCache.IteratorWithSize; +import org.sufficientlysecure.keychain.util.Preferences; import org.sufficientlysecure.keychain.util.ProgressScaler; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.FileNotFoundException; import java.io.IOException; +import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.Date; import java.util.Iterator; +import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; /** @@ -93,6 +100,8 @@ public class KeychainIntentService extends IntentService implements Progressable public static final String ACTION_DECRYPT_VERIFY = Constants.INTENT_PREFIX + "DECRYPT_VERIFY"; + public static final String ACTION_VERIFY_KEYBASE_PROOF = Constants.INTENT_PREFIX + "VERIFY_KEYBASE_PROOF"; + public static final String ACTION_DECRYPT_METADATA = Constants.INTENT_PREFIX + "DECRYPT_METADATA"; public static final String ACTION_EDIT_KEYRING = Constants.INTENT_PREFIX + "EDIT_KEYRING"; @@ -142,6 +151,10 @@ public class KeychainIntentService extends IntentService implements Progressable public static final String DECRYPT_PASSPHRASE = "passphrase"; public static final String DECRYPT_NFC_DECRYPTED_SESSION_KEY = "nfc_decrypted_session_key"; + // keybase proof + public static final String KEYBASE_REQUIRED_FINGERPRINT = "keybase_required_fingerprint"; + public static final String KEYBASE_PROOF = "keybase_proof"; + // save keyring public static final String EDIT_KEYRING_PARCEL = "save_parcel"; public static final String EDIT_KEYRING_PASSPHRASE = "passphrase"; @@ -291,6 +304,72 @@ public class KeychainIntentService extends IntentService implements Progressable sendErrorToHandler(e); } + } else if (ACTION_VERIFY_KEYBASE_PROOF.equals(action)) { + try { + Proof proof = new Proof(new JSONObject(data.getString(KEYBASE_PROOF))); + setProgress(R.string.keybase_message_fetching_data, 0, 100); + + Prover prover = Prover.findProverFor(proof); + + if (prover == null) { + sendProofError(getString(R.string.keybase_no_prover_found) + ": " + proof.getPrettyName()); + return; + } + + if (!prover.fetchProofData()) { + sendProofError(prover.getLog(), getString(R.string.keybase_problem_fetching_evidence)); + return; + } + + byte[] messageBytes = prover.getPgpMessage().getBytes(); + if (prover.rawMessageCheckRequired()) { + InputStream messageByteStream = PGPUtil.getDecoderStream(new ByteArrayInputStream(messageBytes)); + String problem = prover.checkRawMessageBytes(messageByteStream); + if (problem != null) { + sendProofError(prover.getLog(), problem); + return; + } + } + + // kind of awkward, but this whole class wants to pull bytes out of “data” + data.putInt(KeychainIntentService.TARGET, KeychainIntentService.IO_BYTES); + data.putByteArray(KeychainIntentService.DECRYPT_CIPHERTEXT_BYTES, messageBytes); + + InputData inputData = createDecryptInputData(data); + OutputStream outStream = createCryptOutputStream(data); + String fingerprint = data.getString(KEYBASE_REQUIRED_FINGERPRINT); + + PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder( + this, new ProviderHelper(this), this, + inputData, outStream + ); + builder.setSignedLiteralData(true).setRequiredSignerFingerprint(fingerprint); + + DecryptVerifyResult decryptVerifyResult = builder.build().execute(); + outStream.close(); + + if (!decryptVerifyResult.success()) { + OperationLog log = decryptVerifyResult.getLog(); + OperationResult.LogEntryParcel lastEntry = null; + for (OperationResult.LogEntryParcel entry : log) { + lastEntry = entry; + } + sendProofError(getString(lastEntry.mType.getMsgId())); + return; + } + + if (!prover.validate(outStream.toString())) { + sendProofError(getString(R.string.keybase_message_payload_mismatch)); + return; + } + + Bundle resultData = new Bundle(); + resultData.putString(KeychainIntentServiceHandler.DATA_MESSAGE, "OK"); + sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, resultData); + } catch (Exception e) { + sendErrorToHandler(e); + } + } else if (ACTION_DECRYPT_VERIFY.equals(action)) { try { @@ -597,6 +676,21 @@ public class KeychainIntentService extends IntentService implements Progressable } + private void sendProofError(List log, String label) { + String msg = null; + for (String m : log) { + Log.e(Constants.TAG, label + ": " + m); + msg = m; + } + sendProofError(label + ": " + msg); + } + + private void sendProofError(String msg) { + Bundle bundle = new Bundle(); + bundle.putString(KeychainIntentServiceHandler.DATA_ERROR, msg); + sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, bundle); + } + private void sendErrorToHandler(Exception e) { // TODO: Implement a better exception handling here // contextualize the exception, if necessary @@ -607,7 +701,6 @@ public class KeychainIntentService extends IntentService implements Progressable } else { message = e.getMessage(); } - Log.d(Constants.TAG, "KeychainIntentService Exception: ", e); Bundle data = new Bundle(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java index 0bc75b3a9..a7ba4accf 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java @@ -78,6 +78,7 @@ public class ViewKeyActivity extends ActionBarActivity implements public static final String EXTRA_SELECTED_TAB = "selected_tab"; public static final int TAB_MAIN = 0; public static final int TAB_SHARE = 1; + public static final int TAB_TRUST = 2; // view private ViewPager mViewPager; @@ -183,6 +184,11 @@ public class ViewKeyActivity extends ActionBarActivity implements mTabsAdapter.addTab(ViewKeyShareFragment.class, shareBundle, getString(R.string.key_view_tab_share)); + Bundle trustBundle = new Bundle(); + trustBundle.putParcelable(ViewKeyMainFragment.ARG_DATA_URI, dataUri); + mTabsAdapter.addTab(ViewKeyTrustFragment.class, trustBundle, + getString(R.string.key_view_tab_trust)); + // update layout after operations mSlidingTabLayout.setViewPager(mViewPager); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyTrustFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyTrustFragment.java new file mode 100644 index 000000000..ef6cd50f1 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyTrustFragment.java @@ -0,0 +1,443 @@ +/* + * Copyright (C) 2014 Tim Bray + * + * 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 . + */ + +package org.sufficientlysecure.keychain.ui; + +import android.app.ProgressDialog; +import android.content.Intent; +import android.database.Cursor; +import android.graphics.Typeface; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Bundle; +import android.os.Message; +import android.os.Messenger; +import android.support.v4.app.LoaderManager; +import android.support.v4.content.CursorLoader; +import android.support.v4.content.Loader; +import android.text.SpannableStringBuilder; +import android.text.Spanned; +import android.text.method.LinkMovementMethod; +import android.text.style.ClickableSpan; +import android.text.style.StyleSpan; +import android.text.style.URLSpan; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TableLayout; +import android.widget.TableRow; +import android.widget.TextView; + +import com.textuality.keybase.lib.KeybaseException; +import com.textuality.keybase.lib.Proof; +import com.textuality.keybase.lib.User; + +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; +import org.sufficientlysecure.keychain.service.KeychainIntentService; +import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; +import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; +import org.sufficientlysecure.keychain.util.Log; + +import java.util.ArrayList; +import java.util.Date; +import java.util.Hashtable; +import java.util.List; + +public class ViewKeyTrustFragment extends LoaderFragment implements + LoaderManager.LoaderCallbacks { + + private View mStartSearch; + private TextView mTrustReadout; + private TextView mReportHeader; + private TableLayout mProofListing; + private LayoutInflater mInflater; + private View mProofVerifyHeader; + private TextView mProofVerifyDetail; + + private static final int LOADER_ID_DATABASE = 1; + + // for retrieving the key we’re working on + private Uri mDataUri; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup superContainer, Bundle savedInstanceState) { + View root = super.onCreateView(inflater, superContainer, savedInstanceState); + View view = inflater.inflate(R.layout.view_key_trust_fragment, getContainer()); + mInflater = inflater; + + mTrustReadout = (TextView) view.findViewById(R.id.view_key_trust_readout); + mStartSearch = view.findViewById(R.id.view_key_trust_search_cloud); + mStartSearch.setEnabled(false); + mReportHeader = (TextView) view.findViewById(R.id.view_key_trust_cloud_narrative); + mProofListing = (TableLayout) view.findViewById(R.id.view_key_proof_list); + mProofVerifyHeader = view.findViewById(R.id.view_key_proof_verify_header); + mProofVerifyDetail = (TextView) view.findViewById(R.id.view_key_proof_verify_detail); + mReportHeader.setVisibility(View.GONE); + mProofListing.setVisibility(View.GONE); + mProofVerifyHeader.setVisibility(View.GONE); + mProofVerifyDetail.setVisibility(View.GONE); + + return root; + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + Uri dataUri = getArguments().getParcelable(ViewKeyMainFragment.ARG_DATA_URI); + if (dataUri == null) { + Log.e(Constants.TAG, "Data missing. Should be Uri of key!"); + getActivity().finish(); + return; + } + mDataUri = dataUri; + + // retrieve the key from the database + getLoaderManager().initLoader(LOADER_ID_DATABASE, null, this); + } + + static final String[] TRUST_PROJECTION = new String[]{ + KeyRings._ID, KeyRings.FINGERPRINT, KeyRings.IS_REVOKED, KeyRings.EXPIRY, + KeyRings.HAS_ANY_SECRET, KeyRings.VERIFIED + }; + static final int INDEX_TRUST_FINGERPRINT = 1; + static final int INDEX_TRUST_IS_REVOKED = 2; + static final int INDEX_TRUST_EXPIRY = 3; + static final int INDEX_UNIFIED_HAS_ANY_SECRET = 4; + static final int INDEX_VERIFIED = 5; + + public Loader onCreateLoader(int id, Bundle args) { + setContentShown(false); + + switch (id) { + case LOADER_ID_DATABASE: { + Uri baseUri = KeyRings.buildUnifiedKeyRingUri(mDataUri); + return new CursorLoader(getActivity(), baseUri, TRUST_PROJECTION, null, null, null); + } + // decided to just use an AsyncTask for keybase, but maybe later + default: + return null; + } + } + + public void onLoadFinished(Loader loader, Cursor data) { + /* TODO better error handling? May cause problems when a key is deleted, + * because the notification triggers faster than the activity closes. + */ + // Avoid NullPointerExceptions... + if (data.getCount() == 0) { + return; + } + + boolean nothingSpecial = true; + StringBuilder message = new StringBuilder(); + + // Swap the new cursor in. (The framework will take care of closing the + // old cursor once we return.) + if (data.moveToFirst()) { + + if (data.getInt(INDEX_UNIFIED_HAS_ANY_SECRET) != 0) { + message.append(getString(R.string.key_trust_it_is_yours)).append("\n"); + nothingSpecial = false; + } else if (data.getInt(INDEX_VERIFIED) != 0) { + message.append(getString(R.string.key_trust_already_verified)).append("\n"); + nothingSpecial = false; + } + + // If this key is revoked, don’t trust it! + if (data.getInt(INDEX_TRUST_IS_REVOKED) != 0) { + message.append(getString(R.string.key_trust_revoked)). + append(getString(R.string.key_trust_old_keys)); + + nothingSpecial = false; + } else { + Date expiryDate = new Date(data.getLong(INDEX_TRUST_EXPIRY) * 1000); + if (!data.isNull(INDEX_TRUST_EXPIRY) && expiryDate.before(new Date())) { + + // if expired, don’t trust it! + message.append(getString(R.string.key_trust_expired)). + append(getString(R.string.key_trust_old_keys)); + + nothingSpecial = false; + } + } + + if (nothingSpecial) { + message.append(getString(R.string.key_trust_maybe)); + } + + final byte[] fp = data.getBlob(INDEX_TRUST_FINGERPRINT); + final String fingerprint = KeyFormattingUtils.convertFingerprintToHex(fp); + if (fingerprint != null) { + + mStartSearch.setEnabled(true); + mStartSearch.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + new DescribeKey().execute(fingerprint); + } + }); + } + } + + mTrustReadout.setText(message); + setContentShown(true); + } + + /** + * This is called when the last Cursor provided to onLoadFinished() above is about to be closed. + * We need to make sure we are no longer using it. + */ + public void onLoaderReset(Loader loader) { + // no-op in this case I think + } + + class ResultPage { + String mHeader; + final List mProofs; + + public ResultPage(String header, List proofs) { + mHeader = header; + mProofs = proofs; + } + } + + // look for evidence from keybase in the background, make tabular version of result + // + private class DescribeKey extends AsyncTask { + + @Override + protected ResultPage doInBackground(String... args) { + String fingerprint = args[0]; + + final ArrayList proofList = new ArrayList(); + final Hashtable> proofs = new Hashtable>(); + try { + User keybaseUser = User.findByFingerprint(fingerprint); + for (Proof proof : keybaseUser.getProofs()) { + Integer proofType = proof.getType(); + appendIfOK(proofs, proofType, proof); + } + + // a one-liner in a modern programming language + for (Integer proofType : proofs.keySet()) { + Proof[] x = {}; + Proof[] proofsFor = proofs.get(proofType).toArray(x); + if (proofsFor.length > 0) { + SpannableStringBuilder ssb = new SpannableStringBuilder(); + ssb.append(getProofNarrative(proofType)).append(" "); + + int i = 0; + while (i < proofsFor.length - 1) { + appendProofLinks(ssb, fingerprint, proofsFor[i]); + ssb.append(", "); + i++; + } + appendProofLinks(ssb, fingerprint, proofsFor[i]); + proofList.add(ssb); + } + } + + } catch (KeybaseException ignored) { + } + + return new ResultPage(getString(R.string.key_trust_results_prefix), proofList); + } + + private SpannableStringBuilder appendProofLinks(SpannableStringBuilder ssb, final String fingerprint, final Proof proof) throws KeybaseException { + int startAt = ssb.length(); + String handle = proof.getHandle(); + ssb.append(handle); + ssb.setSpan(new URLSpan(proof.getServiceUrl()), startAt, startAt + handle.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + if (haveProofFor(proof.getType())) { + ssb.append("\u00a0["); + startAt = ssb.length(); + ssb.append("Verify"); + ClickableSpan clicker = new ClickableSpan() { + @Override + public void onClick(View view) { + verify(proof, fingerprint); + } + }; + ssb.setSpan(clicker, startAt, startAt + "Verify".length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + ssb.append("]"); + } + return ssb; + } + + @Override + protected void onPostExecute(ResultPage result) { + super.onPostExecute(result); + if (result.mHeader == null) { + result.mHeader = getActivity().getString(R.string.key_trust_no_cloud_evidence); + } + + mStartSearch.setVisibility(View.GONE); + mReportHeader.setVisibility(View.VISIBLE); + mProofListing.setVisibility(View.VISIBLE); + mReportHeader.setText(result.mHeader); + + int rowNumber = 1; + for (CharSequence s : result.mProofs) { + TableRow row = (TableRow) mInflater.inflate(R.layout.view_key_keybase_proof, null); + TextView number = (TextView) row.findViewById(R.id.proof_number); + TextView text = (TextView) row.findViewById(R.id.proof_text); + number.setText(Integer.toString(rowNumber++) + ". "); + text.setText(s); + text.setMovementMethod(LinkMovementMethod.getInstance()); + mProofListing.addView(row); + } + + // mSearchReport.loadDataWithBaseURL("file:///android_res/drawable/", s, "text/html", "UTF-8", null); + } + } + + private String getProofNarrative(int proofType) { + int stringIndex; + switch (proofType) { + case Proof.PROOF_TYPE_TWITTER: stringIndex = R.string.keybase_narrative_twitter; break; + case Proof.PROOF_TYPE_GITHUB: stringIndex = R.string.keybase_narrative_github; break; + case Proof.PROOF_TYPE_DNS: stringIndex = R.string.keybase_narrative_dns; break; + case Proof.PROOF_TYPE_WEB_SITE: stringIndex = R.string.keybase_narrative_web_site; break; + case Proof.PROOF_TYPE_HACKERNEWS: stringIndex = R.string.keybase_narrative_hackernews; break; + case Proof.PROOF_TYPE_COINBASE: stringIndex = R.string.keybase_narrative_coinbase; break; + case Proof.PROOF_TYPE_REDDIT: stringIndex = R.string.keybase_narrative_reddit; break; + default: stringIndex = R.string.keybase_narrative_unknown; + } + return getActivity().getString(stringIndex); + } + + private void appendIfOK(Hashtable> table, Integer proofType, Proof proof) throws KeybaseException { + if (!proofIsOK(proof)) { + return; + } + ArrayList list = table.get(proofType); + if (list == null) { + list = new ArrayList(); + table.put(proofType, list); + } + list.add(proof); + } + + // We only accept http & https proofs. Maybe whitelist later? + private boolean proofIsOK(Proof proof) throws KeybaseException { + Uri uri = Uri.parse(proof.getServiceUrl()); + String scheme = uri.getScheme(); + return ("https".equalsIgnoreCase(scheme) || "http".equalsIgnoreCase(scheme)); + } + + // which proofs do we have working verifiers for? + private boolean haveProofFor(int proofType) { + switch (proofType) { + case Proof.PROOF_TYPE_TWITTER: return true; + case Proof.PROOF_TYPE_GITHUB: return true; + case Proof.PROOF_TYPE_DNS: return false; + case Proof.PROOF_TYPE_WEB_SITE: return true; + case Proof.PROOF_TYPE_HACKERNEWS: return true; + case Proof.PROOF_TYPE_COINBASE: return false; + case Proof.PROOF_TYPE_REDDIT: return false; + default: return false; + } + } + + private void verify(final Proof proof, final String fingerprint) { + Intent intent = new Intent(getActivity(), KeychainIntentService.class); + Bundle data = new Bundle(); + intent.setAction(KeychainIntentService.ACTION_VERIFY_KEYBASE_PROOF); + + data.putString(KeychainIntentService.KEYBASE_PROOF, proof.toString()); + data.putString(KeychainIntentService.KEYBASE_REQUIRED_FINGERPRINT, fingerprint); + intent.putExtra(KeychainIntentService.EXTRA_DATA, data); + + mProofVerifyDetail.setVisibility(View.GONE); + + // Create a new Messenger for the communication back after proof work is done + // + KeychainIntentServiceHandler handler = new KeychainIntentServiceHandler(getActivity(), + getString(R.string.progress_decrypting), ProgressDialog.STYLE_HORIZONTAL) { + public void handleMessage(Message message) { + // handle messages by standard KeychainIntentServiceHandler first + super.handleMessage(message); + + if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) { + Bundle returnData = message.getData(); + String msg = returnData.getString(KeychainIntentServiceHandler.DATA_MESSAGE); + SpannableStringBuilder ssb = new SpannableStringBuilder(); + + if ((msg != null) && msg.equals("OK")) { + //yay + String serviceUrl, urlLabel, postUrl; + try { + serviceUrl = proof.getServiceUrl(); + if (serviceUrl.startsWith("https://")) { + urlLabel = serviceUrl.substring("https://".length()); + } else if (serviceUrl.startsWith("http://")) { + urlLabel = serviceUrl.substring("http://".length()); + } else { + urlLabel = serviceUrl; + } + postUrl = proof.getHumanUrl(); + + } catch (KeybaseException e) { + throw new RuntimeException(e); + } + ssb.append(getString(R.string.keybase_proof_succeeded)); + StyleSpan bold = new StyleSpan(Typeface.BOLD); + ssb.setSpan(bold, 0, ssb.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + ssb.append("\n\n"); + int length = ssb.length(); + String segment = getString(R.string.keybase_a_post); + ssb.append(segment); + URLSpan postLink = new URLSpan(postUrl); + ssb.setSpan(postLink, length, length + segment.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + ssb.append(" ").append(getString(R.string.keybase_fetched_from)).append(" "); + URLSpan serviceLink = new URLSpan(serviceUrl); + length = ssb.length(); + ssb.append(urlLabel); + ssb.setSpan(serviceLink, length, length + urlLabel.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + ssb.append(" ").append(getString(R.string.keybase_contained_signature)); + + } else { + msg = returnData.getString(KeychainIntentServiceHandler.DATA_ERROR); + ssb.append(getString(R.string.keybase_proof_failure)); + if (msg == null) { + msg = getString(R.string.keybase_unknown_proof_failure); + StyleSpan bold = new StyleSpan(Typeface.BOLD); + ssb.setSpan(bold, 0, ssb.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + ssb.append("\n\n").append(msg); + } + } + mProofVerifyHeader.setVisibility(View.VISIBLE); + mProofVerifyDetail.setVisibility(View.VISIBLE); + mProofVerifyDetail.setText(ssb); + } + } + }; + + // Create a new Messenger for the communication back + Messenger messenger = new Messenger(handler); + intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger); + + // show progress dialog + handler.showProgressDialog(getActivity()); + + // start service with intent + getActivity().startService(intent); + } +} -- cgit v1.2.3 From 3c19e6cfc12f6b24cf202aaaf9ad3e14223161d3 Mon Sep 17 00:00:00 2001 From: Tim Bray Date: Fri, 7 Nov 2014 21:07:10 -0800 Subject: Fix a no-result corner case, and make verifications clickable --- .../java/org/sufficientlysecure/keychain/ui/ViewKeyTrustFragment.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyTrustFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyTrustFragment.java index ef6cd50f1..540dcc0b1 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyTrustFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyTrustFragment.java @@ -284,7 +284,7 @@ public class ViewKeyTrustFragment extends LoaderFragment implements @Override protected void onPostExecute(ResultPage result) { super.onPostExecute(result); - if (result.mHeader == null) { + if (result.mProofs.isEmpty()) { result.mHeader = getActivity().getString(R.string.key_trust_no_cloud_evidence); } @@ -425,6 +425,7 @@ public class ViewKeyTrustFragment extends LoaderFragment implements } mProofVerifyHeader.setVisibility(View.VISIBLE); mProofVerifyDetail.setVisibility(View.VISIBLE); + mProofVerifyDetail.setMovementMethod(LinkMovementMethod.getInstance()); mProofVerifyDetail.setText(ssb); } } -- cgit v1.2.3 From 36bac67dd5f19b72a58584f2fab104e6e26df66a Mon Sep 17 00:00:00 2001 From: Tim Bray Date: Tue, 11 Nov 2014 18:45:36 -0800 Subject: All keybase proofs now in place --- .../keychain/service/KeychainIntentService.java | 38 +++++++-- .../service/KeychainIntentServiceHandler.java | 5 ++ .../keychain/ui/ViewKeyTrustFragment.java | 90 ++++++++++++---------- 3 files changed, 89 insertions(+), 44 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java index 42e0c7cc9..8a670df25 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -84,6 +84,12 @@ import java.util.Iterator; import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; +import de.measite.minidns.Client; +import de.measite.minidns.Question; +import de.measite.minidns.Record; +import de.measite.minidns.record.Data; +import de.measite.minidns.record.TXT; + /** * This Service contains all important long lasting operations for APG. It receives Intents with * data from the activities or other apps, queues these intents, executes them, and stops itself @@ -124,6 +130,7 @@ public class KeychainIntentService extends IntentService implements Progressable // encrypt, decrypt, import export public static final String TARGET = "target"; public static final String SOURCE = "source"; + // possible targets: public static final int IO_BYTES = 1; public static final int IO_URI = 2; @@ -321,12 +328,27 @@ public class KeychainIntentService extends IntentService implements Progressable return; } + String domain = prover.dnsTxtCheckRequired(); + if (domain != null) { + Record[] records = new Client().query(new Question(domain, Record.TYPE.TXT)).getAnswers(); + List> extents = new ArrayList>(); + for (Record r : records) { + Data d = r.getPayload(); + if (d instanceof TXT) { + extents.add(((TXT) d).getExtents()); + } + } + if (!prover.checkDnsTxt(extents)) { + sendProofError(prover.getLog(), null); + return; + } + } + byte[] messageBytes = prover.getPgpMessage().getBytes(); if (prover.rawMessageCheckRequired()) { InputStream messageByteStream = PGPUtil.getDecoderStream(new ByteArrayInputStream(messageBytes)); - String problem = prover.checkRawMessageBytes(messageByteStream); - if (problem != null) { - sendProofError(prover.getLog(), problem); + if (!prover.checkRawMessageBytes(messageByteStream)) { + sendProofError(prover.getLog(), null); return; } } @@ -365,6 +387,11 @@ public class KeychainIntentService extends IntentService implements Progressable Bundle resultData = new Bundle(); resultData.putString(KeychainIntentServiceHandler.DATA_MESSAGE, "OK"); + + // these help the handler construct a useful human-readable message + resultData.putString(KeychainIntentServiceHandler.KEYBASE_PROOF_URL, prover.getProofUrl()); + resultData.putString(KeychainIntentServiceHandler.KEYBASE_PRESENCE_URL, prover.getPresenceUrl()); + resultData.putString(KeychainIntentServiceHandler.KEYBASE_PRESENCE_LABEL, prover.getPresenceLabel()); sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, resultData); } catch (Exception e) { sendErrorToHandler(e); @@ -678,11 +705,12 @@ public class KeychainIntentService extends IntentService implements Progressable private void sendProofError(List log, String label) { String msg = null; + label = (label == null) ? "" : label + ": "; for (String m : log) { - Log.e(Constants.TAG, label + ": " + m); + Log.e(Constants.TAG, label + m); msg = m; } - sendProofError(label + ": " + msg); + sendProofError(label + msg); } private void sendProofError(String msg) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java index 180020d0b..fc65757f5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java @@ -45,6 +45,11 @@ public class KeychainIntentServiceHandler extends Handler { public static final String DATA_MESSAGE = "message"; public static final String DATA_MESSAGE_ID = "message_id"; + // keybase proof specific + public static final String KEYBASE_PROOF_URL = "keybase_proof_url"; + public static final String KEYBASE_PRESENCE_URL = "keybase_presence_url"; + public static final String KEYBASE_PRESENCE_LABEL = "keybase_presence_label"; + Activity mActivity; ProgressDialogFragment mProgressDialogFragment; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyTrustFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyTrustFragment.java index 540dcc0b1..4965b2525 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyTrustFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyTrustFragment.java @@ -324,9 +324,6 @@ public class ViewKeyTrustFragment extends LoaderFragment implements } private void appendIfOK(Hashtable> table, Integer proofType, Proof proof) throws KeybaseException { - if (!proofIsOK(proof)) { - return; - } ArrayList list = table.get(proofType); if (list == null) { list = new ArrayList(); @@ -335,23 +332,16 @@ public class ViewKeyTrustFragment extends LoaderFragment implements list.add(proof); } - // We only accept http & https proofs. Maybe whitelist later? - private boolean proofIsOK(Proof proof) throws KeybaseException { - Uri uri = Uri.parse(proof.getServiceUrl()); - String scheme = uri.getScheme(); - return ("https".equalsIgnoreCase(scheme) || "http".equalsIgnoreCase(scheme)); - } - // which proofs do we have working verifiers for? private boolean haveProofFor(int proofType) { switch (proofType) { case Proof.PROOF_TYPE_TWITTER: return true; case Proof.PROOF_TYPE_GITHUB: return true; - case Proof.PROOF_TYPE_DNS: return false; + case Proof.PROOF_TYPE_DNS: return true; case Proof.PROOF_TYPE_WEB_SITE: return true; case Proof.PROOF_TYPE_HACKERNEWS: return true; - case Proof.PROOF_TYPE_COINBASE: return false; - case Proof.PROOF_TYPE_REDDIT: return false; + case Proof.PROOF_TYPE_COINBASE: return true; + case Proof.PROOF_TYPE_REDDIT: return true; default: return false; } } @@ -381,47 +371,69 @@ public class ViewKeyTrustFragment extends LoaderFragment implements SpannableStringBuilder ssb = new SpannableStringBuilder(); if ((msg != null) && msg.equals("OK")) { + //yay - String serviceUrl, urlLabel, postUrl; - try { - serviceUrl = proof.getServiceUrl(); - if (serviceUrl.startsWith("https://")) { - urlLabel = serviceUrl.substring("https://".length()); - } else if (serviceUrl.startsWith("http://")) { - urlLabel = serviceUrl.substring("http://".length()); - } else { - urlLabel = serviceUrl; - } - postUrl = proof.getHumanUrl(); - - } catch (KeybaseException e) { - throw new RuntimeException(e); + String proofUrl = returnData.getString(KeychainIntentServiceHandler.KEYBASE_PROOF_URL); + String presenceUrl = returnData.getString(KeychainIntentServiceHandler.KEYBASE_PRESENCE_URL); + String presenceLabel = returnData.getString(KeychainIntentServiceHandler.KEYBASE_PRESENCE_LABEL); + + String proofLabel; + switch (proof.getType()) { + case Proof.PROOF_TYPE_TWITTER: + proofLabel = getString(R.string.keybase_twitter_proof); + break; + case Proof.PROOF_TYPE_DNS: + proofLabel = getString(R.string.keybase_dns_proof); + break; + case Proof.PROOF_TYPE_WEB_SITE: + proofLabel = getString(R.string.keybase_web_site_proof); + break; + case Proof.PROOF_TYPE_GITHUB: + proofLabel = getString(R.string.keybase_github_proof); + break; + case Proof.PROOF_TYPE_REDDIT: + proofLabel = getString(R.string.keybase_reddit_proof); + break; + default: + proofLabel = getString(R.string.keybase_a_post); + break; } + ssb.append(getString(R.string.keybase_proof_succeeded)); StyleSpan bold = new StyleSpan(Typeface.BOLD); ssb.setSpan(bold, 0, ssb.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); ssb.append("\n\n"); int length = ssb.length(); - String segment = getString(R.string.keybase_a_post); - ssb.append(segment); - URLSpan postLink = new URLSpan(postUrl); - ssb.setSpan(postLink, length, length + segment.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - ssb.append(" ").append(getString(R.string.keybase_fetched_from)).append(" "); - URLSpan serviceLink = new URLSpan(serviceUrl); + ssb.append(proofLabel); + if (proofUrl != null) { + URLSpan postLink = new URLSpan(proofUrl); + ssb.setSpan(postLink, length, length + proofLabel.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } + if (Proof.PROOF_TYPE_DNS == proof.getType()) { + ssb.append(" ").append(getString(R.string.keybase_for_the_domain)).append(" "); + } else { + ssb.append(" ").append(getString(R.string.keybase_fetched_from)).append(" "); + } length = ssb.length(); - ssb.append(urlLabel); - ssb.setSpan(serviceLink, length, length + urlLabel.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + URLSpan presenceLink = new URLSpan(presenceUrl); + ssb.append(presenceLabel); + ssb.setSpan(presenceLink, length, length + presenceLabel.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + if (Proof.PROOF_TYPE_REDDIT == proof.getType()) { + ssb.append(", "). + append(getString(R.string.keybase_reddit_attribution)). + append(" “").append(proof.getHandle()).append("”, "); + } ssb.append(" ").append(getString(R.string.keybase_contained_signature)); - } else { + // verification failed! msg = returnData.getString(KeychainIntentServiceHandler.DATA_ERROR); ssb.append(getString(R.string.keybase_proof_failure)); if (msg == null) { msg = getString(R.string.keybase_unknown_proof_failure); - StyleSpan bold = new StyleSpan(Typeface.BOLD); - ssb.setSpan(bold, 0, ssb.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - ssb.append("\n\n").append(msg); } + StyleSpan bold = new StyleSpan(Typeface.BOLD); + ssb.setSpan(bold, 0, ssb.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + ssb.append("\n\n").append(msg); } mProofVerifyHeader.setVisibility(View.VISIBLE); mProofVerifyDetail.setVisibility(View.VISIBLE); -- cgit v1.2.3 From 0f59e6bd950087d99a0909e55276e649639bb51b Mon Sep 17 00:00:00 2001 From: Tim Bray Date: Tue, 18 Nov 2014 22:12:50 -0800 Subject: In the ImportKeysList display, arrange for Keybase UserIDs to sort below the rest. Also mention Keybase stuff other than Twitter/GitHub/Website --- .../keychain/ui/ViewKeyTrustFragment.java | 5 +++-- .../keychain/ui/adapter/ImportKeysAdapter.java | 18 +++++++++++++++++- 2 files changed, 20 insertions(+), 3 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyTrustFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyTrustFragment.java index 4965b2525..ef14299b1 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyTrustFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyTrustFragment.java @@ -268,14 +268,15 @@ public class ViewKeyTrustFragment extends LoaderFragment implements if (haveProofFor(proof.getType())) { ssb.append("\u00a0["); startAt = ssb.length(); - ssb.append("Verify"); + String verify = getString(R.string.keybase_verify); + ssb.append(verify); ClickableSpan clicker = new ClickableSpan() { @Override public void onClick(View view) { verify(proof, fingerprint); } }; - ssb.setSpan(clicker, startAt, startAt + "Verify".length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + ssb.setSpan(clicker, startAt, startAt + verify.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); ssb.append("]"); } return ssb; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java index 6c81e9193..f3dce5823 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java @@ -213,8 +213,24 @@ public class ImportKeysAdapter extends ArrayAdapter { // destroyLoader view from holder holder.userIdsList.removeAllViews(); + // we want conventional gpg UserIDs first, then Keybase ”proofs” HashMap> mergedUserIds = entry.getMergedUserIds(); - for (Map.Entry> pair : mergedUserIds.entrySet()) { + ArrayList>> sortedIds = new ArrayList>>(mergedUserIds.entrySet()); + java.util.Collections.sort(sortedIds, new java.util.Comparator>>() { + @Override + public int compare(Map.Entry> entry1, Map.Entry> entry2) { + + // sort keybase UserIds after non-Keybase + boolean e1IsKeybase = entry1.getKey().contains(":"); + boolean e2IsKeybase = entry2.getKey().contains(":"); + if (e1IsKeybase != e2IsKeybase) { + return (e1IsKeybase) ? 1 : -1; + } + return entry1.getKey().compareTo(entry2.getKey()); + } + }); + + for (Map.Entry> pair : sortedIds) { String cUserId = pair.getKey(); HashSet cEmails = pair.getValue(); -- cgit v1.2.3 From b5cdeb7f5a54be7443894ca2cb4bd27359fae9ce Mon Sep 17 00:00:00 2001 From: Tim Bray Date: Wed, 19 Nov 2014 14:35:05 -0800 Subject: Prevent multiple cloud-trust-search launches. Handle DNS query failure gracefully. Fixes #1007 & #1008. --- .../keychain/service/KeychainIntentService.java | 8 +++++++- .../org/sufficientlysecure/keychain/ui/ViewKeyTrustFragment.java | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java index 8a670df25..954963fb6 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -85,6 +85,7 @@ import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; import de.measite.minidns.Client; +import de.measite.minidns.DNSMessage; import de.measite.minidns.Question; import de.measite.minidns.Record; import de.measite.minidns.record.Data; @@ -330,7 +331,12 @@ public class KeychainIntentService extends IntentService implements Progressable String domain = prover.dnsTxtCheckRequired(); if (domain != null) { - Record[] records = new Client().query(new Question(domain, Record.TYPE.TXT)).getAnswers(); + DNSMessage dnsQuery = new Client().query(new Question(domain, Record.TYPE.TXT)); + if (dnsQuery == null) { + sendProofError(prover.getLog(), getString(R.string.keybase_dns_query_failure)); + return; + } + Record[] records = dnsQuery.getAnswers(); List> extents = new ArrayList>(); for (Record r : records) { Data d = r.getPayload(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyTrustFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyTrustFragment.java index ef14299b1..c85571493 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyTrustFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyTrustFragment.java @@ -190,6 +190,7 @@ public class ViewKeyTrustFragment extends LoaderFragment implements mStartSearch.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { + mStartSearch.setEnabled(false); new DescribeKey().execute(fingerprint); } }); -- cgit v1.2.3 From fd60d49d262a7920279a0f87060c7084069165e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Sat, 22 Nov 2014 00:10:15 +0100 Subject: Use master key id for keybase proof verification --- .../sufficientlysecure/keychain/pgp/PgpDecryptVerify.java | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java index 4161f2928..b094208a5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java @@ -274,17 +274,11 @@ public class PgpDecryptVerify extends BaseOperation { return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log); } - CanonicalizedPublicKey encryptKey = signingKey; - try { - encryptKey = signingRing.getEncryptionSubKey(); - } catch (PgpKeyNotFoundException e) { - } - String fingerprint = KeyFormattingUtils.convertFingerprintToHex(signingKey.getFingerprint()); - String cryptFingerprint = KeyFormattingUtils.convertFingerprintToHex(encryptKey.getFingerprint()); - if (!(mRequiredSignerFingerprint.equals(fingerprint) || mRequiredSignerFingerprint.equals(cryptFingerprint))) { + String fingerprint = KeyFormattingUtils.convertFingerprintToHex(signingRing.getFingerprint()); + if (!(mRequiredSignerFingerprint.equals(fingerprint))) { log.add(LogType.MSG_VL_ERROR_MISSING_KEY, indent); - Log.d(Constants.TAG, "Key mismatch; wanted " + mRequiredSignerFingerprint + - " got " + fingerprint + "/" + cryptFingerprint); + Log.d(Constants.TAG, "Fingerprint mismatch; wanted " + mRequiredSignerFingerprint + + " got " + fingerprint + "!"); return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log); } -- cgit v1.2.3 From bbbc45e4e9909806a91afe415265b507533f7556 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Sat, 22 Nov 2014 00:29:14 +0100 Subject: Dont accept signatures by expired or revoked subkeys --- .../keychain/pgp/OpenPgpSignatureResultBuilder.java | 4 ---- .../sufficientlysecure/keychain/pgp/PgpDecryptVerify.java | 15 +++++++++++---- .../keychain/service/KeychainIntentService.java | 1 + .../keychain/ui/ViewKeyTrustFragment.java | 2 +- 4 files changed, 13 insertions(+), 9 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/OpenPgpSignatureResultBuilder.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/OpenPgpSignatureResultBuilder.java index aa324c7ed..fc5064e79 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/OpenPgpSignatureResultBuilder.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/OpenPgpSignatureResultBuilder.java @@ -84,10 +84,6 @@ public class OpenPgpSignatureResultBuilder { this.mUserIds = userIds; } - public boolean isValidSignature() { - return mValidSignature; - } - public void initValid(CanonicalizedPublicKeyRing signingRing, CanonicalizedPublicKey signingKey) { setSignatureAvailable(true); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java index b094208a5..ea9e165ba 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java @@ -22,6 +22,7 @@ import android.content.Context; import android.webkit.MimeTypeMap; import org.openintents.openpgp.OpenPgpMetadata; +import org.openintents.openpgp.OpenPgpSignatureResult; import org.spongycastle.bcpg.ArmoredInputStream; import org.spongycastle.openpgp.PGPCompressedData; import org.spongycastle.openpgp.PGPEncryptedData; @@ -332,7 +333,10 @@ public class PgpDecryptVerify extends BaseOperation { } signatureResultBuilder.setValidSignature(validSignature); - if (!signatureResultBuilder.isValidSignature()) { + OpenPgpSignatureResult signatureResult = signatureResultBuilder.build(); + + if (signatureResult.getStatus() != OpenPgpSignatureResult.SIGNATURE_SUCCESS_CERTIFIED + || signatureResult.getStatus() != OpenPgpSignatureResult.SIGNATURE_SUCCESS_UNCERTIFIED) { log.add(LogType.MSG_VL_ERROR_INTEGRITY_CHECK, indent); return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log); } @@ -344,7 +348,7 @@ public class PgpDecryptVerify extends BaseOperation { // Return a positive result, with metadata and verification info DecryptVerifyResult result = new DecryptVerifyResult(DecryptVerifyResult.RESULT_OK, log); - result.setSignatureResult(signatureResultBuilder.build()); + result.setSignatureResult(signatureResult); return result; } @@ -773,6 +777,8 @@ public class PgpDecryptVerify extends BaseOperation { metadata = null; } + OpenPgpSignatureResult signatureResult = signatureResultBuilder.build(); + if (encryptedData.isIntegrityProtected()) { updateProgress(R.string.progress_verifying_integrity, 95, 100); @@ -786,7 +792,8 @@ public class PgpDecryptVerify extends BaseOperation { // If no valid signature is present: // Handle missing integrity protection like failed integrity protection! // The MDC packet can be stripped by an attacker! - if (!signatureResultBuilder.isValidSignature()) { + if (signatureResult.getStatus() != OpenPgpSignatureResult.SIGNATURE_SUCCESS_CERTIFIED + || signatureResult.getStatus() != OpenPgpSignatureResult.SIGNATURE_SUCCESS_UNCERTIFIED) { log.add(LogType.MSG_DC_ERROR_INTEGRITY_CHECK, indent); return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log); } @@ -800,7 +807,7 @@ public class PgpDecryptVerify extends BaseOperation { DecryptVerifyResult result = new DecryptVerifyResult(DecryptVerifyResult.RESULT_OK, log); result.setDecryptMetadata(metadata); - result.setSignatureResult(signatureResultBuilder.build()); + result.setSignatureResult(signatureResult); return result; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java index 92c64a4e1..a4a3a801a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -30,6 +30,7 @@ import com.textuality.keybase.lib.Proof; import com.textuality.keybase.lib.prover.Prover; import org.json.JSONObject; +import org.openintents.openpgp.OpenPgpSignatureResult; import org.spongycastle.openpgp.PGPUtil; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyTrustFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyTrustFragment.java index c85571493..677646441 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyTrustFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyTrustFragment.java @@ -362,7 +362,7 @@ public class ViewKeyTrustFragment extends LoaderFragment implements // Create a new Messenger for the communication back after proof work is done // KeychainIntentServiceHandler handler = new KeychainIntentServiceHandler(getActivity(), - getString(R.string.progress_decrypting), ProgressDialog.STYLE_HORIZONTAL) { + getString(R.string.progress_verifying_signature), ProgressDialog.STYLE_HORIZONTAL) { public void handleMessage(Message message) { // handle messages by standard KeychainIntentServiceHandler first super.handleMessage(message); -- cgit v1.2.3 From 9c133d343fbc297ed6f3ee39b74cea5dfcc9c207 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Sat, 22 Nov 2014 02:55:42 +0100 Subject: fix signature check --- .../java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java index ea9e165ba..5589a3521 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java @@ -336,7 +336,7 @@ public class PgpDecryptVerify extends BaseOperation { OpenPgpSignatureResult signatureResult = signatureResultBuilder.build(); if (signatureResult.getStatus() != OpenPgpSignatureResult.SIGNATURE_SUCCESS_CERTIFIED - || signatureResult.getStatus() != OpenPgpSignatureResult.SIGNATURE_SUCCESS_UNCERTIFIED) { + && signatureResult.getStatus() != OpenPgpSignatureResult.SIGNATURE_SUCCESS_UNCERTIFIED) { log.add(LogType.MSG_VL_ERROR_INTEGRITY_CHECK, indent); return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log); } @@ -793,7 +793,7 @@ public class PgpDecryptVerify extends BaseOperation { // Handle missing integrity protection like failed integrity protection! // The MDC packet can be stripped by an attacker! if (signatureResult.getStatus() != OpenPgpSignatureResult.SIGNATURE_SUCCESS_CERTIFIED - || signatureResult.getStatus() != OpenPgpSignatureResult.SIGNATURE_SUCCESS_UNCERTIFIED) { + && signatureResult.getStatus() != OpenPgpSignatureResult.SIGNATURE_SUCCESS_UNCERTIFIED) { log.add(LogType.MSG_DC_ERROR_INTEGRITY_CHECK, indent); return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log); } -- cgit v1.2.3 From e72c082acd9f17be4a21970603df0f6a621221d7 Mon Sep 17 00:00:00 2001 From: Tim Bray Date: Fri, 21 Nov 2014 19:44:05 -0800 Subject: Add check that proof & database fingerprints are the same --- .../org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java | 3 ++- .../keychain/service/KeychainIntentService.java | 9 ++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java index ea9e165ba..5a8bfda29 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java @@ -336,7 +336,8 @@ public class PgpDecryptVerify extends BaseOperation { OpenPgpSignatureResult signatureResult = signatureResultBuilder.build(); if (signatureResult.getStatus() != OpenPgpSignatureResult.SIGNATURE_SUCCESS_CERTIFIED - || signatureResult.getStatus() != OpenPgpSignatureResult.SIGNATURE_SUCCESS_UNCERTIFIED) { + && signatureResult.getStatus() != OpenPgpSignatureResult.SIGNATURE_SUCCESS_UNCERTIFIED) { + Log.d(Constants.TAG, "STATUS IS " + signatureResult.getStatus()); log.add(LogType.MSG_VL_ERROR_INTEGRITY_CHECK, indent); return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java index a4a3a801a..dc9592710 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -30,7 +30,6 @@ import com.textuality.keybase.lib.Proof; import com.textuality.keybase.lib.prover.Prover; import org.json.JSONObject; -import org.openintents.openpgp.OpenPgpSignatureResult; import org.spongycastle.openpgp.PGPUtil; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; @@ -324,6 +323,11 @@ public class KeychainIntentService extends IntentService implements Progressable sendProofError(prover.getLog(), getString(R.string.keybase_problem_fetching_evidence)); return; } + String requiredFingerprint = data.getString(KEYBASE_REQUIRED_FINGERPRINT); + if (!prover.checkFingerprint(requiredFingerprint)) { + sendProofError(getString(R.string.keybase_key_mismatch)); + return; + } String domain = prover.dnsTxtCheckRequired(); if (domain != null) { @@ -361,13 +365,12 @@ public class KeychainIntentService extends IntentService implements Progressable InputData inputData = createDecryptInputData(data); OutputStream outStream = createCryptOutputStream(data); - String fingerprint = data.getString(KEYBASE_REQUIRED_FINGERPRINT); PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder( this, new ProviderHelper(this), this, inputData, outStream ); - builder.setSignedLiteralData(true).setRequiredSignerFingerprint(fingerprint); + builder.setSignedLiteralData(true).setRequiredSignerFingerprint(requiredFingerprint); DecryptVerifyResult decryptVerifyResult = builder.build().execute(); outStream.close(); -- cgit v1.2.3 From 1c4b8c193d35f2226d621aa448e6775ff49fa2c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Thu, 8 Jan 2015 14:48:13 +0100 Subject: Experimental API support for detached signatures (not tested) --- .../operations/results/SignEncryptResult.java | 16 ++++ .../keychain/pgp/CanonicalizedSecretKey.java | 2 +- .../keychain/pgp/PgpSignEncrypt.java | 94 +++++++++++++++++----- .../keychain/remote/OpenPgpService.java | 47 ++++++----- .../keychain/service/KeychainIntentService.java | 3 +- 5 files changed, 118 insertions(+), 44 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/SignEncryptResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/SignEncryptResult.java index 57daf3430..c336f8502 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/SignEncryptResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/SignEncryptResult.java @@ -37,6 +37,7 @@ public class SignEncryptResult extends OperationResult { int mNfcAlgo; Date mNfcTimestamp; String mNfcPassphrase; + byte[] mDetachedSignature; public long getKeyIdPassphraseNeeded() { return mKeyIdPassphraseNeeded; @@ -54,6 +55,10 @@ public class SignEncryptResult extends OperationResult { mNfcPassphrase = passphrase; } + public void setDetachedSignature(byte[] detachedSignature) { + mDetachedSignature = detachedSignature; + } + public long getNfcKeyId() { return mNfcKeyId; } @@ -74,6 +79,10 @@ public class SignEncryptResult extends OperationResult { return mNfcPassphrase; } + public byte[] getDetachedSignature() { + return mDetachedSignature; + } + public boolean isPending() { return (mResult & RESULT_PENDING) == RESULT_PENDING; } @@ -87,6 +96,7 @@ public class SignEncryptResult extends OperationResult { mNfcHash = source.readInt() != 0 ? source.createByteArray() : null; mNfcAlgo = source.readInt(); mNfcTimestamp = source.readInt() != 0 ? new Date(source.readLong()) : null; + mDetachedSignature = source.readInt() != 0 ? source.createByteArray() : null; } public int describeContents() { @@ -108,6 +118,12 @@ public class SignEncryptResult extends OperationResult { } else { dest.writeInt(0); } + if (mDetachedSignature != null) { + dest.writeInt(1); + dest.writeByteArray(mDetachedSignature); + } else { + dest.writeInt(0); + } } public static final Creator CREATOR = new Creator() { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java index 6ccadac2e..cffb09420 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java @@ -247,7 +247,7 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey { int signatureType; if (cleartext) { - // for sign-only ascii text + // for sign-only ascii text (cleartext signature) signatureType = PGPSignature.CANONICAL_TEXT_DOCUMENT; } else { signatureType = PGPSignature.BINARY_DOCUMENT; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java index 3c3bcc890..5151667ed 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java @@ -50,6 +50,7 @@ import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.ProgressScaler; import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -78,7 +79,8 @@ public class PgpSignEncrypt extends BaseOperation { private int mSignatureHashAlgorithm; private String mSignaturePassphrase; private long mAdditionalEncryptId; - private boolean mCleartextInput; + private boolean mCleartextSignature; + private boolean mDetachedSignature; private String mOriginalFilename; private boolean mFailOnMissingEncryptionKeyIds; @@ -113,7 +115,8 @@ public class PgpSignEncrypt extends BaseOperation { this.mSignatureHashAlgorithm = builder.mSignatureHashAlgorithm; this.mSignaturePassphrase = builder.mSignaturePassphrase; this.mAdditionalEncryptId = builder.mAdditionalEncryptId; - this.mCleartextInput = builder.mCleartextInput; + this.mCleartextSignature = builder.mCleartextSignature; + this.mDetachedSignature = builder.mDetachedSignature; this.mNfcSignedHash = builder.mNfcSignedHash; this.mNfcCreationTimestamp = builder.mNfcCreationTimestamp; this.mOriginalFilename = builder.mOriginalFilename; @@ -140,7 +143,8 @@ public class PgpSignEncrypt extends BaseOperation { private int mSignatureHashAlgorithm = 0; private String mSignaturePassphrase = null; private long mAdditionalEncryptId = Constants.key.none; - private boolean mCleartextInput = false; + private boolean mCleartextSignature = false; + private boolean mDetachedSignature = false; private String mOriginalFilename = ""; private byte[] mNfcSignedHash = null; private Date mNfcCreationTimestamp = null; @@ -222,14 +226,13 @@ public class PgpSignEncrypt extends BaseOperation { return this; } - /** - * TODO: test this option! - * - * @param cleartextInput - * @return - */ - public Builder setCleartextInput(boolean cleartextInput) { - mCleartextInput = cleartextInput; + public Builder setCleartextSignature(boolean cleartextSignature) { + mCleartextSignature = cleartextSignature; + return this; + } + + public Builder setDetachedSignature(boolean detachedSignature) { + mDetachedSignature = detachedSignature; return this; } @@ -408,7 +411,7 @@ public class PgpSignEncrypt extends BaseOperation { updateProgress(R.string.progress_preparing_signature, 4, 100); try { - boolean cleartext = mCleartextInput && mEnableAsciiArmorOutput && !enableEncryption; + boolean cleartext = mCleartextSignature && mEnableAsciiArmorOutput && !enableEncryption; signatureGenerator = signingKey.getSignatureGenerator( mSignatureHashAlgorithm, cleartext, mNfcSignedHash, mNfcCreationTimestamp); } catch (PgpGeneralException e) { @@ -424,6 +427,9 @@ public class PgpSignEncrypt extends BaseOperation { OutputStream encryptionOut = null; BCPGOutputStream bcpgOut; + ByteArrayOutputStream detachedByteOut = null; + BCPGOutputStream detachedBcpgOut = null; + try { if (enableEncryption) { @@ -452,7 +458,7 @@ public class PgpSignEncrypt extends BaseOperation { PGPLiteralDataGenerator literalGen = new PGPLiteralDataGenerator(); char literalDataFormatTag; - if (mCleartextInput) { + if (mCleartextSignature) { literalDataFormatTag = PGPLiteralData.UTF8; } else { literalDataFormatTag = PGPLiteralData.BINARY; @@ -482,7 +488,7 @@ public class PgpSignEncrypt extends BaseOperation { literalGen.close(); indent -= 1; - } else if (enableSignature && mCleartextInput && mEnableAsciiArmorOutput) { + } else if (enableSignature && mCleartextSignature && mEnableAsciiArmorOutput) { /* cleartext signature: sign-only of ascii text */ updateProgress(R.string.progress_signing, 8, 100); @@ -517,11 +523,44 @@ public class PgpSignEncrypt extends BaseOperation { armorOut.endClearText(); pOut = new BCPGOutputStream(armorOut); - } else if (enableSignature && !mCleartextInput) { + } else if (enableSignature && mDetachedSignature) { + /* detached signature */ + + updateProgress(R.string.progress_signing, 8, 100); + log.add(LogType.MSG_SE_SIGNING, indent); + + InputStream in = mData.getInputStream(); + + // handle output stream separately for detached signatures + detachedByteOut = new ByteArrayOutputStream(); + OutputStream detachedOut = detachedByteOut; + if (mEnableAsciiArmorOutput) { + detachedOut = new ArmoredOutputStream(detachedOut); + } + detachedBcpgOut = new BCPGOutputStream(detachedOut); + + long alreadyWritten = 0; + int length; + byte[] buffer = new byte[1 << 16]; + while ((length = in.read(buffer)) > 0) { + // pipe input stream directly into output stream, no changes to data + mOutStream.write(buffer, 0, length); + + signatureGenerator.update(buffer, 0, length); + + alreadyWritten += length; + if (mData.getSize() > 0) { + long progress = 100 * alreadyWritten / mData.getSize(); + progressScaler.setProgress((int) progress, 100); + } + } + + pOut = null; + } else if (enableSignature && !mCleartextSignature && !mDetachedSignature) { /* sign-only binary (files/data stream) */ updateProgress(R.string.progress_signing, 8, 100); - log.add(LogType.MSG_SE_ENCRYPTING, indent); + log.add(LogType.MSG_SE_SIGNING, indent); InputStream in = mData.getInputStream(); @@ -556,13 +595,18 @@ public class PgpSignEncrypt extends BaseOperation { literalGen.close(); } else { pOut = null; + // TODO: Is this log right? log.add(LogType.MSG_SE_CLEARSIGN_ONLY, indent); } if (enableSignature) { updateProgress(R.string.progress_generating_signature, 95, 100); try { - signatureGenerator.generate().encode(pOut); + if (detachedBcpgOut != null) { + signatureGenerator.generate().encode(detachedBcpgOut); + } else { + signatureGenerator.generate().encode(pOut); + } } catch (NfcSyncPGPContentSignerBuilder.NfcInteractionNeeded e) { // this secret key diverts to a OpenPGP card, throw exception with hash that will be signed log.add(LogType.MSG_SE_PENDING_NFC, indent); @@ -607,10 +651,22 @@ public class PgpSignEncrypt extends BaseOperation { updateProgress(R.string.progress_done, 100, 100); log.add(LogType.MSG_SE_OK, indent); - return new SignEncryptResult(SignEncryptResult.RESULT_OK, log); - + SignEncryptResult result = new SignEncryptResult(SignEncryptResult.RESULT_OK, log); + if (detachedByteOut != null) { + try { + detachedByteOut.flush(); + detachedByteOut.close(); + } catch (IOException e) { + // silently catch + } + result.setDetachedSignature(detachedByteOut.toByteArray()); + } + return result; } + /** + * Remove whitespaces on line endings + */ private static void processLine(final String pLine, final ArmoredOutputStream pArmoredOutput, final PGPSignatureGenerator pSignatureGenerator) throws IOException, SignatureException { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java index a5813567a..478013f55 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java @@ -222,9 +222,10 @@ public class OpenPgpService extends RemoteService { } private Intent signImpl(Intent data, ParcelFileDescriptor input, - ParcelFileDescriptor output, AccountSettings accSettings) { + ParcelFileDescriptor output, AccountSettings accSettings, + boolean cleartextSign) { try { - boolean asciiArmor = data.getBooleanExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true); + boolean asciiArmor = cleartextSign || data.getBooleanExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true); byte[] nfcSignedHash = data.getByteArrayExtra(OpenPgpApi.EXTRA_NFC_SIGNED_HASH); if (nfcSignedHash != null) { @@ -284,6 +285,8 @@ public class OpenPgpService extends RemoteService { inputData, os ); builder.setEnableAsciiArmorOutput(asciiArmor) + .setCleartextSignature(cleartextSign) + .setDetachedSignature(!cleartextSign) .setVersionHeader(PgpHelper.getVersionForHeader(this)) .setSignatureHashAlgorithm(accSettings.getHashAlgorithm()) .setSignatureMasterKeyId(accSettings.getKeyId()) @@ -291,9 +294,6 @@ public class OpenPgpService extends RemoteService { .setSignaturePassphrase(passphrase) .setNfcState(nfcSignedHash, nfcCreationDate); - // TODO: currently always assume cleartext input, no sign-only of binary currently! - builder.setCleartextInput(true); - // execute PGP operation! SignEncryptResult pgpResult = builder.build().execute(); @@ -313,20 +313,20 @@ public class OpenPgpService extends RemoteService { "Encountered unhandled type of pending action not supported by API!"); } } else if (pgpResult.success()) { - // see end of method + Intent result = new Intent(); + if (!cleartextSign) { + result.putExtra(OpenPgpApi.RESULT_DETACHED_SIGNATURE, pgpResult.getDetachedSignature()); + } + result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS); + return result; } else { LogEntryParcel errorMsg = pgpResult.getLog().getLast(); throw new Exception(getString(errorMsg.mType.getMsgId())); } - } finally { is.close(); os.close(); } - - Intent result = new Intent(); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS); - return result; } catch (Exception e) { Log.d(Constants.TAG, "signImpl", e); Intent result = new Intent(); @@ -444,7 +444,9 @@ public class OpenPgpService extends RemoteService { "Encountered unhandled type of pending action not supported by API!"); } } else if (pgpResult.success()) { - // see end of method + Intent result = new Intent(); + result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS); + return result; } else { LogEntryParcel errorMsg = pgpResult.getLog().getLast(); throw new Exception(getString(errorMsg.mType.getMsgId())); @@ -454,10 +456,6 @@ public class OpenPgpService extends RemoteService { is.close(); os.close(); } - - Intent result = new Intent(); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS); - return result; } catch (Exception e) { Log.d(Constants.TAG, "encryptAndSignImpl", e); Intent result = new Intent(); @@ -482,7 +480,6 @@ public class OpenPgpService extends RemoteService { os = new ParcelFileDescriptor.AutoCloseOutputStream(output); } - Intent result = new Intent(); try { String passphrase = data.getStringExtra(OpenPgpApi.EXTRA_PASSPHRASE); long inputLength = is.available(); @@ -522,6 +519,7 @@ public class OpenPgpService extends RemoteService { "Encountered unhandled type of pending action not supported by API!"); } } else if (pgpResult.success()) { + Intent result = new Intent(); OpenPgpSignatureResult signatureResult = pgpResult.getSignatureResult(); if (signatureResult != null) { @@ -557,6 +555,9 @@ public class OpenPgpService extends RemoteService { result.putExtra(OpenPgpApi.RESULT_METADATA, metadata); } } + + result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS); + return result; } else { LogEntryParcel errorMsg = pgpResult.getLog().getLast(); throw new Exception(getString(errorMsg.mType.getMsgId())); @@ -567,9 +568,6 @@ public class OpenPgpService extends RemoteService { os.close(); } } - - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS); - return result; } catch (Exception e) { Log.d(Constants.TAG, "decryptAndVerifyImpl", e); Intent result = new Intent(); @@ -718,8 +716,13 @@ public class OpenPgpService extends RemoteService { } String action = data.getAction(); - if (OpenPgpApi.ACTION_SIGN.equals(action)) { - return signImpl(data, input, output, accSettings); + if (OpenPgpApi.ACTION_CLEARTEXT_SIGN.equals(action)) { + return signImpl(data, input, output, accSettings, true); + } else if (OpenPgpApi.ACTION_SIGN.equals(action)) { + // DEPRECATED: same as ACTION_CLEARTEXT_SIGN + return signImpl(data, input, output, accSettings, true); + } else if (OpenPgpApi.ACTION_DETACHED_SIGN.equals(action)) { + return signImpl(data, input, output, accSettings, false); } else if (OpenPgpApi.ACTION_ENCRYPT.equals(action)) { return encryptAndSignImpl(data, input, output, accSettings, false); } else if (OpenPgpApi.ACTION_SIGN_AND_ENCRYPT.equals(action)) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java index 479810203..2dc057941 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -33,7 +33,6 @@ import org.sufficientlysecure.keychain.operations.EditKeyOperation; import org.sufficientlysecure.keychain.operations.results.DeleteResult; import org.sufficientlysecure.keychain.operations.results.EditKeyResult; import org.sufficientlysecure.keychain.operations.results.ExportResult; -import org.sufficientlysecure.keychain.operations.results.PgpEditKeyResult; import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.operations.results.CertifyResult; import org.sufficientlysecure.keychain.util.FileHelper; @@ -474,7 +473,7 @@ public class KeychainIntentService extends IntentService implements Progressable // this assumes that the bytes are cleartext (valid for current implementation!) if (source == IO_BYTES) { - builder.setCleartextInput(true); + builder.setCleartextSignature(true); } SignEncryptResult result = builder.build().execute(); -- cgit v1.2.3 From a87a45aa9abd00bb78c42ab11c8da007b892369d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Thu, 8 Jan 2015 14:57:09 +0100 Subject: No output stream for detached signatures, makes no sense to pipe it through --- .../main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java index 5151667ed..3c6c86338 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java @@ -543,8 +543,7 @@ public class PgpSignEncrypt extends BaseOperation { int length; byte[] buffer = new byte[1 << 16]; while ((length = in.read(buffer)) > 0) { - // pipe input stream directly into output stream, no changes to data - mOutStream.write(buffer, 0, length); + // no output stream is written, no changed to original data! signatureGenerator.update(buffer, 0, length); -- cgit v1.2.3 From 16f924eef3de6c79f8257f56b60f8812125757d1 Mon Sep 17 00:00:00 2001 From: Abraham Philip Date: Fri, 9 Jan 2015 05:07:50 +0530 Subject: fixed crash when file scheme is passed, broadened deletion scope --- .../ui/dialog/DeleteFileDialogFragment.java | 35 +++++++++++++++++----- 1 file changed, 28 insertions(+), 7 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteFileDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteFileDialogFragment.java index 42e21cd57..0926de1d0 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteFileDialogFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteFileDialogFragment.java @@ -18,6 +18,7 @@ package org.sufficientlysecure.keychain.ui.dialog; import android.app.Dialog; +import android.content.ContentResolver; import android.content.DialogInterface; import android.net.Uri; import android.os.Build; @@ -27,9 +28,12 @@ import android.support.v4.app.DialogFragment; import android.support.v4.app.FragmentActivity; import android.widget.Toast; +import org.apache.http.conn.scheme.Scheme; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.util.FileHelper; +import java.io.File; + public class DeleteFileDialogFragment extends DialogFragment { private static final String ARG_DELETE_URI = "delete_uri"; @@ -69,21 +73,38 @@ public class DeleteFileDialogFragment extends DialogFragment { @Override public void onClick(DialogInterface dialog, int id) { dismiss(); + String scheme = deleteUri.getScheme(); - // We can not securely delete Uris, so just use usual delete on them - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - if (DocumentsContract.deleteDocument(getActivity().getContentResolver(), deleteUri)) { + if(scheme.equals(ContentResolver.SCHEME_FILE)) { + if(new File(deleteUri.getPath()).delete()) { Toast.makeText(getActivity(), R.string.file_delete_successful, Toast.LENGTH_SHORT).show(); return; } } + else if(scheme.equals(ContentResolver.SCHEME_CONTENT)) { + // We can not securely delete Uris, so just use usual delete on them + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + if (DocumentsContract.deleteDocument(getActivity().getContentResolver(), deleteUri)) { + Toast.makeText(getActivity(), R.string.file_delete_successful, Toast.LENGTH_SHORT).show(); + return; + } + } - if (getActivity().getContentResolver().delete(deleteUri, null, null) > 0) { - Toast.makeText(getActivity(), R.string.file_delete_successful, Toast.LENGTH_SHORT).show(); - return; + if (getActivity().getContentResolver().delete(deleteUri, null, null) > 0) { + Toast.makeText(getActivity(), R.string.file_delete_successful, Toast.LENGTH_SHORT).show(); + return; + } + + // some Uri's a ContentResolver fails to delete is handled by the java.io.File's delete + // via the path of the Uri + if(new File(deleteUri.getPath()).delete()) { + Toast.makeText(getActivity(), R.string.file_delete_successful, Toast.LENGTH_SHORT).show(); + return; + } } - Toast.makeText(getActivity(), getActivity().getString(R.string.error_file_delete_failed, deleteFilename), Toast.LENGTH_SHORT).show(); + Toast.makeText(getActivity(), getActivity().getString(R.string.error_file_delete_failed, + deleteFilename), Toast.LENGTH_SHORT).show(); // Note: We can't delete every file... // If possible we should find out if deletion is possible before even showing the option to do so. -- cgit v1.2.3 From fc3397de5dabf23fac0de3fd297bcc4125864861 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Mon, 12 Jan 2015 20:03:03 +0100 Subject: add support for user attributes (during canonicalization) --- .../operations/results/OperationResult.java | 15 ++ .../keychain/pgp/UncachedKeyRing.java | 166 +++++++++++++++++++++ .../keychain/pgp/WrappedSignature.java | 9 ++ .../keychain/pgp/affirmation/LinkedIdentity.java | 160 ++++++++++++++++++++ 4 files changed, 350 insertions(+) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/LinkedIdentity.java (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java index 1388c0eac..5884dd2d5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java @@ -416,6 +416,21 @@ public abstract class OperationResult implements Parcelable { MSG_KC_UID_REVOKE_OLD (LogLevel.DEBUG, R.string.msg_kc_uid_revoke_old), MSG_KC_UID_REMOVE (LogLevel.DEBUG, R.string.msg_kc_uid_remove), MSG_KC_UID_WARN_ENCODING (LogLevel.WARN, R.string.msg_kc_uid_warn_encoding), + MSG_KC_UAT_JPEG (LogLevel.DEBUG, R.string.msg_kc_uat_jpeg), + MSG_KC_UAT_UNKNOWN (LogLevel.DEBUG, R.string.msg_kc_uat_unknown), + MSG_KC_UAT_BAD_ERR (LogLevel.WARN, R.string.msg_kc_uat_bad_err), + MSG_KC_UAT_BAD_LOCAL (LogLevel.WARN, R.string.msg_kc_uat_bad_local), + MSG_KC_UAT_BAD_TIME (LogLevel.WARN, R.string.msg_kc_uat_bad_time), + MSG_KC_UAT_BAD_TYPE (LogLevel.WARN, R.string.msg_kc_uat_bad_type), + MSG_KC_UAT_BAD (LogLevel.WARN, R.string.msg_kc_uat_bad), + MSG_KC_UAT_CERT_DUP (LogLevel.DEBUG, R.string.msg_kc_uat_cert_dup), + MSG_KC_UAT_DUP (LogLevel.DEBUG, R.string.msg_kc_uat_dup), + MSG_KC_UAT_FOREIGN (LogLevel.DEBUG, R.string.msg_kc_uat_foreign), + MSG_KC_UAT_NO_CERT (LogLevel.DEBUG, R.string.msg_kc_uat_no_cert), + MSG_KC_UAT_REVOKE_DUP (LogLevel.DEBUG, R.string.msg_kc_uat_revoke_dup), + MSG_KC_UAT_REVOKE_OLD (LogLevel.DEBUG, R.string.msg_kc_uat_revoke_old), + MSG_KC_UAT_REMOVE (LogLevel.DEBUG, R.string.msg_kc_uat_remove), + MSG_KC_UAT_WARN_ENCODING (LogLevel.WARN, R.string.msg_kc_uat_warn_encoding), // keyring consolidation diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java index a445e161f..404228a3e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java @@ -21,6 +21,7 @@ package org.sufficientlysecure.keychain.pgp; import org.spongycastle.bcpg.ArmoredOutputStream; import org.spongycastle.bcpg.PublicKeyAlgorithmTags; import org.spongycastle.bcpg.SignatureSubpacketTags; +import org.spongycastle.bcpg.UserAttributeSubpacketTags; import org.spongycastle.bcpg.sig.KeyFlags; import org.spongycastle.openpgp.PGPKeyRing; import org.spongycastle.openpgp.PGPObjectFactory; @@ -30,6 +31,7 @@ import org.spongycastle.openpgp.PGPSecretKey; import org.spongycastle.openpgp.PGPSecretKeyRing; import org.spongycastle.openpgp.PGPSignature; import org.spongycastle.openpgp.PGPSignatureList; +import org.spongycastle.openpgp.PGPUserAttributeSubpacketVector; import org.spongycastle.openpgp.PGPUtil; import org.spongycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator; import org.sufficientlysecure.keychain.Constants; @@ -605,6 +607,170 @@ public class UncachedKeyRing { return null; } + ArrayList processedUserAttributes = new ArrayList<>(); + for (PGPUserAttributeSubpacketVector userAttribute : + new IterableIterator(masterKey.getUserAttributes())) { + + if (userAttribute.getSubpacket(UserAttributeSubpacketTags.IMAGE_ATTRIBUTE) != null) { + log.add(LogType.MSG_KC_UAT_JPEG, indent); + } else { + log.add(LogType.MSG_KC_UAT_UNKNOWN, indent); + } + + try { + indent += 1; + + // check for duplicate user attributes + if (processedUserAttributes.contains(userAttribute)) { + log.add(LogType.MSG_KC_UAT_DUP, indent); + // strip out the first found user id with this name + modified = PGPPublicKey.removeCertification(modified, userAttribute); + } + processedUserAttributes.add(userAttribute); + + PGPSignature selfCert = null; + revocation = null; + + // look through signatures for this specific user id + @SuppressWarnings("unchecked") + Iterator signaturesIt = masterKey.getSignaturesForUserAttribute(userAttribute); + if (signaturesIt != null) { + for (PGPSignature zert : new IterableIterator(signaturesIt)) { + WrappedSignature cert = new WrappedSignature(zert); + long certId = cert.getKeyId(); + + int type = zert.getSignatureType(); + if (type != PGPSignature.DEFAULT_CERTIFICATION + && type != PGPSignature.NO_CERTIFICATION + && type != PGPSignature.CASUAL_CERTIFICATION + && type != PGPSignature.POSITIVE_CERTIFICATION + && type != PGPSignature.CERTIFICATION_REVOCATION) { + log.add(LogType.MSG_KC_UAT_BAD_TYPE, + indent, "0x" + Integer.toString(zert.getSignatureType(), 16)); + modified = PGPPublicKey.removeCertification(modified, userAttribute, zert); + badCerts += 1; + continue; + } + + if (cert.getCreationTime().after(nowPlusOneDay)) { + // Creation date in the future? No way! + log.add(LogType.MSG_KC_UAT_BAD_TIME, indent); + modified = PGPPublicKey.removeCertification(modified, userAttribute, zert); + badCerts += 1; + continue; + } + + if (cert.isLocal()) { + // Creation date in the future? No way! + log.add(LogType.MSG_KC_UAT_BAD_LOCAL, indent); + modified = PGPPublicKey.removeCertification(modified, userAttribute, zert); + badCerts += 1; + continue; + } + + // If this is a foreign signature, ... + if (certId != masterKeyId) { + // never mind any further for public keys, but remove them from secret ones + if (isSecret()) { + log.add(LogType.MSG_KC_UAT_FOREIGN, + indent, KeyFormattingUtils.convertKeyIdToHex(certId)); + modified = PGPPublicKey.removeCertification(modified, userAttribute, zert); + badCerts += 1; + } + continue; + } + + // Otherwise, first make sure it checks out + try { + cert.init(masterKey); + if (!cert.verifySignature(masterKey, userAttribute)) { + log.add(LogType.MSG_KC_UAT_BAD, + indent); + modified = PGPPublicKey.removeCertification(modified, userAttribute, zert); + badCerts += 1; + continue; + } + } catch (PgpGeneralException e) { + log.add(LogType.MSG_KC_UAT_BAD_ERR, + indent); + modified = PGPPublicKey.removeCertification(modified, userAttribute, zert); + badCerts += 1; + continue; + } + + switch (type) { + case PGPSignature.DEFAULT_CERTIFICATION: + case PGPSignature.NO_CERTIFICATION: + case PGPSignature.CASUAL_CERTIFICATION: + case PGPSignature.POSITIVE_CERTIFICATION: + if (selfCert == null) { + selfCert = zert; + } else if (selfCert.getCreationTime().before(cert.getCreationTime())) { + log.add(LogType.MSG_KC_UAT_CERT_DUP, + indent); + modified = PGPPublicKey.removeCertification(modified, userAttribute, selfCert); + redundantCerts += 1; + selfCert = zert; + } else { + log.add(LogType.MSG_KC_UAT_CERT_DUP, + indent); + modified = PGPPublicKey.removeCertification(modified, userAttribute, zert); + redundantCerts += 1; + } + // If there is a revocation certificate, and it's older than this, drop it + if (revocation != null + && revocation.getCreationTime().before(selfCert.getCreationTime())) { + log.add(LogType.MSG_KC_UAT_REVOKE_OLD, + indent); + modified = PGPPublicKey.removeCertification(modified, userAttribute, revocation); + revocation = null; + redundantCerts += 1; + } + break; + + case PGPSignature.CERTIFICATION_REVOCATION: + // If this is older than the (latest) self cert, drop it + if (selfCert != null && selfCert.getCreationTime().after(zert.getCreationTime())) { + log.add(LogType.MSG_KC_UAT_REVOKE_OLD, + indent); + modified = PGPPublicKey.removeCertification(modified, userAttribute, zert); + redundantCerts += 1; + continue; + } + // first revocation? remember it. + if (revocation == null) { + revocation = zert; + // more revocations? at least one is superfluous, then. + } else if (revocation.getCreationTime().before(cert.getCreationTime())) { + log.add(LogType.MSG_KC_UAT_REVOKE_DUP, + indent); + modified = PGPPublicKey.removeCertification(modified, userAttribute, revocation); + redundantCerts += 1; + revocation = zert; + } else { + log.add(LogType.MSG_KC_UAT_REVOKE_DUP, + indent); + modified = PGPPublicKey.removeCertification(modified, userAttribute, zert); + redundantCerts += 1; + } + break; + } + } + } + + // If no valid certificate (if only a revocation) remains, drop it + if (selfCert == null && revocation == null) { + log.add(LogType.MSG_KC_UAT_REMOVE, + indent); + modified = PGPPublicKey.removeCertification(modified, userAttribute); + } + + } finally { + indent -= 1; + } + } + + // Replace modified key in the keyring ring = replacePublicKey(ring, modified); indent -= 1; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java index c395ca52d..3dc02d3ed 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java @@ -29,6 +29,7 @@ import org.spongycastle.openpgp.PGPObjectFactory; import org.spongycastle.openpgp.PGPPublicKey; import org.spongycastle.openpgp.PGPSignature; import org.spongycastle.openpgp.PGPSignatureList; +import org.spongycastle.openpgp.PGPUserAttributeSubpacketVector; import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; @@ -199,6 +200,14 @@ public class WrappedSignature { } } + boolean verifySignature(PGPPublicKey key, PGPUserAttributeSubpacketVector attribute) throws PgpGeneralException { + try { + return mSig.verifyCertification(attribute, key); + } catch (PGPException e) { + throw new PgpGeneralException("Error!", e); + } + } + public boolean verifySignature(UncachedPublicKey key, byte[] rawUserId) throws PgpGeneralException { return verifySignature(key.getPublicKey(), rawUserId); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/LinkedIdentity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/LinkedIdentity.java new file mode 100644 index 000000000..dcbaa1c1c --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/LinkedIdentity.java @@ -0,0 +1,160 @@ +package org.sufficientlysecure.keychain.pgp.affirmation; + +import org.spongycastle.bcpg.UserAttributeSubpacket; +import org.spongycastle.util.Strings; +import org.spongycastle.util.encoders.Hex; +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.util.Log; + +import java.net.URI; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map.Entry; +import java.util.Set; + +public class LinkedIdentity { + + protected byte[] mData; + public final String mNonce; + public final URI mSubUri; + final Set mFlags; + final HashMap mParams; + + protected LinkedIdentity(byte[] data, String nonce, Set flags, + HashMap params, URI subUri) { + if ( ! nonce.matches("[0-9a-zA-Z]+")) { + throw new AssertionError("bug: nonce must be hexstring!"); + } + + mData = data; + mNonce = nonce; + mFlags = flags; + mParams = params; + mSubUri = subUri; + } + + LinkedIdentity(String nonce, Set flags, + HashMap params, URI subUri) { + this(null, nonce, flags, params, subUri); + } + + public byte[] encode() { + if (mData != null) { + return mData; + } + + StringBuilder b = new StringBuilder(); + b.append("pgpid:"); + + // add flags + if (mFlags != null) { + boolean first = true; + for (String flag : mFlags) { + if (!first) { + b.append(";"); + } + first = false; + b.append(flag); + } + } + + // add parameters + if (mParams != null) { + boolean first = true; + Iterator> it = mParams.entrySet().iterator(); + while (it.hasNext()) { + if (!first) { + b.append(";"); + } + first = false; + Entry entry = it.next(); + b.append(entry.getKey()).append("=").append(entry.getValue()); + } + } + + b.append("@"); + b.append(mSubUri); + + byte[] nonceBytes = Hex.decode(mNonce); + byte[] data = Strings.toUTF8ByteArray(b.toString()); + + byte[] result = new byte[data.length+12]; + System.arraycopy(nonceBytes, 0, result, 0, 12); + System.arraycopy(data, 0, result, 12, result.length); + + return result; + } + + /** This method parses an affirmation from a UserAttributeSubpacket, or returns null if the + * subpacket can not be parsed as a valid affirmation. + */ + public static LinkedIdentity parseAffirmation(UserAttributeSubpacket subpacket) { + if (subpacket.getType() != 100) { + return null; + } + + byte[] data = subpacket.getData(); + String nonce = Hex.toHexString(data, 0, 12); + + try { + return parseUri(nonce, Strings.fromUTF8ByteArray(Arrays.copyOfRange(data, 12, data.length))); + + } catch (IllegalArgumentException e) { + Log.e(Constants.TAG, "error parsing uri in (suspected) affirmation packet"); + return null; + } + } + + protected static LinkedIdentity parseUri (String nonce, String uriString) { + URI uri = URI.create(uriString); + + if ("pgpid".equals(uri.getScheme())) { + Log.e(Constants.TAG, "unknown uri scheme in (suspected) affirmation packet"); + return null; + } + + if (!uri.isOpaque()) { + Log.e(Constants.TAG, "non-opaque uri in (suspected) affirmation packet"); + return null; + } + + String specific = uri.getSchemeSpecificPart(); + if (!specific.contains("@")) { + Log.e(Constants.TAG, "unknown uri scheme in affirmation packet"); + return null; + } + + String[] pieces = specific.split("@", 2); + URI subUri = URI.create(pieces[1]); + + Set flags = new HashSet(); + HashMap params = new HashMap(); + { + String[] rawParams = pieces[0].split(";"); + for (String param : rawParams) { + String[] p = param.split("=", 2); + if (p.length == 1) { + flags.add(param); + } else { + params.put(p[0], p[1]); + } + } + } + + return new LinkedIdentity(nonce, flags, params, subUri); + + } + + public static String generateNonce() { + // TODO make this actually random + // byte[] data = new byte[96]; + // new SecureRandom().nextBytes(data); + // return Hex.toHexString(data); + + // debug for now + return "0123456789ABCDEF01234567"; + } + +} -- cgit v1.2.3 From fc85ef71a87032e97d2fc3d83baa7fc507f0fd7b Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Tue, 13 Jan 2015 00:10:59 +0100 Subject: remove LinkedIdentity (committed earlier by accident) --- .../keychain/pgp/affirmation/LinkedIdentity.java | 160 --------------------- 1 file changed, 160 deletions(-) delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/LinkedIdentity.java (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/LinkedIdentity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/LinkedIdentity.java deleted file mode 100644 index dcbaa1c1c..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/LinkedIdentity.java +++ /dev/null @@ -1,160 +0,0 @@ -package org.sufficientlysecure.keychain.pgp.affirmation; - -import org.spongycastle.bcpg.UserAttributeSubpacket; -import org.spongycastle.util.Strings; -import org.spongycastle.util.encoders.Hex; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.util.Log; - -import java.net.URI; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Map.Entry; -import java.util.Set; - -public class LinkedIdentity { - - protected byte[] mData; - public final String mNonce; - public final URI mSubUri; - final Set mFlags; - final HashMap mParams; - - protected LinkedIdentity(byte[] data, String nonce, Set flags, - HashMap params, URI subUri) { - if ( ! nonce.matches("[0-9a-zA-Z]+")) { - throw new AssertionError("bug: nonce must be hexstring!"); - } - - mData = data; - mNonce = nonce; - mFlags = flags; - mParams = params; - mSubUri = subUri; - } - - LinkedIdentity(String nonce, Set flags, - HashMap params, URI subUri) { - this(null, nonce, flags, params, subUri); - } - - public byte[] encode() { - if (mData != null) { - return mData; - } - - StringBuilder b = new StringBuilder(); - b.append("pgpid:"); - - // add flags - if (mFlags != null) { - boolean first = true; - for (String flag : mFlags) { - if (!first) { - b.append(";"); - } - first = false; - b.append(flag); - } - } - - // add parameters - if (mParams != null) { - boolean first = true; - Iterator> it = mParams.entrySet().iterator(); - while (it.hasNext()) { - if (!first) { - b.append(";"); - } - first = false; - Entry entry = it.next(); - b.append(entry.getKey()).append("=").append(entry.getValue()); - } - } - - b.append("@"); - b.append(mSubUri); - - byte[] nonceBytes = Hex.decode(mNonce); - byte[] data = Strings.toUTF8ByteArray(b.toString()); - - byte[] result = new byte[data.length+12]; - System.arraycopy(nonceBytes, 0, result, 0, 12); - System.arraycopy(data, 0, result, 12, result.length); - - return result; - } - - /** This method parses an affirmation from a UserAttributeSubpacket, or returns null if the - * subpacket can not be parsed as a valid affirmation. - */ - public static LinkedIdentity parseAffirmation(UserAttributeSubpacket subpacket) { - if (subpacket.getType() != 100) { - return null; - } - - byte[] data = subpacket.getData(); - String nonce = Hex.toHexString(data, 0, 12); - - try { - return parseUri(nonce, Strings.fromUTF8ByteArray(Arrays.copyOfRange(data, 12, data.length))); - - } catch (IllegalArgumentException e) { - Log.e(Constants.TAG, "error parsing uri in (suspected) affirmation packet"); - return null; - } - } - - protected static LinkedIdentity parseUri (String nonce, String uriString) { - URI uri = URI.create(uriString); - - if ("pgpid".equals(uri.getScheme())) { - Log.e(Constants.TAG, "unknown uri scheme in (suspected) affirmation packet"); - return null; - } - - if (!uri.isOpaque()) { - Log.e(Constants.TAG, "non-opaque uri in (suspected) affirmation packet"); - return null; - } - - String specific = uri.getSchemeSpecificPart(); - if (!specific.contains("@")) { - Log.e(Constants.TAG, "unknown uri scheme in affirmation packet"); - return null; - } - - String[] pieces = specific.split("@", 2); - URI subUri = URI.create(pieces[1]); - - Set flags = new HashSet(); - HashMap params = new HashMap(); - { - String[] rawParams = pieces[0].split(";"); - for (String param : rawParams) { - String[] p = param.split("=", 2); - if (p.length == 1) { - flags.add(param); - } else { - params.put(p[0], p[1]); - } - } - } - - return new LinkedIdentity(nonce, flags, params, subUri); - - } - - public static String generateNonce() { - // TODO make this actually random - // byte[] data = new byte[96]; - // new SecureRandom().nextBytes(data); - // return Hex.toHexString(data); - - // debug for now - return "0123456789ABCDEF01234567"; - } - -} -- cgit v1.2.3 From 50e515c6cdeede9552a577814c1a7c59325ae8c6 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Tue, 13 Jan 2015 20:35:27 +0100 Subject: add support for user attributes in merge() routine --- .../keychain/pgp/UncachedKeyRing.java | 30 ++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java index 404228a3e..04fb955fa 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java @@ -1018,8 +1018,8 @@ public class UncachedKeyRing { /** This operation merges information from a different keyring, returning a combined * UncachedKeyRing. * - * The combined keyring contains the subkeys and user ids of both input keyrings, but it does - * not necessarily have the canonicalized property. + * The combined keyring contains the subkeys, user ids and user attributes of both input + * keyrings, but it does not necessarily have the canonicalized property. * * @param other The UncachedKeyRing to merge. Must not be empty, and of the same masterKeyId * @return A consolidated UncachedKeyRing with the data of both input keyrings. Same type as @@ -1139,6 +1139,32 @@ public class UncachedKeyRing { modified = PGPPublicKey.addCertification(modified, rawUserId, cert); } } + + // Copy over all user attribute certificates + for (PGPUserAttributeSubpacketVector vector : + new IterableIterator(key.getUserAttributes())) { + @SuppressWarnings("unchecked") + Iterator signaturesIt = key.getSignaturesForUserAttribute(vector); + // no signatures for this user attribute attribute, skip it + if (signaturesIt == null) { + continue; + } + for (PGPSignature cert : new IterableIterator(signaturesIt)) { + // Don't merge foreign stuff into secret keys + if (cert.getKeyID() != masterKeyId && isSecret()) { + continue; + } + byte[] encoded = cert.getEncoded(); + // Known cert, skip it + if (certs.contains(encoded)) { + continue; + } + newCerts += 1; + certs.add(encoded); + modified = PGPPublicKey.addCertification(modified, vector, cert); + } + } + // If anything changed, save the updated (sub)key if (modified != resultKey) { result = replacePublicKey(result, modified); -- cgit v1.2.3 From 84eece622bb321c316a230432b85559ab2067084 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Mon, 12 Jan 2015 20:59:37 +0100 Subject: support addition of user attributes Conflicts: OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java OpenKeychain/src/main/res/values/strings.xml --- .../operations/results/OperationResult.java | 2 + .../keychain/pgp/PgpKeyOperation.java | 52 ++++++++++++++++++++-- .../keychain/service/SaveKeyringParcel.java | 6 +++ 3 files changed, 57 insertions(+), 3 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java index 5884dd2d5..9824173f5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java @@ -495,6 +495,8 @@ public abstract class OperationResult implements Parcelable { MSG_MF_UID_PRIMARY (LogLevel.INFO, R.string.msg_mf_uid_primary), MSG_MF_UID_REVOKE (LogLevel.INFO, R.string.msg_mf_uid_revoke), MSG_MF_UID_ERROR_EMPTY (LogLevel.ERROR, R.string.msg_mf_uid_error_empty), + MSG_MF_UAT_ADD_IMAGE (LogLevel.INFO, R.string.msg_mf_uat_add_image), + MSG_MF_UAT_ADD_UNKNOWN (LogLevel.INFO, R.string.msg_mf_uat_add_unknown), MSG_MF_UNLOCK_ERROR (LogLevel.ERROR, R.string.msg_mf_unlock_error), MSG_MF_UNLOCK (LogLevel.DEBUG, R.string.msg_mf_unlock), diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java index 128928bb3..8facbfd2a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java @@ -34,6 +34,7 @@ import org.spongycastle.openpgp.PGPSecretKeyRing; import org.spongycastle.openpgp.PGPSignature; import org.spongycastle.openpgp.PGPSignatureGenerator; import org.spongycastle.openpgp.PGPSignatureSubpacketGenerator; +import org.spongycastle.openpgp.PGPUserAttributeSubpacketVector; import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor; import org.spongycastle.openpgp.operator.PBESecretKeyEncryptor; import org.spongycastle.openpgp.operator.PGPContentSignerBuilder; @@ -478,7 +479,7 @@ public class PgpKeyOperation { PGPPublicKey modifiedPublicKey = masterPublicKey; // 2a. Add certificates for new user ids - subProgressPush(15, 25); + subProgressPush(15, 23); for (int i = 0; i < saveParcel.mAddUserIds.size(); i++) { progress(R.string.progress_modify_adduid, (i - 1) * (100 / saveParcel.mAddUserIds.size())); @@ -522,8 +523,33 @@ public class PgpKeyOperation { } subProgressPop(); - // 2b. Add revocations for revoked user ids - subProgressPush(25, 40); + // 2b. Add certificates for new user ids + subProgressPush(23, 32); + for (int i = 0; i < saveParcel.mAddUserAttribute.size(); i++) { + + progress(R.string.progress_modify_adduat, (i - 1) * (100 / saveParcel.mAddUserAttribute.size())); + WrappedUserAttribute attribute = saveParcel.mAddUserAttribute.get(i); + + switch (attribute.getType()) { + case WrappedUserAttribute.UAT_UNKNOWN: + log.add(LogType.MSG_MF_UAT_ADD_UNKNOWN, indent); + break; + case WrappedUserAttribute.UAT_IMAGE: + log.add(LogType.MSG_MF_UAT_ADD_IMAGE, indent); + break; + } + + PGPUserAttributeSubpacketVector vector = attribute.getVector(); + + // generate and add new certificate + PGPSignature cert = generateUserAttributeSignature(masterPrivateKey, + masterPublicKey, vector); + modifiedPublicKey = PGPPublicKey.addCertification(modifiedPublicKey, vector, cert); + } + subProgressPop(); + + // 2c. Add revocations for revoked user ids + subProgressPush(32, 40); for (int i = 0; i < saveParcel.mRevokeUserIds.size(); i++) { progress(R.string.progress_modify_revokeuid, (i - 1) * (100 / saveParcel.mRevokeUserIds.size())); @@ -1174,6 +1200,26 @@ public class PgpKeyOperation { return sGen.generateCertification(userId, pKey); } + private static PGPSignature generateUserAttributeSignature( + PGPPrivateKey masterPrivateKey, PGPPublicKey pKey, + PGPUserAttributeSubpacketVector vector) + throws IOException, PGPException, SignatureException { + PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder( + masterPrivateKey.getPublicKeyPacket().getAlgorithm(), HashAlgorithmTags.SHA512) + .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); + PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder); + + PGPSignatureSubpacketGenerator hashedPacketsGen = new PGPSignatureSubpacketGenerator(); + { + /* critical subpackets: we consider those important for a modern pgp implementation */ + hashedPacketsGen.setSignatureCreationTime(true, new Date()); + } + + sGen.setHashedSubpackets(hashedPacketsGen.generate()); + sGen.init(PGPSignature.POSITIVE_CERTIFICATION, masterPrivateKey); + return sGen.generateCertification(vector, pKey); + } + private static PGPSignature generateRevocationSignature( PGPPrivateKey masterPrivateKey, PGPPublicKey pKey, String userId) throws IOException, PGPException, SignatureException { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java index 810190fee..a314c8768 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java @@ -21,6 +21,7 @@ package org.sufficientlysecure.keychain.service; import android.os.Parcel; import android.os.Parcelable; +import org.sufficientlysecure.keychain.pgp.WrappedUserAttribute; import java.io.Serializable; import java.util.ArrayList; @@ -49,6 +50,7 @@ public class SaveKeyringParcel implements Parcelable { public ChangeUnlockParcel mNewUnlock; public ArrayList mAddUserIds; + public ArrayList mAddUserAttribute; public ArrayList mAddSubKeys; public ArrayList mChangeSubKeys; @@ -71,6 +73,7 @@ public class SaveKeyringParcel implements Parcelable { public void reset() { mNewUnlock = null; mAddUserIds = new ArrayList(); + mAddUserAttribute = new ArrayList(); mAddSubKeys = new ArrayList(); mChangePrimaryUserId = null; mChangeSubKeys = new ArrayList(); @@ -162,6 +165,7 @@ public class SaveKeyringParcel implements Parcelable { mNewUnlock = source.readParcelable(getClass().getClassLoader()); mAddUserIds = source.createStringArrayList(); + mAddUserAttribute = (ArrayList) source.readSerializable(); mAddSubKeys = (ArrayList) source.readSerializable(); mChangeSubKeys = (ArrayList) source.readSerializable(); @@ -184,6 +188,7 @@ public class SaveKeyringParcel implements Parcelable { destination.writeParcelable(mNewUnlock, 0); destination.writeStringList(mAddUserIds); + destination.writeSerializable(mAddUserAttribute); destination.writeSerializable(mAddSubKeys); destination.writeSerializable(mChangeSubKeys); @@ -214,6 +219,7 @@ public class SaveKeyringParcel implements Parcelable { String out = "mMasterKeyId: " + mMasterKeyId + "\n"; out += "mNewUnlock: " + mNewUnlock + "\n"; out += "mAddUserIds: " + mAddUserIds + "\n"; + out += "mAddUserAttribute: " + mAddUserAttribute + "\n"; out += "mAddSubKeys: " + mAddSubKeys + "\n"; out += "mChangeSubKeys: " + mChangeSubKeys + "\n"; out += "mChangePrimaryUserId: " + mChangePrimaryUserId + "\n"; -- cgit v1.2.3 From abd12116134a07a79672d38d040c16f2e2dd20b4 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Tue, 13 Jan 2015 20:34:19 +0100 Subject: hack to make WrappedUserAttribute serializable Conflicts: OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedUserAttribute.java --- .../keychain/pgp/WrappedUserAttribute.java | 90 ++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedUserAttribute.java (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedUserAttribute.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedUserAttribute.java new file mode 100644 index 000000000..2359d48ac --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedUserAttribute.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2014 Vincent Breitmoser + * + * 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 . + */ + +package org.sufficientlysecure.keychain.pgp; + +import org.spongycastle.bcpg.BCPGInputStream; +import org.spongycastle.bcpg.BCPGOutputStream; +import org.spongycastle.bcpg.Packet; +import org.spongycastle.bcpg.UserAttributePacket; +import org.spongycastle.bcpg.UserAttributeSubpacket; +import org.spongycastle.bcpg.UserAttributeSubpacketTags; +import org.spongycastle.openpgp.PGPUserAttributeSubpacketVector; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectStreamException; +import java.io.Serializable; + +public class WrappedUserAttribute implements Serializable { + + public static final int UAT_UNKNOWN = 0; + public static final int UAT_IMAGE = UserAttributeSubpacketTags.IMAGE_ATTRIBUTE; + + private PGPUserAttributeSubpacketVector mVector; + + WrappedUserAttribute(PGPUserAttributeSubpacketVector vector) { + mVector = vector; + } + + PGPUserAttributeSubpacketVector getVector() { + return mVector; + } + + public int getType() { + if (mVector.getSubpacket(UserAttributeSubpacketTags.IMAGE_ATTRIBUTE) != null) { + return UAT_IMAGE; + } + return 0; + } + + public static WrappedUserAttribute fromSubpacket (int type, byte[] data) { + UserAttributeSubpacket subpacket = new UserAttributeSubpacket(type, data); + PGPUserAttributeSubpacketVector vector = new PGPUserAttributeSubpacketVector( + new UserAttributeSubpacket[] { subpacket }); + + return new WrappedUserAttribute(vector); + + } + + /** Writes this object to an ObjectOutputStream. */ + private void writeObject(java.io.ObjectOutputStream out) throws IOException { + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + BCPGOutputStream bcpg = new BCPGOutputStream(baos); + bcpg.writePacket(new UserAttributePacket(mVector.toSubpacketArray())); + out.writeObject(baos.toByteArray()); + + } + + private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { + + byte[] data = (byte[]) in.readObject(); + BCPGInputStream bcpg = new BCPGInputStream(new ByteArrayInputStream(data)); + Packet p = bcpg.readPacket(); + if ( ! UserAttributePacket.class.isInstance(p)) { + throw new IOException("Could not decode UserAttributePacket!"); + } + mVector = new PGPUserAttributeSubpacketVector(((UserAttributePacket) p).getSubpackets()); + + } + + private void readObjectNoData() throws ObjectStreamException { + } + +} -- cgit v1.2.3 From 2e3545949ba9ab48ed21cb2198c9f0d2b8691ba2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Tue, 13 Jan 2015 21:55:53 +0100 Subject: Start working on Material Design --- .../keychain/remote/ui/AppsListActivity.java | 7 ++- .../keychain/ui/BaseActivity.java | 48 +++++++++++++++++++++ .../keychain/ui/DecryptActivity.java | 7 ++- .../keychain/ui/DrawerActivity.java | 7 +-- .../keychain/ui/EncryptFilesActivity.java | 7 ++- .../keychain/ui/EncryptTextActivity.java | 7 ++- .../keychain/ui/KeyListActivity.java | 10 +++-- .../keychain/ui/SafeSlingerActivity.java | 50 ++++------------------ 8 files changed, 88 insertions(+), 55 deletions(-) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BaseActivity.java (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppsListActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppsListActivity.java index 11b0deb33..ba27b22f2 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppsListActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppsListActivity.java @@ -28,9 +28,12 @@ public class AppsListActivity extends DrawerActivity { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.api_apps_list_activity); - activateDrawerNavigation(savedInstanceState); } + @Override + protected int getLayoutResource() { + return R.layout.api_apps_list_activity; + } + } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BaseActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BaseActivity.java new file mode 100644 index 000000000..6e83f6101 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BaseActivity.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2015 Dominik Schürmann + * + * 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 . + */ + +package org.sufficientlysecure.keychain.ui; + +import android.os.Bundle; +import android.support.v7.app.ActionBarActivity; +import android.support.v7.widget.Toolbar; + +import org.sufficientlysecure.keychain.R; + +/** + * Sets action bar + */ +public abstract class BaseActivity extends ActionBarActivity { + private Toolbar toolbar; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(getLayoutResource()); + toolbar = (Toolbar) findViewById(R.id.toolbar); + if (toolbar != null) { + setSupportActionBar(toolbar); + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + } + } + + protected abstract int getLayoutResource(); + + protected void setActionBarIcon(int iconRes) { + toolbar.setNavigationIcon(iconRes); + } +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java index 681e22e1e..ccff3fd6a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java @@ -40,8 +40,6 @@ public class DecryptActivity extends DrawerActivity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.decrypt_activity); - activateDrawerNavigation(savedInstanceState); View actionFile = findViewById(R.id.decrypt_files); @@ -66,6 +64,11 @@ public class DecryptActivity extends DrawerActivity { }); } + @Override + protected int getLayoutResource() { + return R.layout.decrypt_activity; + } + @TargetApi(VERSION_CODES.HONEYCOMB) @Override protected void onResume() { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DrawerActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DrawerActivity.java index da46de486..5bf0e75dd 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DrawerActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DrawerActivity.java @@ -42,7 +42,7 @@ import android.widget.TextView; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; -public class DrawerActivity extends ActionBarActivity { +public abstract class DrawerActivity extends BaseActivity { private FixedDrawerLayout mDrawerLayout; private ListView mDrawerList; private ActionBarDrawerToggle mDrawerToggle; @@ -96,8 +96,9 @@ public class DrawerActivity extends ActionBarActivity { // enable ActionBar app icon to behave as action to toggle nav drawer // if the drawer is not locked if (!mIsDrawerLocked) { - getSupportActionBar().setDisplayHomeAsUpEnabled(true); - getSupportActionBar().setHomeButtonEnabled(true); + // TODO +// getSupportActionBar().setDisplayHomeAsUpEnabled(true); +// getSupportActionBar().setHomeButtonEnabled(true); } // ActionBarDrawerToggle ties together the the proper interactions diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java index 054d85323..d0e66156c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java @@ -309,8 +309,6 @@ public class EncryptFilesActivity extends EncryptActivity implements EncryptActi public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.encrypt_files_activity); - // if called with an intent action, do not init drawer navigation if (ACTION_ENCRYPT_DATA.equals(getIntent().getAction())) { // lock drawer @@ -327,6 +325,11 @@ public class EncryptFilesActivity extends EncryptActivity implements EncryptActi mUseArmor = Preferences.getPreferences(this).getDefaultAsciiArmor(); } + @Override + protected int getLayoutResource() { + return R.layout.encrypt_files_activity; + } + @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.encrypt_file_activity, menu); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java index 958daa122..0850ead3b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java @@ -288,8 +288,6 @@ public class EncryptTextActivity extends EncryptActivity implements EncryptActiv public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.encrypt_text_activity); - // if called with an intent action, do not init drawer navigation if (ACTION_ENCRYPT_TEXT.equals(getIntent().getAction())) { // lock drawer @@ -304,6 +302,11 @@ public class EncryptTextActivity extends EncryptActivity implements EncryptActiv updateModeFragment(); } + @Override + protected int getLayoutResource() { + return R.layout.encrypt_text_activity; + } + @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.encrypt_text_activity, menu); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java index ba03400d7..6b3cf5fe4 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java @@ -50,6 +50,7 @@ public class KeyListActivity extends DrawerActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); +// setActionBarIcon(R.drawable.ic_ab_drawer); setTitle(R.string.nav_keys); @@ -63,10 +64,13 @@ public class KeyListActivity extends DrawerActivity { mExportHelper = new ExportHelper(this); - setContentView(R.layout.key_list_activity); - // now setup navigation drawer in DrawerActivity... - activateDrawerNavigation(savedInstanceState); +// activateDrawerNavigation(savedInstanceState); + } + + @Override + protected int getLayoutResource() { + return R.layout.key_list_activity; } @Override diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SafeSlingerActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SafeSlingerActivity.java index 20e1bbe97..c91d91ad9 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SafeSlingerActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SafeSlingerActivity.java @@ -73,47 +73,15 @@ public class SafeSlingerActivity extends ActionBarActivity { mMasterKeyId = getIntent().getLongExtra(EXTRA_MASTER_KEY_ID, 0); - // NOTE: there are two versions of this layout, for API >= 11 and one for < 11 - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { - NumberPicker picker = (NumberPicker) findViewById(R.id.safe_slinger_picker); - picker.setMinValue(2); - picker.setMaxValue(10); - picker.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() { - @Override - public void onValueChange(NumberPicker picker, int oldVal, int newVal) { - mSelectedNumber = newVal; - } - }); - } else { - Spinner spinner = (Spinner) findViewById(R.id.safe_slinger_spinner); - - List list = new ArrayList(); - list.add("2"); - list.add("3"); - list.add("4"); - list.add("5"); - list.add("6"); - list.add("7"); - list.add("8"); - list.add("9"); - list.add("10"); - - ArrayAdapter dataAdapter = new ArrayAdapter(this, - android.R.layout.simple_spinner_item, list); - dataAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); - spinner.setAdapter(dataAdapter); - spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { - @Override - public void onItemSelected(AdapterView parent, View view, int position, long id) { - mSelectedNumber = position + 2; - } - - @Override - public void onNothingSelected(AdapterView parent) { - - } - }); - } + NumberPicker picker = (NumberPicker) findViewById(R.id.safe_slinger_picker); + picker.setMinValue(2); + picker.setMaxValue(10); + picker.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() { + @Override + public void onValueChange(NumberPicker picker, int oldVal, int newVal) { + mSelectedNumber = newVal; + } + }); ImageView buttonIcon = (ImageView) findViewById(R.id.safe_slinger_button_image); buttonIcon.setColorFilter(getResources().getColor(R.color.tertiary_text_light), -- cgit v1.2.3 From d8ff737fc5392362707ad70fbe964ac9e299457f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Tue, 13 Jan 2015 23:15:13 +0100 Subject: Use Toolbar and new BaseActivity --- .../sufficientlysecure/keychain/ui/CertifyKeyActivity.java | 8 +++----- .../org/sufficientlysecure/keychain/ui/CreateKeyActivity.java | 9 ++++++--- .../org/sufficientlysecure/keychain/ui/EditKeyActivity.java | 9 ++++++--- .../org/sufficientlysecure/keychain/ui/FirstTimeActivity.java | 8 +++++--- .../java/org/sufficientlysecure/keychain/ui/HelpActivity.java | 9 ++++++--- .../sufficientlysecure/keychain/ui/ImportKeysActivity.java | 9 ++++++--- .../sufficientlysecure/keychain/ui/LogDisplayActivity.java | 7 +++++-- .../java/org/sufficientlysecure/keychain/ui/NfcActivity.java | 9 ++++++--- .../org/sufficientlysecure/keychain/ui/NfcIntentActivity.java | 8 +++++--- .../sufficientlysecure/keychain/ui/QrCodeViewActivity.java | 9 ++++++--- .../sufficientlysecure/keychain/ui/SafeSlingerActivity.java | 9 ++++++--- .../keychain/ui/SelectPublicKeyActivity.java | 9 ++++++--- .../org/sufficientlysecure/keychain/ui/UploadKeyActivity.java | 9 ++++++--- .../org/sufficientlysecure/keychain/ui/ViewCertActivity.java | 9 ++++++--- .../org/sufficientlysecure/keychain/ui/ViewKeyActivity.java | 11 +++++++---- .../keychain/ui/ViewKeyAdvancedActivity.java | 9 ++++++--- 16 files changed, 91 insertions(+), 50 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java index a97e73934..24d002368 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java @@ -26,17 +26,15 @@ import org.sufficientlysecure.keychain.R; /** * Signs the specified public key with the specified secret master key */ -public class CertifyKeyActivity extends ActionBarActivity { +public class CertifyKeyActivity extends BaseActivity { public static final String EXTRA_RESULT = "operation_result"; public static final String EXTRA_KEY_IDS = "extra_key_ids"; public static final String EXTRA_CERTIFY_KEY_ID = "certify_key_id"; @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setContentView(R.layout.certify_key_activity); + protected int getLayoutResource() { + return R.layout.certify_key_activity; } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java index 534ac5811..c95ad90a1 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java @@ -24,7 +24,7 @@ import android.support.v7.app.ActionBarActivity; import org.sufficientlysecure.keychain.R; -public class CreateKeyActivity extends ActionBarActivity { +public class CreateKeyActivity extends BaseActivity { public static final String EXTRA_NAME = "name"; public static final String EXTRA_EMAIL = "email"; @@ -37,8 +37,6 @@ public class CreateKeyActivity extends ActionBarActivity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.create_key_activity); - // pass extras into fragment CreateKeyInputFragment frag = CreateKeyInputFragment.newInstance( @@ -48,6 +46,11 @@ public class CreateKeyActivity extends ActionBarActivity { loadFragment(null, frag, FRAG_ACTION_START); } + @Override + protected int getLayoutResource() { + return R.layout.create_key_activity; + } + public void loadFragment(Bundle savedInstanceState, Fragment fragment, int action) { // However, if we're being restored from a previous state, // then we don't need to do anything and should return or else diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java index 98049d89b..1615430e7 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java @@ -26,7 +26,7 @@ import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.service.SaveKeyringParcel; import org.sufficientlysecure.keychain.util.Log; -public class EditKeyActivity extends ActionBarActivity { +public class EditKeyActivity extends BaseActivity { public static final String EXTRA_SAVE_KEYRING_PARCEL = "save_keyring_parcel"; @@ -36,8 +36,6 @@ public class EditKeyActivity extends ActionBarActivity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.edit_key_activity); - Uri dataUri = getIntent().getData(); SaveKeyringParcel saveKeyringParcel = getIntent().getParcelableExtra(EXTRA_SAVE_KEYRING_PARCEL); if (dataUri == null && saveKeyringParcel == null) { @@ -49,6 +47,11 @@ public class EditKeyActivity extends ActionBarActivity { loadFragment(savedInstanceState, dataUri, saveKeyringParcel); } + @Override + protected int getLayoutResource() { + return R.layout.edit_key_activity; + } + private void loadFragment(Bundle savedInstanceState, Uri dataUri, SaveKeyringParcel saveKeyringParcel) { // However, if we're being restored from a previous state, // then we don't need to do anything and should return or else diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/FirstTimeActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/FirstTimeActivity.java index f18e475fc..277b08c48 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/FirstTimeActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/FirstTimeActivity.java @@ -29,7 +29,7 @@ import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.util.Preferences; import org.sufficientlysecure.keychain.util.Log; -public class FirstTimeActivity extends ActionBarActivity { +public class FirstTimeActivity extends BaseActivity { View mCreateKey; View mImportKey; @@ -43,8 +43,6 @@ public class FirstTimeActivity extends ActionBarActivity { super.onCreate(savedInstanceState); - setContentView(R.layout.first_time_activity); - mCreateKey = findViewById(R.id.first_time_create_key); mImportKey = findViewById(R.id.first_time_import_key); mSkipSetup = findViewById(R.id.first_time_cancel); @@ -72,7 +70,11 @@ public class FirstTimeActivity extends ActionBarActivity { startActivityForResult(intent, REQUEST_CODE_CREATE_OR_IMPORT_KEY); } }); + } + @Override + protected int getLayoutResource() { + return R.layout.first_time_activity; } @Override diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpActivity.java index bbc1e4b1f..412de9984 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpActivity.java @@ -27,7 +27,7 @@ import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.ui.adapter.PagerTabStripAdapter; import org.sufficientlysecure.keychain.ui.widget.SlidingTabLayout; -public class HelpActivity extends ActionBarActivity { +public class HelpActivity extends BaseActivity { public static final String EXTRA_SELECTED_TAB = "selected_tab"; public static final int TAB_START = 0; @@ -49,8 +49,6 @@ public class HelpActivity extends ActionBarActivity { actionBar.setDisplayHomeAsUpEnabled(false); actionBar.setHomeButtonEnabled(false); - setContentView(R.layout.help_activity); - mViewPager = (ViewPager) findViewById(R.id.pager); SlidingTabLayout slidingTabLayout = (SlidingTabLayout) findViewById(R.id.sliding_tab_layout); @@ -98,4 +96,9 @@ public class HelpActivity extends ActionBarActivity { // switch to tab selected by extra mViewPager.setCurrentItem(selectedTab); } + + @Override + protected int getLayoutResource() { + return R.layout.help_activity; + } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java index dfb7b3056..1e413f5ac 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java @@ -51,7 +51,7 @@ import org.sufficientlysecure.keychain.util.ParcelableFileCache.IteratorWithSize import java.io.IOException; import java.util.ArrayList; -public class ImportKeysActivity extends ActionBarActivity { +public class ImportKeysActivity extends BaseActivity { public static final String ACTION_IMPORT_KEY = OpenKeychainIntents.IMPORT_KEY; public static final String ACTION_IMPORT_KEY_FROM_KEYSERVER = OpenKeychainIntents.IMPORT_KEY_FROM_KEYSERVER; public static final String ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_RESULT = @@ -90,8 +90,6 @@ public class ImportKeysActivity extends ActionBarActivity { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.import_keys_activity); - mImportButton = findViewById(R.id.import_import); mImportButton.setOnClickListener(new OnClickListener() { @Override @@ -103,6 +101,11 @@ public class ImportKeysActivity extends ActionBarActivity { handleActions(savedInstanceState, getIntent()); } + @Override + protected int getLayoutResource() { + return R.layout.import_keys_activity; + } + protected void handleActions(Bundle savedInstanceState, Intent intent) { String action = intent.getAction(); Bundle extras = intent.getExtras(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayActivity.java index 4a2b88518..f5eac09b1 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayActivity.java @@ -25,7 +25,7 @@ import android.view.View; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.ui.util.ActionBarHelper; -public class LogDisplayActivity extends ActionBarActivity { +public class LogDisplayActivity extends BaseActivity { @Override public void onCreate(Bundle savedInstanceState) { @@ -42,8 +42,11 @@ public class LogDisplayActivity extends ActionBarActivity { } } ); + } - setContentView(R.layout.log_display_activity); + @Override + protected int getLayoutResource() { + return R.layout.log_display_activity; } } \ No newline at end of file diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcActivity.java index d0e40a9b8..53b17654c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcActivity.java @@ -38,7 +38,7 @@ import java.util.Locale; * For the full specs, see http://g10code.com/docs/openpgp-card-2.0.pdf */ @TargetApi(Build.VERSION_CODES.GINGERBREAD_MR1) -public class NfcActivity extends ActionBarActivity { +public class NfcActivity extends BaseActivity { // actions public static final String ACTION_SIGN_HASH = "sign_hash"; @@ -82,8 +82,6 @@ public class NfcActivity extends ActionBarActivity { getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); - setContentView(R.layout.nfc_activity); - Intent intent = getIntent(); Bundle data = intent.getExtras(); String action = intent.getAction(); @@ -123,6 +121,11 @@ public class NfcActivity extends ActionBarActivity { } } + @Override + protected int getLayoutResource() { + return R.layout.nfc_activity; + } + /** * Called when the system is about to start resuming a previous activity, * disables NFC Foreground Dispatch diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcIntentActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcIntentActivity.java index cb15dbec2..bb5277119 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcIntentActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcIntentActivity.java @@ -36,7 +36,7 @@ import java.nio.ByteBuffer; * For the full specs, see http://g10code.com/docs/openpgp-card-2.0.pdf */ @TargetApi(Build.VERSION_CODES.GINGERBREAD_MR1) -public class NfcIntentActivity extends ActionBarActivity { +public class NfcIntentActivity extends BaseActivity { // special extra for OpenPgpService public static final String EXTRA_DATA = "data"; @@ -54,8 +54,6 @@ public class NfcIntentActivity extends ActionBarActivity { getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); - setContentView(R.layout.nfc_activity); - Intent intent = getIntent(); Bundle data = intent.getExtras(); String action = intent.getAction(); @@ -87,7 +85,11 @@ public class NfcIntentActivity extends ActionBarActivity { Log.e(Constants.TAG, "IOException!", e); finish(); } + } + @Override + protected int getLayoutResource() { + return R.layout.nfc_activity; } /** diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeViewActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeViewActivity.java index cf0c3eb88..b0343a961 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeViewActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeViewActivity.java @@ -36,7 +36,7 @@ import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.ui.util.Notify.Style; import org.sufficientlysecure.keychain.ui.util.QrCodeUtils; -public class QrCodeViewActivity extends ActionBarActivity { +public class QrCodeViewActivity extends BaseActivity { private ImageView mFingerprintQrCode; @@ -56,8 +56,6 @@ public class QrCodeViewActivity extends ActionBarActivity { } ); - setContentView(R.layout.qr_code_activity); - Uri dataUri = getIntent().getData(); if (dataUri == null) { Log.e(Constants.TAG, "Data missing. Should be Uri of key!"); @@ -108,6 +106,11 @@ public class QrCodeViewActivity extends ActionBarActivity { } } + @Override + protected int getLayoutResource() { + return R.layout.qr_code_activity; + } + @Override protected void onResume() { super.onResume(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SafeSlingerActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SafeSlingerActivity.java index c91d91ad9..deecffeea 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SafeSlingerActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SafeSlingerActivity.java @@ -56,7 +56,7 @@ import edu.cmu.cylab.starslinger.exchange.ExchangeActivity; import edu.cmu.cylab.starslinger.exchange.ExchangeConfig; @TargetApi(Build.VERSION_CODES.HONEYCOMB) -public class SafeSlingerActivity extends ActionBarActivity { +public class SafeSlingerActivity extends BaseActivity { private static final int REQUEST_CODE_SAFE_SLINGER = 211; @@ -69,8 +69,6 @@ public class SafeSlingerActivity extends ActionBarActivity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.safe_slinger_activity); - mMasterKeyId = getIntent().getLongExtra(EXTRA_MASTER_KEY_ID, 0); NumberPicker picker = (NumberPicker) findViewById(R.id.safe_slinger_picker); @@ -96,6 +94,11 @@ public class SafeSlingerActivity extends ActionBarActivity { }); } + @Override + protected int getLayoutResource() { + return R.layout.safe_slinger_activity; + } + private void startExchange(long masterKeyId, int number) { // retrieve public key blob and start SafeSlinger Uri uri = KeychainContract.KeyRingData.buildPublicKeyRingUri(masterKeyId); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyActivity.java index 148aa7d67..3ee1e14cc 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyActivity.java @@ -27,7 +27,7 @@ import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.ui.util.ActionBarHelper; -public class SelectPublicKeyActivity extends ActionBarActivity { +public class SelectPublicKeyActivity extends BaseActivity { // Actions for internal use only: public static final String ACTION_SELECT_PUBLIC_KEYS = Constants.INTENT_PREFIX @@ -63,8 +63,6 @@ public class SelectPublicKeyActivity extends ActionBarActivity { } ); - setContentView(R.layout.select_public_key_activity); - setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL); handleIntent(getIntent()); @@ -101,6 +99,11 @@ public class SelectPublicKeyActivity extends ActionBarActivity { } + @Override + protected int getLayoutResource() { + return R.layout.select_public_key_activity; + } + @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java index 497486a5e..297a35eb5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java @@ -44,7 +44,7 @@ import org.sufficientlysecure.keychain.util.Log; /** * Sends the selected public key to a keyserver */ -public class UploadKeyActivity extends ActionBarActivity { +public class UploadKeyActivity extends BaseActivity { private View mUploadButton; private Spinner mKeyServerSpinner; @@ -54,8 +54,6 @@ public class UploadKeyActivity extends ActionBarActivity { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.upload_key_activity); - mUploadButton = findViewById(R.id.upload_key_action_upload); mKeyServerSpinner = (Spinner) findViewById(R.id.upload_key_keyserver); @@ -86,6 +84,11 @@ public class UploadKeyActivity extends ActionBarActivity { } } + @Override + protected int getLayoutResource() { + return R.layout.upload_key_activity; + } + private void uploadKey() { // Send all information needed to service to upload key in other thread Intent intent = new Intent(this, KeychainIntentService.class); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java index 34c08a6c7..5dede6627 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java @@ -49,7 +49,7 @@ import org.sufficientlysecure.keychain.util.Log; import java.util.Date; -public class ViewCertActivity extends ActionBarActivity +public class ViewCertActivity extends BaseActivity implements LoaderManager.LoaderCallbacks { // These are the rows that we will retrieve. @@ -86,8 +86,6 @@ public class ViewCertActivity extends ActionBarActivity ActionBar actionBar = getSupportActionBar(); actionBar.setDisplayHomeAsUpEnabled(true); - setContentView(R.layout.view_cert_activity); - mSigneeKey = (TextView) findViewById(R.id.signee_key); mSigneeUid = (TextView) findViewById(R.id.signee_uid); mAlgorithm = (TextView) findViewById(R.id.algorithm); @@ -112,6 +110,11 @@ public class ViewCertActivity extends ActionBarActivity getSupportLoaderManager().initLoader(0, null, this); } + @Override + protected int getLayoutResource() { + return R.layout.view_cert_activity; + } + @Override public Loader onCreateLoader(int id, Bundle args) { // Now create and return a CursorLoader that will take care of diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java index 0bc75b3a9..e441ff414 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java @@ -67,7 +67,7 @@ import org.sufficientlysecure.keychain.ui.util.Notify; import java.util.Date; import java.util.HashMap; -public class ViewKeyActivity extends ActionBarActivity implements +public class ViewKeyActivity extends BaseActivity implements LoaderManager.LoaderCallbacks { ExportHelper mExportHelper; @@ -111,8 +111,6 @@ public class ViewKeyActivity extends ActionBarActivity implements actionBar.setIcon(android.R.color.transparent); actionBar.setHomeButtonEnabled(true); - setContentView(R.layout.view_key_activity); - mStatusLayout = (LinearLayout) findViewById(R.id.view_key_status_layout); mStatusText = (TextView) findViewById(R.id.view_key_status_text); mStatusImage = (ImageView) findViewById(R.id.view_key_status_image); @@ -124,7 +122,7 @@ public class ViewKeyActivity extends ActionBarActivity implements mSlidingTabLayout.setCustomTabColorizer(new TabColorizer() { @Override public int getIndicatorColor(int position) { - return 0xFFAA66CC; + return 0xFF4caf50; } @Override @@ -169,6 +167,11 @@ public class ViewKeyActivity extends ActionBarActivity implements mViewPager.setCurrentItem(switchToTab); } + @Override + protected int getLayoutResource() { + return R.layout.view_key_activity; + } + private void initTabs(Uri dataUri) { mTabsAdapter = new PagerTabStripAdapter(this); mViewPager.setAdapter(mTabsAdapter); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvancedActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvancedActivity.java index f49f8e7cf..9fdcaaaf9 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvancedActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvancedActivity.java @@ -31,7 +31,7 @@ import org.sufficientlysecure.keychain.ui.util.ActionBarHelper; import org.sufficientlysecure.keychain.util.ExportHelper; import org.sufficientlysecure.keychain.util.Log; -public class ViewKeyAdvancedActivity extends ActionBarActivity { +public class ViewKeyAdvancedActivity extends BaseActivity { ExportHelper mExportHelper; ProviderHelper mProviderHelper; @@ -55,8 +55,6 @@ public class ViewKeyAdvancedActivity extends ActionBarActivity { } ); - setContentView(R.layout.view_key_advanced_activity); - Uri dataUri = getIntent().getData(); if (dataUri == null) { Log.e(Constants.TAG, "Data missing. Should be uri of key!"); @@ -69,6 +67,11 @@ public class ViewKeyAdvancedActivity extends ActionBarActivity { startFragment(savedInstanceState, dataUri); } + @Override + protected int getLayoutResource() { + return R.layout.view_key_advanced_activity; + } + private void startFragment(Bundle savedInstanceState, Uri dataUri) { // However, if we're being restored from a previous state, -- cgit v1.2.3 From 7da3ddae7bb168329bc3ac04962f9e7a42c7b8f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Tue, 13 Jan 2015 23:43:18 +0100 Subject: Refactor BaseActivity --- .../keychain/remote/ui/AccountSettingsActivity.java | 9 +++++++-- .../keychain/remote/ui/AppSettingsActivity.java | 17 +++++++++++------ .../keychain/remote/ui/AppsListActivity.java | 4 ++-- .../keychain/remote/ui/RemoteServiceActivity.java | 19 +++++++++++++++---- .../sufficientlysecure/keychain/ui/BaseActivity.java | 10 +++++++--- .../keychain/ui/CertifyKeyActivity.java | 4 ++-- .../keychain/ui/CreateKeyActivity.java | 4 ++-- .../keychain/ui/DecryptActivity.java | 4 ++-- .../keychain/ui/DrawerActivity.java | 5 ++--- .../keychain/ui/EditKeyActivity.java | 4 ++-- .../keychain/ui/EncryptFilesActivity.java | 4 ++-- .../keychain/ui/EncryptTextActivity.java | 4 ++-- .../keychain/ui/FirstTimeActivity.java | 4 ++-- .../sufficientlysecure/keychain/ui/HelpActivity.java | 4 ++-- .../keychain/ui/ImportKeysActivity.java | 4 ++-- .../keychain/ui/KeyListActivity.java | 6 +++--- .../keychain/ui/LogDisplayActivity.java | 4 ++-- .../sufficientlysecure/keychain/ui/NfcActivity.java | 4 ++-- .../keychain/ui/NfcIntentActivity.java | 4 ++-- .../keychain/ui/QrCodeViewActivity.java | 4 ++-- .../keychain/ui/SafeSlingerActivity.java | 4 ++-- .../keychain/ui/SelectPublicKeyActivity.java | 4 ++-- .../keychain/ui/UploadKeyActivity.java | 4 ++-- .../keychain/ui/ViewCertActivity.java | 4 ++-- .../keychain/ui/ViewKeyActivity.java | 4 ++-- .../keychain/ui/ViewKeyAdvancedActivity.java | 5 ++--- 26 files changed, 85 insertions(+), 62 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsActivity.java index 0e9678980..7d77a989d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsActivity.java @@ -27,6 +27,7 @@ import android.view.View; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.ui.BaseActivity; import org.sufficientlysecure.keychain.ui.util.ActionBarHelper; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.remote.AccountSettings; @@ -35,7 +36,7 @@ import org.sufficientlysecure.keychain.operations.results.OperationResult.LogTyp import org.sufficientlysecure.keychain.operations.results.SingletonResult; import org.sufficientlysecure.keychain.util.Log; -public class AccountSettingsActivity extends ActionBarActivity { +public class AccountSettingsActivity extends BaseActivity { private Uri mAccountUri; private AccountSettingsFragment mAccountSettingsFragment; @@ -55,7 +56,6 @@ public class AccountSettingsActivity extends ActionBarActivity { } }); - setContentView(R.layout.api_account_settings_activity); mAccountSettingsFragment = (AccountSettingsFragment) getSupportFragmentManager().findFragmentById( R.id.api_account_settings_fragment); @@ -72,6 +72,11 @@ public class AccountSettingsActivity extends ActionBarActivity { } } + @Override + protected void initLayout() { + setContentView(R.layout.api_account_settings_activity); + } + @Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java index 56e3b22e2..d84a03698 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java @@ -33,9 +33,10 @@ import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.remote.AppSettings; import org.sufficientlysecure.keychain.operations.results.OperationResult; +import org.sufficientlysecure.keychain.ui.BaseActivity; import org.sufficientlysecure.keychain.util.Log; -public class AppSettingsActivity extends ActionBarActivity { +public class AppSettingsActivity extends BaseActivity { private Uri mAppUri; private AppSettingsFragment mSettingsFragment; @@ -49,12 +50,11 @@ public class AppSettingsActivity extends ActionBarActivity { super.onCreate(savedInstanceState); // let the actionbar look like Android's contact app - ActionBar actionBar = getSupportActionBar(); - actionBar.setDisplayHomeAsUpEnabled(true); - actionBar.setIcon(android.R.color.transparent); - actionBar.setHomeButtonEnabled(true); +// ActionBar actionBar = getSupportActionBar(); +// actionBar.setDisplayHomeAsUpEnabled(true); +// actionBar.setIcon(android.R.color.transparent); +// actionBar.setHomeButtonEnabled(true); - setContentView(R.layout.api_app_settings_activity); mSettingsFragment = (AppSettingsFragment) getSupportFragmentManager().findFragmentById( R.id.api_app_settings_fragment); @@ -71,6 +71,11 @@ public class AppSettingsActivity extends ActionBarActivity { } } + @Override + protected void initLayout() { + setContentView(R.layout.api_app_settings_activity); + } + @Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppsListActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppsListActivity.java index ba27b22f2..079b3065e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppsListActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppsListActivity.java @@ -32,8 +32,8 @@ public class AppsListActivity extends DrawerActivity { } @Override - protected int getLayoutResource() { - return R.layout.api_apps_list_activity; + protected void initLayout() { + setContentView(R.layout.api_apps_list_activity); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/RemoteServiceActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/RemoteServiceActivity.java index d7b723eb0..a9a7c75f5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/RemoteServiceActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/RemoteServiceActivity.java @@ -39,6 +39,7 @@ import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.remote.AccountSettings; import org.sufficientlysecure.keychain.remote.AppSettings; +import org.sufficientlysecure.keychain.ui.BaseActivity; import org.sufficientlysecure.keychain.ui.SelectPublicKeyFragment; import org.sufficientlysecure.keychain.ui.util.ActionBarHelper; import org.sufficientlysecure.keychain.ui.util.Notify; @@ -46,7 +47,7 @@ import org.sufficientlysecure.keychain.util.Log; import java.util.ArrayList; -public class RemoteServiceActivity extends ActionBarActivity { +public class RemoteServiceActivity extends BaseActivity { public static final String ACTION_REGISTER = Constants.INTENT_PREFIX + "API_ACTIVITY_REGISTER"; public static final String ACTION_CREATE_ACCOUNT = Constants.INTENT_PREFIX @@ -96,6 +97,11 @@ public class RemoteServiceActivity extends ActionBarActivity { handleActions(getIntent(), savedInstanceState); } + @Override + protected void initLayout() { + // done in handleActions() + } + protected void handleActions(Intent intent, Bundle savedInstanceState) { String action = intent.getAction(); @@ -108,6 +114,7 @@ public class RemoteServiceActivity extends ActionBarActivity { Log.d(Constants.TAG, "ACTION_REGISTER packageName: " + packageName); setContentView(R.layout.api_remote_register_app); + initToolbar(); mAppSettingsFragment = (AppSettingsFragment) getSupportFragmentManager().findFragmentById( R.id.api_app_settings_fragment); @@ -145,6 +152,7 @@ public class RemoteServiceActivity extends ActionBarActivity { final String accName = extras.getString(EXTRA_ACC_NAME); setContentView(R.layout.api_remote_create_account); + initToolbar(); mAccSettingsFragment = (AccountSettingsFragment) getSupportFragmentManager().findFragmentById( R.id.api_account_settings_fragment); @@ -248,6 +256,9 @@ public class RemoteServiceActivity extends ActionBarActivity { } } + setContentView(R.layout.api_remote_select_pub_keys); + initToolbar(); + // Inflate a "Done"/"Cancel" custom action bar view ActionBarHelper.setTwoButtonView(getSupportActionBar(), R.string.btn_okay, R.drawable.ic_action_done, @@ -272,7 +283,6 @@ public class RemoteServiceActivity extends ActionBarActivity { } ); - setContentView(R.layout.api_remote_select_pub_keys); // set text on view TextView textView = (TextView) findViewById(R.id.api_select_pub_keys_text); @@ -303,6 +313,9 @@ public class RemoteServiceActivity extends ActionBarActivity { Spannable redErrorMessage = new SpannableString(errorMessage); redErrorMessage.setSpan(new ForegroundColorSpan(Color.RED), 0, errorMessage.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + setContentView(R.layout.api_remote_error_message); + initToolbar(); + // Inflate a "Done" custom action bar view ActionBarHelper.setOneButtonView(getSupportActionBar(), R.string.btn_okay, R.drawable.ic_action_done, @@ -316,8 +329,6 @@ public class RemoteServiceActivity extends ActionBarActivity { } ); - setContentView(R.layout.api_remote_error_message); - // set text on view TextView textView = (TextView) findViewById(R.id.api_app_error_message_text); textView.setText(redErrorMessage); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BaseActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BaseActivity.java index 6e83f6101..ee73bb8f2 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BaseActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BaseActivity.java @@ -32,7 +32,13 @@ public abstract class BaseActivity extends ActionBarActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(getLayoutResource()); + initLayout(); + initToolbar(); + } + + protected abstract void initLayout(); + + protected void initToolbar() { toolbar = (Toolbar) findViewById(R.id.toolbar); if (toolbar != null) { setSupportActionBar(toolbar); @@ -40,8 +46,6 @@ public abstract class BaseActivity extends ActionBarActivity { } } - protected abstract int getLayoutResource(); - protected void setActionBarIcon(int iconRes) { toolbar.setNavigationIcon(iconRes); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java index 24d002368..6850eca13 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java @@ -33,8 +33,8 @@ public class CertifyKeyActivity extends BaseActivity { public static final String EXTRA_CERTIFY_KEY_ID = "certify_key_id"; @Override - protected int getLayoutResource() { - return R.layout.certify_key_activity; + protected void initLayout() { + setContentView(R.layout.certify_key_activity); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java index c95ad90a1..82d3279f4 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java @@ -47,8 +47,8 @@ public class CreateKeyActivity extends BaseActivity { } @Override - protected int getLayoutResource() { - return R.layout.create_key_activity; + protected void initLayout() { + setContentView(R.layout.create_key_activity); } public void loadFragment(Bundle savedInstanceState, Fragment fragment, int action) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java index ccff3fd6a..a84461a92 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java @@ -65,8 +65,8 @@ public class DecryptActivity extends DrawerActivity { } @Override - protected int getLayoutResource() { - return R.layout.decrypt_activity; + protected void initLayout() { + setContentView(R.layout.decrypt_activity); } @TargetApi(VERSION_CODES.HONEYCOMB) diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DrawerActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DrawerActivity.java index 5bf0e75dd..b3521ebcc 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DrawerActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DrawerActivity.java @@ -96,9 +96,8 @@ public abstract class DrawerActivity extends BaseActivity { // enable ActionBar app icon to behave as action to toggle nav drawer // if the drawer is not locked if (!mIsDrawerLocked) { - // TODO -// getSupportActionBar().setDisplayHomeAsUpEnabled(true); -// getSupportActionBar().setHomeButtonEnabled(true); + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + getSupportActionBar().setHomeButtonEnabled(true); } // ActionBarDrawerToggle ties together the the proper interactions diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java index 1615430e7..492c81758 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java @@ -48,8 +48,8 @@ public class EditKeyActivity extends BaseActivity { } @Override - protected int getLayoutResource() { - return R.layout.edit_key_activity; + protected void initLayout() { + setContentView(R.layout.edit_key_activity); } private void loadFragment(Bundle savedInstanceState, Uri dataUri, SaveKeyringParcel saveKeyringParcel) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java index d0e66156c..1494d05e1 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java @@ -326,8 +326,8 @@ public class EncryptFilesActivity extends EncryptActivity implements EncryptActi } @Override - protected int getLayoutResource() { - return R.layout.encrypt_files_activity; + protected void initLayout() { + setContentView(R.layout.encrypt_files_activity); } @Override diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java index 0850ead3b..757d1fb02 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java @@ -303,8 +303,8 @@ public class EncryptTextActivity extends EncryptActivity implements EncryptActiv } @Override - protected int getLayoutResource() { - return R.layout.encrypt_text_activity; + protected void initLayout() { + setContentView(R.layout.encrypt_text_activity); } @Override diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/FirstTimeActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/FirstTimeActivity.java index 277b08c48..e5db48304 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/FirstTimeActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/FirstTimeActivity.java @@ -73,8 +73,8 @@ public class FirstTimeActivity extends BaseActivity { } @Override - protected int getLayoutResource() { - return R.layout.first_time_activity; + protected void initLayout() { + setContentView(R.layout.first_time_activity); } @Override diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpActivity.java index 412de9984..8d4d3c915 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpActivity.java @@ -98,7 +98,7 @@ public class HelpActivity extends BaseActivity { } @Override - protected int getLayoutResource() { - return R.layout.help_activity; + protected void initLayout() { + setContentView(R.layout.help_activity); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java index 1e413f5ac..f1677cb67 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java @@ -102,8 +102,8 @@ public class ImportKeysActivity extends BaseActivity { } @Override - protected int getLayoutResource() { - return R.layout.import_keys_activity; + protected void initLayout() { + setContentView(R.layout.import_keys_activity); } protected void handleActions(Bundle savedInstanceState, Intent intent) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java index 6b3cf5fe4..7d037f85d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java @@ -65,12 +65,12 @@ public class KeyListActivity extends DrawerActivity { mExportHelper = new ExportHelper(this); // now setup navigation drawer in DrawerActivity... -// activateDrawerNavigation(savedInstanceState); + activateDrawerNavigation(savedInstanceState); } @Override - protected int getLayoutResource() { - return R.layout.key_list_activity; + protected void initLayout() { + setContentView(R.layout.key_list_activity); } @Override diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayActivity.java index f5eac09b1..fd74e1654 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayActivity.java @@ -45,8 +45,8 @@ public class LogDisplayActivity extends BaseActivity { } @Override - protected int getLayoutResource() { - return R.layout.log_display_activity; + protected void initLayout() { + setContentView(R.layout.log_display_activity); } } \ No newline at end of file diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcActivity.java index 53b17654c..3a70502ea 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcActivity.java @@ -122,8 +122,8 @@ public class NfcActivity extends BaseActivity { } @Override - protected int getLayoutResource() { - return R.layout.nfc_activity; + protected void initLayout() { + setContentView(R.layout.nfc_activity); } /** diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcIntentActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcIntentActivity.java index bb5277119..945d98379 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcIntentActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcIntentActivity.java @@ -88,8 +88,8 @@ public class NfcIntentActivity extends BaseActivity { } @Override - protected int getLayoutResource() { - return R.layout.nfc_activity; + protected void initLayout() { + setContentView(R.layout.nfc_activity); } /** diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeViewActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeViewActivity.java index b0343a961..42ad2258a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeViewActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeViewActivity.java @@ -107,8 +107,8 @@ public class QrCodeViewActivity extends BaseActivity { } @Override - protected int getLayoutResource() { - return R.layout.qr_code_activity; + protected void initLayout() { + setContentView(R.layout.qr_code_activity); } @Override diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SafeSlingerActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SafeSlingerActivity.java index deecffeea..d5193b2a2 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SafeSlingerActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SafeSlingerActivity.java @@ -95,8 +95,8 @@ public class SafeSlingerActivity extends BaseActivity { } @Override - protected int getLayoutResource() { - return R.layout.safe_slinger_activity; + protected void initLayout() { + setContentView(R.layout.safe_slinger_activity); } private void startExchange(long masterKeyId, int number) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyActivity.java index 3ee1e14cc..f7e19706e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyActivity.java @@ -100,8 +100,8 @@ public class SelectPublicKeyActivity extends BaseActivity { } @Override - protected int getLayoutResource() { - return R.layout.select_public_key_activity; + protected void initLayout() { + setContentView(R.layout.select_public_key_activity); } @Override diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java index 297a35eb5..6cf346c97 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java @@ -85,8 +85,8 @@ public class UploadKeyActivity extends BaseActivity { } @Override - protected int getLayoutResource() { - return R.layout.upload_key_activity; + protected void initLayout() { + setContentView(R.layout.upload_key_activity); } private void uploadKey() { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java index 5dede6627..a88b0f7cf 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java @@ -111,8 +111,8 @@ public class ViewCertActivity extends BaseActivity } @Override - protected int getLayoutResource() { - return R.layout.view_cert_activity; + protected void initLayout() { + setContentView(R.layout.view_cert_activity); } @Override diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java index e441ff414..ae80679d0 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java @@ -168,8 +168,8 @@ public class ViewKeyActivity extends BaseActivity implements } @Override - protected int getLayoutResource() { - return R.layout.view_key_activity; + protected void initLayout() { + setContentView(R.layout.view_key_activity); } private void initTabs(Uri dataUri) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvancedActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvancedActivity.java index 9fdcaaaf9..7176232c5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvancedActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvancedActivity.java @@ -68,11 +68,10 @@ public class ViewKeyAdvancedActivity extends BaseActivity { } @Override - protected int getLayoutResource() { - return R.layout.view_key_advanced_activity; + protected void initLayout() { + setContentView(R.layout.view_key_advanced_activity); } - private void startFragment(Bundle savedInstanceState, Uri dataUri) { // However, if we're being restored from a previous state, // then we don't need to do anything and should return or else -- cgit v1.2.3 From 2b1c5358b77c88340639ae296dac01fdbf72295d Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Tue, 13 Jan 2015 23:09:48 +0100 Subject: make user_ids table typed, with attribute_data support Conflicts: OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java --- .../keychain/provider/KeychainContract.java | 10 ++- .../keychain/provider/KeychainDatabase.java | 35 ++++---- .../keychain/provider/KeychainProvider.java | 92 ++++++++++++++-------- .../keychain/provider/ProviderHelper.java | 19 +++-- .../keychain/ui/CertifyKeyFragment.java | 22 +++--- .../keychain/ui/EditKeyFragment.java | 3 +- .../keychain/ui/ViewKeyMainFragment.java | 4 +- .../keychain/ui/adapter/UserIdsAdapter.java | 16 ++-- .../keychain/util/ContactHelper.java | 7 +- 9 files changed, 120 insertions(+), 88 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java index 2c02e429d..f4e00c36c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java @@ -51,9 +51,11 @@ public class KeychainContract { String EXPIRY = "expiry"; } - interface UserIdsColumns { + interface UserPacketsColumns { String MASTER_KEY_ID = "master_key_id"; // foreign key to key_rings._ID + String TYPE = "type"; // not a database id String USER_ID = "user_id"; // not a database id + String ATTRIBUTE_DATA = "attribute_data"; // not a database id String RANK = "rank"; // ONLY used for sorting! no key, no nothing! String IS_PRIMARY = "is_primary"; String IS_REVOKED = "is_revoked"; @@ -105,7 +107,7 @@ public class KeychainContract { public static final String BASE_API_APPS = "api_apps"; public static final String PATH_ACCOUNTS = "accounts"; - public static class KeyRings implements BaseColumns, KeysColumns, UserIdsColumns { + public static class KeyRings implements BaseColumns, KeysColumns, UserPacketsColumns { public static final String MASTER_KEY_ID = KeysColumns.MASTER_KEY_ID; public static final String IS_REVOKED = KeysColumns.IS_REVOKED; public static final String VERIFIED = CertsColumns.VERIFIED; @@ -225,7 +227,7 @@ public class KeychainContract { } - public static class UserIds implements UserIdsColumns, BaseColumns { + public static class UserPackets implements UserPacketsColumns, BaseColumns { public static final String VERIFIED = "verified"; public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon() .appendPath(BASE_KEY_RINGS).build(); @@ -304,7 +306,7 @@ public class KeychainContract { } public static class Certs implements CertsColumns, BaseColumns { - public static final String USER_ID = UserIdsColumns.USER_ID; + public static final String USER_ID = UserPacketsColumns.USER_ID; public static final String SIGNER_UID = "signer_user_id"; public static final int UNVERIFIED = 0; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java index 84a50dc65..5ce5eec17 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java @@ -33,7 +33,7 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.ApiAppsColumns; import org.sufficientlysecure.keychain.provider.KeychainContract.CertsColumns; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingsColumns; import org.sufficientlysecure.keychain.provider.KeychainContract.KeysColumns; -import org.sufficientlysecure.keychain.provider.KeychainContract.UserIdsColumns; +import org.sufficientlysecure.keychain.provider.KeychainContract.UserPacketsColumns; import org.sufficientlysecure.keychain.ui.ConsolidateDialogActivity; import org.sufficientlysecure.keychain.util.Log; @@ -52,7 +52,7 @@ import java.io.IOException; */ public class KeychainDatabase extends SQLiteOpenHelper { private static final String DATABASE_NAME = "openkeychain.db"; - private static final int DATABASE_VERSION = 6; + private static final int DATABASE_VERSION = 7; static Boolean apgHack = false; private Context mContext; @@ -60,7 +60,7 @@ public class KeychainDatabase extends SQLiteOpenHelper { String KEY_RINGS_PUBLIC = "keyrings_public"; String KEY_RINGS_SECRET = "keyrings_secret"; String KEYS = "keys"; - String USER_IDS = "user_ids"; + String USER_PACKETS = "user_ids"; String CERTS = "certs"; String API_APPS = "api_apps"; String API_ACCOUNTS = "api_accounts"; @@ -106,18 +106,20 @@ public class KeychainDatabase extends SQLiteOpenHelper { + Tables.KEY_RINGS_PUBLIC + "(" + KeyRingsColumns.MASTER_KEY_ID + ") ON DELETE CASCADE" + ")"; - private static final String CREATE_USER_IDS = - "CREATE TABLE IF NOT EXISTS " + Tables.USER_IDS + "(" - + UserIdsColumns.MASTER_KEY_ID + " INTEGER, " - + UserIdsColumns.USER_ID + " TEXT, " + private static final String CREATE_USER_PACKETS = + "CREATE TABLE IF NOT EXISTS " + Tables.USER_PACKETS + "(" + + UserPacketsColumns.MASTER_KEY_ID + " INTEGER, " + + UserPacketsColumns.TYPE + " INT, " + + UserPacketsColumns.USER_ID + " TEXT, " + + UserPacketsColumns.ATTRIBUTE_DATA + " BLOB, " - + UserIdsColumns.IS_PRIMARY + " INTEGER, " - + UserIdsColumns.IS_REVOKED + " INTEGER, " - + UserIdsColumns.RANK+ " INTEGER, " + + UserPacketsColumns.IS_PRIMARY + " INTEGER, " + + UserPacketsColumns.IS_REVOKED + " INTEGER, " + + UserPacketsColumns.RANK+ " INTEGER, " - + "PRIMARY KEY(" + UserIdsColumns.MASTER_KEY_ID + ", " + UserIdsColumns.USER_ID + "), " - + "UNIQUE (" + UserIdsColumns.MASTER_KEY_ID + ", " + UserIdsColumns.RANK + "), " - + "FOREIGN KEY(" + UserIdsColumns.MASTER_KEY_ID + ") REFERENCES " + + "PRIMARY KEY(" + UserPacketsColumns.MASTER_KEY_ID + ", " + UserPacketsColumns.USER_ID + "), " + + "UNIQUE (" + UserPacketsColumns.MASTER_KEY_ID + ", " + UserPacketsColumns.RANK + "), " + + "FOREIGN KEY(" + UserPacketsColumns.MASTER_KEY_ID + ") REFERENCES " + Tables.KEY_RINGS_PUBLIC + "(" + KeyRingsColumns.MASTER_KEY_ID + ") ON DELETE CASCADE" + ")"; @@ -138,7 +140,7 @@ public class KeychainDatabase extends SQLiteOpenHelper { + "FOREIGN KEY(" + CertsColumns.MASTER_KEY_ID + ") REFERENCES " + Tables.KEY_RINGS_PUBLIC + "(" + KeyRingsColumns.MASTER_KEY_ID + ") ON DELETE CASCADE," + "FOREIGN KEY(" + CertsColumns.MASTER_KEY_ID + ", " + CertsColumns.RANK + ") REFERENCES " - + Tables.USER_IDS + "(" + UserIdsColumns.MASTER_KEY_ID + ", " + UserIdsColumns.RANK + ") ON DELETE CASCADE" + + Tables.USER_PACKETS + "(" + UserPacketsColumns.MASTER_KEY_ID + ", " + UserPacketsColumns.RANK + ") ON DELETE CASCADE" + ")"; private static final String CREATE_API_APPS = @@ -189,7 +191,7 @@ public class KeychainDatabase extends SQLiteOpenHelper { db.execSQL(CREATE_KEYRINGS_PUBLIC); db.execSQL(CREATE_KEYRINGS_SECRET); db.execSQL(CREATE_KEYS); - db.execSQL(CREATE_USER_IDS); + db.execSQL(CREATE_USER_PACKETS); db.execSQL(CREATE_CERTS); db.execSQL(CREATE_API_APPS); db.execSQL(CREATE_API_APPS_ACCOUNTS); @@ -238,6 +240,9 @@ public class KeychainDatabase extends SQLiteOpenHelper { case 5: // do consolidate for 3.0 beta3 // fall through + case 6: + db.execSQL("ALTER TABLE user_ids ADD COLUMN type INTEGER"); + db.execSQL("ALTER TABLE user_ids ADD COLUMN attribute_data BLOB"); } // always do consolidate after upgrade diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java index d40287690..13a923f03 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java @@ -37,7 +37,8 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.Certs; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.KeychainContract.Keys; -import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds; +import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets; +import org.sufficientlysecure.keychain.provider.KeychainContract.UserPacketsColumns; import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables; import org.sufficientlysecure.keychain.util.Log; @@ -205,7 +206,7 @@ public class KeychainProvider extends ContentProvider { return Keys.CONTENT_TYPE; case KEY_RING_USER_IDS: - return UserIds.CONTENT_TYPE; + return UserPackets.CONTENT_TYPE; case KEY_RING_SECRET: return KeyRings.CONTENT_ITEM_TYPE; @@ -262,7 +263,7 @@ public class KeychainProvider extends ContentProvider { projectionMap.put(KeyRings.EXPIRY, Tables.KEYS + "." + Keys.EXPIRY); projectionMap.put(KeyRings.ALGORITHM, Tables.KEYS + "." + Keys.ALGORITHM); projectionMap.put(KeyRings.FINGERPRINT, Tables.KEYS + "." + Keys.FINGERPRINT); - projectionMap.put(KeyRings.USER_ID, UserIds.USER_ID); + projectionMap.put(KeyRings.USER_ID, UserPackets.USER_ID); projectionMap.put(KeyRings.VERIFIED, KeyRings.VERIFIED); projectionMap.put(KeyRings.PUBKEY_DATA, Tables.KEY_RINGS_PUBLIC + "." + KeyRingData.KEY_RING_DATA @@ -296,11 +297,12 @@ public class KeychainProvider extends ContentProvider { qb.setTables( Tables.KEYS - + " INNER JOIN " + Tables.USER_IDS + " ON (" + + " INNER JOIN " + Tables.USER_PACKETS + " ON (" + Tables.KEYS + "." + Keys.MASTER_KEY_ID + " = " - + Tables.USER_IDS + "." + UserIds.MASTER_KEY_ID - + " AND " + Tables.USER_IDS + "." + UserIds.RANK + " = 0" + + Tables.USER_PACKETS + "." + UserPackets.MASTER_KEY_ID + // we KNOW that the rank zero user packet is a user id! + + " AND " + Tables.USER_PACKETS + "." + UserPackets.RANK + " = 0" + ") LEFT JOIN " + Tables.CERTS + " ON (" + Tables.KEYS + "." + Keys.MASTER_KEY_ID + " = " @@ -376,7 +378,7 @@ public class KeychainProvider extends ContentProvider { String subkey = Long.valueOf(uri.getLastPathSegment()).toString(); qb.appendWhere(" AND EXISTS (" + " SELECT 1 FROM " + Tables.KEYS + " AS tmp" - + " WHERE tmp." + UserIds.MASTER_KEY_ID + + " WHERE tmp." + UserPackets.MASTER_KEY_ID + " = " + Tables.KEYS + "." + Keys.MASTER_KEY_ID + " AND tmp." + Keys.KEY_ID + " = " + subkey + "" + ")"); @@ -398,15 +400,15 @@ public class KeychainProvider extends ContentProvider { if (i != 0) { emailWhere += " OR "; } - emailWhere += "tmp." + UserIds.USER_ID + " LIKE "; + emailWhere += "tmp." + UserPackets.USER_ID + " LIKE "; // match '*', so it has to be at the *end* of the user id emailWhere += DatabaseUtils.sqlEscapeString("%<" + chunks[i] + ">"); gotCondition = true; } if(gotCondition) { qb.appendWhere(" AND EXISTS (" - + " SELECT 1 FROM " + Tables.USER_IDS + " AS tmp" - + " WHERE tmp." + UserIds.MASTER_KEY_ID + + " SELECT 1 FROM " + Tables.USER_PACKETS + " AS tmp" + + " WHERE tmp." + UserPackets.MASTER_KEY_ID + " = " + Tables.KEYS + "." + Keys.MASTER_KEY_ID + " AND (" + emailWhere + ")" + ")"); @@ -420,7 +422,7 @@ public class KeychainProvider extends ContentProvider { } if (TextUtils.isEmpty(sortOrder)) { - sortOrder = Tables.USER_IDS + "." + UserIds.USER_ID + " ASC"; + sortOrder = Tables.USER_PACKETS + "." + UserPackets.USER_ID + " ASC"; } // uri to watch is all /key_rings/ @@ -459,36 +461,42 @@ public class KeychainProvider extends ContentProvider { case KEY_RINGS_USER_IDS: case KEY_RING_USER_IDS: { HashMap projectionMap = new HashMap(); - projectionMap.put(UserIds._ID, Tables.USER_IDS + ".oid AS _id"); - projectionMap.put(UserIds.MASTER_KEY_ID, Tables.USER_IDS + "." + UserIds.MASTER_KEY_ID); - projectionMap.put(UserIds.USER_ID, Tables.USER_IDS + "." + UserIds.USER_ID); - projectionMap.put(UserIds.RANK, Tables.USER_IDS + "." + UserIds.RANK); - projectionMap.put(UserIds.IS_PRIMARY, Tables.USER_IDS + "." + UserIds.IS_PRIMARY); - projectionMap.put(UserIds.IS_REVOKED, Tables.USER_IDS + "." + UserIds.IS_REVOKED); + projectionMap.put(UserPackets._ID, Tables.USER_PACKETS + ".oid AS _id"); + projectionMap.put(UserPackets.MASTER_KEY_ID, Tables.USER_PACKETS + "." + UserPackets.MASTER_KEY_ID); + projectionMap.put(UserPackets.TYPE, Tables.USER_PACKETS + "." + UserPackets.TYPE); + projectionMap.put(UserPackets.USER_ID, Tables.USER_PACKETS + "." + UserPackets.USER_ID); + projectionMap.put(UserPackets.ATTRIBUTE_DATA, Tables.USER_PACKETS + "." + UserPackets.ATTRIBUTE_DATA); + projectionMap.put(UserPackets.RANK, Tables.USER_PACKETS + "." + UserPackets.RANK); + projectionMap.put(UserPackets.IS_PRIMARY, Tables.USER_PACKETS + "." + UserPackets.IS_PRIMARY); + projectionMap.put(UserPackets.IS_REVOKED, Tables.USER_PACKETS + "." + UserPackets.IS_REVOKED); // we take the minimum (>0) here, where "1" is "verified by known secret key" - projectionMap.put(UserIds.VERIFIED, "MIN(" + Certs.VERIFIED + ") AS " + UserIds.VERIFIED); + projectionMap.put(UserPackets.VERIFIED, "MIN(" + Certs.VERIFIED + ") AS " + UserPackets.VERIFIED); qb.setProjectionMap(projectionMap); - qb.setTables(Tables.USER_IDS + qb.setTables(Tables.USER_PACKETS + " LEFT JOIN " + Tables.CERTS + " ON (" - + Tables.USER_IDS + "." + UserIds.MASTER_KEY_ID + " = " + + Tables.USER_PACKETS + "." + UserPackets.MASTER_KEY_ID + " = " + Tables.CERTS + "." + Certs.MASTER_KEY_ID - + " AND " + Tables.USER_IDS + "." + UserIds.RANK + " = " + + " AND " + Tables.USER_PACKETS + "." + UserPackets.RANK + " = " + Tables.CERTS + "." + Certs.RANK + " AND " + Tables.CERTS + "." + Certs.VERIFIED + " > 0" + ")"); - groupBy = Tables.USER_IDS + "." + UserIds.MASTER_KEY_ID - + ", " + Tables.USER_IDS + "." + UserIds.RANK; + groupBy = Tables.USER_PACKETS + "." + UserPackets.MASTER_KEY_ID + + ", " + Tables.USER_PACKETS + "." + UserPackets.RANK; + + // for now, we only respect user ids here, so TYPE must be NULL + // TODO expand with KEY_RING_USER_PACKETS query type which lifts this restriction + qb.appendWhere(Tables.USER_PACKETS + "." + UserPackets.TYPE + " IS NULL AND "); // If we are searching for a particular keyring's ids, add where if (match == KEY_RING_USER_IDS) { - qb.appendWhere(Tables.USER_IDS + "." + UserIds.MASTER_KEY_ID + " = "); + qb.appendWhere(Tables.USER_PACKETS + "." + UserPackets.MASTER_KEY_ID + " = "); qb.appendWhereEscapeString(uri.getPathSegments().get(1)); } if (TextUtils.isEmpty(sortOrder)) { - sortOrder = Tables.USER_IDS + "." + UserIds.MASTER_KEY_ID + " ASC" - + "," + Tables.USER_IDS + "." + UserIds.RANK + " ASC"; + sortOrder = Tables.USER_PACKETS + "." + UserPackets.MASTER_KEY_ID + " ASC" + + "," + Tables.USER_PACKETS + "." + UserPackets.RANK + " ASC"; } break; @@ -542,20 +550,24 @@ public class KeychainProvider extends ContentProvider { projectionMap.put(Certs.CREATION, Tables.CERTS + "." + Certs.CREATION); projectionMap.put(Certs.KEY_ID_CERTIFIER, Tables.CERTS + "." + Certs.KEY_ID_CERTIFIER); projectionMap.put(Certs.DATA, Tables.CERTS + "." + Certs.DATA); - projectionMap.put(Certs.USER_ID, Tables.USER_IDS + "." + UserIds.USER_ID); - projectionMap.put(Certs.SIGNER_UID, "signer." + UserIds.USER_ID + " AS " + Certs.SIGNER_UID); + projectionMap.put(Certs.USER_ID, Tables.USER_PACKETS + "." + UserPackets.USER_ID); + projectionMap.put(Certs.SIGNER_UID, "signer." + UserPackets.USER_ID + " AS " + Certs.SIGNER_UID); qb.setProjectionMap(projectionMap); qb.setTables(Tables.CERTS - + " JOIN " + Tables.USER_IDS + " ON (" + + " JOIN " + Tables.USER_PACKETS + " ON (" + Tables.CERTS + "." + Certs.MASTER_KEY_ID + " = " - + Tables.USER_IDS + "." + UserIds.MASTER_KEY_ID + + Tables.USER_PACKETS + "." + UserPackets.MASTER_KEY_ID + " AND " + Tables.CERTS + "." + Certs.RANK + " = " - + Tables.USER_IDS + "." + UserIds.RANK - + ") LEFT JOIN " + Tables.USER_IDS + " AS signer ON (" + + Tables.USER_PACKETS + "." + UserPackets.RANK + // for now, we only return user ids here, so TYPE must be NULL + // TODO at some point, we should lift this restriction + + " AND " + + Tables.USER_PACKETS + "." + UserPackets.TYPE + " IS NULL" + + ") LEFT JOIN " + Tables.USER_PACKETS + " AS signer ON (" + Tables.CERTS + "." + Certs.KEY_ID_CERTIFIER + " = " - + "signer." + UserIds.MASTER_KEY_ID + + "signer." + UserPackets.MASTER_KEY_ID + " AND " + "signer." + Keys.RANK + " = 0" + ")"); @@ -662,8 +674,18 @@ public class KeychainProvider extends ContentProvider { break; case KEY_RING_USER_IDS: - db.insertOrThrow(Tables.USER_IDS, null, values); - keyId = values.getAsLong(UserIds.MASTER_KEY_ID); + // iff TYPE is null, user_id MUST be null as well + if ( ! (values.get(UserPacketsColumns.TYPE) == null + ? (values.get(UserPacketsColumns.USER_ID) != null && values.get(UserPacketsColumns.ATTRIBUTE_DATA) == null) + : (values.get(UserPacketsColumns.ATTRIBUTE_DATA) != null && values.get(UserPacketsColumns.USER_ID) == null) + )) { + throw new AssertionError("Incorrect type for user packet! This is a bug!"); + } + if (values.get(UserPacketsColumns.RANK) == 0 && values.get(UserPacketsColumns.USER_ID) == null) { + throw new AssertionError("Rank 0 user packet must be a user id!"); + } + db.insertOrThrow(Tables.USER_PACKETS, null, values); + keyId = values.getAsLong(UserPackets.MASTER_KEY_ID); break; case KEY_RING_CERTS: diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java index 4f1b4b6c1..b3f98117d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java @@ -31,6 +31,7 @@ import android.support.v4.util.LongSparseArray; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.operations.results.ImportKeyResult; +import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.util.ParcelableFileCache.IteratorWithSize; import org.sufficientlysecure.keychain.util.Preferences; @@ -53,7 +54,6 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.Certs; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.KeychainContract.Keys; -import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds; import org.sufficientlysecure.keychain.remote.AccountSettings; import org.sufficientlysecure.keychain.remote.AppSettings; import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; @@ -1236,13 +1236,16 @@ public class ProviderHelper { private ContentProviderOperation buildUserIdOperations(long masterKeyId, UserIdItem item, int rank) { ContentValues values = new ContentValues(); - values.put(UserIds.MASTER_KEY_ID, masterKeyId); - values.put(UserIds.USER_ID, item.userId); - values.put(UserIds.IS_PRIMARY, item.isPrimary); - values.put(UserIds.IS_REVOKED, item.isRevoked); - values.put(UserIds.RANK, rank); - - Uri uri = UserIds.buildUserIdsUri(masterKeyId); + values.put(UserPackets.MASTER_KEY_ID, masterKeyId); + values.put(UserPackets.USER_ID, item.userId); + values.put(UserPackets.IS_PRIMARY, item.isPrimary); + values.put(UserPackets.IS_REVOKED, item.isRevoked); + values.put(UserPackets.RANK, rank); + // we explicitly set these to null here, to indicate that this is a user id, not an attribute + values.put(UserPackets.TYPE, (String) null); + values.put(UserPackets.ATTRIBUTE_DATA, (String) null); + + Uri uri = UserPackets.buildUserIdsUri(masterKeyId); return ContentProviderOperation.newInsert(uri).withValues(values).build(); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java index 4d10d8639..841485c7c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java @@ -49,7 +49,7 @@ import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.pgp.KeyRing; import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing; -import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds; +import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets; import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.service.CertifyActionsParcel; @@ -82,11 +82,11 @@ public class CertifyKeyFragment extends LoaderFragment private long mSignMasterKeyId = Constants.key.none; public static final String[] USER_IDS_PROJECTION = new String[]{ - UserIds._ID, - UserIds.MASTER_KEY_ID, - UserIds.USER_ID, - UserIds.IS_PRIMARY, - UserIds.IS_REVOKED + UserPackets._ID, + UserPackets.MASTER_KEY_ID, + UserPackets.USER_ID, + UserPackets.IS_PRIMARY, + UserPackets.IS_REVOKED }; private static final int INDEX_MASTER_KEY_ID = 1; private static final int INDEX_USER_ID = 2; @@ -182,7 +182,7 @@ public class CertifyKeyFragment extends LoaderFragment @Override public Loader onCreateLoader(int id, Bundle args) { - Uri uri = UserIds.buildUserIdsUri(); + Uri uri = UserPackets.buildUserIdsUri(); String selection, ids[]; { @@ -196,15 +196,15 @@ public class CertifyKeyFragment extends LoaderFragment } } // put together selection string - selection = UserIds.IS_REVOKED + " = 0" + " AND " - + Tables.USER_IDS + "." + UserIds.MASTER_KEY_ID + selection = UserPackets.IS_REVOKED + " = 0" + " AND " + + Tables.USER_PACKETS + "." + UserPackets.MASTER_KEY_ID + " IN (" + placeholders + ")"; } return new CursorLoader(getActivity(), uri, USER_IDS_PROJECTION, selection, ids, - Tables.USER_IDS + "." + UserIds.MASTER_KEY_ID + " ASC" - + ", " + Tables.USER_IDS + "." + UserIds.USER_ID + " ASC" + Tables.USER_PACKETS + "." + UserPackets.MASTER_KEY_ID + " ASC" + + ", " + Tables.USER_PACKETS + "." + UserPackets.USER_ID + " ASC" ); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java index 0f4bfefd4..afe6afb3c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java @@ -47,6 +47,7 @@ import org.sufficientlysecure.keychain.pgp.KeyRing; import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing; import org.sufficientlysecure.keychain.provider.KeychainContract; +import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.provider.ProviderHelper.NotFoundException; import org.sufficientlysecure.keychain.service.KeychainIntentService; @@ -334,7 +335,7 @@ public class EditKeyFragment extends LoaderFragment implements switch (id) { case LOADER_ID_USER_IDS: { - Uri baseUri = KeychainContract.UserIds.buildUserIdsUri(mDataUri); + Uri baseUri = UserPackets.buildUserIdsUri(mDataUri); return new CursorLoader(getActivity(), baseUri, UserIdsAdapter.USER_IDS_PROJECTION, null, null, null); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java index f1453c40c..205d19628 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java @@ -37,10 +37,10 @@ import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround; import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; +import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; -import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.provider.ProviderHelper.NotFoundException; import org.sufficientlysecure.keychain.ui.adapter.UserIdsAdapter; @@ -199,7 +199,7 @@ public class ViewKeyMainFragment extends LoaderFragment implements return new CursorLoader(getActivity(), baseUri, UNIFIED_PROJECTION, null, null, null); } case LOADER_ID_USER_IDS: { - Uri baseUri = UserIds.buildUserIdsUri(mDataUri); + Uri baseUri = UserPackets.buildUserIdsUri(mDataUri); return new CursorLoader(getActivity(), baseUri, UserIdsAdapter.USER_IDS_PROJECTION, null, null, null); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java index a2e1930d3..a778c7fa7 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java @@ -19,7 +19,6 @@ package org.sufficientlysecure.keychain.ui.adapter; import android.content.Context; import android.database.Cursor; -import android.graphics.PorterDuff; import android.graphics.Typeface; import android.support.v4.widget.CursorAdapter; import android.view.LayoutInflater; @@ -32,10 +31,9 @@ import android.widget.ImageView; import android.widget.TextView; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.ui.util.FormattingUtils; +import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets; import org.sufficientlysecure.keychain.pgp.KeyRing; import org.sufficientlysecure.keychain.provider.KeychainContract.Certs; -import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds; import org.sufficientlysecure.keychain.service.SaveKeyringParcel; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; @@ -47,12 +45,12 @@ public class UserIdsAdapter extends CursorAdapter implements AdapterView.OnItemC private SaveKeyringParcel mSaveKeyringParcel; public static final String[] USER_IDS_PROJECTION = new String[]{ - UserIds._ID, - UserIds.USER_ID, - UserIds.RANK, - UserIds.VERIFIED, - UserIds.IS_PRIMARY, - UserIds.IS_REVOKED + UserPackets._ID, + UserPackets.USER_ID, + UserPackets.RANK, + UserPackets.VERIFIED, + UserPackets.IS_PRIMARY, + UserPackets.IS_REVOKED }; private static final int INDEX_ID = 0; private static final int INDEX_USER_ID = 1; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ContactHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ContactHelper.java index 1c4eece6b..4ce7a1bac 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ContactHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ContactHelper.java @@ -35,6 +35,7 @@ import android.util.Patterns; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.pgp.KeyRing; +import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.provider.KeychainContract; @@ -57,10 +58,10 @@ public class ContactHelper { KeychainContract.KeyRings.EXPIRY, KeychainContract.KeyRings.IS_REVOKED}; public static final String[] USER_IDS_PROJECTION = new String[]{ - KeychainContract.UserIds.USER_ID + UserPackets.USER_ID }; - public static final String NON_REVOKED_SELECTION = KeychainContract.UserIds.IS_REVOKED + "=0"; + public static final String NON_REVOKED_SELECTION = UserPackets.IS_REVOKED + "=0"; public static final String[] ID_PROJECTION = new String[]{ContactsContract.RawContacts._ID}; public static final String[] SOURCE_ID_PROJECTION = new String[]{ContactsContract.RawContacts.SOURCE_ID}; @@ -413,7 +414,7 @@ public class ContactHelper { int rawContactId, long masterKeyId) { ops.add(selectByRawContactAndItemType(ContentProviderOperation.newDelete(ContactsContract.Data.CONTENT_URI), rawContactId, ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE).build()); - Cursor ids = resolver.query(KeychainContract.UserIds.buildUserIdsUri(masterKeyId), + Cursor ids = resolver.query(UserPackets.buildUserIdsUri(masterKeyId), USER_IDS_PROJECTION, NON_REVOKED_SELECTION, null, null); if (ids != null) { while (ids.moveToNext()) { -- cgit v1.2.3 From c57355b24a33200b1d6c35bfcac92d4c5bdfa908 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Wed, 14 Jan 2015 00:00:04 +0100 Subject: actually import user attributes (though they are not shown anywhere yet) --- .../operations/results/OperationResult.java | 12 ++ .../keychain/pgp/PgpKeyOperation.java | 2 +- .../keychain/pgp/UncachedPublicKey.java | 30 +++++ .../keychain/pgp/WrappedSignature.java | 3 + .../keychain/pgp/WrappedUserAttribute.java | 21 +++- .../keychain/provider/KeychainProvider.java | 4 +- .../keychain/provider/ProviderHelper.java | 129 +++++++++++++++++++-- 7 files changed, 185 insertions(+), 16 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java index 9824173f5..556d70cb2 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java @@ -343,6 +343,18 @@ public abstract class OperationResult implements Parcelable { MSG_IP_UID_REORDER(LogLevel.DEBUG, R.string.msg_ip_uid_reorder), MSG_IP_UID_PROCESSING (LogLevel.DEBUG, R.string.msg_ip_uid_processing), MSG_IP_UID_REVOKED (LogLevel.DEBUG, R.string.msg_ip_uid_revoked), + MSG_IP_UAT_CLASSIFYING (LogLevel.DEBUG, R.string.msg_ip_uat_classifying), + MSG_IP_UAT_PROCESSING_IMAGE (LogLevel.DEBUG, R.string.msg_ip_uat_processing_image), + MSG_IP_UAT_PROCESSING_UNKNOWN (LogLevel.DEBUG, R.string.msg_ip_uat_processing_unknown), + MSG_IP_UAT_REVOKED (LogLevel.DEBUG, R.string.msg_ip_uat_revoked), + MSG_IP_UAT_CERT_BAD (LogLevel.WARN, R.string.msg_ip_uat_cert_bad), + MSG_IP_UAT_CERT_OLD (LogLevel.DEBUG, R.string.msg_ip_uat_cert_old), + MSG_IP_UAT_CERT_NONREVOKE (LogLevel.DEBUG, R.string.msg_ip_uat_cert_nonrevoke), + MSG_IP_UAT_CERT_NEW (LogLevel.DEBUG, R.string.msg_ip_uat_cert_new), + MSG_IP_UAT_CERT_ERROR (LogLevel.WARN, R.string.msg_ip_uat_cert_error), + MSG_IP_UAT_CERTS_UNKNOWN (LogLevel.DEBUG, R.plurals.msg_ip_uat_certs_unknown), + MSG_IP_UAT_CERT_GOOD_REVOKE (LogLevel.DEBUG, R.string.msg_ip_uat_cert_good_revoke), + MSG_IP_UAT_CERT_GOOD (LogLevel.DEBUG, R.string.msg_ip_uat_cert_good), // import secret MSG_IS(LogLevel.START, R.string.msg_is), diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java index 8facbfd2a..18a5410bf 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java @@ -531,7 +531,7 @@ public class PgpKeyOperation { WrappedUserAttribute attribute = saveParcel.mAddUserAttribute.get(i); switch (attribute.getType()) { - case WrappedUserAttribute.UAT_UNKNOWN: + case WrappedUserAttribute.UAT_NONE: log.add(LogType.MSG_MF_UAT_ADD_UNKNOWN, indent); break; case WrappedUserAttribute.UAT_IMAGE: diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java index fe3ab96a5..9e3528515 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java @@ -24,6 +24,7 @@ import org.spongycastle.bcpg.sig.KeyFlags; import org.spongycastle.openpgp.PGPPublicKey; import org.spongycastle.openpgp.PGPSignature; import org.spongycastle.openpgp.PGPSignatureSubpacketVector; +import org.spongycastle.openpgp.PGPUserAttributeSubpacketVector; import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.util.IterableIterator; @@ -215,6 +216,15 @@ public class UncachedPublicKey { return userIds; } + public ArrayList getUnorderedUserAttributes() { + ArrayList userAttributes = new ArrayList(); + for (PGPUserAttributeSubpacketVector userAttribute : + new IterableIterator(mPublicKey.getUserAttributes())) { + userAttributes.add(new WrappedUserAttribute(userAttribute)); + } + return userAttributes; + } + public boolean isElGamalEncrypt() { return getAlgorithm() == PGPPublicKey.ELGAMAL_ENCRYPT; } @@ -270,6 +280,25 @@ public class UncachedPublicKey { } } + public Iterator getSignaturesForUserAttribute(WrappedUserAttribute attribute) { + final Iterator it = mPublicKey.getSignaturesForUserAttribute(attribute.getVector()); + if (it != null) { + return new Iterator() { + public void remove() { + it.remove(); + } + public WrappedSignature next() { + return new WrappedSignature(it.next()); + } + public boolean hasNext() { + return it.hasNext(); + } + }; + } else { + return null; + } + } + /** Get all key usage flags. * If at least one key flag subpacket is present return these. If no * subpacket is present it returns null. @@ -299,4 +328,5 @@ public class UncachedPublicKey { } return mCacheUsage; } + } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java index 3dc02d3ed..cb03970e2 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java @@ -214,6 +214,9 @@ public class WrappedSignature { public boolean verifySignature(CanonicalizedPublicKey key, String uid) throws PgpGeneralException { return verifySignature(key.getPublicKey(), uid); } + public boolean verifySignature(UncachedPublicKey key, WrappedUserAttribute attribute) throws PgpGeneralException { + return verifySignature(key.getPublicKey(), attribute.getVector()); + } public static WrappedSignature fromBytes(byte[] data) { PGPObjectFactory factory = new PGPObjectFactory(data); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedUserAttribute.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedUserAttribute.java index 2359d48ac..248ef11aa 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedUserAttribute.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedUserAttribute.java @@ -33,7 +33,7 @@ import java.io.Serializable; public class WrappedUserAttribute implements Serializable { - public static final int UAT_UNKNOWN = 0; + public static final int UAT_NONE = 0; public static final int UAT_IMAGE = UserAttributeSubpacketTags.IMAGE_ATTRIBUTE; private PGPUserAttributeSubpacketVector mVector; @@ -47,8 +47,9 @@ public class WrappedUserAttribute implements Serializable { } public int getType() { - if (mVector.getSubpacket(UserAttributeSubpacketTags.IMAGE_ATTRIBUTE) != null) { - return UAT_IMAGE; + UserAttributeSubpacket[] subpackets = mVector.toSubpacketArray(); + if (subpackets.length > 0) { + return subpackets[0].getType(); } return 0; } @@ -62,6 +63,20 @@ public class WrappedUserAttribute implements Serializable { } + public byte[] getEncoded () throws IOException { + UserAttributeSubpacket[] subpackets = mVector.toSubpacketArray(); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + for (UserAttributeSubpacket subpacket : subpackets) { + subpacket.encode(out); + } + return out.toByteArray(); + } + + public static WrappedUserAttribute fromData (byte[] data) { + // TODO + return null; + } + /** Writes this object to an ObjectOutputStream. */ private void writeObject(java.io.ObjectOutputStream out) throws IOException { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java index 13a923f03..29b9c5f9f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java @@ -486,10 +486,12 @@ public class KeychainProvider extends ContentProvider { // for now, we only respect user ids here, so TYPE must be NULL // TODO expand with KEY_RING_USER_PACKETS query type which lifts this restriction - qb.appendWhere(Tables.USER_PACKETS + "." + UserPackets.TYPE + " IS NULL AND "); + qb.appendWhere(Tables.USER_PACKETS + "." + UserPackets.TYPE + " IS NULL"); // If we are searching for a particular keyring's ids, add where if (match == KEY_RING_USER_IDS) { + // TODO remove with the thing above + qb.appendWhere(" AND "); qb.appendWhere(Tables.USER_PACKETS + "." + UserPackets.MASTER_KEY_ID + " = "); qb.appendWhereEscapeString(uri.getPathSegments().get(1)); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java index b3f98117d..c3990229d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java @@ -31,6 +31,7 @@ import android.support.v4.util.LongSparseArray; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.operations.results.ImportKeyResult; +import org.sufficientlysecure.keychain.pgp.WrappedUserAttribute; import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.util.ParcelableFileCache.IteratorWithSize; @@ -439,18 +440,18 @@ public class ProviderHelper { // classify and order user ids. primary are moved to the front, revoked to the back, // otherwise the order in the keyfile is preserved. + List uids = new ArrayList(); + if (trustedKeys.size() == 0) { log(LogType.MSG_IP_UID_CLASSIFYING_ZERO); } else { log(LogType.MSG_IP_UID_CLASSIFYING, trustedKeys.size()); } mIndent += 1; - List uids = new ArrayList(); - for (byte[] rawUserId : new IterableIterator( - masterKey.getUnorderedRawUserIds().iterator())) { + for (byte[] rawUserId : masterKey.getUnorderedRawUserIds()) { String userId = Utf8Util.fromUTF8ByteArrayReplaceBadEncoding(rawUserId); - UserIdItem item = new UserIdItem(); + UserPacketItem item = new UserPacketItem(); uids.add(item); item.userId = userId; @@ -533,6 +534,105 @@ public class ProviderHelper { } mIndent -= 1; + ArrayList userAttributes = masterKey.getUnorderedUserAttributes(); + // Don't spam the log if there aren't even any attributes + if ( ! userAttributes.isEmpty()) { + log(LogType.MSG_IP_UAT_CLASSIFYING); + } + + mIndent += 1; + for (WrappedUserAttribute userAttribute : userAttributes) { + + UserPacketItem item = new UserPacketItem(); + uids.add(item); + item.type = userAttribute.getType(); + item.attributeData = userAttribute.getEncoded(); + + int unknownCerts = 0; + + switch (item.type) { + case WrappedUserAttribute.UAT_IMAGE: + log(LogType.MSG_IP_UAT_PROCESSING_IMAGE); + break; + default: + log(LogType.MSG_IP_UAT_PROCESSING_UNKNOWN); + break; + } + mIndent += 1; + // look through signatures for this specific key + for (WrappedSignature cert : new IterableIterator( + masterKey.getSignaturesForUserAttribute(userAttribute))) { + long certId = cert.getKeyId(); + // self signature + if (certId == masterKeyId) { + + // NOTE self-certificates are already verified during canonicalization, + // AND we know there is at most one cert plus at most one revocation + if (!cert.isRevocation()) { + item.selfCert = cert; + } else { + item.isRevoked = true; + log(LogType.MSG_IP_UAT_REVOKED); + } + continue; + + } + + // do we have a trusted key for this? + if (trustedKeys.indexOfKey(certId) < 0) { + unknownCerts += 1; + continue; + } + + // verify signatures from known private keys + CanonicalizedPublicKey trustedKey = trustedKeys.get(certId); + + try { + cert.init(trustedKey); + // if it doesn't certify, leave a note and skip + if ( ! cert.verifySignature(masterKey, userAttribute)) { + log(LogType.MSG_IP_UAT_CERT_BAD); + continue; + } + + log(cert.isRevocation() + ? LogType.MSG_IP_UAT_CERT_GOOD_REVOKE + : LogType.MSG_IP_UAT_CERT_GOOD, + KeyFormattingUtils.convertKeyIdToHexShort(trustedKey.getKeyId()) + ); + + // check if there is a previous certificate + WrappedSignature prev = item.trustedCerts.get(cert.getKeyId()); + if (prev != null) { + // if it's newer, skip this one + if (prev.getCreationTime().after(cert.getCreationTime())) { + log(LogType.MSG_IP_UAT_CERT_OLD); + continue; + } + // if the previous one was a non-revokable certification, no need to look further + if (!prev.isRevocation() && !prev.isRevokable()) { + log(LogType.MSG_IP_UAT_CERT_NONREVOKE); + continue; + } + log(LogType.MSG_IP_UAT_CERT_NEW); + } + item.trustedCerts.put(cert.getKeyId(), cert); + + } catch (PgpGeneralException e) { + log(LogType.MSG_IP_UAT_CERT_ERROR, + KeyFormattingUtils.convertKeyIdToHex(cert.getKeyId())); + } + + } + + if (unknownCerts > 0) { + log(LogType.MSG_IP_UAT_CERTS_UNKNOWN, unknownCerts); + } + mIndent -= 1; + + } + mIndent -= 1; + progress.setProgress(LogType.MSG_IP_UID_REORDER.getMsgId(), 65, 100); log(LogType.MSG_IP_UID_REORDER); // primary before regular before revoked (see UserIdItem.compareTo) @@ -540,7 +640,7 @@ public class ProviderHelper { Collections.sort(uids); // iterate and put into db for (int userIdRank = 0; userIdRank < uids.size(); userIdRank++) { - UserIdItem item = uids.get(userIdRank); + UserPacketItem item = uids.get(userIdRank); operations.add(buildUserIdOperations(masterKeyId, item, userIdRank)); if (item.selfCert != null) { // TODO get rid of "self verified" status? this cannot even happen anymore! @@ -605,15 +705,23 @@ public class ProviderHelper { } - private static class UserIdItem implements Comparable { + private static class UserPacketItem implements Comparable { + Integer type; String userId; + byte[] attributeData; boolean isPrimary = false; boolean isRevoked = false; WrappedSignature selfCert; LongSparseArray trustedCerts = new LongSparseArray(); @Override - public int compareTo(UserIdItem o) { + public int compareTo(UserPacketItem o) { + // if one is a user id, but the other isn't, the user id always comes first. + // we compare for null values here, so != is the correct operator! + // noinspection NumberEquality + if (type != o.type) { + return type == null ? -1 : 1; + } // if one key is primary but the other isn't, the primary one always comes first if (isPrimary != o.isPrimary) { return isPrimary ? -1 : 1; @@ -1234,16 +1342,15 @@ public class ProviderHelper { * Build ContentProviderOperation to add PublicUserIds to database corresponding to a keyRing */ private ContentProviderOperation - buildUserIdOperations(long masterKeyId, UserIdItem item, int rank) { + buildUserIdOperations(long masterKeyId, UserPacketItem item, int rank) { ContentValues values = new ContentValues(); values.put(UserPackets.MASTER_KEY_ID, masterKeyId); + values.put(UserPackets.TYPE, item.type); values.put(UserPackets.USER_ID, item.userId); + values.put(UserPackets.ATTRIBUTE_DATA, item.attributeData); values.put(UserPackets.IS_PRIMARY, item.isPrimary); values.put(UserPackets.IS_REVOKED, item.isRevoked); values.put(UserPackets.RANK, rank); - // we explicitly set these to null here, to indicate that this is a user id, not an attribute - values.put(UserPackets.TYPE, (String) null); - values.put(UserPackets.ATTRIBUTE_DATA, (String) null); Uri uri = UserPackets.buildUserIdsUri(masterKeyId); -- cgit v1.2.3 From 5517b4f8cf471c29dd881baec58efd450f6cd5ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Wed, 14 Jan 2015 02:03:20 +0100 Subject: Launcher icon fixes --- .../org/sufficientlysecure/keychain/ui/PreferencesActivity.java | 6 +----- .../keychain/ui/PreferencesKeyServerActivity.java | 9 ++++++--- 2 files changed, 7 insertions(+), 8 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesActivity.java index 51fac4779..1769caa47 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesActivity.java @@ -20,7 +20,6 @@ package org.sufficientlysecure.keychain.ui; 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; @@ -33,8 +32,8 @@ import org.spongycastle.bcpg.HashAlgorithmTags; import org.spongycastle.openpgp.PGPEncryptedData; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.util.Preferences; import org.sufficientlysecure.keychain.ui.widget.IntegerListPreference; +import org.sufficientlysecure.keychain.util.Preferences; import java.util.List; @@ -130,9 +129,6 @@ public class PreferencesActivity extends PreferenceActivity { initializeUseNumKeypadForYubikeyPin( (CheckBoxPreference) findPreference(Constants.Pref.USE_NUMKEYPAD_FOR_YUBIKEY_PIN)); - } else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) { - // Load the legacy preferences headers - addPreferencesFromResource(R.xml.preference_headers_legacy); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesKeyServerActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesKeyServerActivity.java index 2a8ef171c..9e2e443af 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesKeyServerActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesKeyServerActivity.java @@ -35,7 +35,7 @@ import org.sufficientlysecure.keychain.ui.widget.KeyServerEditor; import java.util.Vector; -public class PreferencesKeyServerActivity extends ActionBarActivity implements OnClickListener, +public class PreferencesKeyServerActivity extends BaseActivity implements OnClickListener, EditorListener { public static final String EXTRA_KEY_SERVERS = "key_servers"; @@ -68,8 +68,6 @@ public class PreferencesKeyServerActivity extends ActionBarActivity implements O } ); - setContentView(R.layout.key_server_preference); - mInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); mTitle = (TextView) findViewById(R.id.title); @@ -102,6 +100,11 @@ public class PreferencesKeyServerActivity extends ActionBarActivity implements O makeServerList(servers); } + @Override + protected void initLayout() { + setContentView(R.layout.key_server_preference); + } + private void makeServerList(String[] servers) { if (servers != null) { mEditors.removeAllViews(); -- cgit v1.2.3 From d9e0f0a2719c948312ced8bcfe74f71ca9bb48c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Wed, 14 Jan 2015 10:35:40 +0100 Subject: Fix Toolbars in decrypt activities --- .../org/sufficientlysecure/keychain/ui/DecryptFilesActivity.java | 9 ++++++--- .../org/sufficientlysecure/keychain/ui/DecryptTextActivity.java | 9 ++++++--- 2 files changed, 12 insertions(+), 6 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesActivity.java index 9d972d8c0..59159929c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesActivity.java @@ -27,7 +27,7 @@ import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.api.OpenKeychainIntents; import org.sufficientlysecure.keychain.util.Log; -public class DecryptFilesActivity extends ActionBarActivity { +public class DecryptFilesActivity extends BaseActivity { /* Intents */ public static final String ACTION_DECRYPT_DATA = OpenKeychainIntents.DECRYPT_DATA; @@ -41,12 +41,15 @@ public class DecryptFilesActivity extends ActionBarActivity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.decrypt_files_activity); - // Handle intent actions handleActions(savedInstanceState, getIntent()); } + @Override + protected void initLayout() { + setContentView(R.layout.decrypt_files_activity); + } + /** * Handles all actions with this intent * diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextActivity.java index 2da76088a..285078dbf 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextActivity.java @@ -35,7 +35,7 @@ import org.sufficientlysecure.keychain.ui.util.Notify; import java.util.regex.Matcher; -public class DecryptTextActivity extends ActionBarActivity { +public class DecryptTextActivity extends BaseActivity { /* Intents */ public static final String ACTION_DECRYPT_TEXT = OpenKeychainIntents.DECRYPT_TEXT; @@ -50,12 +50,15 @@ public class DecryptTextActivity extends ActionBarActivity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setContentView(R.layout.decrypt_text_activity); - // Handle intent actions handleActions(savedInstanceState, getIntent()); } + @Override + protected void initLayout() { + setContentView(R.layout.decrypt_text_activity); + } + /** * Fixing broken PGP MESSAGE Strings coming from GMail/AOSP Mail */ -- cgit v1.2.3 From 466060888714638215e0b02bc25e66172c73c490 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Wed, 14 Jan 2015 11:07:09 +0100 Subject: fix log entry for addition of user attributes --- .../java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java index 18a5410bf..56f7b3309 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java @@ -531,12 +531,12 @@ public class PgpKeyOperation { WrappedUserAttribute attribute = saveParcel.mAddUserAttribute.get(i); switch (attribute.getType()) { - case WrappedUserAttribute.UAT_NONE: - log.add(LogType.MSG_MF_UAT_ADD_UNKNOWN, indent); - break; case WrappedUserAttribute.UAT_IMAGE: log.add(LogType.MSG_MF_UAT_ADD_IMAGE, indent); break; + default: + log.add(LogType.MSG_MF_UAT_ADD_UNKNOWN, indent); + break; } PGPUserAttributeSubpacketVector vector = attribute.getVector(); -- cgit v1.2.3 From 73feaa974cc90c86ca63ba09b86b8a10eb1a7e18 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Wed, 14 Jan 2015 13:05:13 +0100 Subject: small fixes to user attribute handling --- .../operations/results/OperationResult.java | 1 + .../keychain/pgp/PgpKeyOperation.java | 4 ++++ .../keychain/pgp/WrappedUserAttribute.java | 25 +++++++++++++++++++--- 3 files changed, 27 insertions(+), 3 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java index 556d70cb2..8c76ebb8a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java @@ -507,6 +507,7 @@ public abstract class OperationResult implements Parcelable { MSG_MF_UID_PRIMARY (LogLevel.INFO, R.string.msg_mf_uid_primary), MSG_MF_UID_REVOKE (LogLevel.INFO, R.string.msg_mf_uid_revoke), MSG_MF_UID_ERROR_EMPTY (LogLevel.ERROR, R.string.msg_mf_uid_error_empty), + MSG_MF_UAT_ERROR_EMPTY (LogLevel.ERROR, R.string.msg_mf_uat_error_empty), MSG_MF_UAT_ADD_IMAGE (LogLevel.INFO, R.string.msg_mf_uat_add_image), MSG_MF_UAT_ADD_UNKNOWN (LogLevel.INFO, R.string.msg_mf_uat_add_unknown), MSG_MF_UNLOCK_ERROR (LogLevel.ERROR, R.string.msg_mf_unlock_error), diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java index 56f7b3309..4bab7f2b9 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java @@ -531,6 +531,10 @@ public class PgpKeyOperation { WrappedUserAttribute attribute = saveParcel.mAddUserAttribute.get(i); switch (attribute.getType()) { + // the 'none' type must not succeed + case WrappedUserAttribute.UAT_NONE: + log.add(LogType.MSG_MF_UAT_ERROR_EMPTY, indent); + return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null); case WrappedUserAttribute.UAT_IMAGE: log.add(LogType.MSG_MF_UAT_ADD_IMAGE, indent); break; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedUserAttribute.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedUserAttribute.java index 248ef11aa..da6d8b287 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedUserAttribute.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedUserAttribute.java @@ -22,6 +22,7 @@ import org.spongycastle.bcpg.BCPGOutputStream; import org.spongycastle.bcpg.Packet; import org.spongycastle.bcpg.UserAttributePacket; import org.spongycastle.bcpg.UserAttributeSubpacket; +import org.spongycastle.bcpg.UserAttributeSubpacketInputStream; import org.spongycastle.bcpg.UserAttributeSubpacketTags; import org.spongycastle.openpgp.PGPUserAttributeSubpacketVector; @@ -30,6 +31,8 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectStreamException; import java.io.Serializable; +import java.util.ArrayList; +import java.util.Arrays; public class WrappedUserAttribute implements Serializable { @@ -72,9 +75,17 @@ public class WrappedUserAttribute implements Serializable { return out.toByteArray(); } - public static WrappedUserAttribute fromData (byte[] data) { - // TODO - return null; + public static WrappedUserAttribute fromData (byte[] data) throws IOException { + UserAttributeSubpacketInputStream in = + new UserAttributeSubpacketInputStream(new ByteArrayInputStream(data)); + ArrayList list = new ArrayList(); + while (in.available() > 0) { + list.add(in.readPacket()); + } + UserAttributeSubpacket[] result = new UserAttributeSubpacket[list.size()]; + list.toArray(result); + return new WrappedUserAttribute( + new PGPUserAttributeSubpacketVector(result)); } /** Writes this object to an ObjectOutputStream. */ @@ -102,4 +113,12 @@ public class WrappedUserAttribute implements Serializable { private void readObjectNoData() throws ObjectStreamException { } + @Override + public boolean equals(Object o) { + if (!WrappedUserAttribute.class.isInstance(o)) { + return false; + } + return mVector.equals(((WrappedUserAttribute) o).mVector); + } + } -- cgit v1.2.3 From c94ef60c5d93d724dad9e4422fdcc3778ade7ae1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Wed, 14 Jan 2015 14:02:51 +0100 Subject: Fix SearchView --- .../keychain/ui/KeyListFragment.java | 24 ++++------------------ 1 file changed, 4 insertions(+), 20 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java index d0be052d8..7fa403485 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java @@ -110,8 +110,6 @@ public class KeyListFragment extends LoaderFragment private String mQuery; private SearchView mSearchView; - boolean hideMenu = false; - /** * Load custom layout with StickyListView from library */ @@ -172,8 +170,8 @@ public class KeyListFragment extends LoaderFragment TextView title = (TextView) getActivity().findViewById(R.id.custom_actionbar_text); title.setText(R.string.swipe_to_update); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { - hideMenu = true; - activity.invalidateOptionsMenu(); +// hideMenu = true; +// activity.invalidateOptionsMenu(); } } else { bar.setTitle(getActivity().getTitle()); @@ -184,8 +182,8 @@ public class KeyListFragment extends LoaderFragment bar.setDisplayShowCustomEnabled(false); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { - hideMenu = false; - activity.invalidateOptionsMenu(); +// hideMenu = false; +// activity.invalidateOptionsMenu(); } } } @@ -470,10 +468,6 @@ public class KeyListFragment extends LoaderFragment MenuItemCompat.setOnActionExpandListener(searchItem, new MenuItemCompat.OnActionExpandListener() { @Override public boolean onMenuItemActionExpand(MenuItem item) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { - hideMenu = true; - getActivity().invalidateOptionsMenu(); - } // disable swipe-to-refresh // mSwipeRefreshLayout.setIsLocked(true); @@ -485,22 +479,12 @@ public class KeyListFragment extends LoaderFragment mQuery = null; getLoaderManager().restartLoader(0, null, KeyListFragment.this); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { - hideMenu = false; - getActivity().invalidateOptionsMenu(); - } // enable swipe-to-refresh // mSwipeRefreshLayout.setIsLocked(false); return true; } }); - if (hideMenu) { - for (int i = 0; i < menu.size(); i++) { - menu.getItem(i).setVisible(false); - } - } - super.onCreateOptionsMenu(menu, inflater); } -- cgit v1.2.3 From 8ef104281b9e240e9f4598d5c0dbcef5f13fe477 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Wed, 14 Jan 2015 14:12:23 +0100 Subject: fix ambiguous column name in advanced key info --- .../org/sufficientlysecure/keychain/ui/ViewKeyAdvancedFragment.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvancedFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvancedFragment.java index 9c37f2d94..61bd126ce 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvancedFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvancedFragment.java @@ -80,7 +80,7 @@ public class ViewKeyAdvancedFragment extends LoaderFragment implements static final String CERTS_SORT_ORDER = KeychainDatabase.Tables.CERTS + "." + KeychainContract.Certs.RANK + " ASC, " + KeychainContract.Certs.VERIFIED + " DESC, " - + KeychainContract.Certs.TYPE + " DESC, " + + KeychainDatabase.Tables.CERTS + "." + KeychainContract.Certs.TYPE + " DESC, " + KeychainContract.Certs.SIGNER_UID + " ASC"; /** -- cgit v1.2.3 From 85b6669625c9b94972fb03ec0de2da689c24d299 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Wed, 14 Jan 2015 19:14:30 +0100 Subject: Integrate QR Code library instead of requiring the app to be installed, also due to security reasons --- .../org/sufficientlysecure/keychain/ui/QrCodeScanActivity.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeScanActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeScanActivity.java index 5966870df..28488879b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeScanActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeScanActivity.java @@ -78,7 +78,11 @@ public class QrCodeScanActivity extends FragmentActivity { // scan using xzing's Barcode Scanner and return result parcel in OpenKeychain returnResult = true; - new IntentIntegrator(this).initiateScan(); + IntentIntegrator integrator = new IntentIntegrator(this); + integrator.setDesiredBarcodeFormats(IntentIntegrator.QR_CODE_TYPES) + .setPrompt(getString(R.string.import_qr_code_text)) + .setResultDisplayDuration(0) + .initiateScan(); } else if (ACTION_QR_CODE_API.equals(action)) { // scan using xzing's Barcode Scanner from outside OpenKeychain @@ -168,7 +172,7 @@ public class QrCodeScanActivity extends FragmentActivity { return; } - if ( ! result.success()) { + if (!result.success()) { // only return if no success... Intent data = new Intent(); data.putExtras(returnData); -- cgit v1.2.3 From 1516ebf26afdd10cab81da945251015af2aa819d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Wed, 14 Jan 2015 20:18:03 +0100 Subject: Toolbar for settings --- .../keychain/ui/DrawerActivity.java | 3 +- .../keychain/ui/ImportKeysCloudFragment.java | 2 +- .../keychain/ui/PreferencesActivity.java | 478 ------------------- .../keychain/ui/PreferencesKeyServerActivity.java | 169 ------- .../keychain/ui/SettingsActivity.java | 506 +++++++++++++++++++++ .../keychain/ui/SettingsKeyServerActivity.java | 169 +++++++ 6 files changed, 677 insertions(+), 650 deletions(-) delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesActivity.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesKeyServerActivity.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsKeyServerActivity.java (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DrawerActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DrawerActivity.java index b3521ebcc..712516b8d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DrawerActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DrawerActivity.java @@ -27,7 +27,6 @@ import android.support.v4.app.ActionBarDrawerToggle; import android.support.v4.view.GravityCompat; import android.support.v4.widget.DrawerLayout; import android.support.v4.widget.FixedDrawerLayout; -import android.support.v7.app.ActionBarActivity; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; @@ -179,7 +178,7 @@ public abstract class DrawerActivity extends BaseActivity { switch (item.getItemId()) { case MENU_ID_PREFERENCE: { - Intent intent = new Intent(this, PreferencesActivity.class); + Intent intent = new Intent(this, SettingsActivity.class); startActivity(intent); return true; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysCloudFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysCloudFragment.java index 03aba344a..89826b8e9 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysCloudFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysCloudFragment.java @@ -110,7 +110,7 @@ public class ImportKeysCloudFragment extends Fragment { mConfigButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { - Intent i = new Intent(mImportActivity, PreferencesActivity.class); + Intent i = new Intent(mImportActivity, SettingsActivity.class); // GRR, for some reason I can’t set the Action or I get an incomprehensible // exception about “modern two-pane layouts” // i.setAction(PreferencesActivity.ACTION_PREFS_CLOUD); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesActivity.java deleted file mode 100644 index 1769caa47..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesActivity.java +++ /dev/null @@ -1,478 +0,0 @@ -/* - * Copyright (C) 2010-2014 Thialfihar - * - * 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 . - */ - -package org.sufficientlysecure.keychain.ui; - -import android.annotation.SuppressLint; -import android.content.Context; -import android.content.Intent; -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 org.spongycastle.bcpg.CompressionAlgorithmTags; -import org.spongycastle.bcpg.HashAlgorithmTags; -import org.spongycastle.openpgp.PGPEncryptedData; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.ui.widget.IntegerListPreference; -import org.sufficientlysecure.keychain.util.Preferences; - -import java.util.List; - -@SuppressLint("NewApi") -public class PreferencesActivity extends PreferenceActivity { - - public static final String ACTION_PREFS_CLOUD = "org.sufficientlysecure.keychain.ui.PREFS_CLOUD"; - public static final String ACTION_PREFS_ADV = "org.sufficientlysecure.keychain.ui.PREFS_ADV"; - - public static final int REQUEST_CODE_KEYSERVER_PREF = 0x00007005; - - private PreferenceScreen mKeyServerPreference = null; - private static Preferences sPreferences; - - @Override - protected void onCreate(Bundle savedInstanceState) { - sPreferences = Preferences.getPreferences(this); - super.onCreate(savedInstanceState); - - String action = getIntent().getAction(); - - if (action != null && action.equals(ACTION_PREFS_CLOUD)) { - addPreferencesFromResource(R.xml.cloud_search_prefs); - - mKeyServerPreference = (PreferenceScreen) findPreference(Constants.Pref.KEY_SERVERS); - mKeyServerPreference.setSummary(keyserverSummary(this)); - mKeyServerPreference - .setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { - public boolean onPreferenceClick(Preference preference) { - Intent intent = new Intent(PreferencesActivity.this, - PreferencesKeyServerActivity.class); - intent.putExtra(PreferencesKeyServerActivity.EXTRA_KEY_SERVERS, - sPreferences.getKeyServers()); - startActivityForResult(intent, REQUEST_CODE_KEYSERVER_PREF); - return false; - } - }); - initializeSearchKeyserver( - (CheckBoxPreference) findPreference(Constants.Pref.SEARCH_KEYSERVER) - ); - initializeSearchKeybase( - (CheckBoxPreference) findPreference(Constants.Pref.SEARCH_KEYBASE) - ); - - } else if (action != null && action.equals(ACTION_PREFS_ADV)) { - addPreferencesFromResource(R.xml.adv_preferences); - - initializePassphraseCacheSubs( - (CheckBoxPreference) findPreference(Constants.Pref.PASSPHRASE_CACHE_SUBS)); - - initializePassphraseCacheTtl( - (IntegerListPreference) findPreference(Constants.Pref.PASSPHRASE_CACHE_TTL)); - - initializeEncryptionAlgorithm( - (IntegerListPreference) findPreference(Constants.Pref.DEFAULT_ENCRYPTION_ALGORITHM)); - - initializeHashAlgorithm( - (IntegerListPreference) findPreference(Constants.Pref.DEFAULT_HASH_ALGORITHM)); - - int[] valueIds = new int[]{ - CompressionAlgorithmTags.UNCOMPRESSED, - CompressionAlgorithmTags.ZIP, - CompressionAlgorithmTags.ZLIB, - CompressionAlgorithmTags.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]; - } - - initializeMessageCompression( - (IntegerListPreference) findPreference(Constants.Pref.DEFAULT_MESSAGE_COMPRESSION), - entries, values); - - initializeFileCompression( - (IntegerListPreference) findPreference(Constants.Pref.DEFAULT_FILE_COMPRESSION), - entries, values); - - initializeAsciiArmor( - (CheckBoxPreference) findPreference(Constants.Pref.DEFAULT_ASCII_ARMOR)); - - initializeWriteVersionHeader( - (CheckBoxPreference) findPreference(Constants.Pref.WRITE_VERSION_HEADER)); - - initializeUseDefaultYubikeyPin( - (CheckBoxPreference) findPreference(Constants.Pref.USE_DEFAULT_YUBIKEY_PIN)); - - initializeUseNumKeypadForYubikeyPin( - (CheckBoxPreference) findPreference(Constants.Pref.USE_NUMKEYPAD_FOR_YUBIKEY_PIN)); - - } - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - switch (requestCode) { - case REQUEST_CODE_KEYSERVER_PREF: { - if (resultCode == RESULT_CANCELED || data == null) { - return; - } - String servers[] = data - .getStringArrayExtra(PreferencesKeyServerActivity.EXTRA_KEY_SERVERS); - sPreferences.setKeyServers(servers); - mKeyServerPreference.setSummary(keyserverSummary(this)); - break; - } - - default: { - super.onActivityResult(requestCode, resultCode, data); - break; - } - } - } - - /* Called only on Honeycomb and later */ - @Override - public void onBuildHeaders(List
target) { - super.onBuildHeaders(target); - loadHeadersFromResource(R.xml.preference_headers, target); - } - - /** - * This fragment shows the Cloud Search preferences in android 3.0+ - */ - public static class CloudSearchPrefsFragment 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.cloud_search_prefs); - - mKeyServerPreference = (PreferenceScreen) findPreference(Constants.Pref.KEY_SERVERS); - mKeyServerPreference.setSummary(keyserverSummary(getActivity())); - - mKeyServerPreference - .setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { - public boolean onPreferenceClick(Preference preference) { - Intent intent = new Intent(getActivity(), - PreferencesKeyServerActivity.class); - intent.putExtra(PreferencesKeyServerActivity.EXTRA_KEY_SERVERS, - sPreferences.getKeyServers()); - startActivityForResult(intent, REQUEST_CODE_KEYSERVER_PREF); - return false; - } - }); - initializeSearchKeyserver( - (CheckBoxPreference) findPreference(Constants.Pref.SEARCH_KEYSERVER) - ); - initializeSearchKeybase( - (CheckBoxPreference) findPreference(Constants.Pref.SEARCH_KEYBASE) - ); - } - - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - switch (requestCode) { - case REQUEST_CODE_KEYSERVER_PREF: { - if (resultCode == RESULT_CANCELED || data == null) { - return; - } - String servers[] = data - .getStringArrayExtra(PreferencesKeyServerActivity.EXTRA_KEY_SERVERS); - sPreferences.setKeyServers(servers); - mKeyServerPreference.setSummary(keyserverSummary(getActivity())); - 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); - - initializePassphraseCacheSubs( - (CheckBoxPreference) findPreference(Constants.Pref.PASSPHRASE_CACHE_SUBS)); - - initializePassphraseCacheTtl( - (IntegerListPreference) findPreference(Constants.Pref.PASSPHRASE_CACHE_TTL)); - - initializeEncryptionAlgorithm( - (IntegerListPreference) findPreference(Constants.Pref.DEFAULT_ENCRYPTION_ALGORITHM)); - - initializeHashAlgorithm( - (IntegerListPreference) findPreference(Constants.Pref.DEFAULT_HASH_ALGORITHM)); - - int[] valueIds = new int[]{ - CompressionAlgorithmTags.UNCOMPRESSED, - CompressionAlgorithmTags.ZIP, - CompressionAlgorithmTags.ZLIB, - CompressionAlgorithmTags.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]; - } - - initializeMessageCompression( - (IntegerListPreference) findPreference(Constants.Pref.DEFAULT_MESSAGE_COMPRESSION), - entries, values); - - initializeFileCompression( - (IntegerListPreference) findPreference(Constants.Pref.DEFAULT_FILE_COMPRESSION), - entries, values); - - initializeAsciiArmor( - (CheckBoxPreference) findPreference(Constants.Pref.DEFAULT_ASCII_ARMOR)); - - initializeWriteVersionHeader( - (CheckBoxPreference) findPreference(Constants.Pref.WRITE_VERSION_HEADER)); - - initializeUseDefaultYubikeyPin( - (CheckBoxPreference) findPreference(Constants.Pref.USE_DEFAULT_YUBIKEY_PIN)); - - initializeUseNumKeypadForYubikeyPin( - (CheckBoxPreference) findPreference(Constants.Pref.USE_NUMKEYPAD_FOR_YUBIKEY_PIN)); - } - } - - protected boolean isValidFragment(String fragmentName) { - return AdvancedPrefsFragment.class.getName().equals(fragmentName) - || CloudSearchPrefsFragment.class.getName().equals(fragmentName) - || super.isValidFragment(fragmentName); - } - - private static void initializePassphraseCacheSubs(final CheckBoxPreference mPassphraseCacheSubs) { - mPassphraseCacheSubs.setChecked(sPreferences.getPassphraseCacheSubs()); - mPassphraseCacheSubs.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { - public boolean onPreferenceChange(Preference preference, Object newValue) { - mPassphraseCacheSubs.setChecked((Boolean) newValue); - sPreferences.setPassphraseCacheSubs((Boolean) newValue); - return false; - } - }); - } - - private static void initializePassphraseCacheTtl(final IntegerListPreference mPassphraseCacheTtl) { - mPassphraseCacheTtl.setValue("" + sPreferences.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()); - sPreferences.setPassphraseCacheTtl(Integer.parseInt(newValue.toString())); - return false; - } - }); - } - - 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, - PGPEncryptedData.IDEA,}; - String entries[] = {"AES-128", "AES-192", "AES-256", "Blowfish", "Twofish", "CAST5", - "DES", "Triple DES", "IDEA",}; - String values[] = new String[valueIds.length]; - for (int i = 0; i < values.length; ++i) { - values[i] = "" + valueIds[i]; - } - mEncryptionAlgorithm.setEntries(entries); - mEncryptionAlgorithm.setEntryValues(values); - mEncryptionAlgorithm.setValue("" + sPreferences.getDefaultEncryptionAlgorithm()); - mEncryptionAlgorithm.setSummary(mEncryptionAlgorithm.getEntry()); - mEncryptionAlgorithm - .setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { - public boolean onPreferenceChange(Preference preference, Object newValue) { - mEncryptionAlgorithm.setValue(newValue.toString()); - mEncryptionAlgorithm.setSummary(mEncryptionAlgorithm.getEntry()); - sPreferences.setDefaultEncryptionAlgorithm(Integer.parseInt(newValue - .toString())); - return false; - } - }); - } - - private static void initializeHashAlgorithm(final IntegerListPreference mHashAlgorithm) { - int[] valueIds = new int[]{HashAlgorithmTags.RIPEMD160, - HashAlgorithmTags.SHA1, HashAlgorithmTags.SHA224, HashAlgorithmTags.SHA256, - HashAlgorithmTags.SHA384, HashAlgorithmTags.SHA512,}; - String[] entries = new String[]{"RIPEMD-160", "SHA-1", "SHA-224", "SHA-256", "SHA-384", - "SHA-512",}; - String[] values = new String[valueIds.length]; - for (int i = 0; i < values.length; ++i) { - values[i] = "" + valueIds[i]; - } - mHashAlgorithm.setEntries(entries); - mHashAlgorithm.setEntryValues(values); - mHashAlgorithm.setValue("" + sPreferences.getDefaultHashAlgorithm()); - mHashAlgorithm.setSummary(mHashAlgorithm.getEntry()); - mHashAlgorithm.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { - public boolean onPreferenceChange(Preference preference, Object newValue) { - mHashAlgorithm.setValue(newValue.toString()); - mHashAlgorithm.setSummary(mHashAlgorithm.getEntry()); - sPreferences.setDefaultHashAlgorithm(Integer.parseInt(newValue.toString())); - return false; - } - }); - } - - private static void initializeMessageCompression(final IntegerListPreference mMessageCompression, - String[] entries, String[] values) { - mMessageCompression.setEntries(entries); - mMessageCompression.setEntryValues(values); - mMessageCompression.setValue("" + sPreferences.getDefaultMessageCompression()); - mMessageCompression.setSummary(mMessageCompression.getEntry()); - mMessageCompression - .setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { - public boolean onPreferenceChange(Preference preference, Object newValue) { - mMessageCompression.setValue(newValue.toString()); - mMessageCompression.setSummary(mMessageCompression.getEntry()); - sPreferences.setDefaultMessageCompression(Integer.parseInt(newValue - .toString())); - return false; - } - }); - } - - private static void initializeFileCompression - (final IntegerListPreference mFileCompression, String[] entries, String[] values) { - mFileCompression.setEntries(entries); - mFileCompression.setEntryValues(values); - mFileCompression.setValue("" + sPreferences.getDefaultFileCompression()); - mFileCompression.setSummary(mFileCompression.getEntry()); - mFileCompression.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { - public boolean onPreferenceChange(Preference preference, Object newValue) { - mFileCompression.setValue(newValue.toString()); - mFileCompression.setSummary(mFileCompression.getEntry()); - sPreferences.setDefaultFileCompression(Integer.parseInt(newValue.toString())); - return false; - } - }); - } - - private static void initializeAsciiArmor(final CheckBoxPreference mAsciiArmor) { - mAsciiArmor.setChecked(sPreferences.getDefaultAsciiArmor()); - mAsciiArmor.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { - public boolean onPreferenceChange(Preference preference, Object newValue) { - mAsciiArmor.setChecked((Boolean) newValue); - sPreferences.setDefaultAsciiArmor((Boolean) newValue); - return false; - } - }); - } - - private static void initializeWriteVersionHeader(final CheckBoxPreference mWriteVersionHeader) { - mWriteVersionHeader.setChecked(sPreferences.getWriteVersionHeader()); - mWriteVersionHeader.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { - public boolean onPreferenceChange(Preference preference, Object newValue) { - mWriteVersionHeader.setChecked((Boolean) newValue); - sPreferences.setWriteVersionHeader((Boolean) newValue); - return false; - } - }); - } - - private static void initializeSearchKeyserver(final CheckBoxPreference mSearchKeyserver) { - Preferences.CloudSearchPrefs prefs = sPreferences.getCloudSearchPrefs(); - mSearchKeyserver.setChecked(prefs.searchKeyserver); - mSearchKeyserver.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { - @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - mSearchKeyserver.setChecked((Boolean) newValue); - sPreferences.setSearchKeyserver((Boolean) newValue); - return false; - } - }); - } - - private static void initializeSearchKeybase(final CheckBoxPreference mSearchKeybase) { - Preferences.CloudSearchPrefs prefs = sPreferences.getCloudSearchPrefs(); - mSearchKeybase.setChecked(prefs.searchKeybase); - mSearchKeybase.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { - @Override - public boolean onPreferenceChange(Preference preference, Object newValue) { - mSearchKeybase.setChecked((Boolean) newValue); - sPreferences.setSearchKeybase((Boolean) newValue); - return false; - } - }); - } - - public static String keyserverSummary(Context context) { - String[] servers = sPreferences.getKeyServers(); - String serverSummary = context.getResources().getQuantityString( - R.plurals.n_keyservers, servers.length, servers.length); - return serverSummary + "; " + context.getString(R.string.label_preferred) + ": " + sPreferences.getPreferredKeyserver(); - } - - private static void initializeUseDefaultYubikeyPin(final CheckBoxPreference mUseDefaultYubikeyPin) { - mUseDefaultYubikeyPin.setChecked(sPreferences.useDefaultYubikeyPin()); - mUseDefaultYubikeyPin.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { - public boolean onPreferenceChange(Preference preference, Object newValue) { - mUseDefaultYubikeyPin.setChecked((Boolean) newValue); - sPreferences.setUseDefaultYubikeyPin((Boolean) newValue); - return false; - } - }); - } - - private static void initializeUseNumKeypadForYubikeyPin(final CheckBoxPreference mUseNumKeypadForYubikeyPin) { - mUseNumKeypadForYubikeyPin.setChecked(sPreferences.useNumKeypadForYubikeyPin()); - mUseNumKeypadForYubikeyPin.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { - public boolean onPreferenceChange(Preference preference, Object newValue) { - mUseNumKeypadForYubikeyPin.setChecked((Boolean) newValue); - sPreferences.setUseNumKeypadForYubikeyPin((Boolean) newValue); - return false; - } - }); - } -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesKeyServerActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesKeyServerActivity.java deleted file mode 100644 index 9e2e443af..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PreferencesKeyServerActivity.java +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright (C) 2010-2014 Thialfihar - * - * 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 . - */ - -package org.sufficientlysecure.keychain.ui; - -import android.content.Context; -import android.content.Intent; -import android.os.Bundle; -import android.support.v7.app.ActionBarActivity; -import android.view.LayoutInflater; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.ViewGroup; -import android.widget.TextView; - -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.ui.util.ActionBarHelper; -import org.sufficientlysecure.keychain.ui.widget.Editor; -import org.sufficientlysecure.keychain.ui.widget.Editor.EditorListener; -import org.sufficientlysecure.keychain.ui.widget.KeyServerEditor; - -import java.util.Vector; - -public class PreferencesKeyServerActivity extends BaseActivity implements OnClickListener, - EditorListener { - - public static final String EXTRA_KEY_SERVERS = "key_servers"; - - private LayoutInflater mInflater; - private ViewGroup mEditors; - private View mAdd; - private View mRotate; - private TextView mTitle; - private TextView mSummary; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - // Inflate a "Done"/"Cancel" custom action bar view - ActionBarHelper.setTwoButtonView(getSupportActionBar(), R.string.btn_okay, R.drawable.ic_action_done, - new View.OnClickListener() { - @Override - public void onClick(View v) { - // ok - okClicked(); - } - }, R.string.btn_do_not_save, R.drawable.ic_action_cancel, new View.OnClickListener() { - @Override - public void onClick(View v) { - // cancel - cancelClicked(); - } - } - ); - - mInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); - - mTitle = (TextView) findViewById(R.id.title); - mSummary = (TextView) findViewById(R.id.summary); - mSummary.setText(getText(R.string.label_first_keyserver_is_used)); - - mTitle.setText(R.string.label_keyservers); - - mEditors = (ViewGroup) findViewById(R.id.editors); - mAdd = findViewById(R.id.add); - mAdd.setOnClickListener(this); - - mRotate = findViewById(R.id.rotate); - mRotate.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View view) { - Vector servers = serverList(); - String first = servers.get(0); - if (first != null) { - servers.remove(0); - servers.add(first); - String[] dummy = {}; - makeServerList(servers.toArray(dummy)); - } - } - }); - - Intent intent = getIntent(); - String servers[] = intent.getStringArrayExtra(EXTRA_KEY_SERVERS); - makeServerList(servers); - } - - @Override - protected void initLayout() { - setContentView(R.layout.key_server_preference); - } - - private void makeServerList(String[] servers) { - if (servers != null) { - mEditors.removeAllViews(); - for (String serv : servers) { - KeyServerEditor view = (KeyServerEditor) mInflater.inflate( - R.layout.key_server_editor, mEditors, false); - view.setEditorListener(this); - view.setValue(serv); - mEditors.addView(view); - } - } - } - - public void onDeleted(Editor editor, boolean wasNewItem) { - // nothing to do - } - - @Override - public void onEdited() { - - } - - public void onClick(View v) { - KeyServerEditor view = (KeyServerEditor) mInflater.inflate(R.layout.key_server_editor, - mEditors, false); - view.setEditorListener(this); - mEditors.addView(view); - } - - private void cancelClicked() { - setResult(RESULT_CANCELED, null); - finish(); - } - - private Vector serverList() { - Vector servers = new Vector(); - for (int i = 0; i < mEditors.getChildCount(); ++i) { - KeyServerEditor editor = (KeyServerEditor) mEditors.getChildAt(i); - String tmp = editor.getValue(); - if (tmp.length() > 0) { - servers.add(tmp); - } - } - return servers; - } - - private void okClicked() { - Intent data = new Intent(); - Vector servers = new Vector(); - for (int i = 0; i < mEditors.getChildCount(); ++i) { - KeyServerEditor editor = (KeyServerEditor) mEditors.getChildAt(i); - String tmp = editor.getValue(); - if (tmp.length() > 0) { - servers.add(tmp); - } - } - String[] dummy = new String[0]; - data.putExtra(EXTRA_KEY_SERVERS, servers.toArray(dummy)); - setResult(RESULT_OK, data); - finish(); - } -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java new file mode 100644 index 000000000..8ef6ec187 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java @@ -0,0 +1,506 @@ +/* + * Copyright (C) 2010-2014 Thialfihar + * + * 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 . + */ + +package org.sufficientlysecure.keychain.ui; + +import android.content.Context; +import android.content.Intent; +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.widget.Toolbar; +import android.view.View; +import android.view.ViewGroup; +import android.widget.LinearLayout; + +import org.spongycastle.bcpg.CompressionAlgorithmTags; +import org.spongycastle.bcpg.HashAlgorithmTags; +import org.spongycastle.openpgp.PGPEncryptedData; +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.ui.widget.IntegerListPreference; +import org.sufficientlysecure.keychain.util.Preferences; + +import java.util.List; + +public class SettingsActivity extends PreferenceActivity { + + public static final String ACTION_PREFS_CLOUD = "org.sufficientlysecure.keychain.ui.PREFS_CLOUD"; + public static final String ACTION_PREFS_ADV = "org.sufficientlysecure.keychain.ui.PREFS_ADV"; + + public static final int REQUEST_CODE_KEYSERVER_PREF = 0x00007005; + + private PreferenceScreen mKeyServerPreference = null; + private static Preferences sPreferences; + + @Override + protected void onCreate(Bundle savedInstanceState) { + sPreferences = Preferences.getPreferences(this); + super.onCreate(savedInstanceState); + + setupToolbar(); + + String action = getIntent().getAction(); + + if (action != null && action.equals(ACTION_PREFS_CLOUD)) { + addPreferencesFromResource(R.xml.cloud_search_prefs); + + mKeyServerPreference = (PreferenceScreen) findPreference(Constants.Pref.KEY_SERVERS); + mKeyServerPreference.setSummary(keyserverSummary(this)); + mKeyServerPreference + .setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { + public boolean onPreferenceClick(Preference preference) { + Intent intent = new Intent(SettingsActivity.this, + SettingsKeyServerActivity.class); + intent.putExtra(SettingsKeyServerActivity.EXTRA_KEY_SERVERS, + sPreferences.getKeyServers()); + startActivityForResult(intent, REQUEST_CODE_KEYSERVER_PREF); + return false; + } + }); + initializeSearchKeyserver( + (CheckBoxPreference) findPreference(Constants.Pref.SEARCH_KEYSERVER) + ); + initializeSearchKeybase( + (CheckBoxPreference) findPreference(Constants.Pref.SEARCH_KEYBASE) + ); + + } else if (action != null && action.equals(ACTION_PREFS_ADV)) { + addPreferencesFromResource(R.xml.adv_preferences); + + initializePassphraseCacheSubs( + (CheckBoxPreference) findPreference(Constants.Pref.PASSPHRASE_CACHE_SUBS)); + + initializePassphraseCacheTtl( + (IntegerListPreference) findPreference(Constants.Pref.PASSPHRASE_CACHE_TTL)); + + initializeEncryptionAlgorithm( + (IntegerListPreference) findPreference(Constants.Pref.DEFAULT_ENCRYPTION_ALGORITHM)); + + initializeHashAlgorithm( + (IntegerListPreference) findPreference(Constants.Pref.DEFAULT_HASH_ALGORITHM)); + + int[] valueIds = new int[]{ + CompressionAlgorithmTags.UNCOMPRESSED, + CompressionAlgorithmTags.ZIP, + CompressionAlgorithmTags.ZLIB, + CompressionAlgorithmTags.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]; + } + + initializeMessageCompression( + (IntegerListPreference) findPreference(Constants.Pref.DEFAULT_MESSAGE_COMPRESSION), + entries, values); + + initializeFileCompression( + (IntegerListPreference) findPreference(Constants.Pref.DEFAULT_FILE_COMPRESSION), + entries, values); + + initializeAsciiArmor( + (CheckBoxPreference) findPreference(Constants.Pref.DEFAULT_ASCII_ARMOR)); + + initializeWriteVersionHeader( + (CheckBoxPreference) findPreference(Constants.Pref.WRITE_VERSION_HEADER)); + + initializeUseDefaultYubikeyPin( + (CheckBoxPreference) findPreference(Constants.Pref.USE_DEFAULT_YUBIKEY_PIN)); + + initializeUseNumKeypadForYubikeyPin( + (CheckBoxPreference) findPreference(Constants.Pref.USE_NUMKEYPAD_FOR_YUBIKEY_PIN)); + + } + } + + /** + * Hack to get Toolbar in PreferenceActivity. See http://stackoverflow.com/a/26614696 + */ + private void setupToolbar() { + ViewGroup root = (ViewGroup) findViewById(android.R.id.content); + LinearLayout content = (LinearLayout) root.getChildAt(0); + LinearLayout toolbarContainer = (LinearLayout) View.inflate(this, R.layout.preference_toolbar_activity, null); + + root.removeAllViews(); + toolbarContainer.addView(content); + root.addView(toolbarContainer); + + Toolbar toolbar = (Toolbar) toolbarContainer.findViewById(R.id.toolbar); + toolbar.setTitle(R.string.title_preferences); + toolbar.setNavigationIcon(getResources().getDrawable(R.drawable.ic_arrow_back_white_24dp)); + toolbar.setNavigationOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + //What to do on back clicked + finish(); + } + }); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + switch (requestCode) { + case REQUEST_CODE_KEYSERVER_PREF: { + if (resultCode == RESULT_CANCELED || data == null) { + return; + } + String servers[] = data + .getStringArrayExtra(SettingsKeyServerActivity.EXTRA_KEY_SERVERS); + sPreferences.setKeyServers(servers); + mKeyServerPreference.setSummary(keyserverSummary(this)); + break; + } + + default: { + super.onActivityResult(requestCode, resultCode, data); + break; + } + } + } + + /* Called only on Honeycomb and later */ + @Override + public void onBuildHeaders(List
target) { + super.onBuildHeaders(target); + loadHeadersFromResource(R.xml.preference_headers, target); + } + + /** + * This fragment shows the Cloud Search preferences in android 3.0+ + */ + public static class CloudSearchPrefsFragment 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.cloud_search_prefs); + + mKeyServerPreference = (PreferenceScreen) findPreference(Constants.Pref.KEY_SERVERS); + mKeyServerPreference.setSummary(keyserverSummary(getActivity())); + + mKeyServerPreference + .setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { + public boolean onPreferenceClick(Preference preference) { + Intent intent = new Intent(getActivity(), + SettingsKeyServerActivity.class); + intent.putExtra(SettingsKeyServerActivity.EXTRA_KEY_SERVERS, + sPreferences.getKeyServers()); + startActivityForResult(intent, REQUEST_CODE_KEYSERVER_PREF); + return false; + } + }); + initializeSearchKeyserver( + (CheckBoxPreference) findPreference(Constants.Pref.SEARCH_KEYSERVER) + ); + initializeSearchKeybase( + (CheckBoxPreference) findPreference(Constants.Pref.SEARCH_KEYBASE) + ); + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + switch (requestCode) { + case REQUEST_CODE_KEYSERVER_PREF: { + if (resultCode == RESULT_CANCELED || data == null) { + return; + } + String servers[] = data + .getStringArrayExtra(SettingsKeyServerActivity.EXTRA_KEY_SERVERS); + sPreferences.setKeyServers(servers); + mKeyServerPreference.setSummary(keyserverSummary(getActivity())); + 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); + + initializePassphraseCacheSubs( + (CheckBoxPreference) findPreference(Constants.Pref.PASSPHRASE_CACHE_SUBS)); + + initializePassphraseCacheTtl( + (IntegerListPreference) findPreference(Constants.Pref.PASSPHRASE_CACHE_TTL)); + + initializeEncryptionAlgorithm( + (IntegerListPreference) findPreference(Constants.Pref.DEFAULT_ENCRYPTION_ALGORITHM)); + + initializeHashAlgorithm( + (IntegerListPreference) findPreference(Constants.Pref.DEFAULT_HASH_ALGORITHM)); + + int[] valueIds = new int[]{ + CompressionAlgorithmTags.UNCOMPRESSED, + CompressionAlgorithmTags.ZIP, + CompressionAlgorithmTags.ZLIB, + CompressionAlgorithmTags.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]; + } + + initializeMessageCompression( + (IntegerListPreference) findPreference(Constants.Pref.DEFAULT_MESSAGE_COMPRESSION), + entries, values); + + initializeFileCompression( + (IntegerListPreference) findPreference(Constants.Pref.DEFAULT_FILE_COMPRESSION), + entries, values); + + initializeAsciiArmor( + (CheckBoxPreference) findPreference(Constants.Pref.DEFAULT_ASCII_ARMOR)); + + initializeWriteVersionHeader( + (CheckBoxPreference) findPreference(Constants.Pref.WRITE_VERSION_HEADER)); + + initializeUseDefaultYubikeyPin( + (CheckBoxPreference) findPreference(Constants.Pref.USE_DEFAULT_YUBIKEY_PIN)); + + initializeUseNumKeypadForYubikeyPin( + (CheckBoxPreference) findPreference(Constants.Pref.USE_NUMKEYPAD_FOR_YUBIKEY_PIN)); + } + } + + protected boolean isValidFragment(String fragmentName) { + return AdvancedPrefsFragment.class.getName().equals(fragmentName) + || CloudSearchPrefsFragment.class.getName().equals(fragmentName) + || super.isValidFragment(fragmentName); + } + + private static void initializePassphraseCacheSubs(final CheckBoxPreference mPassphraseCacheSubs) { + mPassphraseCacheSubs.setChecked(sPreferences.getPassphraseCacheSubs()); + mPassphraseCacheSubs.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { + public boolean onPreferenceChange(Preference preference, Object newValue) { + mPassphraseCacheSubs.setChecked((Boolean) newValue); + sPreferences.setPassphraseCacheSubs((Boolean) newValue); + return false; + } + }); + } + + private static void initializePassphraseCacheTtl(final IntegerListPreference mPassphraseCacheTtl) { + mPassphraseCacheTtl.setValue("" + sPreferences.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()); + sPreferences.setPassphraseCacheTtl(Integer.parseInt(newValue.toString())); + return false; + } + }); + } + + 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, + PGPEncryptedData.IDEA,}; + String entries[] = {"AES-128", "AES-192", "AES-256", "Blowfish", "Twofish", "CAST5", + "DES", "Triple DES", "IDEA",}; + String values[] = new String[valueIds.length]; + for (int i = 0; i < values.length; ++i) { + values[i] = "" + valueIds[i]; + } + mEncryptionAlgorithm.setEntries(entries); + mEncryptionAlgorithm.setEntryValues(values); + mEncryptionAlgorithm.setValue("" + sPreferences.getDefaultEncryptionAlgorithm()); + mEncryptionAlgorithm.setSummary(mEncryptionAlgorithm.getEntry()); + mEncryptionAlgorithm + .setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { + public boolean onPreferenceChange(Preference preference, Object newValue) { + mEncryptionAlgorithm.setValue(newValue.toString()); + mEncryptionAlgorithm.setSummary(mEncryptionAlgorithm.getEntry()); + sPreferences.setDefaultEncryptionAlgorithm(Integer.parseInt(newValue + .toString())); + return false; + } + }); + } + + private static void initializeHashAlgorithm(final IntegerListPreference mHashAlgorithm) { + int[] valueIds = new int[]{HashAlgorithmTags.RIPEMD160, + HashAlgorithmTags.SHA1, HashAlgorithmTags.SHA224, HashAlgorithmTags.SHA256, + HashAlgorithmTags.SHA384, HashAlgorithmTags.SHA512,}; + String[] entries = new String[]{"RIPEMD-160", "SHA-1", "SHA-224", "SHA-256", "SHA-384", + "SHA-512",}; + String[] values = new String[valueIds.length]; + for (int i = 0; i < values.length; ++i) { + values[i] = "" + valueIds[i]; + } + mHashAlgorithm.setEntries(entries); + mHashAlgorithm.setEntryValues(values); + mHashAlgorithm.setValue("" + sPreferences.getDefaultHashAlgorithm()); + mHashAlgorithm.setSummary(mHashAlgorithm.getEntry()); + mHashAlgorithm.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { + public boolean onPreferenceChange(Preference preference, Object newValue) { + mHashAlgorithm.setValue(newValue.toString()); + mHashAlgorithm.setSummary(mHashAlgorithm.getEntry()); + sPreferences.setDefaultHashAlgorithm(Integer.parseInt(newValue.toString())); + return false; + } + }); + } + + private static void initializeMessageCompression(final IntegerListPreference mMessageCompression, + String[] entries, String[] values) { + mMessageCompression.setEntries(entries); + mMessageCompression.setEntryValues(values); + mMessageCompression.setValue("" + sPreferences.getDefaultMessageCompression()); + mMessageCompression.setSummary(mMessageCompression.getEntry()); + mMessageCompression + .setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { + public boolean onPreferenceChange(Preference preference, Object newValue) { + mMessageCompression.setValue(newValue.toString()); + mMessageCompression.setSummary(mMessageCompression.getEntry()); + sPreferences.setDefaultMessageCompression(Integer.parseInt(newValue + .toString())); + return false; + } + }); + } + + private static void initializeFileCompression + (final IntegerListPreference mFileCompression, String[] entries, String[] values) { + mFileCompression.setEntries(entries); + mFileCompression.setEntryValues(values); + mFileCompression.setValue("" + sPreferences.getDefaultFileCompression()); + mFileCompression.setSummary(mFileCompression.getEntry()); + mFileCompression.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { + public boolean onPreferenceChange(Preference preference, Object newValue) { + mFileCompression.setValue(newValue.toString()); + mFileCompression.setSummary(mFileCompression.getEntry()); + sPreferences.setDefaultFileCompression(Integer.parseInt(newValue.toString())); + return false; + } + }); + } + + private static void initializeAsciiArmor(final CheckBoxPreference mAsciiArmor) { + mAsciiArmor.setChecked(sPreferences.getDefaultAsciiArmor()); + mAsciiArmor.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { + public boolean onPreferenceChange(Preference preference, Object newValue) { + mAsciiArmor.setChecked((Boolean) newValue); + sPreferences.setDefaultAsciiArmor((Boolean) newValue); + return false; + } + }); + } + + private static void initializeWriteVersionHeader(final CheckBoxPreference mWriteVersionHeader) { + mWriteVersionHeader.setChecked(sPreferences.getWriteVersionHeader()); + mWriteVersionHeader.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { + public boolean onPreferenceChange(Preference preference, Object newValue) { + mWriteVersionHeader.setChecked((Boolean) newValue); + sPreferences.setWriteVersionHeader((Boolean) newValue); + return false; + } + }); + } + + private static void initializeSearchKeyserver(final CheckBoxPreference mSearchKeyserver) { + Preferences.CloudSearchPrefs prefs = sPreferences.getCloudSearchPrefs(); + mSearchKeyserver.setChecked(prefs.searchKeyserver); + mSearchKeyserver.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + mSearchKeyserver.setChecked((Boolean) newValue); + sPreferences.setSearchKeyserver((Boolean) newValue); + return false; + } + }); + } + + private static void initializeSearchKeybase(final CheckBoxPreference mSearchKeybase) { + Preferences.CloudSearchPrefs prefs = sPreferences.getCloudSearchPrefs(); + mSearchKeybase.setChecked(prefs.searchKeybase); + mSearchKeybase.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + mSearchKeybase.setChecked((Boolean) newValue); + sPreferences.setSearchKeybase((Boolean) newValue); + return false; + } + }); + } + + public static String keyserverSummary(Context context) { + String[] servers = sPreferences.getKeyServers(); + String serverSummary = context.getResources().getQuantityString( + R.plurals.n_keyservers, servers.length, servers.length); + return serverSummary + "; " + context.getString(R.string.label_preferred) + ": " + sPreferences.getPreferredKeyserver(); + } + + private static void initializeUseDefaultYubikeyPin(final CheckBoxPreference mUseDefaultYubikeyPin) { + mUseDefaultYubikeyPin.setChecked(sPreferences.useDefaultYubikeyPin()); + mUseDefaultYubikeyPin.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { + public boolean onPreferenceChange(Preference preference, Object newValue) { + mUseDefaultYubikeyPin.setChecked((Boolean) newValue); + sPreferences.setUseDefaultYubikeyPin((Boolean) newValue); + return false; + } + }); + } + + private static void initializeUseNumKeypadForYubikeyPin(final CheckBoxPreference mUseNumKeypadForYubikeyPin) { + mUseNumKeypadForYubikeyPin.setChecked(sPreferences.useNumKeypadForYubikeyPin()); + mUseNumKeypadForYubikeyPin.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { + public boolean onPreferenceChange(Preference preference, Object newValue) { + mUseNumKeypadForYubikeyPin.setChecked((Boolean) newValue); + sPreferences.setUseNumKeypadForYubikeyPin((Boolean) newValue); + return false; + } + }); + } +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsKeyServerActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsKeyServerActivity.java new file mode 100644 index 000000000..365e8026c --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsKeyServerActivity.java @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2010-2014 Thialfihar + * + * 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 . + */ + +package org.sufficientlysecure.keychain.ui; + +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.support.v7.app.ActionBarActivity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; +import android.widget.TextView; + +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.ui.util.ActionBarHelper; +import org.sufficientlysecure.keychain.ui.widget.Editor; +import org.sufficientlysecure.keychain.ui.widget.Editor.EditorListener; +import org.sufficientlysecure.keychain.ui.widget.KeyServerEditor; + +import java.util.Vector; + +public class SettingsKeyServerActivity extends BaseActivity implements OnClickListener, + EditorListener { + + public static final String EXTRA_KEY_SERVERS = "key_servers"; + + private LayoutInflater mInflater; + private ViewGroup mEditors; + private View mAdd; + private View mRotate; + private TextView mTitle; + private TextView mSummary; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + // Inflate a "Done"/"Cancel" custom action bar view + ActionBarHelper.setTwoButtonView(getSupportActionBar(), R.string.btn_okay, R.drawable.ic_action_done, + new View.OnClickListener() { + @Override + public void onClick(View v) { + // ok + okClicked(); + } + }, R.string.btn_do_not_save, R.drawable.ic_action_cancel, new View.OnClickListener() { + @Override + public void onClick(View v) { + // cancel + cancelClicked(); + } + } + ); + + mInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); + + mTitle = (TextView) findViewById(R.id.title); + mSummary = (TextView) findViewById(R.id.summary); + mSummary.setText(getText(R.string.label_first_keyserver_is_used)); + + mTitle.setText(R.string.label_keyservers); + + mEditors = (ViewGroup) findViewById(R.id.editors); + mAdd = findViewById(R.id.add); + mAdd.setOnClickListener(this); + + mRotate = findViewById(R.id.rotate); + mRotate.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View view) { + Vector servers = serverList(); + String first = servers.get(0); + if (first != null) { + servers.remove(0); + servers.add(first); + String[] dummy = {}; + makeServerList(servers.toArray(dummy)); + } + } + }); + + Intent intent = getIntent(); + String servers[] = intent.getStringArrayExtra(EXTRA_KEY_SERVERS); + makeServerList(servers); + } + + @Override + protected void initLayout() { + setContentView(R.layout.key_server_preference); + } + + private void makeServerList(String[] servers) { + if (servers != null) { + mEditors.removeAllViews(); + for (String serv : servers) { + KeyServerEditor view = (KeyServerEditor) mInflater.inflate( + R.layout.key_server_editor, mEditors, false); + view.setEditorListener(this); + view.setValue(serv); + mEditors.addView(view); + } + } + } + + public void onDeleted(Editor editor, boolean wasNewItem) { + // nothing to do + } + + @Override + public void onEdited() { + + } + + public void onClick(View v) { + KeyServerEditor view = (KeyServerEditor) mInflater.inflate(R.layout.key_server_editor, + mEditors, false); + view.setEditorListener(this); + mEditors.addView(view); + } + + private void cancelClicked() { + setResult(RESULT_CANCELED, null); + finish(); + } + + private Vector serverList() { + Vector servers = new Vector(); + for (int i = 0; i < mEditors.getChildCount(); ++i) { + KeyServerEditor editor = (KeyServerEditor) mEditors.getChildAt(i); + String tmp = editor.getValue(); + if (tmp.length() > 0) { + servers.add(tmp); + } + } + return servers; + } + + private void okClicked() { + Intent data = new Intent(); + Vector servers = new Vector(); + for (int i = 0; i < mEditors.getChildCount(); ++i) { + KeyServerEditor editor = (KeyServerEditor) mEditors.getChildAt(i); + String tmp = editor.getValue(); + if (tmp.length() > 0) { + servers.add(tmp); + } + } + String[] dummy = new String[0]; + data.putExtra(EXTRA_KEY_SERVERS, servers.toArray(dummy)); + setResult(RESULT_OK, data); + finish(); + } +} -- cgit v1.2.3 From fe25a68c6a31671932008fe0a0f129593406a33c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Wed, 14 Jan 2015 20:19:56 +0100 Subject: Yubikey numkey by default to true --- .../main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java | 3 +++ .../main/java/org/sufficientlysecure/keychain/util/Preferences.java | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java index 8ef6ec187..e2fc44689 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java @@ -17,8 +17,10 @@ package org.sufficientlysecure.keychain.ui; +import android.annotation.TargetApi; import android.content.Context; import android.content.Intent; +import android.os.Build; import android.os.Bundle; import android.preference.CheckBoxPreference; import android.preference.Preference; @@ -311,6 +313,7 @@ public class SettingsActivity extends PreferenceActivity { } } + @TargetApi(Build.VERSION_CODES.KITKAT) protected boolean isValidFragment(String fragmentName) { return AdvancedPrefsFragment.class.getName().equals(fragmentName) || CloudSearchPrefsFragment.class.getName().equals(fragmentName) diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Preferences.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Preferences.java index 65f4af880..5efd6c419 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Preferences.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Preferences.java @@ -182,7 +182,7 @@ public class Preferences { } public boolean useNumKeypadForYubikeyPin() { - return mSharedPreferences.getBoolean(Pref.USE_NUMKEYPAD_FOR_YUBIKEY_PIN, false); + return mSharedPreferences.getBoolean(Pref.USE_NUMKEYPAD_FOR_YUBIKEY_PIN, true); } public void setUseNumKeypadForYubikeyPin(boolean useNumKeypadForYubikeyPin) { -- cgit v1.2.3 From 09e992081bbe9b4522b940177bd9bd08d692b94c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Thu, 15 Jan 2015 14:48:13 +0100 Subject: Style tabs, add missing drawables --- .../keychain/ui/BaseActivity.java | 10 +- .../keychain/ui/HelpActivity.java | 20 +- .../keychain/ui/ViewKeyActivity.java | 33 +-- .../keychain/ui/widget/SlidingTabLayout.java | 318 --------------------- .../keychain/ui/widget/SlidingTabStrip.java | 211 -------------- 5 files changed, 25 insertions(+), 567 deletions(-) delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SlidingTabLayout.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SlidingTabStrip.java (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BaseActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BaseActivity.java index ee73bb8f2..c38d126d7 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BaseActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BaseActivity.java @@ -27,7 +27,7 @@ import org.sufficientlysecure.keychain.R; * Sets action bar */ public abstract class BaseActivity extends ActionBarActivity { - private Toolbar toolbar; + protected Toolbar mToolbar; @Override protected void onCreate(Bundle savedInstanceState) { @@ -39,14 +39,14 @@ public abstract class BaseActivity extends ActionBarActivity { protected abstract void initLayout(); protected void initToolbar() { - toolbar = (Toolbar) findViewById(R.id.toolbar); - if (toolbar != null) { - setSupportActionBar(toolbar); + mToolbar = (Toolbar) findViewById(R.id.toolbar); + if (mToolbar != null) { + setSupportActionBar(mToolbar); getSupportActionBar().setDisplayHomeAsUpEnabled(true); } } protected void setActionBarIcon(int iconRes) { - toolbar.setNavigationIcon(iconRes); + mToolbar.setNavigationIcon(iconRes); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpActivity.java index 8d4d3c915..2eb35351e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/HelpActivity.java @@ -20,12 +20,12 @@ package org.sufficientlysecure.keychain.ui; import android.content.Intent; import android.os.Bundle; import android.support.v4.view.ViewPager; -import android.support.v7.app.ActionBar; -import android.support.v7.app.ActionBarActivity; +import android.view.View; + +import com.astuetz.PagerSlidingTabStrip; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.ui.adapter.PagerTabStripAdapter; -import org.sufficientlysecure.keychain.ui.widget.SlidingTabLayout; public class HelpActivity extends BaseActivity { public static final String EXTRA_SELECTED_TAB = "selected_tab"; @@ -44,14 +44,16 @@ public class HelpActivity extends BaseActivity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - final ActionBar actionBar = getSupportActionBar(); - actionBar.setDisplayShowTitleEnabled(true); - actionBar.setDisplayHomeAsUpEnabled(false); - actionBar.setHomeButtonEnabled(false); + mToolbar.setNavigationOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + finish(); + } + }); mViewPager = (ViewPager) findViewById(R.id.pager); - SlidingTabLayout slidingTabLayout = - (SlidingTabLayout) findViewById(R.id.sliding_tab_layout); + PagerSlidingTabStrip slidingTabLayout = + (PagerSlidingTabStrip) findViewById(R.id.sliding_tab_layout); mTabsAdapter = new PagerTabStripAdapter(this); mViewPager.setAdapter(mTabsAdapter); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java index ae80679d0..3bb0695a0 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java @@ -21,7 +21,6 @@ package org.sufficientlysecure.keychain.ui; import android.annotation.TargetApi; import android.content.Intent; import android.database.Cursor; -import android.graphics.PorterDuff; import android.net.Uri; import android.nfc.NdefMessage; import android.nfc.NdefRecord; @@ -38,7 +37,6 @@ import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; import android.support.v4.view.ViewPager; import android.support.v7.app.ActionBar; -import android.support.v7.app.ActionBarActivity; import android.view.Menu; import android.view.MenuItem; import android.view.View; @@ -47,22 +45,21 @@ import android.widget.LinearLayout; import android.widget.TextView; import android.widget.Toast; +import com.astuetz.PagerSlidingTabStrip; + import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; -import org.sufficientlysecure.keychain.util.ContactHelper; -import org.sufficientlysecure.keychain.util.ExportHelper; -import org.sufficientlysecure.keychain.util.Preferences; +import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.pgp.KeyRing; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; -import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.ui.adapter.PagerTabStripAdapter; -import org.sufficientlysecure.keychain.ui.widget.SlidingTabLayout; -import org.sufficientlysecure.keychain.ui.widget.SlidingTabLayout.TabColorizer; -import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.Notify; +import org.sufficientlysecure.keychain.util.ContactHelper; +import org.sufficientlysecure.keychain.util.ExportHelper; +import org.sufficientlysecure.keychain.util.Log; import java.util.Date; import java.util.HashMap; @@ -81,7 +78,7 @@ public class ViewKeyActivity extends BaseActivity implements // view private ViewPager mViewPager; - private SlidingTabLayout mSlidingTabLayout; + private PagerSlidingTabStrip mSlidingTabLayout; private PagerTabStripAdapter mTabsAdapter; private LinearLayout mStatusLayout; @@ -117,19 +114,7 @@ public class ViewKeyActivity extends BaseActivity implements mStatusDivider = findViewById(R.id.view_key_status_divider); mViewPager = (ViewPager) findViewById(R.id.view_key_pager); - mSlidingTabLayout = (SlidingTabLayout) findViewById(R.id.view_key_sliding_tab_layout); - - mSlidingTabLayout.setCustomTabColorizer(new TabColorizer() { - @Override - public int getIndicatorColor(int position) { - return 0xFF4caf50; - } - - @Override - public int getDividerColor(int position) { - return 0; - } - }); + mSlidingTabLayout = (PagerSlidingTabStrip) findViewById(R.id.view_key_sliding_tab_layout); int switchToTab = TAB_MAIN; Intent intent = getIntent(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SlidingTabLayout.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SlidingTabLayout.java deleted file mode 100644 index 17471c86c..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SlidingTabLayout.java +++ /dev/null @@ -1,318 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.sufficientlysecure.keychain.ui.widget; - -import android.content.Context; -import android.graphics.Typeface; -import android.os.Build; -import android.support.v4.view.PagerAdapter; -import android.support.v4.view.ViewPager; -import android.util.AttributeSet; -import android.util.TypedValue; -import android.view.Gravity; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.HorizontalScrollView; -import android.widget.TextView; - -/** - * Copied from http://developer.android.com/samples/SlidingTabsColors/index.html - */ - -/** - * To be used with ViewPager to provide a tab indicator component which give constant feedback as to - * the user's scroll progress. - *

- * To use the component, simply add it to your view hierarchy. Then in your - * {@link android.app.Activity} or {@link android.support.v4.app.Fragment} call - * {@link #setViewPager(ViewPager)} providing it the ViewPager this layout is being used for. - *

- * The colors can be customized in two ways. The first and simplest is to provide an array of colors - * via {@link #setSelectedIndicatorColors(int...)} and {@link #setDividerColors(int...)}. The - * alternative is via the {@link TabColorizer} interface which provides you complete control over - * which color is used for any individual position. - *

- * The views used as tabs can be customized by calling {@link #setCustomTabView(int, int)}, - * providing the layout ID of your custom layout. - */ -public class SlidingTabLayout extends HorizontalScrollView { - - /** - * Allows complete control over the colors drawn in the tab layout. Set with - * {@link #setCustomTabColorizer(TabColorizer)}. - */ - public interface TabColorizer { - - /** - * @return return the color of the indicator used when {@code position} is selected. - */ - int getIndicatorColor(int position); - - /** - * @return return the color of the divider drawn to the right of {@code position}. - */ - int getDividerColor(int position); - - } - - private static final int TITLE_OFFSET_DIPS = 24; - private static final int TAB_VIEW_PADDING_DIPS = 16; - private static final int TAB_VIEW_TEXT_SIZE_SP = 12; - - private int mTitleOffset; - - private int mTabViewLayoutId; - private int mTabViewTextViewId; - - private ViewPager mViewPager; - private ViewPager.OnPageChangeListener mViewPagerPageChangeListener; - - private final SlidingTabStrip mTabStrip; - - public SlidingTabLayout(Context context) { - this(context, null); - } - - public SlidingTabLayout(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public SlidingTabLayout(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - - // Disable the Scroll Bar - setHorizontalScrollBarEnabled(false); - // Make sure that the Tab Strips fills this View - setFillViewport(true); - - mTitleOffset = (int) (TITLE_OFFSET_DIPS * getResources().getDisplayMetrics().density); - - mTabStrip = new SlidingTabStrip(context); - addView(mTabStrip, LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); - } - - /** - * Set the custom {@link TabColorizer} to be used. - *

- * If you only require simple custmisation then you can use - * {@link #setSelectedIndicatorColors(int...)} and {@link #setDividerColors(int...)} to achieve - * similar effects. - */ - public void setCustomTabColorizer(TabColorizer tabColorizer) { - mTabStrip.setCustomTabColorizer(tabColorizer); - } - - /** - * Sets the colors to be used for indicating the selected tab. These colors are treated as a - * circular array. Providing one color will mean that all tabs are indicated with the same color. - */ - public void setSelectedIndicatorColors(int... colors) { - mTabStrip.setSelectedIndicatorColors(colors); - } - - /** - * Sets the colors to be used for tab dividers. These colors are treated as a circular array. - * Providing one color will mean that all tabs are indicated with the same color. - */ - public void setDividerColors(int... colors) { - mTabStrip.setDividerColors(colors); - } - - /** - * Set the {@link ViewPager.OnPageChangeListener}. When using {@link SlidingTabLayout} you are - * required to set any {@link ViewPager.OnPageChangeListener} through this method. This is so - * that the layout can update it's scroll position correctly. - * - * @see ViewPager#setOnPageChangeListener(ViewPager.OnPageChangeListener) - */ - public void setOnPageChangeListener(ViewPager.OnPageChangeListener listener) { - mViewPagerPageChangeListener = listener; - } - - /** - * Set the custom layout to be inflated for the tab views. - * - * @param layoutResId Layout id to be inflated - * @param textViewId id of the {@link TextView} in the inflated view - */ - public void setCustomTabView(int layoutResId, int textViewId) { - mTabViewLayoutId = layoutResId; - mTabViewTextViewId = textViewId; - } - - /** - * Sets the associated view pager. Note that the assumption here is that the pager content - * (number of tabs and tab titles) does not change after this call has been made. - */ - public void setViewPager(ViewPager viewPager) { - mTabStrip.removeAllViews(); - - mViewPager = viewPager; - if (viewPager != null) { - viewPager.setOnPageChangeListener(new InternalViewPagerListener()); - populateTabStrip(); - } - } - - /** - * Create a default view to be used for tabs. This is called if a custom tab view is not set via - * {@link #setCustomTabView(int, int)}. - */ - protected TextView createDefaultTabView(Context context) { - TextView textView = new TextView(context); - textView.setGravity(Gravity.CENTER); - textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, TAB_VIEW_TEXT_SIZE_SP); - textView.setTypeface(Typeface.DEFAULT_BOLD); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { - // If we're running on Honeycomb or newer, then we can use the Theme's - // selectableItemBackground to ensure that the View has a pressed state - TypedValue outValue = new TypedValue(); - getContext().getTheme().resolveAttribute(android.R.attr.selectableItemBackground, - outValue, true); - textView.setBackgroundResource(outValue.resourceId); - } - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { - // If we're running on ICS or newer, enable all-caps to match the Action Bar tab style - textView.setAllCaps(true); - } - - int padding = (int) (TAB_VIEW_PADDING_DIPS * getResources().getDisplayMetrics().density); - textView.setPadding(padding, padding, padding, padding); - - return textView; - } - - private void populateTabStrip() { - final PagerAdapter adapter = mViewPager.getAdapter(); - final View.OnClickListener tabClickListener = new TabClickListener(); - - for (int i = 0; i < adapter.getCount(); i++) { - View tabView = null; - TextView tabTitleView = null; - - if (mTabViewLayoutId != 0) { - // If there is a custom tab view layout id set, try and inflate it - tabView = LayoutInflater.from(getContext()).inflate(mTabViewLayoutId, mTabStrip, - false); - tabTitleView = (TextView) tabView.findViewById(mTabViewTextViewId); - } - - if (tabView == null) { - tabView = createDefaultTabView(getContext()); - } - - if (tabTitleView == null && TextView.class.isInstance(tabView)) { - tabTitleView = (TextView) tabView; - } - - tabTitleView.setText(adapter.getPageTitle(i)); - tabView.setOnClickListener(tabClickListener); - - mTabStrip.addView(tabView); - } - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - - if (mViewPager != null) { - scrollToTab(mViewPager.getCurrentItem(), 0); - } - } - - private void scrollToTab(int tabIndex, int positionOffset) { - final int tabStripChildCount = mTabStrip.getChildCount(); - if (tabStripChildCount == 0 || tabIndex < 0 || tabIndex >= tabStripChildCount) { - return; - } - - View selectedChild = mTabStrip.getChildAt(tabIndex); - if (selectedChild != null) { - int targetScrollX = selectedChild.getLeft() + positionOffset; - - if (tabIndex > 0 || positionOffset > 0) { - // If we're not at the first child and are mid-scroll, make sure we obey the offset - targetScrollX -= mTitleOffset; - } - - scrollTo(targetScrollX, 0); - } - } - - private class InternalViewPagerListener implements ViewPager.OnPageChangeListener { - private int mScrollState; - - @Override - public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { - int tabStripChildCount = mTabStrip.getChildCount(); - if ((tabStripChildCount == 0) || (position < 0) || (position >= tabStripChildCount)) { - return; - } - - mTabStrip.onViewPagerPageChanged(position, positionOffset); - - View selectedTitle = mTabStrip.getChildAt(position); - int extraOffset = (selectedTitle != null) - ? (int) (positionOffset * selectedTitle.getWidth()) - : 0; - scrollToTab(position, extraOffset); - - if (mViewPagerPageChangeListener != null) { - mViewPagerPageChangeListener.onPageScrolled(position, positionOffset, - positionOffsetPixels); - } - } - - @Override - public void onPageScrollStateChanged(int state) { - mScrollState = state; - - if (mViewPagerPageChangeListener != null) { - mViewPagerPageChangeListener.onPageScrollStateChanged(state); - } - } - - @Override - public void onPageSelected(int position) { - if (mScrollState == ViewPager.SCROLL_STATE_IDLE) { - mTabStrip.onViewPagerPageChanged(position, 0f); - scrollToTab(position, 0); - } - - if (mViewPagerPageChangeListener != null) { - mViewPagerPageChangeListener.onPageSelected(position); - } - } - - } - - private class TabClickListener implements View.OnClickListener { - @Override - public void onClick(View v) { - for (int i = 0; i < mTabStrip.getChildCount(); i++) { - if (v == mTabStrip.getChildAt(i)) { - mViewPager.setCurrentItem(i); - return; - } - } - } - } - -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SlidingTabStrip.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SlidingTabStrip.java deleted file mode 100644 index 4c41e12c5..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SlidingTabStrip.java +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.sufficientlysecure.keychain.ui.widget; - -import android.R; -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.util.AttributeSet; -import android.util.TypedValue; -import android.view.View; -import android.widget.LinearLayout; - -/** - * Copied from http://developer.android.com/samples/SlidingTabsColors/index.html - */ -class SlidingTabStrip extends LinearLayout { - - private static final int DEFAULT_BOTTOM_BORDER_THICKNESS_DIPS = 2; - private static final byte DEFAULT_BOTTOM_BORDER_COLOR_ALPHA = 0x26; - private static final int SELECTED_INDICATOR_THICKNESS_DIPS = 8; - private static final int DEFAULT_SELECTED_INDICATOR_COLOR = 0xFFAA66CC; - - private static final int DEFAULT_DIVIDER_THICKNESS_DIPS = 1; - private static final byte DEFAULT_DIVIDER_COLOR_ALPHA = 0x20; - private static final float DEFAULT_DIVIDER_HEIGHT = 0.5f; - - private final int mBottomBorderThickness; - private final Paint mBottomBorderPaint; - - private final int mSelectedIndicatorThickness; - private final Paint mSelectedIndicatorPaint; - - private final int mDefaultBottomBorderColor; - - private final Paint mDividerPaint; - private final float mDividerHeight; - - private int mSelectedPosition; - private float mSelectionOffset; - - private SlidingTabLayout.TabColorizer mCustomTabColorizer; - private final SimpleTabColorizer mDefaultTabColorizer; - - SlidingTabStrip(Context context) { - this(context, null); - } - - SlidingTabStrip(Context context, AttributeSet attrs) { - super(context, attrs); - setWillNotDraw(false); - - final float density = getResources().getDisplayMetrics().density; - - TypedValue outValue = new TypedValue(); - context.getTheme().resolveAttribute(R.attr.colorForeground, outValue, true); - final int themeForegroundColor = outValue.data; - - mDefaultBottomBorderColor = setColorAlpha(themeForegroundColor, - DEFAULT_BOTTOM_BORDER_COLOR_ALPHA); - - mDefaultTabColorizer = new SimpleTabColorizer(); - mDefaultTabColorizer.setIndicatorColors(DEFAULT_SELECTED_INDICATOR_COLOR); - mDefaultTabColorizer.setDividerColors(setColorAlpha(themeForegroundColor, - DEFAULT_DIVIDER_COLOR_ALPHA)); - - mBottomBorderThickness = (int) (DEFAULT_BOTTOM_BORDER_THICKNESS_DIPS * density); - mBottomBorderPaint = new Paint(); - mBottomBorderPaint.setColor(mDefaultBottomBorderColor); - - mSelectedIndicatorThickness = (int) (SELECTED_INDICATOR_THICKNESS_DIPS * density); - mSelectedIndicatorPaint = new Paint(); - - mDividerHeight = DEFAULT_DIVIDER_HEIGHT; - mDividerPaint = new Paint(); - mDividerPaint.setStrokeWidth((int) (DEFAULT_DIVIDER_THICKNESS_DIPS * density)); - } - - void setCustomTabColorizer(SlidingTabLayout.TabColorizer customTabColorizer) { - mCustomTabColorizer = customTabColorizer; - invalidate(); - } - - void setSelectedIndicatorColors(int... colors) { - // Make sure that the custom colorizer is removed - mCustomTabColorizer = null; - mDefaultTabColorizer.setIndicatorColors(colors); - invalidate(); - } - - void setDividerColors(int... colors) { - // Make sure that the custom colorizer is removed - mCustomTabColorizer = null; - mDefaultTabColorizer.setDividerColors(colors); - invalidate(); - } - - void onViewPagerPageChanged(int position, float positionOffset) { - mSelectedPosition = position; - mSelectionOffset = positionOffset; - invalidate(); - } - - @Override - protected void onDraw(Canvas canvas) { - final int height = getHeight(); - final int childCount = getChildCount(); - final int dividerHeightPx = (int) (Math.min(Math.max(0f, mDividerHeight), 1f) * height); - final SlidingTabLayout.TabColorizer tabColorizer = mCustomTabColorizer != null - ? mCustomTabColorizer - : mDefaultTabColorizer; - - // Thick colored underline below the current selection - if (childCount > 0) { - View selectedTitle = getChildAt(mSelectedPosition); - int left = selectedTitle.getLeft(); - int right = selectedTitle.getRight(); - int color = tabColorizer.getIndicatorColor(mSelectedPosition); - - if (mSelectionOffset > 0f && mSelectedPosition < (getChildCount() - 1)) { - int nextColor = tabColorizer.getIndicatorColor(mSelectedPosition + 1); - if (color != nextColor) { - color = blendColors(nextColor, color, mSelectionOffset); - } - - // Draw the selection partway between the tabs - View nextTitle = getChildAt(mSelectedPosition + 1); - left = (int) (mSelectionOffset * nextTitle.getLeft() + - (1.0f - mSelectionOffset) * left); - right = (int) (mSelectionOffset * nextTitle.getRight() + - (1.0f - mSelectionOffset) * right); - } - - mSelectedIndicatorPaint.setColor(color); - - canvas.drawRect(left, height - mSelectedIndicatorThickness, right, - height, mSelectedIndicatorPaint); - } - - // Thin underline along the entire bottom edge - canvas.drawRect(0, height - mBottomBorderThickness, getWidth(), height, mBottomBorderPaint); - - // Vertical separators between the titles - int separatorTop = (height - dividerHeightPx) / 2; - for (int i = 0; i < childCount - 1; i++) { - View child = getChildAt(i); - mDividerPaint.setColor(tabColorizer.getDividerColor(i)); - canvas.drawLine(child.getRight(), separatorTop, child.getRight(), - separatorTop + dividerHeightPx, mDividerPaint); - } - } - - /** - * Set the alpha value of the {@code color} to be the given {@code alpha} value. - */ - private static int setColorAlpha(int color, byte alpha) { - return Color.argb(alpha, Color.red(color), Color.green(color), Color.blue(color)); - } - - /** - * Blend {@code color1} and {@code color2} using the given ratio. - * - * @param ratio of which to blend. 1.0 will return {@code color1}, 0.5 will give an even blend, - * 0.0 will return {@code color2}. - */ - private static int blendColors(int color1, int color2, float ratio) { - final float inverseRation = 1f - ratio; - float r = (Color.red(color1) * ratio) + (Color.red(color2) * inverseRation); - float g = (Color.green(color1) * ratio) + (Color.green(color2) * inverseRation); - float b = (Color.blue(color1) * ratio) + (Color.blue(color2) * inverseRation); - return Color.rgb((int) r, (int) g, (int) b); - } - - private static class SimpleTabColorizer implements SlidingTabLayout.TabColorizer { - private int[] mIndicatorColors; - private int[] mDividerColors; - - @Override - public final int getIndicatorColor(int position) { - return mIndicatorColors[position % mIndicatorColors.length]; - } - - @Override - public final int getDividerColor(int position) { - return mDividerColors[position % mDividerColors.length]; - } - - void setIndicatorColors(int... colors) { - mIndicatorColors = colors; - } - - void setDividerColors(int... colors) { - mDividerColors = colors; - } - } -} \ No newline at end of file -- cgit v1.2.3 From b6f0fb91dad78506f6498eec60de7ea9040e0276 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Fri, 16 Jan 2015 13:50:25 +0100 Subject: show notification if KeyListActivity is spawned with an EXTRA_RESULT Closes #1029 Conflicts: OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java --- .../org/sufficientlysecure/keychain/ui/FirstTimeActivity.java | 3 ++- .../java/org/sufficientlysecure/keychain/ui/KeyListActivity.java | 9 +++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/FirstTimeActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/FirstTimeActivity.java index e5db48304..e487c8947 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/FirstTimeActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/FirstTimeActivity.java @@ -98,7 +98,7 @@ public class FirstTimeActivity extends BaseActivity { if (srcData != null) { intent.putExtras(srcData); } - startActivityForResult(intent, 0); + startActivity(intent); finish(); } @@ -107,4 +107,5 @@ public class FirstTimeActivity extends BaseActivity { public boolean onKeyDown(int keyCode, KeyEvent event) { return keyCode == KeyEvent.KEYCODE_MENU || super.onKeyDown(keyCode, event); } + } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java index 7d037f85d..0b06bd06f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java @@ -64,6 +64,15 @@ public class KeyListActivity extends DrawerActivity { mExportHelper = new ExportHelper(this); + setContentView(R.layout.key_list_activity); + + Intent data = getIntent(); + // If we got an EXTRA_RESULT in the intent, show the notification + if (data != null && data.hasExtra(OperationResult.EXTRA_RESULT)) { + OperationResult result = data.getParcelableExtra(OperationResult.EXTRA_RESULT); + result.createNotify(this).show(); + } + // now setup navigation drawer in DrawerActivity... activateDrawerNavigation(savedInstanceState); } -- cgit v1.2.3 From 491c12d5d3d321e94a0a18219c83702cf4a517e6 Mon Sep 17 00:00:00 2001 From: Vincent Date: Fri, 16 Jan 2015 15:41:43 +0100 Subject: No setContentView in onCreate for KeyListActivity --- .../main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java | 2 -- 1 file changed, 2 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java index 0b06bd06f..1d9a9cf64 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java @@ -64,8 +64,6 @@ public class KeyListActivity extends DrawerActivity { mExportHelper = new ExportHelper(this); - setContentView(R.layout.key_list_activity); - Intent data = getIntent(); // If we got an EXTRA_RESULT in the intent, show the notification if (data != null && data.hasExtra(OperationResult.EXTRA_RESULT)) { -- cgit v1.2.3 From 198ddfeff7324533fb2daea778891def04f8e8c2 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Mon, 19 Jan 2015 15:43:35 +0100 Subject: use Notify helper everywhere, replace supertoasts with snackbar library --- .../keychain/operations/results/CertifyResult.java | 66 ++++-------- .../keychain/operations/results/DeleteResult.java | 64 ++++-------- .../operations/results/ImportKeyResult.java | 68 +++++-------- .../operations/results/OperationResult.java | 67 ++++++------- .../operations/results/SingletonResult.java | 29 ------ .../keychain/ui/util/Notify.java | 111 +++++++++++++++++++-- 6 files changed, 196 insertions(+), 209 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/CertifyResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/CertifyResult.java index 7b38cd244..94684851a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/CertifyResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/CertifyResult.java @@ -21,18 +21,14 @@ package org.sufficientlysecure.keychain.operations.results; import android.app.Activity; import android.content.Intent; import android.os.Parcel; -import android.os.Parcelable; -import android.view.View; - -import com.github.johnpersano.supertoasts.SuperCardToast; -import com.github.johnpersano.supertoasts.SuperToast; -import com.github.johnpersano.supertoasts.SuperToast.Duration; -import com.github.johnpersano.supertoasts.util.OnClickWrapper; -import com.github.johnpersano.supertoasts.util.Style; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.ui.LogDisplayActivity; import org.sufficientlysecure.keychain.ui.LogDisplayFragment; +import org.sufficientlysecure.keychain.ui.util.Notify; +import org.sufficientlysecure.keychain.ui.util.Notify.ActionListener; +import org.sufficientlysecure.keychain.ui.util.Notify.Showable; +import org.sufficientlysecure.keychain.ui.util.Notify.Style; public class CertifyResult extends OperationResult { @@ -78,30 +74,31 @@ public class CertifyResult extends OperationResult { } }; - public SuperCardToast createNotify(final Activity activity) { + public Showable createNotify(final Activity activity) { int resultType = getResult(); String str; - int duration, color; + int duration; + Style style; // Not an overall failure if ((resultType & OperationResult.RESULT_ERROR) == 0) { String withWarnings; - duration = Duration.EXTRA_LONG; - color = Style.GREEN; + duration = Notify.LENGTH_LONG; + style = Style.OK; withWarnings = ""; // Any warnings? if ((resultType & ImportKeyResult.RESULT_WARNINGS) > 0) { duration = 0; - color = Style.ORANGE; + style = Style.WARN; withWarnings += activity.getString(R.string.with_warnings); } if ((resultType & ImportKeyResult.RESULT_CANCELLED) > 0) { duration = 0; - color = Style.ORANGE; + style = Style.WARN; withWarnings += activity.getString(R.string.with_cancelled); } @@ -111,46 +108,27 @@ public class CertifyResult extends OperationResult { if (mCertifyError > 0) { // definitely switch to warning-style message in this case! duration = 0; - color = Style.RED; + style = Style.ERROR; str += " " + activity.getResources().getQuantityString( R.plurals.certify_keys_with_errors, mCertifyError, mCertifyError); } } else { duration = 0; - color = Style.RED; + style = Style.ERROR; str = activity.getResources().getQuantityString(R.plurals.certify_error, mCertifyError, mCertifyError); } - boolean button = getLog() != null && !getLog().isEmpty(); - SuperCardToast toast = new SuperCardToast(activity, - button ? SuperToast.Type.BUTTON : SuperToast.Type.STANDARD, - Style.getStyle(color, SuperToast.Animations.POPUP)); - toast.setText(str); - toast.setDuration(duration); - toast.setIndeterminate(duration == 0); - toast.setSwipeToDismiss(true); - // If we have a log and it's non-empty, show a View Log button - if (button) { - toast.setButtonIcon(R.drawable.ic_action_view_as_list, - activity.getResources().getString(R.string.view_log)); - toast.setButtonTextColor(activity.getResources().getColor(R.color.black)); - toast.setTextColor(activity.getResources().getColor(R.color.black)); - toast.setOnClickWrapper(new OnClickWrapper("supercardtoast", - new SuperToast.OnClickListener() { - @Override - public void onClick(View view, Parcelable token) { - Intent intent = new Intent( - activity, LogDisplayActivity.class); - intent.putExtra(LogDisplayFragment.EXTRA_RESULT, CertifyResult.this); - activity.startActivity(intent); - } - } - )); - } - - return toast; + return Notify.createNotify(activity, str, duration, style, new ActionListener() { + @Override + public void onAction() { + Intent intent = new Intent( + activity, LogDisplayActivity.class); + intent.putExtra(LogDisplayFragment.EXTRA_RESULT, CertifyResult.this); + activity.startActivity(intent); + } + }, R.string.view_log); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DeleteResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DeleteResult.java index 1ca5ad20a..e69fb59f2 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DeleteResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DeleteResult.java @@ -24,15 +24,13 @@ import android.os.Parcel; import android.os.Parcelable; import android.view.View; -import com.github.johnpersano.supertoasts.SuperCardToast; -import com.github.johnpersano.supertoasts.SuperToast; -import com.github.johnpersano.supertoasts.SuperToast.Duration; -import com.github.johnpersano.supertoasts.util.OnClickWrapper; -import com.github.johnpersano.supertoasts.util.Style; - import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.ui.LogDisplayActivity; import org.sufficientlysecure.keychain.ui.LogDisplayFragment; +import org.sufficientlysecure.keychain.ui.util.Notify; +import org.sufficientlysecure.keychain.ui.util.Notify.ActionListener; +import org.sufficientlysecure.keychain.ui.util.Notify.Showable; +import org.sufficientlysecure.keychain.ui.util.Notify.Style; public class DeleteResult extends OperationResult { @@ -68,31 +66,32 @@ public class DeleteResult extends OperationResult { } }; - public SuperCardToast createNotify(final Activity activity) { + public Showable createNotify(final Activity activity) { int resultType = getResult(); String str; - int duration, color; + int duration; + Style style; // Not an overall failure if ((resultType & OperationResult.RESULT_ERROR) == 0) { String untilCancelled; - duration = Duration.EXTRA_LONG; - color = Style.GREEN; + duration = Notify.LENGTH_LONG; + style = Style.OK; untilCancelled = ""; // Any warnings? if ((resultType & ImportKeyResult.RESULT_CANCELLED) > 0) { duration = 0; - color = Style.ORANGE; + style = Style.WARN; untilCancelled += activity.getString(R.string.with_cancelled); } // New and updated keys if (mOk > 0 && mFail > 0) { - color = Style.ORANGE; + style = Style.WARN; duration = 0; str = activity.getResources().getQuantityString( R.plurals.delete_ok_but_fail_1, mOk, mOk); @@ -105,13 +104,13 @@ public class DeleteResult extends OperationResult { str = activity.getString(R.string.delete_cancelled); } else { duration = 0; - color = Style.RED; + style = Style.ERROR; str = "internal error"; } } else { duration = 0; - color = Style.RED; + style = Style.ERROR; if (mFail == 0) { str = activity.getString(R.string.delete_nothing); } else { @@ -119,34 +118,15 @@ public class DeleteResult extends OperationResult { } } - boolean button = getLog() != null && !getLog().isEmpty(); - SuperCardToast toast = new SuperCardToast(activity, - button ? SuperToast.Type.BUTTON : SuperToast.Type.STANDARD, - Style.getStyle(color, SuperToast.Animations.POPUP)); - toast.setText(str); - toast.setDuration(duration); - toast.setIndeterminate(duration == 0); - toast.setSwipeToDismiss(true); - // If we have a log and it's non-empty, show a View Log button - if (button) { - toast.setButtonIcon(R.drawable.ic_action_view_as_list, - activity.getResources().getString(R.string.view_log)); - toast.setButtonTextColor(activity.getResources().getColor(R.color.black)); - toast.setTextColor(activity.getResources().getColor(R.color.black)); - toast.setOnClickWrapper(new OnClickWrapper("supercardtoast", - new SuperToast.OnClickListener() { - @Override - public void onClick(View view, Parcelable token) { - Intent intent = new Intent( - activity, LogDisplayActivity.class); - intent.putExtra(LogDisplayFragment.EXTRA_RESULT, DeleteResult.this); - activity.startActivity(intent); - } - } - )); - } - - return toast; + return Notify.createNotify(activity, str, duration, style, new ActionListener() { + @Override + public void onAction() { + Intent intent = new Intent( + activity, LogDisplayActivity.class); + intent.putExtra(LogDisplayFragment.EXTRA_RESULT, DeleteResult.this); + activity.startActivity(intent); + } + }, R.string.view_log); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/ImportKeyResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/ImportKeyResult.java index 1dd038a23..ecde90ea6 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/ImportKeyResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/ImportKeyResult.java @@ -21,18 +21,14 @@ package org.sufficientlysecure.keychain.operations.results; import android.app.Activity; import android.content.Intent; import android.os.Parcel; -import android.os.Parcelable; -import android.view.View; - -import com.github.johnpersano.supertoasts.SuperCardToast; -import com.github.johnpersano.supertoasts.SuperToast; -import com.github.johnpersano.supertoasts.SuperToast.Duration; -import com.github.johnpersano.supertoasts.util.OnClickWrapper; -import com.github.johnpersano.supertoasts.util.Style; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.ui.LogDisplayActivity; import org.sufficientlysecure.keychain.ui.LogDisplayFragment; +import org.sufficientlysecure.keychain.ui.util.Notify; +import org.sufficientlysecure.keychain.ui.util.Notify.ActionListener; +import org.sufficientlysecure.keychain.ui.util.Notify.Showable; +import org.sufficientlysecure.keychain.ui.util.Notify.Style; public class ImportKeyResult extends OperationResult { @@ -114,30 +110,31 @@ public class ImportKeyResult extends OperationResult { } }; - public SuperCardToast createNotify(final Activity activity) { + public Showable createNotify(final Activity activity) { int resultType = getResult(); String str; - int duration, color; + int duration; + Style style; // Not an overall failure if ((resultType & OperationResult.RESULT_ERROR) == 0) { String withWarnings; - duration = Duration.EXTRA_LONG; - color = Style.GREEN; + duration = Notify.LENGTH_LONG; + style = Style.OK; withWarnings = ""; // Any warnings? if ((resultType & ImportKeyResult.RESULT_WARNINGS) > 0) { duration = 0; - color = Style.ORANGE; + style = Style.WARN; withWarnings += activity.getString(R.string.with_warnings); } if ((resultType & ImportKeyResult.RESULT_CANCELLED) > 0) { duration = 0; - color = Style.ORANGE; + style = Style.WARN; withWarnings += activity.getString(R.string.with_cancelled); } @@ -155,20 +152,20 @@ public class ImportKeyResult extends OperationResult { R.plurals.import_keys_added, mNewKeys, mNewKeys, withWarnings); } else { duration = 0; - color = Style.RED; + style = Style.ERROR; str = "internal error"; } if (isOkWithErrors()) { // definitely switch to warning-style message in this case! duration = 0; - color = Style.RED; + style = Style.ERROR; str += " " + activity.getResources().getQuantityString( R.plurals.import_keys_with_errors, mBadKeys, mBadKeys); } } else { duration = 0; - color = Style.RED; + style = Style.ERROR; if (isFailNothing()) { str = activity.getString((resultType & ImportKeyResult.RESULT_CANCELLED) > 0 ? R.string.import_error_nothing_cancelled @@ -178,34 +175,15 @@ public class ImportKeyResult extends OperationResult { } } - boolean button = getLog() != null && !getLog().isEmpty(); - SuperCardToast toast = new SuperCardToast(activity, - button ? SuperToast.Type.BUTTON : SuperToast.Type.STANDARD, - Style.getStyle(color, SuperToast.Animations.POPUP)); - toast.setText(str); - toast.setDuration(duration); - toast.setIndeterminate(duration == 0); - toast.setSwipeToDismiss(true); - // If we have a log and it's non-empty, show a View Log button - if (button) { - toast.setButtonIcon(R.drawable.ic_action_view_as_list, - activity.getResources().getString(R.string.view_log)); - toast.setButtonTextColor(activity.getResources().getColor(R.color.black)); - toast.setTextColor(activity.getResources().getColor(R.color.black)); - toast.setOnClickWrapper(new OnClickWrapper("supercardtoast", - new SuperToast.OnClickListener() { - @Override - public void onClick(View view, Parcelable token) { - Intent intent = new Intent( - activity, LogDisplayActivity.class); - intent.putExtra(LogDisplayFragment.EXTRA_RESULT, ImportKeyResult.this); - activity.startActivity(intent); - } - } - )); - } - - return toast; + return Notify.createNotify(activity, str, duration, style, new ActionListener() { + @Override + public void onAction() { + Intent intent = new Intent( + activity, LogDisplayActivity.class); + intent.putExtra(LogDisplayFragment.EXTRA_RESULT, ImportKeyResult.this); + activity.startActivity(intent); + } + }, R.string.view_log); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java index 8c76ebb8a..6552948fa 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java @@ -20,19 +20,24 @@ package org.sufficientlysecure.keychain.operations.results; import android.app.Activity; import android.content.Intent; +import android.graphics.Color; import android.os.Parcel; import android.os.Parcelable; import android.view.View; -import com.github.johnpersano.supertoasts.SuperCardToast; -import com.github.johnpersano.supertoasts.SuperToast; -import com.github.johnpersano.supertoasts.util.OnClickWrapper; -import com.github.johnpersano.supertoasts.util.Style; +import com.nispok.snackbar.Snackbar; +import com.nispok.snackbar.Snackbar.SnackbarDuration; +import com.nispok.snackbar.SnackbarManager; +import com.nispok.snackbar.listeners.ActionClickListener; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.ui.LogDisplayActivity; import org.sufficientlysecure.keychain.ui.LogDisplayFragment; +import org.sufficientlysecure.keychain.ui.util.Notify; +import org.sufficientlysecure.keychain.ui.util.Notify.ActionListener; +import org.sufficientlysecure.keychain.ui.util.Notify.Showable; +import org.sufficientlysecure.keychain.ui.util.Notify.Style; import org.sufficientlysecure.keychain.util.IterableIterator; import org.sufficientlysecure.keychain.util.Log; @@ -195,58 +200,44 @@ public abstract class OperationResult implements Parcelable { } - public SuperCardToast createNotify(final Activity activity) { - - int color; + public Showable createNotify(final Activity activity) { Log.d(Constants.TAG, "mLog.getLast()"+mLog.getLast()); Log.d(Constants.TAG, "mLog.getLast().mType"+mLog.getLast().mType); Log.d(Constants.TAG, "mLog.getLast().mType.getMsgId()"+mLog.getLast().mType.getMsgId()); // Take the last message as string - String str = activity.getString(mLog.getLast().mType.getMsgId()); + int msgId = mLog.getLast().mType.getMsgId(); + + Style style; // Not an overall failure if (cancelled()) { - color = Style.RED; + style = Style.ERROR; } else if (success()) { if (getLog().containsWarnings()) { - color = Style.ORANGE; + style = Style.WARN; } else { - color = Style.GREEN; + style = Style.OK; } } else { - color = Style.RED; + style = Style.ERROR; } - boolean button = getLog() != null && !getLog().isEmpty(); - SuperCardToast toast = new SuperCardToast(activity, - button ? SuperToast.Type.BUTTON : SuperToast.Type.STANDARD, - Style.getStyle(color, SuperToast.Animations.POPUP)); - toast.setText(str); - toast.setDuration(SuperToast.Duration.EXTRA_LONG); - toast.setIndeterminate(false); - toast.setSwipeToDismiss(true); - // If we have a log and it's non-empty, show a View Log button - if (button) { - toast.setButtonIcon(R.drawable.ic_action_view_as_list, - activity.getResources().getString(R.string.view_log)); - toast.setButtonTextColor(activity.getResources().getColor(R.color.black)); - toast.setTextColor(activity.getResources().getColor(R.color.black)); - toast.setOnClickWrapper(new OnClickWrapper("supercardtoast", - new SuperToast.OnClickListener() { - @Override - public void onClick(View view, Parcelable token) { - Intent intent = new Intent( - activity, LogDisplayActivity.class); - intent.putExtra(LogDisplayFragment.EXTRA_RESULT, OperationResult.this); - activity.startActivity(intent); - } - } - )); + if (getLog() == null || getLog().isEmpty()) { + return Notify.createNotify(activity, msgId, Notify.LENGTH_LONG, style); } - return toast; + return Notify.createNotify(activity, msgId, Notify.LENGTH_LONG, style, + new ActionListener() { + @Override + public void onAction() { + Intent intent = new Intent( + activity, LogDisplayActivity.class); + intent.putExtra(LogDisplayFragment.EXTRA_RESULT, OperationResult.this); + activity.startActivity(intent); + } + }, R.string.view_log); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/SingletonResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/SingletonResult.java index 43cc85522..b53eda5f6 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/SingletonResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/SingletonResult.java @@ -40,35 +40,6 @@ public class SingletonResult extends OperationResult { mLog.add(reason, 0); } - @Override - public SuperCardToast createNotify(final Activity activity) { - - // there is exactly one error msg - use that one - String str = activity.getString(mLog.iterator().next().mType.getMsgId()); - int color; - - // Determine color by result type - if (cancelled()) { - color = Style.RED; - } else if (success()) { - if (getLog().containsWarnings()) { - color = Style.ORANGE; - } else { - color = Style.GREEN; - } - } else { - color = Style.RED; - } - - SuperCardToast toast = new SuperCardToast(activity, SuperToast.Type.STANDARD, - Style.getStyle(color, SuperToast.Animations.POPUP)); - toast.setText(str); - toast.setDuration(SuperToast.Duration.EXTRA_LONG); - toast.setIndeterminate(false); - toast.setSwipeToDismiss(true); - return toast; - } - @Override public void writeToParcel(Parcel dest, int flags) { super.writeToParcel(dest, flags); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/Notify.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/Notify.java index 551ac039d..66d6bf9e3 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/Notify.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/Notify.java @@ -19,18 +19,23 @@ package org.sufficientlysecure.keychain.ui.util; import android.app.Activity; import android.content.res.Resources; +import android.graphics.Color; -import com.github.johnpersano.supertoasts.SuperCardToast; -import com.github.johnpersano.supertoasts.SuperToast; +import com.nispok.snackbar.Snackbar; +import com.nispok.snackbar.Snackbar.SnackbarDuration; +import com.nispok.snackbar.SnackbarManager; +import com.nispok.snackbar.listeners.ActionClickListener; /** - * @author danielhass * Notify wrapper which allows a more easy use of different notification libraries */ public class Notify { public static enum Style {OK, WARN, INFO, ERROR} + public static final int LENGTH_INDEFINITE = 0; + public static final int LENGTH_LONG = 3500; + /** * Shows a simple in-layout notification with the CharSequence given as parameter * @param activity @@ -39,21 +44,94 @@ public class Notify { */ public static void showNotify(Activity activity, CharSequence text, Style style) { - SuperCardToast st = new SuperCardToast(activity); - st.setText(text); - st.setDuration(SuperToast.Duration.MEDIUM); - switch (style){ + Snackbar bar = Snackbar.with(activity) + .text(text) + .duration(SnackbarDuration.LENGTH_LONG); + + switch (style) { case OK: - st.setBackground(SuperToast.Background.GREEN); break; case WARN: - st.setBackground(SuperToast.Background.ORANGE); + bar.textColor(Color.YELLOW); break; case ERROR: - st.setBackground(SuperToast.Background.RED); + bar.textColor(Color.RED); break; } - st.show(); + + SnackbarManager.show(bar); + + } + + public static Showable createNotify (Activity activity, int resId, int duration, Style style) { + final Snackbar bar = Snackbar.with(activity) + .text(resId); + if (duration == LENGTH_INDEFINITE) { + bar.duration(SnackbarDuration.LENGTH_INDEFINITE); + } else { + bar.duration(duration); + } + + switch (style) { + case OK: + bar.actionColor(Color.GREEN); + break; + case WARN: + bar.textColor(Color.YELLOW); + break; + case ERROR: + bar.textColor(Color.RED); + break; + } + + return new Showable () { + @Override + public void show() { + SnackbarManager.show(bar); + } + }; + } + + public static Showable createNotify(Activity activity, int resId, int duration, Style style, + final ActionListener listener, int resIdAction) { + return createNotify(activity, activity.getString(resId), duration, style, listener, resIdAction); + } + + public static Showable createNotify(Activity activity, String msg, int duration, Style style, + final ActionListener listener, int resIdAction) { + final Snackbar bar = Snackbar.with(activity) + .text(msg) + .actionLabel(resIdAction) + .actionListener(new ActionClickListener() { + @Override + public void onActionClicked(Snackbar snackbar) { + listener.onAction(); + } + }); + if (duration == LENGTH_INDEFINITE) { + bar.duration(SnackbarDuration.LENGTH_INDEFINITE); + } else { + bar.duration(duration); + } + + switch (style) { + case OK: + bar.actionColor(Color.GREEN); + break; + case WARN: + bar.textColor(Color.YELLOW); + break; + case ERROR: + bar.textColor(Color.RED); + break; + } + + return new Showable () { + @Override + public void show() { + SnackbarManager.show(bar); + } + }; } @@ -67,4 +145,15 @@ public class Notify { public static void showNotify(Activity activity, int resId, Style style) throws Resources.NotFoundException { showNotify(activity, activity.getResources().getText(resId), style); } + + public interface Showable { + public void show(); + + } + + public interface ActionListener { + public void onAction(); + + } + } \ No newline at end of file -- cgit v1.2.3 From 3ac466c9db5f3a10a9d25fd7d85efb71fc7ad5dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Mon, 19 Jan 2015 17:22:31 +0100 Subject: Disable sharing chooser blacklisting for lollipop --- .../org/sufficientlysecure/keychain/ui/DecryptTextFragment.java | 2 +- .../org/sufficientlysecure/keychain/ui/EncryptTextActivity.java | 1 + .../main/java/org/sufficientlysecure/keychain/util/ShareHelper.java | 6 ++++-- 3 files changed, 6 insertions(+), 3 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextFragment.java index fa7abf0f5..83ba64ce2 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextFragment.java @@ -111,7 +111,7 @@ public class DecryptTextFragment extends DecryptFragment { Intent prototype = createSendIntent(text); String title = getString(R.string.title_share_file); - // we don't want to decrypt the decypted, no inception ;) + // we don't want to decrypt the decrypted, no inception ;) String[] blacklist = new String[]{ Constants.PACKAGE_NAME + ".ui.DecryptTextActivity", "org.thialfihar.android.apg.ui.DecryptActivity" diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java index 757d1fb02..9b06a0b75 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java @@ -247,6 +247,7 @@ public class EncryptTextActivity extends EncryptActivity implements EncryptActiv users.add(userId[1]); } } + // pass trough email addresses as extra for email applications sendIntent.putExtra(Intent.EXTRA_EMAIL, users.toArray(new String[users.size()])); } return sendIntent; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ShareHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ShareHelper.java index 51e58565f..e97438772 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ShareHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ShareHelper.java @@ -43,9 +43,11 @@ public class ShareHelper { * Put together from some stackoverflow posts... */ public Intent createChooserExcluding(Intent prototype, String title, String[] activityBlacklist) { - // Produced an empty list on Huawei U8860 with Android Version 4.0.3 and weird results on 2.3 + // Produced an empty list on Huawei U8860 with Android Version 4.0.3 // TODO: test on 4.1, 4.2, 4.3, only tested on 4.4 - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) { + // Disabled on 5.0 because using EXTRA_INITIAL_INTENTS prevents the usage based sorting + // introduced in 5.0: https://medium.com/@xXxXxXxXxXam/how-lollipops-share-menu-is-organized-d204888f606d + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT || Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { return Intent.createChooser(prototype, title); } -- cgit v1.2.3 From e71bd3d9dd80d7f9721192238b9f30093c1c6bfc Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Mon, 19 Jan 2015 17:29:33 +0100 Subject: always show revoked user ids last! --- .../org/sufficientlysecure/keychain/provider/ProviderHelper.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java index c3990229d..b2af5a0a0 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java @@ -716,6 +716,10 @@ public class ProviderHelper { @Override public int compareTo(UserPacketItem o) { + // revoked keys always come last! + if (isRevoked != o.isRevoked) { + return isRevoked ? 1 : -1; + } // if one is a user id, but the other isn't, the user id always comes first. // we compare for null values here, so != is the correct operator! // noinspection NumberEquality @@ -726,10 +730,6 @@ public class ProviderHelper { if (isPrimary != o.isPrimary) { return isPrimary ? -1 : 1; } - // revoked keys always come last! - if (isRevoked != o.isRevoked) { - return isRevoked ? 1 : -1; - } return 0; } } -- cgit v1.2.3 From a65edcdb2ffb7399daf5359f0f57bf791c23b7d8 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Mon, 19 Jan 2015 18:31:27 +0100 Subject: only respect most recent signature for key flags --- .../keychain/pgp/CanonicalizedPublicKey.java | 8 ++-- .../keychain/pgp/UncachedPublicKey.java | 46 ++++++++++++++++++---- 2 files changed, 42 insertions(+), 12 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKey.java index 3539a4ceb..b026d9257 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKey.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKey.java @@ -53,7 +53,7 @@ public class CanonicalizedPublicKey extends UncachedPublicKey { public boolean canSign() { // if key flags subpacket is available, honor it! - if (getKeyUsage() != null) { + if (getKeyUsage() != 0) { return (getKeyUsage() & KeyFlags.SIGN_DATA) != 0; } @@ -66,7 +66,7 @@ public class CanonicalizedPublicKey extends UncachedPublicKey { public boolean canCertify() { // if key flags subpacket is available, honor it! - if (getKeyUsage() != null) { + if (getKeyUsage() != 0) { return (getKeyUsage() & KeyFlags.CERTIFY_OTHER) != 0; } @@ -79,7 +79,7 @@ public class CanonicalizedPublicKey extends UncachedPublicKey { public boolean canEncrypt() { // if key flags subpacket is available, honor it! - if (getKeyUsage() != null) { + if (getKeyUsage() != 0) { return (getKeyUsage() & (KeyFlags.ENCRYPT_COMMS | KeyFlags.ENCRYPT_STORAGE)) != 0; } @@ -93,7 +93,7 @@ public class CanonicalizedPublicKey extends UncachedPublicKey { public boolean canAuthenticate() { // if key flags subpacket is available, honor it! - if (getKeyUsage() != null) { + if (getKeyUsage() != 0) { return (getKeyUsage() & KeyFlags.AUTHENTICATION) != 0; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java index 9e3528515..1efc25076 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java @@ -305,26 +305,56 @@ public class UncachedPublicKey { * * Note that this method has package visiblity because it is used in test * cases. Certificates of UncachedPublicKey instances can NOT be assumed to - * be verified, so the result of this method should not be used in other - * places! + * be verified or even by the correct key, so the result of this method + * should never be used in other places! */ @SuppressWarnings("unchecked") Integer getKeyUsage() { if (mCacheUsage == null) { + PGPSignature mostRecentSig = null; for (PGPSignature sig : new IterableIterator(mPublicKey.getSignatures())) { if (mPublicKey.isMasterKey() && sig.getKeyID() != mPublicKey.getKeyID()) { continue; } - PGPSignatureSubpacketVector hashed = sig.getHashedSubPackets(); + switch (sig.getSignatureType()) { + case PGPSignature.DEFAULT_CERTIFICATION: + case PGPSignature.POSITIVE_CERTIFICATION: + case PGPSignature.CASUAL_CERTIFICATION: + case PGPSignature.NO_CERTIFICATION: + case PGPSignature.SUBKEY_BINDING: + break; + // if this is not one of the above types, don't care + default: + continue; + } + + // If we have no sig yet, take the first we can get + if (mostRecentSig == null) { + mostRecentSig = sig; + continue; + } + + // If the new sig is less recent, skip it + if (mostRecentSig.getCreationTime().after(sig.getCreationTime())) { + continue; + } + + // Otherwise, note it down as the new "most recent" one + mostRecentSig = sig; + } + + // Initialize to 0 as cached but empty value, if there is no sig (can't happen + // for canonicalized keyring), or there is no KEY_FLAGS packet in the sig + mCacheUsage = 0; + if (mostRecentSig != null) { + // If a mostRecentSig has been found, (cache and) return its flags + PGPSignatureSubpacketVector hashed = mostRecentSig.getHashedSubPackets(); if (hashed != null && hashed.getSubpacket(SignatureSubpacketTags.KEY_FLAGS) != null) { - // init if at least one key flag subpacket has been found - if (mCacheUsage == null) { - mCacheUsage = 0; - } - mCacheUsage |= hashed.getKeyFlags(); + mCacheUsage = hashed.getKeyFlags(); } } + } return mCacheUsage; } -- cgit v1.2.3 From 0e0970c347f0a2f78f190d6d26205178037f5095 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Sat, 24 Jan 2015 23:05:50 +0100 Subject: move key stripping into ChangeSubkey, support divert-to-card --- .../keychain/pgp/PgpKeyOperation.java | 43 ++++++++++------------ .../keychain/pgp/UncachedKeyRing.java | 4 +- .../keychain/service/SaveKeyringParcel.java | 29 +++++++++++---- .../keychain/ui/EditKeyFragment.java | 12 +++--- .../keychain/ui/adapter/SubkeysAdapter.java | 7 +++- 5 files changed, 56 insertions(+), 39 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java index 4bab7f2b9..4cf5fc459 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java @@ -20,6 +20,7 @@ package org.sufficientlysecure.keychain.pgp; import org.spongycastle.bcpg.CompressionAlgorithmTags; import org.spongycastle.bcpg.HashAlgorithmTags; +import org.spongycastle.bcpg.S2K; import org.spongycastle.bcpg.SymmetricKeyAlgorithmTags; import org.spongycastle.bcpg.sig.Features; import org.spongycastle.bcpg.sig.KeyFlags; @@ -715,6 +716,24 @@ public class PgpKeyOperation { return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null); } + if (change.mDummyStrip || change.mDummyDivert) { + // IT'S DANGEROUS~ + // no really, it is. this operation irrevocably removes the private key data from the key + if (change.mDummyStrip) { + sKey = PGPSecretKey.constructGnuDummyKey(sKey.getPublicKey(), + S2K.GNU_PROTECTION_MODE_NO_PRIVATE_KEY); + } else { + sKey = PGPSecretKey.constructGnuDummyKey(sKey.getPublicKey(), + S2K.GNU_PROTECTION_MODE_DIVERT_TO_CARD); + } + sKR = PGPSecretKeyRing.insertSecretKey(sKR, sKey); + } + + // This doesn't concern us any further + if (change.mExpiry == null && change.mFlags == null) { + continue; + } + // expiry must not be in the past if (change.mExpiry != null && change.mExpiry != 0 && new Date(change.mExpiry*1000).before(new Date())) { @@ -805,30 +824,6 @@ public class PgpKeyOperation { } subProgressPop(); - // 4c. For each subkey to be stripped... do so - subProgressPush(65, 70); - for (int i = 0; i < saveParcel.mStripSubKeys.size(); i++) { - - progress(R.string.progress_modify_subkeystrip, (i-1) * (100 / saveParcel.mStripSubKeys.size())); - long strip = saveParcel.mStripSubKeys.get(i); - log.add(LogType.MSG_MF_SUBKEY_STRIP, - indent, KeyFormattingUtils.convertKeyIdToHex(strip)); - - PGPSecretKey sKey = sKR.getSecretKey(strip); - if (sKey == null) { - log.add(LogType.MSG_MF_ERROR_SUBKEY_MISSING, - indent+1, KeyFormattingUtils.convertKeyIdToHex(strip)); - return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null); - } - - // IT'S DANGEROUS~ - // no really, it is. this operation irrevocably removes the private key data from the key - sKey = PGPSecretKey.constructGnuDummyKey(sKey.getPublicKey()); - sKR = PGPSecretKeyRing.insertSecretKey(sKR, sKey); - - } - subProgressPop(); - // 5. Generate and add new subkeys subProgressPush(70, 90); for (int i = 0; i < saveParcel.mAddSubKeys.size(); i++) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java index 04fb955fa..df333553b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java @@ -20,6 +20,7 @@ package org.sufficientlysecure.keychain.pgp; import org.spongycastle.bcpg.ArmoredOutputStream; import org.spongycastle.bcpg.PublicKeyAlgorithmTags; +import org.spongycastle.bcpg.S2K; import org.spongycastle.bcpg.SignatureSubpacketTags; import org.spongycastle.bcpg.UserAttributeSubpacketTags; import org.spongycastle.bcpg.sig.KeyFlags; @@ -1221,7 +1222,8 @@ public class UncachedKeyRing { // if this is a secret key which does not yet occur in the secret ring if (sKey == null) { // generate a stripped secret (sub)key - sKey = PGPSecretKey.constructGnuDummyKey(key); + sKey = PGPSecretKey.constructGnuDummyKey(key, + S2K.GNU_PROTECTION_MODE_NO_PRIVATE_KEY); } sKey = PGPSecretKey.replacePublicKey(sKey, key); return PGPSecretKeyRing.insertSecretKey(secRing, sKey); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java index a314c8768..b8ee750b7 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java @@ -58,7 +58,6 @@ public class SaveKeyringParcel implements Parcelable { public ArrayList mRevokeUserIds; public ArrayList mRevokeSubKeys; - public ArrayList mStripSubKeys; public SaveKeyringParcel() { reset(); @@ -79,7 +78,6 @@ public class SaveKeyringParcel implements Parcelable { mChangeSubKeys = new ArrayList(); mRevokeUserIds = new ArrayList(); mRevokeSubKeys = new ArrayList(); - mStripSubKeys = new ArrayList(); } // performance gain for using Parcelable here would probably be negligible, @@ -112,10 +110,14 @@ public class SaveKeyringParcel implements Parcelable { } public static class SubkeyChange implements Serializable { - public long mKeyId; + public final long mKeyId; public Integer mFlags; // this is a long unix timestamp, in seconds (NOT MILLISECONDS!) public Long mExpiry; + // if this flag is true, the subkey should be changed to a stripped key + public boolean mDummyStrip; + // if this flag is true, the subkey should be changed to a divert-to-card key + public boolean mDummyDivert; public SubkeyChange(long keyId) { mKeyId = keyId; @@ -127,11 +129,25 @@ public class SaveKeyringParcel implements Parcelable { mExpiry = expiry; } + public SubkeyChange(long keyId, boolean dummyStrip, boolean dummyDivert) { + this(keyId, null, null); + + // these flags are mutually exclusive! + if (dummyStrip && dummyDivert) { + throw new AssertionError( + "cannot set strip and divert flags at the same time - this is a bug!"); + } + mDummyStrip = dummyStrip; + mDummyDivert = dummyDivert; + } + @Override public String toString() { String out = "mKeyId: " + mKeyId + ", "; out += "mFlags: " + mFlags + ", "; - out += "mExpiry: " + mExpiry; + out += "mExpiry: " + mExpiry + ", "; + out += "mDummyStrip: " + mDummyStrip + ", "; + out += "mDummyDivert: " + mDummyDivert; return out; } @@ -173,7 +189,6 @@ public class SaveKeyringParcel implements Parcelable { mRevokeUserIds = source.createStringArrayList(); mRevokeSubKeys = (ArrayList) source.readSerializable(); - mStripSubKeys = (ArrayList) source.readSerializable(); } @Override @@ -196,7 +211,6 @@ public class SaveKeyringParcel implements Parcelable { destination.writeStringList(mRevokeUserIds); destination.writeSerializable(mRevokeSubKeys); - destination.writeSerializable(mStripSubKeys); } public static final Creator CREATOR = new Creator() { @@ -224,8 +238,7 @@ public class SaveKeyringParcel implements Parcelable { out += "mChangeSubKeys: " + mChangeSubKeys + "\n"; out += "mChangePrimaryUserId: " + mChangePrimaryUserId + "\n"; out += "mRevokeUserIds: " + mRevokeUserIds + "\n"; - out += "mRevokeSubKeys: " + mRevokeSubKeys + "\n"; - out += "mStripSubKeys: " + mStripSubKeys; + out += "mRevokeSubKeys: " + mRevokeSubKeys; return out; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java index afe6afb3c..330589c7c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java @@ -55,6 +55,7 @@ import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; import org.sufficientlysecure.keychain.service.PassphraseCacheService; import org.sufficientlysecure.keychain.service.SaveKeyringParcel; import org.sufficientlysecure.keychain.service.SaveKeyringParcel.ChangeUnlockParcel; +import org.sufficientlysecure.keychain.service.SaveKeyringParcel.SubkeyChange; import org.sufficientlysecure.keychain.ui.adapter.SubkeysAdapter; import org.sufficientlysecure.keychain.ui.adapter.SubkeysAddedAdapter; import org.sufficientlysecure.keychain.ui.adapter.UserIdsAdapter; @@ -478,12 +479,13 @@ public class EditKeyFragment extends LoaderFragment implements } break; case EditSubkeyDialogFragment.MESSAGE_STRIP: - // toggle - if (mSaveKeyringParcel.mStripSubKeys.contains(keyId)) { - mSaveKeyringParcel.mStripSubKeys.remove(keyId); - } else { - mSaveKeyringParcel.mStripSubKeys.add(keyId); + SubkeyChange change = mSaveKeyringParcel.getSubkeyChange(keyId); + if (change == null) { + mSaveKeyringParcel.mChangeSubKeys.add(new SubkeyChange(keyId, true, false)); + break; } + // toggle + change.mDummyStrip = !change.mDummyStrip; break; } getLoaderManager().getLoader(LOADER_ID_SUBKEYS).forceLoad(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java index a032e96fc..a8fa3f1aa 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java @@ -35,6 +35,7 @@ import android.widget.ImageView; import android.widget.TextView; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.service.SaveKeyringParcel.SubkeyChange; import org.sufficientlysecure.keychain.ui.util.FormattingUtils; import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; @@ -160,7 +161,11 @@ public class SubkeysAdapter extends CursorAdapter { cursor.getString(INDEX_KEY_CURVE_OID) )); - if (mSaveKeyringParcel != null && mSaveKeyringParcel.mStripSubKeys.contains(keyId)) { + SubkeyChange change = mSaveKeyringParcel != null + ? mSaveKeyringParcel.getSubkeyChange(keyId) + : null; + + if (change.mDummyStrip) { algorithmStr.append(", "); final SpannableString boldStripped = new SpannableString( context.getString(R.string.key_stripped) -- cgit v1.2.3 From fb2fa195bfff709af23d1394a3ff739ebc2d0ddd Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Sat, 24 Jan 2015 23:11:54 +0100 Subject: allow explicit re-certification in SaveKeyringParcel --- .../java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java | 2 +- .../org/sufficientlysecure/keychain/service/SaveKeyringParcel.java | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java index 4cf5fc459..928a0f96b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java @@ -730,7 +730,7 @@ public class PgpKeyOperation { } // This doesn't concern us any further - if (change.mExpiry == null && change.mFlags == null) { + if (!change.mRecertify && (change.mExpiry == null && change.mFlags == null)) { continue; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java index b8ee750b7..a8823cd5c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java @@ -118,11 +118,18 @@ public class SaveKeyringParcel implements Parcelable { public boolean mDummyStrip; // if this flag is true, the subkey should be changed to a divert-to-card key public boolean mDummyDivert; + // if this flag is true, the key will be recertified even if the above values are no-ops + public boolean mRecertify; public SubkeyChange(long keyId) { mKeyId = keyId; } + public SubkeyChange(long keyId, boolean recertify) { + mKeyId = keyId; + mRecertify = recertify; + } + public SubkeyChange(long keyId, Integer flags, Long expiry) { mKeyId = keyId; mFlags = flags; -- cgit v1.2.3 From 1516f951b79381f839806bc3a5f1dc653b1a9b6a Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Sun, 25 Jan 2015 01:57:58 +0100 Subject: work on divert-to-key and other keyring stuff - allow modifySecretKeyRing operation without passphrase, but a only restricted subset of operations (ie, s2k strip/divert) - pass byte array with serial number to key edit operation to initialize divert-to-card key - update spongycastle to support serial numbers in iv for divert-to-card --- .../operations/results/OperationResult.java | 2 + .../keychain/pgp/PgpKeyOperation.java | 89 ++++++++++++++++++++-- .../keychain/pgp/UncachedKeyRing.java | 4 +- .../keychain/service/SaveKeyringParcel.java | 31 ++++++-- .../keychain/ui/EditKeyFragment.java | 2 +- 5 files changed, 112 insertions(+), 16 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java index 8c76ebb8a..f295d09a9 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java @@ -473,6 +473,7 @@ public abstract class OperationResult implements Parcelable { // secret key modify MSG_MF (LogLevel.START, R.string.msg_mr), + MSG_MF_ERROR_DIVERT_SERIAL (LogLevel.ERROR, R.string.msg_mf_error_divert_serial), MSG_MF_ERROR_ENCODE (LogLevel.ERROR, R.string.msg_mf_error_encode), MSG_MF_ERROR_FINGERPRINT (LogLevel.ERROR, R.string.msg_mf_error_fingerprint), MSG_MF_ERROR_KEYID (LogLevel.ERROR, R.string.msg_mf_error_keyid), @@ -485,6 +486,7 @@ public abstract class OperationResult implements Parcelable { MSG_MF_ERROR_PASSPHRASE_MASTER(LogLevel.ERROR, R.string.msg_mf_error_passphrase_master), MSG_MF_ERROR_PAST_EXPIRY(LogLevel.ERROR, R.string.msg_mf_error_past_expiry), MSG_MF_ERROR_PGP (LogLevel.ERROR, R.string.msg_mf_error_pgp), + MSG_MF_ERROR_RESTRICTED(LogLevel.ERROR, R.string.msg_mf_error_restricted), MSG_MF_ERROR_REVOKED_PRIMARY (LogLevel.ERROR, R.string.msg_mf_error_revoked_primary), MSG_MF_ERROR_SIG (LogLevel.ERROR, R.string.msg_mf_error_sig), MSG_MF_ERROR_SUBKEY_MISSING(LogLevel.ERROR, R.string.msg_mf_error_subkey_missing), diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java index 928a0f96b..bd7759d43 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java @@ -20,7 +20,6 @@ package org.sufficientlysecure.keychain.pgp; import org.spongycastle.bcpg.CompressionAlgorithmTags; import org.spongycastle.bcpg.HashAlgorithmTags; -import org.spongycastle.bcpg.S2K; import org.spongycastle.bcpg.SymmetricKeyAlgorithmTags; import org.spongycastle.bcpg.sig.Features; import org.spongycastle.bcpg.sig.KeyFlags; @@ -390,6 +389,9 @@ public class PgpKeyOperation { * with a passphrase fails, the operation will fail with an unlocking error. More specific * handling of errors should be done in UI code! * + * If the passphrase is null, only a restricted subset of operations will be available, + * namely stripping of subkeys and changing the protection mode of dummy keys. + * */ public PgpEditKeyResult modifySecretKeyRing(CanonicalizedSecretKeyRing wsKR, SaveKeyringParcel saveParcel, String passphrase) { @@ -430,6 +432,11 @@ public class PgpKeyOperation { return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null); } + // If we have no passphrase, only allow restricted operation + if (passphrase == null) { + return internalRestricted(sKR, saveParcel, log); + } + // read masterKeyFlags, and use the same as before. // since this is the master key, this contains at least CERTIFY_OTHER PGPPublicKey masterPublicKey = masterSecretKey.getPublicKey(); @@ -716,15 +723,18 @@ public class PgpKeyOperation { return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null); } - if (change.mDummyStrip || change.mDummyDivert) { + if (change.mDummyStrip || change.mDummyDivert != null) { // IT'S DANGEROUS~ // no really, it is. this operation irrevocably removes the private key data from the key if (change.mDummyStrip) { - sKey = PGPSecretKey.constructGnuDummyKey(sKey.getPublicKey(), - S2K.GNU_PROTECTION_MODE_NO_PRIVATE_KEY); + sKey = PGPSecretKey.constructGnuDummyKey(sKey.getPublicKey()); } else { - sKey = PGPSecretKey.constructGnuDummyKey(sKey.getPublicKey(), - S2K.GNU_PROTECTION_MODE_DIVERT_TO_CARD); + // the serial number must be 16 bytes in length + if (change.mDummyDivert.length != 16) { + log.add(LogType.MSG_MF_ERROR_DIVERT_SERIAL, + indent + 1, KeyFormattingUtils.convertKeyIdToHex(change.mKeyId)); + return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null); + } } sKR = PGPSecretKeyRing.insertSecretKey(sKR, sKey); } @@ -932,6 +942,73 @@ public class PgpKeyOperation { } + /** This method does the actual modifications in a keyring just like internal, except it + * supports only the subset of operations which require no passphrase, and will error + * otherwise. + */ + private PgpEditKeyResult internalRestricted(PGPSecretKeyRing sKR, SaveKeyringParcel saveParcel, + OperationLog log) { + + int indent = 1; + + progress(R.string.progress_modify, 0); + + // Make sure the saveParcel includes only operations available without passphrae! + if (!saveParcel.isRestrictedOnly()) { + log.add(LogType.MSG_MF_ERROR_RESTRICTED, indent); + return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null); + } + + // Check if we were cancelled + if (checkCancelled()) { + log.add(LogType.MSG_OPERATION_CANCELLED, indent); + return new PgpEditKeyResult(PgpEditKeyResult.RESULT_CANCELLED, log, null); + } + + // The only operation we can do here: + // 4a. Strip secret keys, or change their protection mode (stripped/divert-to-card) + subProgressPush(50, 60); + for (int i = 0; i < saveParcel.mChangeSubKeys.size(); i++) { + + progress(R.string.progress_modify_subkeychange, (i - 1) * (100 / saveParcel.mChangeSubKeys.size())); + SaveKeyringParcel.SubkeyChange change = saveParcel.mChangeSubKeys.get(i); + log.add(LogType.MSG_MF_SUBKEY_CHANGE, + indent, KeyFormattingUtils.convertKeyIdToHex(change.mKeyId)); + + PGPSecretKey sKey = sKR.getSecretKey(change.mKeyId); + if (sKey == null) { + log.add(LogType.MSG_MF_ERROR_SUBKEY_MISSING, + indent + 1, KeyFormattingUtils.convertKeyIdToHex(change.mKeyId)); + return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null); + } + + if (change.mDummyStrip || change.mDummyDivert != null) { + // IT'S DANGEROUS~ + // no really, it is. this operation irrevocably removes the private key data from the key + if (change.mDummyStrip) { + sKey = PGPSecretKey.constructGnuDummyKey(sKey.getPublicKey()); + } else { + // the serial number must be 16 bytes in length + if (change.mDummyDivert.length != 16) { + log.add(LogType.MSG_MF_ERROR_DIVERT_SERIAL, + indent + 1, KeyFormattingUtils.convertKeyIdToHex(change.mKeyId)); + return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null); + } + sKey = PGPSecretKey.constructGnuDummyKey(sKey.getPublicKey(), change.mDummyDivert); + } + sKR = PGPSecretKeyRing.insertSecretKey(sKR, sKey); + } + + } + + // And we're done! + progress(R.string.progress_done, 100); + log.add(LogType.MSG_MF_SUCCESS, indent); + return new PgpEditKeyResult(OperationResult.RESULT_OK, log, new UncachedKeyRing(sKR)); + + } + + private static PGPSecretKeyRing applyNewUnlock( PGPSecretKeyRing sKR, PGPPublicKey masterPublicKey, diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java index df333553b..04fb955fa 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java @@ -20,7 +20,6 @@ package org.sufficientlysecure.keychain.pgp; import org.spongycastle.bcpg.ArmoredOutputStream; import org.spongycastle.bcpg.PublicKeyAlgorithmTags; -import org.spongycastle.bcpg.S2K; import org.spongycastle.bcpg.SignatureSubpacketTags; import org.spongycastle.bcpg.UserAttributeSubpacketTags; import org.spongycastle.bcpg.sig.KeyFlags; @@ -1222,8 +1221,7 @@ public class UncachedKeyRing { // if this is a secret key which does not yet occur in the secret ring if (sKey == null) { // generate a stripped secret (sub)key - sKey = PGPSecretKey.constructGnuDummyKey(key, - S2K.GNU_PROTECTION_MODE_NO_PRIVATE_KEY); + sKey = PGPSecretKey.constructGnuDummyKey(key); } sKey = PGPSecretKey.replacePublicKey(sKey, key); return PGPSecretKeyRing.insertSecretKey(secRing, sKey); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java index a8823cd5c..3c78f2c40 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java @@ -80,6 +80,23 @@ public class SaveKeyringParcel implements Parcelable { mRevokeSubKeys = new ArrayList(); } + /** Returns true iff this parcel does not contain any operations which require a passphrase. */ + public boolean isRestrictedOnly() { + if (mNewUnlock != null || !mAddUserIds.isEmpty() || !mAddUserAttribute.isEmpty() + || !mAddSubKeys.isEmpty() || mChangePrimaryUserId != null || !mRevokeSubKeys .isEmpty() + || !mRevokeSubKeys.isEmpty()) { + return false; + } + + for (SubkeyChange change : mChangeSubKeys) { + if (change.mRecertify || change.mFlags != null || change.mExpiry != null) { + return false; + } + } + + return true; + } + // performance gain for using Parcelable here would probably be negligible, // use Serializable instead. public static class SubkeyAdd implements Serializable { @@ -114,12 +131,14 @@ public class SaveKeyringParcel implements Parcelable { public Integer mFlags; // this is a long unix timestamp, in seconds (NOT MILLISECONDS!) public Long mExpiry; + // if this flag is true, the key will be recertified even if all above + // values are no-ops + public boolean mRecertify; // if this flag is true, the subkey should be changed to a stripped key public boolean mDummyStrip; - // if this flag is true, the subkey should be changed to a divert-to-card key - public boolean mDummyDivert; - // if this flag is true, the key will be recertified even if the above values are no-ops - public boolean mRecertify; + // if this is non-null, the subkey will be changed to a divert-to-card + // key for the given serial number + public byte[] mDummyDivert; public SubkeyChange(long keyId) { mKeyId = keyId; @@ -136,11 +155,11 @@ public class SaveKeyringParcel implements Parcelable { mExpiry = expiry; } - public SubkeyChange(long keyId, boolean dummyStrip, boolean dummyDivert) { + public SubkeyChange(long keyId, boolean dummyStrip, byte[] dummyDivert) { this(keyId, null, null); // these flags are mutually exclusive! - if (dummyStrip && dummyDivert) { + if (dummyStrip && dummyDivert != null) { throw new AssertionError( "cannot set strip and divert flags at the same time - this is a bug!"); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java index 330589c7c..febda16c3 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java @@ -481,7 +481,7 @@ public class EditKeyFragment extends LoaderFragment implements case EditSubkeyDialogFragment.MESSAGE_STRIP: SubkeyChange change = mSaveKeyringParcel.getSubkeyChange(keyId); if (change == null) { - mSaveKeyringParcel.mChangeSubKeys.add(new SubkeyChange(keyId, true, false)); + mSaveKeyringParcel.mChangeSubKeys.add(new SubkeyChange(keyId, true, null)); break; } // toggle -- cgit v1.2.3 From 41aba69fad5b958cdd01cd4a1e8cbc9828086c2f Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Sun, 25 Jan 2015 02:08:07 +0100 Subject: introduce PromoteKeyOperation to create dummy secret from public keys --- .../keychain/operations/BaseOperation.java | 6 ++ .../keychain/operations/EditKeyOperation.java | 2 +- .../keychain/operations/PromoteKeyOperation.java | 103 +++++++++++++++++++++ .../operations/results/OperationResult.java | 7 ++ .../operations/results/PromoteKeyResult.java | 53 +++++++++++ .../keychain/pgp/CanonicalizedPublicKeyRing.java | 11 +++ .../keychain/service/KeychainIntentService.java | 20 ++++ 7 files changed, 201 insertions(+), 1 deletion(-) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/PromoteKeyOperation.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/PromoteKeyResult.java (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BaseOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BaseOperation.java index c400eb813..e796bdc91 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BaseOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BaseOperation.java @@ -77,6 +77,12 @@ public abstract class BaseOperation implements PassphraseCacheInterface { return mCancelled != null && mCancelled.get(); } + protected void setPreventCancel () { + if (mProgressable != null) { + mProgressable.setPreventCancel(); + } + } + @Override public String getCachedPassphrase(long subKeyId) throws NoSecretKeyException { try { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java index 4d466593b..ebbd45856 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java @@ -29,7 +29,7 @@ import java.util.concurrent.atomic.AtomicBoolean; * create key operations in PgpKeyOperation. It takes care of fetching * and saving the key before and after the operation. * - * @see CertifyActionsParcel + * @see SaveKeyringParcel * */ public class EditKeyOperation extends BaseOperation { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/PromoteKeyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/PromoteKeyOperation.java new file mode 100644 index 000000000..f10d11684 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/PromoteKeyOperation.java @@ -0,0 +1,103 @@ +package org.sufficientlysecure.keychain.operations; + +import android.content.Context; + +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.operations.results.PromoteKeyResult; +import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; +import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; +import org.sufficientlysecure.keychain.operations.results.PgpEditKeyResult; +import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult; +import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing; +import org.sufficientlysecure.keychain.pgp.Progressable; +import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; +import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; +import org.sufficientlysecure.keychain.provider.ProviderHelper; +import org.sufficientlysecure.keychain.provider.ProviderHelper.NotFoundException; +import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; +import org.sufficientlysecure.keychain.util.ProgressScaler; + +import java.util.concurrent.atomic.AtomicBoolean; + +/** An operation which promotes a public key ring to a secret one. + * + * This operation can only be applied to public key rings where no secret key + * is available. Doing this "promotes" the public key ring to a secret one + * without secret key material, using a GNU_DUMMY s2k type. + * + */ +public class PromoteKeyOperation extends BaseOperation { + + public PromoteKeyOperation(Context context, ProviderHelper providerHelper, + Progressable progressable, AtomicBoolean cancelled) { + super(context, providerHelper, progressable, cancelled); + } + + public PromoteKeyResult execute(long masterKeyId) { + + OperationLog log = new OperationLog(); + log.add(LogType.MSG_PR, 0); + + // Perform actual type change + UncachedKeyRing promotedRing; + { + + try { + + // This operation is only allowed for pure public keys + // TODO delete secret keys if they are stripped, or have been moved to the card? + if (mProviderHelper.getCachedPublicKeyRing(masterKeyId).hasAnySecret()) { + log.add(LogType.MSG_PR_ERROR_ALREADY_SECRET, 2); + return new PromoteKeyResult(PromoteKeyResult.RESULT_ERROR, log, null); + } + + log.add(LogType.MSG_PR_FETCHING, 1, + KeyFormattingUtils.convertKeyIdToHex(masterKeyId)); + CanonicalizedPublicKeyRing pubRing = + mProviderHelper.getCanonicalizedPublicKeyRing(masterKeyId); + + // create divert-to-card secret key from public key + promotedRing = pubRing.createDummySecretRing(); + + } catch (PgpKeyNotFoundException e) { + log.add(LogType.MSG_PR_ERROR_KEY_NOT_FOUND, 2); + return new PromoteKeyResult(PromoteKeyResult.RESULT_ERROR, log, null); + } catch (NotFoundException e) { + log.add(LogType.MSG_PR_ERROR_KEY_NOT_FOUND, 2); + return new PromoteKeyResult(PromoteKeyResult.RESULT_ERROR, log, null); + } + } + + // If the edit operation didn't succeed, exit here + if (promotedRing == null) { + // error is already logged by modification + return new PromoteKeyResult(PromoteKeyResult.RESULT_ERROR, log, null); + } + + // Check if the action was cancelled + if (checkCancelled()) { + log.add(LogType.MSG_OPERATION_CANCELLED, 0); + return new PromoteKeyResult(PgpEditKeyResult.RESULT_CANCELLED, log, null); + } + + // Cannot cancel from here on out! + setPreventCancel(); + + // Save the new keyring. + SaveKeyringResult saveResult = mProviderHelper + .saveSecretKeyRing(promotedRing, new ProgressScaler(mProgressable, 60, 95, 100)); + log.add(saveResult, 1); + + // If the save operation didn't succeed, exit here + if (!saveResult.success()) { + return new PromoteKeyResult(PromoteKeyResult.RESULT_ERROR, log, null); + } + + updateProgress(R.string.progress_done, 100, 100); + + log.add(LogType.MSG_PR_SUCCESS, 0); + return new PromoteKeyResult(PromoteKeyResult.RESULT_OK, log, promotedRing.getMasterKeyId()); + + } + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java index f295d09a9..b30552e49 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java @@ -548,6 +548,13 @@ public abstract class OperationResult implements Parcelable { MSG_ED_FETCHING (LogLevel.DEBUG, R.string.msg_ed_fetching), MSG_ED_SUCCESS (LogLevel.OK, R.string.msg_ed_success), + // promote key + MSG_PR (LogLevel.START, R.string.msg_pr), + MSG_PR_ERROR_ALREADY_SECRET (LogLevel.ERROR, R.string.msg_pr_error_already_secret), + MSG_PR_ERROR_KEY_NOT_FOUND (LogLevel.ERROR, R.string.msg_pr_error_key_not_found), + MSG_PR_FETCHING (LogLevel.DEBUG, R.string.msg_pr_fetching), + MSG_PR_SUCCESS (LogLevel.OK, R.string.msg_pr_success), + // messages used in UI code MSG_EK_ERROR_DIVERT (LogLevel.ERROR, R.string.msg_ek_error_divert), MSG_EK_ERROR_DUMMY (LogLevel.ERROR, R.string.msg_ek_error_dummy), diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/PromoteKeyResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/PromoteKeyResult.java new file mode 100644 index 000000000..af9aff84a --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/PromoteKeyResult.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2014 Dominik Schürmann + * Copyright (C) 2014 Vincent Breitmoser + * + * 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 . + */ + +package org.sufficientlysecure.keychain.operations.results; + +import android.os.Parcel; + +public class PromoteKeyResult extends OperationResult { + + public final Long mMasterKeyId; + + public PromoteKeyResult(int result, OperationLog log, Long masterKeyId) { + super(result, log); + mMasterKeyId = masterKeyId; + } + + public PromoteKeyResult(Parcel source) { + super(source); + mMasterKeyId = source.readLong(); + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + dest.writeLong(mMasterKeyId); + } + + public static Creator CREATOR = new Creator() { + public PromoteKeyResult createFromParcel(final Parcel source) { + return new PromoteKeyResult(source); + } + + public PromoteKeyResult[] newArray(final int size) { + return new PromoteKeyResult[size]; + } + }; + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKeyRing.java index 85ef3eaa4..b8379f007 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKeyRing.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKeyRing.java @@ -18,9 +18,11 @@ package org.sufficientlysecure.keychain.pgp; +import org.spongycastle.bcpg.S2K; import org.spongycastle.openpgp.PGPObjectFactory; import org.spongycastle.openpgp.PGPPublicKey; import org.spongycastle.openpgp.PGPPublicKeyRing; +import org.spongycastle.openpgp.PGPSecretKeyRing; import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.util.IterableIterator; @@ -94,4 +96,13 @@ public class CanonicalizedPublicKeyRing extends CanonicalizedKeyRing { }); } + /** Create a dummy secret ring from this key */ + public UncachedKeyRing createDummySecretRing () { + + PGPSecretKeyRing secRing = PGPSecretKeyRing.constructDummyFromPublic(getRing(), + S2K.GNU_PROTECTION_MODE_NO_PRIVATE_KEY); + return new UncachedKeyRing(secRing); + + } + } \ No newline at end of file diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java index 479810203..a2172171a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -30,10 +30,12 @@ import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.operations.CertifyOperation; import org.sufficientlysecure.keychain.operations.DeleteOperation; import org.sufficientlysecure.keychain.operations.EditKeyOperation; +import org.sufficientlysecure.keychain.operations.PromoteKeyOperation; import org.sufficientlysecure.keychain.operations.results.DeleteResult; import org.sufficientlysecure.keychain.operations.results.EditKeyResult; import org.sufficientlysecure.keychain.operations.results.ExportResult; import org.sufficientlysecure.keychain.operations.results.PgpEditKeyResult; +import org.sufficientlysecure.keychain.operations.results.PromoteKeyResult; import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.operations.results.CertifyResult; import org.sufficientlysecure.keychain.util.FileHelper; @@ -91,6 +93,8 @@ public class KeychainIntentService extends IntentService implements Progressable public static final String ACTION_EDIT_KEYRING = Constants.INTENT_PREFIX + "EDIT_KEYRING"; + public static final String ACTION_PROMOTE_KEYRING = Constants.INTENT_PREFIX + "PROMOTE_KEYRING"; + public static final String ACTION_IMPORT_KEYRING = Constants.INTENT_PREFIX + "IMPORT_KEYRING"; public static final String ACTION_EXPORT_KEYRING = Constants.INTENT_PREFIX + "EXPORT_KEYRING"; @@ -161,6 +165,10 @@ public class KeychainIntentService extends IntentService implements Progressable // certify key public static final String CERTIFY_PARCEL = "certify_parcel"; + // promote key + public static final String PROMOTE_MASTER_KEY_ID = "promote_master_key_id"; + public static final String PROMOTE_TYPE = "promote_type"; + // consolidate public static final String CONSOLIDATE_RECOVERY = "consolidate_recovery"; @@ -347,6 +355,18 @@ public class KeychainIntentService extends IntentService implements Progressable // Result sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result); + } else if (ACTION_PROMOTE_KEYRING.equals(action)) { + + // Input + long keyRingId = data.getInt(EXPORT_KEY_RING_MASTER_KEY_ID); + + // Operation + PromoteKeyOperation op = new PromoteKeyOperation(this, providerHelper, this, mActionCanceled); + PromoteKeyResult result = op.execute(keyRingId); + + // Result + sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result); + } else if (ACTION_EXPORT_KEYRING.equals(action)) { // Input -- cgit v1.2.3 From 8d9c3c05341a5cd4f1879df692453d1327ea6a96 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Sun, 25 Jan 2015 12:36:00 +0100 Subject: lift language level to java 7, and some code cleanup --- .../keychain/keyimport/CloudSearch.java | 4 +- .../keychain/keyimport/HkpKeyserver.java | 4 +- .../keychain/keyimport/ImportKeysListEntry.java | 12 +- .../keychain/keyimport/KeybaseKeyserver.java | 4 +- .../keychain/operations/CertifyOperation.java | 2 +- .../keychain/operations/EditKeyOperation.java | 1 - .../keychain/operations/ImportExportOperation.java | 2 +- .../operations/results/OperationResult.java | 6 +- .../keychain/pgp/CanonicalizedKeyRing.java | 1 - .../keychain/pgp/CanonicalizedPublicKeyRing.java | 2 +- .../keychain/pgp/CanonicalizedSecretKey.java | 6 +- .../keychain/pgp/CanonicalizedSecretKeyRing.java | 14 +- .../pgp/OpenPgpSignatureResultBuilder.java | 3 +- .../keychain/pgp/PgpKeyOperation.java | 8 +- .../keychain/pgp/UncachedKeyRing.java | 14 +- .../keychain/pgp/UncachedPublicKey.java | 9 +- .../keychain/pgp/WrappedSignature.java | 5 +- .../keychain/provider/KeychainProvider.java | 12 +- .../keychain/provider/ProviderHelper.java | 28 +- .../keychain/remote/OpenPgpService.java | 57 +-- .../keychain/remote/RemoteService.java | 5 +- .../remote/ui/AccountSettingsActivity.java | 1 - .../keychain/remote/ui/AppSettingsActivity.java | 2 - .../keychain/remote/ui/RemoteServiceActivity.java | 397 +++++++++--------- .../keychain/service/CertifyActionsParcel.java | 2 +- .../keychain/service/KeychainIntentService.java | 467 +++++++++++---------- .../keychain/service/PassphraseCacheService.java | 3 +- .../keychain/service/SaveKeyringParcel.java | 14 +- .../keychain/ui/CertifyKeyActivity.java | 3 - .../keychain/ui/CertifyKeyFragment.java | 2 +- .../keychain/ui/CreateKeyActivity.java | 1 - .../keychain/ui/CreateKeyFinalFragment.java | 1 - .../keychain/ui/CreateKeyInputFragment.java | 4 +- .../keychain/ui/DecryptFilesActivity.java | 1 - .../keychain/ui/DecryptTextActivity.java | 1 - .../keychain/ui/EditKeyActivity.java | 1 - .../keychain/ui/EditKeyFragment.java | 5 +- .../keychain/ui/EncryptAsymmetricFragment.java | 5 +- .../keychain/ui/EncryptFilesActivity.java | 8 +- .../keychain/ui/EncryptFilesFragment.java | 4 +- .../keychain/ui/EncryptTextActivity.java | 6 +- .../keychain/ui/FirstTimeActivity.java | 1 - .../keychain/ui/ImportKeysActivity.java | 158 +++---- .../keychain/ui/ImportKeysCloudFragment.java | 2 +- .../keychain/ui/ImportKeysListFragment.java | 2 +- .../keychain/ui/KeyListFragment.java | 17 +- .../keychain/ui/LogDisplayActivity.java | 1 - .../keychain/ui/NfcActivity.java | 62 +-- .../keychain/ui/NfcIntentActivity.java | 1 - .../keychain/ui/PassphraseWizardActivity.java | 8 +- .../keychain/ui/QrCodeScanActivity.java | 2 +- .../keychain/ui/QrCodeViewActivity.java | 1 - .../keychain/ui/SafeSlingerActivity.java | 9 +- .../keychain/ui/SelectPublicKeyActivity.java | 1 - .../keychain/ui/SelectPublicKeyFragment.java | 5 +- .../keychain/ui/SettingsKeyServerActivity.java | 5 +- .../keychain/ui/UploadKeyActivity.java | 3 +- .../keychain/ui/ViewCertActivity.java | 4 - .../keychain/ui/ViewKeyAdvancedActivity.java | 2 - .../keychain/ui/ViewKeyShareFragment.java | 5 +- .../keychain/ui/adapter/ImportKeysAdapter.java | 4 +- .../ui/adapter/ImportKeysListCloudLoader.java | 8 +- .../keychain/ui/adapter/ImportKeysListLoader.java | 9 +- .../ui/adapter/KeyValueSpinnerAdapter.java | 2 +- .../keychain/ui/adapter/MultiUserIdsAdapter.java | 6 +- .../keychain/ui/adapter/PagerTabStripAdapter.java | 2 +- .../keychain/ui/adapter/SubkeysAdapter.java | 1 - .../keychain/ui/adapter/TabsAdapter.java | 2 +- .../keychain/ui/adapter/UserIdsAdapter.java | 2 +- .../ui/dialog/AddSubkeyDialogFragment.java | 26 +- .../ui/dialog/AddUserIdDialogFragment.java | 4 +- .../ui/dialog/DeleteFileDialogFragment.java | 1 - .../keychain/ui/util/QrCodeUtils.java | 2 +- .../keychain/ui/widget/CertifyKeySpinner.java | 1 - .../ui/widget/EncryptKeyCompletionView.java | 4 +- .../ui/widget/ListAwareSwipeRefreshLayout.java | 5 - .../keychain/ui/widget/SignKeySpinner.java | 1 - .../keychain/util/AlgorithmNames.java | 7 +- .../keychain/util/ContactHelper.java | 40 +- .../keychain/util/EmailKeyHelper.java | 10 +- .../keychain/util/ExportHelper.java | 2 - .../keychain/util/Iso7816TLV.java | 2 +- .../keychain/util/KeyUpdateHelper.java | 15 - .../org/sufficientlysecure/keychain/util/Log.java | 3 - .../keychain/util/ParcelableFileCache.java | 2 - .../keychain/util/Preferences.java | 4 +- .../keychain/util/ShareHelper.java | 4 +- .../keychain/util/TlsHelper.java | 10 +- 88 files changed, 757 insertions(+), 838 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/CloudSearch.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/CloudSearch.java index 255ca1cde..3b281876f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/CloudSearch.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/CloudSearch.java @@ -32,10 +32,10 @@ public class CloudSearch { public static ArrayList search(final String query, Preferences.CloudSearchPrefs cloudPrefs) throws Keyserver.CloudSearchFailureException { - final ArrayList servers = new ArrayList(); + final ArrayList servers = new ArrayList<>(); // it's a Vector for sync, multiple threads might report problems - final Vector problems = new Vector(); + final Vector problems = new Vector<>(); if (cloudPrefs.searchKeyserver) { servers.add(new HkpKeyserver(cloudPrefs.keyserver)); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java index 7f07b8162..f39c552a3 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java @@ -234,7 +234,7 @@ public class HkpKeyserver extends Keyserver { @Override public ArrayList search(String query) throws QueryFailedException, QueryNeedsRepairException { - ArrayList results = new ArrayList(); + ArrayList results = new ArrayList<>(); if (query.length() < 3) { throw new QueryTooShortException(); @@ -305,7 +305,7 @@ public class HkpKeyserver extends Keyserver { entry.setRevoked(matcher.group(6).contains("r")); entry.setExpired(matcher.group(6).contains("e")); - ArrayList userIds = new ArrayList(); + ArrayList userIds = new ArrayList<>(); final String uidLines = matcher.group(7); final Matcher uidMatcher = UID_LINE.matcher(uidLines); while (uidMatcher.find()) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java index d60d7757b..1d5ee76a4 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java @@ -89,7 +89,7 @@ public class ImportKeysListEntry implements Serializable, Parcelable { public ImportKeysListEntry createFromParcel(final Parcel source) { ImportKeysListEntry vr = new ImportKeysListEntry(); vr.mPrimaryUserId = source.readString(); - vr.mUserIds = new ArrayList(); + vr.mUserIds = new ArrayList<>(); source.readStringList(vr.mUserIds); vr.mMergedUserIds = (HashMap>) source.readSerializable(); vr.mKeyId = source.readLong(); @@ -103,7 +103,7 @@ public class ImportKeysListEntry implements Serializable, Parcelable { vr.mSecretKey = source.readByte() == 1; vr.mSelected = source.readByte() == 1; vr.mExtraData = source.readString(); - vr.mOrigins = new ArrayList(); + vr.mOrigins = new ArrayList<>(); source.readStringList(vr.mOrigins); return vr; @@ -265,8 +265,8 @@ public class ImportKeysListEntry implements Serializable, Parcelable { mSecretKey = false; // do not select by default mSelected = false; - mUserIds = new ArrayList(); - mOrigins = new ArrayList(); + mUserIds = new ArrayList<>(); + mOrigins = new ArrayList<>(); } /** @@ -304,7 +304,7 @@ public class ImportKeysListEntry implements Serializable, Parcelable { } public void updateMergedUserIds() { - mMergedUserIds = new HashMap>(); + mMergedUserIds = new HashMap<>(); for (String userId : mUserIds) { String[] userIdSplit = KeyRing.splitUserId(userId); @@ -315,7 +315,7 @@ public class ImportKeysListEntry implements Serializable, Parcelable { // email if (userIdSplit[1] != null) { if (!mMergedUserIds.containsKey(userIdSplit[0])) { - HashSet emails = new HashSet(); + HashSet emails = new HashSet<>(); emails.add(userIdSplit[1]); mMergedUserIds.put(userIdSplit[0], emails); } else { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeybaseKeyserver.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeybaseKeyserver.java index 2363a40b3..e310e9a3f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeybaseKeyserver.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeybaseKeyserver.java @@ -36,7 +36,7 @@ public class KeybaseKeyserver extends Keyserver { @Override public ArrayList search(String query) throws QueryFailedException, QueryNeedsRepairException { - ArrayList results = new ArrayList(); + ArrayList results = new ArrayList<>(); if (query.startsWith("0x")) { // cut off "0x" if a user is searching for a key id @@ -81,7 +81,7 @@ public class KeybaseKeyserver extends Keyserver { final int algorithmId = match.getAlgorithmId(); entry.setAlgorithm(KeyFormattingUtils.getAlgorithmInfo(algorithmId, bitStrength, null)); - ArrayList userIds = new ArrayList(); + ArrayList userIds = new ArrayList<>(); String name = ""; if (fullName != null) { name = fullName + " " + name; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/CertifyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/CertifyOperation.java index a5eb95b07..3b391814e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/CertifyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/CertifyOperation.java @@ -78,7 +78,7 @@ public class CertifyOperation extends BaseOperation { return new CertifyResult(CertifyResult.RESULT_ERROR, log); } - ArrayList certifiedKeys = new ArrayList(); + ArrayList certifiedKeys = new ArrayList<>(); log.add(LogType.MSG_CRT_CERTIFYING, 1); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java index ebbd45856..106c62688 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java @@ -11,7 +11,6 @@ import org.sufficientlysecure.keychain.pgp.Progressable; import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.provider.ProviderHelper.NotFoundException; -import org.sufficientlysecure.keychain.service.CertifyActionsParcel; import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportExportOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportExportOperation.java index 6ca28142f..cd8a33c20 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportExportOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportExportOperation.java @@ -137,7 +137,7 @@ public class ImportExportOperation extends BaseOperation { } int newKeys = 0, oldKeys = 0, badKeys = 0, secret = 0; - ArrayList importedMasterKeyIds = new ArrayList(); + ArrayList importedMasterKeyIds = new ArrayList<>(); boolean cancelled = false; int position = 0; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java index b30552e49..d025727b5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java @@ -735,7 +735,7 @@ public abstract class OperationResult implements Parcelable { public static class OperationLog implements Iterable { - private final List mParcels = new ArrayList(); + private final List mParcels = new ArrayList<>(); /// Simple convenience method public void add(LogType type, int indent, Object... parameters) { @@ -760,7 +760,7 @@ public abstract class OperationResult implements Parcelable { } public boolean containsType(LogType type) { - for(LogEntryParcel entry : new IterableIterator(mParcels.iterator())) { + for(LogEntryParcel entry : new IterableIterator<>(mParcels.iterator())) { if (entry.mType == type) { return true; } @@ -769,7 +769,7 @@ public abstract class OperationResult implements Parcelable { } public boolean containsWarnings() { - for(LogEntryParcel entry : new IterableIterator(mParcels.iterator())) { + for(LogEntryParcel entry : new IterableIterator<>(mParcels.iterator())) { if (entry.mType.mLevel == LogLevel.WARN || entry.mType.mLevel == LogLevel.ERROR) { return true; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedKeyRing.java index db0a9b137..bbf136dac 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedKeyRing.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedKeyRing.java @@ -19,7 +19,6 @@ package org.sufficientlysecure.keychain.pgp; import org.spongycastle.openpgp.PGPKeyRing; -import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.util.IterableIterator; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKeyRing.java index b8379f007..c2506685d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKeyRing.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKeyRing.java @@ -78,7 +78,7 @@ public class CanonicalizedPublicKeyRing extends CanonicalizedKeyRing { public IterableIterator publicKeyIterator() { @SuppressWarnings("unchecked") final Iterator it = getRing().getPublicKeys(); - return new IterableIterator(new Iterator() { + return new IterableIterator<>(new Iterator() { @Override public boolean hasNext() { return it.hasNext(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java index 6ccadac2e..cac5c1d97 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java @@ -182,7 +182,7 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey { * @return */ public LinkedList getSupportedHashAlgorithms() { - LinkedList supported = new LinkedList(); + LinkedList supported = new LinkedList<>(); if (mPrivateKeyState == PRIVATE_KEY_STATE_DIVERT_TO_CARD) { // No support for MD5 @@ -262,11 +262,9 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey { spGen.setSignatureCreationTime(false, nfcCreationTimestamp); signatureGenerator.setHashedSubpackets(spGen.generate()); return signatureGenerator; - } catch (PgpKeyNotFoundException e) { + } catch (PgpKeyNotFoundException | PGPException e) { // TODO: simply throw PGPException! throw new PgpGeneralException("Error initializing signature!", e); - } catch (PGPException e) { - throw new PgpGeneralException("Error initializing signature!", e); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKeyRing.java index eb589c3f9..b5f6a5b09 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKeyRing.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKeyRing.java @@ -18,27 +18,19 @@ package org.sufficientlysecure.keychain.pgp; -import org.spongycastle.bcpg.S2K; -import org.spongycastle.openpgp.PGPException; import org.spongycastle.openpgp.PGPKeyRing; import org.spongycastle.openpgp.PGPObjectFactory; -import org.spongycastle.openpgp.PGPPrivateKey; import org.spongycastle.openpgp.PGPPublicKey; import org.spongycastle.openpgp.PGPSecretKey; import org.spongycastle.openpgp.PGPSecretKeyRing; import org.spongycastle.openpgp.PGPSignature; -import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor; -import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; -import org.sufficientlysecure.keychain.provider.KeychainContract; -import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.util.IterableIterator; import org.sufficientlysecure.keychain.util.Log; import java.io.IOException; import java.util.HashMap; -import java.util.HashSet; import java.util.Iterator; public class CanonicalizedSecretKeyRing extends CanonicalizedKeyRing { @@ -94,7 +86,7 @@ public class CanonicalizedSecretKeyRing extends CanonicalizedKeyRing { public IterableIterator secretKeyIterator() { final Iterator it = mRing.getSecretKeys(); - return new IterableIterator(new Iterator() { + return new IterableIterator<>(new Iterator() { @Override public boolean hasNext() { return it.hasNext(); @@ -114,7 +106,7 @@ public class CanonicalizedSecretKeyRing extends CanonicalizedKeyRing { public IterableIterator publicKeyIterator() { final Iterator it = getRing().getPublicKeys(); - return new IterableIterator(new Iterator() { + return new IterableIterator<>(new Iterator() { @Override public boolean hasNext() { return it.hasNext(); @@ -133,7 +125,7 @@ public class CanonicalizedSecretKeyRing extends CanonicalizedKeyRing { } public HashMap getLocalNotationData() { - HashMap result = new HashMap(); + HashMap result = new HashMap<>(); Iterator it = getRing().getPublicKey().getKeySignatures(); while (it.hasNext()) { WrappedSignature sig = new WrappedSignature(it.next()); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/OpenPgpSignatureResultBuilder.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/OpenPgpSignatureResultBuilder.java index aa324c7ed..ed4715681 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/OpenPgpSignatureResultBuilder.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/OpenPgpSignatureResultBuilder.java @@ -19,7 +19,6 @@ package org.sufficientlysecure.keychain.pgp; import org.openintents.openpgp.OpenPgpSignatureResult; import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.util.Log; @@ -33,7 +32,7 @@ public class OpenPgpSignatureResultBuilder { // OpenPgpSignatureResult private boolean mSignatureOnly = false; private String mPrimaryUserId; - private ArrayList mUserIds = new ArrayList(); + private ArrayList mUserIds = new ArrayList<>(); private long mKeyId; // builder diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java index bd7759d43..aebb52a03 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java @@ -135,7 +135,7 @@ public class PgpKeyOperation { public PgpKeyOperation(Progressable progress) { super(); if (progress != null) { - mProgress = new Stack(); + mProgress = new Stack<>(); mProgress.push(progress); } } @@ -288,13 +288,11 @@ public class PgpKeyOperation { // build new key pair return new JcaPGPKeyPair(algorithm, keyGen.generateKeyPair(), new Date()); - } catch(NoSuchProviderException e) { + } catch(NoSuchProviderException | InvalidAlgorithmParameterException e) { throw new RuntimeException(e); } catch(NoSuchAlgorithmException e) { log.add(LogType.MSG_CR_ERROR_UNKNOWN_ALGO, indent); return null; - } catch(InvalidAlgorithmParameterException e) { - throw new RuntimeException(e); } catch(PGPException e) { Log.e(Constants.TAG, "internal pgp error", e); log.add(LogType.MSG_CR_ERROR_INTERNAL_PGP, indent); @@ -504,7 +502,7 @@ public class PgpKeyOperation { @SuppressWarnings("unchecked") Iterator it = modifiedPublicKey.getSignaturesForID(userId); if (it != null) { - for (PGPSignature cert : new IterableIterator(it)) { + for (PGPSignature cert : new IterableIterator<>(it)) { if (cert.getKeyID() != masterPublicKey.getKeyID()) { // foreign certificate?! error error error log.add(LogType.MSG_MF_ERROR_INTEGRITY, indent); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java index 04fb955fa..af85bd878 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java @@ -445,7 +445,7 @@ public class UncachedKeyRing { } } - ArrayList processedUserIds = new ArrayList(); + ArrayList processedUserIds = new ArrayList<>(); for (byte[] rawUserId : new IterableIterator(masterKey.getRawUserIDs())) { String userId = Utf8Util.fromUTF8ByteArrayReplaceBadEncoding(rawUserId); @@ -470,7 +470,7 @@ public class UncachedKeyRing { @SuppressWarnings("unchecked") Iterator signaturesIt = masterKey.getSignaturesForID(rawUserId); if (signaturesIt != null) { - for (PGPSignature zert : new IterableIterator(signaturesIt)) { + for (PGPSignature zert : new IterableIterator<>(signaturesIt)) { WrappedSignature cert = new WrappedSignature(zert); long certId = cert.getKeyId(); @@ -635,7 +635,7 @@ public class UncachedKeyRing { @SuppressWarnings("unchecked") Iterator signaturesIt = masterKey.getSignaturesForUserAttribute(userAttribute); if (signaturesIt != null) { - for (PGPSignature zert : new IterableIterator(signaturesIt)) { + for (PGPSignature zert : new IterableIterator<>(signaturesIt)) { WrappedSignature cert = new WrappedSignature(zert); long certId = cert.getKeyId(); @@ -778,7 +778,7 @@ public class UncachedKeyRing { } // Keep track of ids we encountered so far - Set knownIds = new HashSet(); + Set knownIds = new HashSet<>(); // Process all keys for (PGPPublicKey key : new IterableIterator(ring.getPublicKeys())) { @@ -1042,7 +1042,7 @@ public class UncachedKeyRing { } // remember which certs we already added. this is cheaper than semantic deduplication - Set certs = new TreeSet(new Comparator() { + Set certs = new TreeSet<>(new Comparator() { public int compare(byte[] left, byte[] right) { // check for length equality if (left.length != right.length) { @@ -1124,7 +1124,7 @@ public class UncachedKeyRing { if (signaturesIt == null) { continue; } - for (PGPSignature cert : new IterableIterator(signaturesIt)) { + for (PGPSignature cert : new IterableIterator<>(signaturesIt)) { // Don't merge foreign stuff into secret keys if (cert.getKeyID() != masterKeyId && isSecret()) { continue; @@ -1149,7 +1149,7 @@ public class UncachedKeyRing { if (signaturesIt == null) { continue; } - for (PGPSignature cert : new IterableIterator(signaturesIt)) { + for (PGPSignature cert : new IterableIterator<>(signaturesIt)) { // Don't merge foreign stuff into secret keys if (cert.getKeyID() != masterKeyId && isSecret()) { continue; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java index 1efc25076..0fe1ccdb6 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java @@ -20,7 +20,6 @@ package org.sufficientlysecure.keychain.pgp; import org.spongycastle.bcpg.ECPublicBCPGKey; import org.spongycastle.bcpg.SignatureSubpacketTags; -import org.spongycastle.bcpg.sig.KeyFlags; import org.spongycastle.openpgp.PGPPublicKey; import org.spongycastle.openpgp.PGPSignature; import org.spongycastle.openpgp.PGPSignatureSubpacketVector; @@ -136,7 +135,7 @@ public class UncachedPublicKey { continue; } - for (PGPSignature sig : new IterableIterator(signaturesIt)) { + for (PGPSignature sig : new IterableIterator<>(signaturesIt)) { try { // if this is a revocation, this is not the user id @@ -200,7 +199,7 @@ public class UncachedPublicKey { } public ArrayList getUnorderedUserIds() { - ArrayList userIds = new ArrayList(); + ArrayList userIds = new ArrayList<>(); for (byte[] rawUserId : new IterableIterator(mPublicKey.getRawUserIDs())) { // use our decoding method userIds.add(Utf8Util.fromUTF8ByteArrayReplaceBadEncoding(rawUserId)); @@ -209,7 +208,7 @@ public class UncachedPublicKey { } public ArrayList getUnorderedRawUserIds() { - ArrayList userIds = new ArrayList(); + ArrayList userIds = new ArrayList<>(); for (byte[] userId : new IterableIterator(mPublicKey.getRawUserIDs())) { userIds.add(userId); } @@ -217,7 +216,7 @@ public class UncachedPublicKey { } public ArrayList getUnorderedUserAttributes() { - ArrayList userAttributes = new ArrayList(); + ArrayList userAttributes = new ArrayList<>(); for (PGPUserAttributeSubpacketVector userAttribute : new IterableIterator(mPublicKey.getUserAttributes())) { userAttributes.add(new WrappedUserAttribute(userAttribute)); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java index cb03970e2..ade075d55 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java @@ -36,7 +36,6 @@ import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.util.Log; import java.io.IOException; -import java.security.SignatureException; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; @@ -80,7 +79,7 @@ public class WrappedSignature { } public ArrayList getEmbeddedSignatures() { - ArrayList sigs = new ArrayList(); + ArrayList sigs = new ArrayList<>(); if (!mSig.hasSubpackets()) { return sigs; } @@ -255,7 +254,7 @@ public class WrappedSignature { } public HashMap getNotation() { - HashMap result = new HashMap(); + HashMap result = new HashMap<>(); // If there is any notation data if (mSig.getHashedSubPackets() != null diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java index 29b9c5f9f..72475472e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java @@ -248,7 +248,7 @@ public class KeychainProvider extends ContentProvider { case KEY_RINGS_UNIFIED: case KEY_RINGS_FIND_BY_EMAIL: case KEY_RINGS_FIND_BY_SUBKEY: { - HashMap projectionMap = new HashMap(); + HashMap projectionMap = new HashMap<>(); projectionMap.put(KeyRings._ID, Tables.KEYS + ".oid AS _id"); projectionMap.put(KeyRings.MASTER_KEY_ID, Tables.KEYS + "." + Keys.MASTER_KEY_ID); projectionMap.put(KeyRings.KEY_ID, Tables.KEYS + "." + Keys.KEY_ID); @@ -432,7 +432,7 @@ public class KeychainProvider extends ContentProvider { } case KEY_RING_KEYS: { - HashMap projectionMap = new HashMap(); + HashMap projectionMap = new HashMap<>(); projectionMap.put(Keys._ID, Tables.KEYS + ".oid AS _id"); projectionMap.put(Keys.MASTER_KEY_ID, Tables.KEYS + "." + Keys.MASTER_KEY_ID); projectionMap.put(Keys.RANK, Tables.KEYS + "." + Keys.RANK); @@ -460,7 +460,7 @@ public class KeychainProvider extends ContentProvider { case KEY_RINGS_USER_IDS: case KEY_RING_USER_IDS: { - HashMap projectionMap = new HashMap(); + HashMap projectionMap = new HashMap<>(); projectionMap.put(UserPackets._ID, Tables.USER_PACKETS + ".oid AS _id"); projectionMap.put(UserPackets.MASTER_KEY_ID, Tables.USER_PACKETS + "." + UserPackets.MASTER_KEY_ID); projectionMap.put(UserPackets.TYPE, Tables.USER_PACKETS + "." + UserPackets.TYPE); @@ -507,7 +507,7 @@ public class KeychainProvider extends ContentProvider { case KEY_RINGS_PUBLIC: case KEY_RING_PUBLIC: { - HashMap projectionMap = new HashMap(); + HashMap projectionMap = new HashMap<>(); projectionMap.put(KeyRingData._ID, Tables.KEY_RINGS_PUBLIC + ".oid AS _id"); projectionMap.put(KeyRingData.MASTER_KEY_ID, KeyRingData.MASTER_KEY_ID); projectionMap.put(KeyRingData.KEY_RING_DATA, KeyRingData.KEY_RING_DATA); @@ -525,7 +525,7 @@ public class KeychainProvider extends ContentProvider { case KEY_RINGS_SECRET: case KEY_RING_SECRET: { - HashMap projectionMap = new HashMap(); + HashMap projectionMap = new HashMap<>(); projectionMap.put(KeyRingData._ID, Tables.KEY_RINGS_SECRET + ".oid AS _id"); projectionMap.put(KeyRingData.MASTER_KEY_ID, KeyRingData.MASTER_KEY_ID); projectionMap.put(KeyRingData.KEY_RING_DATA, KeyRingData.KEY_RING_DATA); @@ -543,7 +543,7 @@ public class KeychainProvider extends ContentProvider { case KEY_RING_CERTS: case KEY_RING_CERTS_SPECIFIC: { - HashMap projectionMap = new HashMap(); + HashMap projectionMap = new HashMap<>(); projectionMap.put(Certs._ID, Tables.CERTS + ".oid AS " + Certs._ID); projectionMap.put(Certs.MASTER_KEY_ID, Tables.CERTS + "." + Certs.MASTER_KEY_ID); projectionMap.put(Certs.RANK, Tables.CERTS + "." + Certs.RANK); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java index b2af5a0a0..a229f454f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java @@ -170,7 +170,7 @@ public class ProviderHelper { Cursor cursor = mContentResolver.query(uri, proj, selection, null, null); try { - HashMap result = new HashMap(proj.length); + HashMap result = new HashMap<>(proj.length); if (cursor != null && cursor.moveToFirst()) { int pos = 0; for (String p : proj) { @@ -221,7 +221,7 @@ public class ProviderHelper { }, KeyRings.HAS_ANY_SECRET + " = 1", null, null); try { - LongSparseArray result = new LongSparseArray(); + LongSparseArray result = new LongSparseArray<>(); if (cursor != null && cursor.moveToFirst()) do { long masterKeyId = cursor.getLong(0); @@ -350,7 +350,7 @@ public class ProviderHelper { mIndent += 1; // save all keys and userIds included in keyRing object in database - operations = new ArrayList(); + operations = new ArrayList<>(); log(LogType.MSG_IP_INSERT_KEYRING); { // insert keyring @@ -440,7 +440,7 @@ public class ProviderHelper { // classify and order user ids. primary are moved to the front, revoked to the back, // otherwise the order in the keyfile is preserved. - List uids = new ArrayList(); + List uids = new ArrayList<>(); if (trustedKeys.size() == 0) { log(LogType.MSG_IP_UID_CLASSIFYING_ZERO); @@ -460,7 +460,7 @@ public class ProviderHelper { log(LogType.MSG_IP_UID_PROCESSING, userId); mIndent += 1; // look through signatures for this specific key - for (WrappedSignature cert : new IterableIterator( + for (WrappedSignature cert : new IterableIterator<>( masterKey.getSignaturesForRawId(rawUserId))) { long certId = cert.getKeyId(); // self signature @@ -560,7 +560,7 @@ public class ProviderHelper { } mIndent += 1; // look through signatures for this specific key - for (WrappedSignature cert : new IterableIterator( + for (WrappedSignature cert : new IterableIterator<>( masterKey.getSignaturesForUserAttribute(userAttribute))) { long certId = cert.getKeyId(); // self signature @@ -712,7 +712,7 @@ public class ProviderHelper { boolean isPrimary = false; boolean isRevoked = false; WrappedSignature selfCert; - LongSparseArray trustedCerts = new LongSparseArray(); + LongSparseArray trustedCerts = new LongSparseArray<>(); @Override public int compareTo(UserPacketItem o) { @@ -1075,7 +1075,7 @@ public class ProviderHelper { // No keys existing might be a legitimate option, we write an empty file in that case cursor.moveToFirst(); ParcelableFileCache cache = - new ParcelableFileCache(mContext, "consolidate_secret.pcl"); + new ParcelableFileCache<>(mContext, "consolidate_secret.pcl"); cache.writeCache(cursor.getCount(), new Iterator() { ParcelableKeyRing ring; @@ -1137,7 +1137,7 @@ public class ProviderHelper { // No keys existing might be a legitimate option, we write an empty file in that case cursor.moveToFirst(); ParcelableFileCache cache = - new ParcelableFileCache(mContext, "consolidate_public.pcl"); + new ParcelableFileCache<>(mContext, "consolidate_public.pcl"); cache.writeCache(cursor.getCount(), new Iterator() { ParcelableKeyRing ring; @@ -1220,9 +1220,9 @@ public class ProviderHelper { mContentResolver.delete(KeyRings.buildUnifiedKeyRingsUri(), null, null); ParcelableFileCache cacheSecret = - new ParcelableFileCache(mContext, "consolidate_secret.pcl"); + new ParcelableFileCache<>(mContext, "consolidate_secret.pcl"); ParcelableFileCache cachePublic = - new ParcelableFileCache(mContext, "consolidate_public.pcl"); + new ParcelableFileCache<>(mContext, "consolidate_public.pcl"); // Set flag that we have a cached consolidation here try { @@ -1380,7 +1380,7 @@ public class ProviderHelper { public ArrayList getRegisteredApiApps() { Cursor cursor = mContentResolver.query(ApiApps.CONTENT_URI, null, null, null, null); - ArrayList packageNames = new ArrayList(); + ArrayList packageNames = new ArrayList<>(); try { if (cursor != null) { int packageNameCol = cursor.getColumnIndex(ApiApps.PACKAGE_NAME); @@ -1485,7 +1485,7 @@ public class ProviderHelper { } public Set getAllKeyIdsForApp(Uri uri) { - Set keyIds = new HashSet(); + Set keyIds = new HashSet<>(); Cursor cursor = mContentResolver.query(uri, null, null, null, null); try { @@ -1505,7 +1505,7 @@ public class ProviderHelper { } public Set getAllFingerprints(Uri uri) { - Set fingerprints = new HashSet(); + Set fingerprints = new HashSet<>(); String[] projection = new String[]{KeyRings.FINGERPRINT}; Cursor cursor = mContentResolver.query(uri, projection, null, null, null); try { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java index a5813567a..9534cc49d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java @@ -85,9 +85,9 @@ public class OpenPgpService extends RemoteService { boolean missingUserIdsCheck = false; boolean duplicateUserIdsCheck = false; - ArrayList keyIds = new ArrayList(); - ArrayList missingUserIds = new ArrayList(); - ArrayList duplicateUserIds = new ArrayList(); + ArrayList keyIds = new ArrayList<>(); + ArrayList missingUserIds = new ArrayList<>(); + ArrayList duplicateUserIds = new ArrayList<>(); if (!noUserIdsCheck) { for (String email : encryptionUserIds) { // try to find the key for this specific email @@ -718,30 +718,33 @@ public class OpenPgpService extends RemoteService { } String action = data.getAction(); - if (OpenPgpApi.ACTION_SIGN.equals(action)) { - return signImpl(data, input, output, accSettings); - } else if (OpenPgpApi.ACTION_ENCRYPT.equals(action)) { - return encryptAndSignImpl(data, input, output, accSettings, false); - } else if (OpenPgpApi.ACTION_SIGN_AND_ENCRYPT.equals(action)) { - return encryptAndSignImpl(data, input, output, accSettings, true); - } else if (OpenPgpApi.ACTION_DECRYPT_VERIFY.equals(action)) { - String currentPkg = getCurrentCallingPackage(); - Set allowedKeyIds = - mProviderHelper.getAllKeyIdsForApp( - ApiAccounts.buildBaseUri(currentPkg)); - return decryptAndVerifyImpl(data, input, output, allowedKeyIds, false); - } else if (OpenPgpApi.ACTION_DECRYPT_METADATA.equals(action)) { - String currentPkg = getCurrentCallingPackage(); - Set allowedKeyIds = - mProviderHelper.getAllKeyIdsForApp( - ApiAccounts.buildBaseUri(currentPkg)); - return decryptAndVerifyImpl(data, input, output, allowedKeyIds, true); - } 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; + switch (action) { + case OpenPgpApi.ACTION_SIGN: + return signImpl(data, input, output, accSettings); + case OpenPgpApi.ACTION_ENCRYPT: + return encryptAndSignImpl(data, input, output, accSettings, false); + case OpenPgpApi.ACTION_SIGN_AND_ENCRYPT: + return encryptAndSignImpl(data, input, output, accSettings, true); + case OpenPgpApi.ACTION_DECRYPT_VERIFY: { + String currentPkg = getCurrentCallingPackage(); + Set allowedKeyIds = + mProviderHelper.getAllKeyIdsForApp( + ApiAccounts.buildBaseUri(currentPkg)); + return decryptAndVerifyImpl(data, input, output, allowedKeyIds, false); + } + case OpenPgpApi.ACTION_DECRYPT_METADATA: { + String currentPkg = getCurrentCallingPackage(); + Set allowedKeyIds = + mProviderHelper.getAllKeyIdsForApp( + ApiAccounts.buildBaseUri(currentPkg)); + return decryptAndVerifyImpl(data, input, output, allowedKeyIds, true); + } + case OpenPgpApi.ACTION_GET_KEY: + return getKeyImpl(data); + case OpenPgpApi.ACTION_GET_KEY_IDS: + return getKeyIdsImpl(data); + default: + return null; } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/RemoteService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/RemoteService.java index e71b52ccd..672f59285 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/RemoteService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/RemoteService.java @@ -27,7 +27,6 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.Signature; import android.net.Uri; import android.os.Binder; -import android.text.TextUtils; import org.openintents.openpgp.OpenPgpError; import org.openintents.openpgp.util.OpenPgpApi; @@ -216,9 +215,7 @@ public abstract class RemoteService extends Service { String[] callingPackages = getPackageManager().getPackagesForUid(uid); // is calling package allowed to use this service? - for (int i = 0; i < callingPackages.length; i++) { - String currentPkg = callingPackages[i]; - + for (String currentPkg : callingPackages) { if (isPackageAllowed(currentPkg)) { return true; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsActivity.java index 7d77a989d..2751db370 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsActivity.java @@ -20,7 +20,6 @@ package org.sufficientlysecure.keychain.remote.ui; import android.content.Intent; import android.net.Uri; import android.os.Bundle; -import android.support.v7.app.ActionBarActivity; import android.view.Menu; import android.view.MenuItem; import android.view.View; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java index d84a03698..e91482e28 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java @@ -22,8 +22,6 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.net.Uri; import android.os.Bundle; -import android.support.v7.app.ActionBar; -import android.support.v7.app.ActionBarActivity; import android.view.Menu; import android.view.MenuItem; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/RemoteServiceActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/RemoteServiceActivity.java index a9a7c75f5..447f02b55 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/RemoteServiceActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/RemoteServiceActivity.java @@ -22,7 +22,6 @@ import android.graphics.Color; import android.graphics.Typeface; import android.net.Uri; import android.os.Bundle; -import android.support.v7.app.ActionBarActivity; import android.text.Spannable; import android.text.SpannableString; import android.text.SpannableStringBuilder; @@ -108,234 +107,244 @@ public class RemoteServiceActivity extends BaseActivity { final Bundle extras = intent.getExtras(); - if (ACTION_REGISTER.equals(action)) { - final String packageName = extras.getString(EXTRA_PACKAGE_NAME); - final byte[] packageSignature = extras.getByteArray(EXTRA_PACKAGE_SIGNATURE); - Log.d(Constants.TAG, "ACTION_REGISTER packageName: " + packageName); + switch (action) { + case ACTION_REGISTER: { + final String packageName = extras.getString(EXTRA_PACKAGE_NAME); + final byte[] packageSignature = extras.getByteArray(EXTRA_PACKAGE_SIGNATURE); + Log.d(Constants.TAG, "ACTION_REGISTER packageName: " + packageName); - setContentView(R.layout.api_remote_register_app); - initToolbar(); + setContentView(R.layout.api_remote_register_app); + initToolbar(); - mAppSettingsFragment = (AppSettingsFragment) getSupportFragmentManager().findFragmentById( - R.id.api_app_settings_fragment); + mAppSettingsFragment = (AppSettingsFragment) getSupportFragmentManager().findFragmentById( + R.id.api_app_settings_fragment); - AppSettings settings = new AppSettings(packageName, packageSignature); - mAppSettingsFragment.setAppSettings(settings); + AppSettings settings = new AppSettings(packageName, packageSignature); + mAppSettingsFragment.setAppSettings(settings); - // Inflate a "Done"/"Cancel" custom action bar view - ActionBarHelper.setTwoButtonView(getSupportActionBar(), - R.string.api_register_allow, R.drawable.ic_action_done, - new View.OnClickListener() { - @Override - public void onClick(View v) { - // Allow + // Inflate a "Done"/"Cancel" custom action bar view + ActionBarHelper.setTwoButtonView(getSupportActionBar(), + R.string.api_register_allow, R.drawable.ic_action_done, + new View.OnClickListener() { + @Override + public void onClick(View v) { + // Allow - mProviderHelper.insertApiApp(mAppSettingsFragment.getAppSettings()); + mProviderHelper.insertApiApp(mAppSettingsFragment.getAppSettings()); - // give data through for new service call - Intent resultData = extras.getParcelable(EXTRA_DATA); - RemoteServiceActivity.this.setResult(RESULT_OK, resultData); - RemoteServiceActivity.this.finish(); - } - }, R.string.api_register_disallow, R.drawable.ic_action_cancel, - new View.OnClickListener() { - @Override - public void onClick(View v) { - // Disallow - RemoteServiceActivity.this.setResult(RESULT_CANCELED); - RemoteServiceActivity.this.finish(); + // give data through for new service call + Intent resultData = extras.getParcelable(EXTRA_DATA); + RemoteServiceActivity.this.setResult(RESULT_OK, resultData); + RemoteServiceActivity.this.finish(); + } + }, R.string.api_register_disallow, R.drawable.ic_action_cancel, + new View.OnClickListener() { + @Override + public void onClick(View v) { + // Disallow + RemoteServiceActivity.this.setResult(RESULT_CANCELED); + RemoteServiceActivity.this.finish(); + } } - } - ); - } else if (ACTION_CREATE_ACCOUNT.equals(action)) { - final String packageName = extras.getString(EXTRA_PACKAGE_NAME); - final String accName = extras.getString(EXTRA_ACC_NAME); + ); + break; + } + case ACTION_CREATE_ACCOUNT: { + final String packageName = extras.getString(EXTRA_PACKAGE_NAME); + final String accName = extras.getString(EXTRA_ACC_NAME); - setContentView(R.layout.api_remote_create_account); - initToolbar(); + setContentView(R.layout.api_remote_create_account); + initToolbar(); - mAccSettingsFragment = (AccountSettingsFragment) getSupportFragmentManager().findFragmentById( - R.id.api_account_settings_fragment); + mAccSettingsFragment = (AccountSettingsFragment) getSupportFragmentManager().findFragmentById( + R.id.api_account_settings_fragment); - TextView text = (TextView) findViewById(R.id.api_remote_create_account_text); + TextView text = (TextView) findViewById(R.id.api_remote_create_account_text); - // update existing? - Uri uri = KeychainContract.ApiAccounts.buildByPackageAndAccountUri(packageName, accName); - AccountSettings settings = mProviderHelper.getApiAccountSettings(uri); - if (settings == null) { - // create new account - settings = new AccountSettings(accName); - mUpdateExistingAccount = false; + // update existing? + Uri uri = KeychainContract.ApiAccounts.buildByPackageAndAccountUri(packageName, accName); + AccountSettings settings = mProviderHelper.getApiAccountSettings(uri); + if (settings == null) { + // create new account + settings = new AccountSettings(accName); + mUpdateExistingAccount = false; - text.setText(R.string.api_create_account_text); - } else { - // update existing account - mUpdateExistingAccount = true; + text.setText(R.string.api_create_account_text); + } else { + // update existing account + mUpdateExistingAccount = true; - text.setText(R.string.api_update_account_text); - } - mAccSettingsFragment.setAccSettings(settings); - - // Inflate a "Done"/"Cancel" custom action bar view - ActionBarHelper.setTwoButtonView(getSupportActionBar(), - R.string.api_settings_save, R.drawable.ic_action_done, - new View.OnClickListener() { - @Override - public void onClick(View v) { - // Save - - // user needs to select a key if it has explicitly requested (None is only allowed for new accounts) - if (mUpdateExistingAccount && mAccSettingsFragment.getAccSettings().getKeyId() == Constants.key.none) { - Notify.showNotify(RemoteServiceActivity.this, getString(R.string.api_register_error_select_key), Notify.Style.ERROR); - } else { - if (mUpdateExistingAccount) { - Uri baseUri = KeychainContract.ApiAccounts.buildBaseUri(packageName); - Uri accountUri = baseUri.buildUpon().appendEncodedPath(accName).build(); - mProviderHelper.updateApiAccount( - accountUri, - mAccSettingsFragment.getAccSettings()); + text.setText(R.string.api_update_account_text); + } + mAccSettingsFragment.setAccSettings(settings); + + // Inflate a "Done"/"Cancel" custom action bar view + ActionBarHelper.setTwoButtonView(getSupportActionBar(), + R.string.api_settings_save, R.drawable.ic_action_done, + new View.OnClickListener() { + @Override + public void onClick(View v) { + // Save + + // user needs to select a key if it has explicitly requested (None is only allowed for new accounts) + if (mUpdateExistingAccount && mAccSettingsFragment.getAccSettings().getKeyId() == Constants.key.none) { + Notify.showNotify(RemoteServiceActivity.this, getString(R.string.api_register_error_select_key), Notify.Style.ERROR); } else { - mProviderHelper.insertApiAccount( - KeychainContract.ApiAccounts.buildBaseUri(packageName), - mAccSettingsFragment.getAccSettings()); + if (mUpdateExistingAccount) { + Uri baseUri = KeychainContract.ApiAccounts.buildBaseUri(packageName); + Uri accountUri = baseUri.buildUpon().appendEncodedPath(accName).build(); + mProviderHelper.updateApiAccount( + accountUri, + mAccSettingsFragment.getAccSettings()); + } else { + mProviderHelper.insertApiAccount( + KeychainContract.ApiAccounts.buildBaseUri(packageName), + mAccSettingsFragment.getAccSettings()); + } + + // give data through for new service call + Intent resultData = extras.getParcelable(EXTRA_DATA); + RemoteServiceActivity.this.setResult(RESULT_OK, resultData); + RemoteServiceActivity.this.finish(); } - - // give data through for new service call - Intent resultData = extras.getParcelable(EXTRA_DATA); - RemoteServiceActivity.this.setResult(RESULT_OK, resultData); + } + }, R.string.api_settings_cancel, R.drawable.ic_action_cancel, + new View.OnClickListener() { + @Override + public void onClick(View v) { + // Cancel + RemoteServiceActivity.this.setResult(RESULT_CANCELED); RemoteServiceActivity.this.finish(); } } - }, R.string.api_settings_cancel, R.drawable.ic_action_cancel, - new View.OnClickListener() { - @Override - public void onClick(View v) { - // Cancel - RemoteServiceActivity.this.setResult(RESULT_CANCELED); - RemoteServiceActivity.this.finish(); - } + ); + + break; + } + case ACTION_SELECT_PUB_KEYS: { + long[] selectedMasterKeyIds = intent.getLongArrayExtra(EXTRA_SELECTED_MASTER_KEY_IDS); + boolean noUserIdsCheck = intent.getBooleanExtra(EXTRA_NO_USER_IDS_CHECK, true); + ArrayList missingUserIds = intent + .getStringArrayListExtra(EXTRA_MISSING_USER_IDS); + ArrayList dublicateUserIds = intent + .getStringArrayListExtra(EXTRA_DUPLICATE_USER_IDS); + + SpannableStringBuilder ssb = new SpannableStringBuilder(); + final SpannableString textIntro = new SpannableString( + noUserIdsCheck ? getString(R.string.api_select_pub_keys_text_no_user_ids) + : getString(R.string.api_select_pub_keys_text) + ); + textIntro.setSpan(new StyleSpan(Typeface.BOLD), 0, textIntro.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + ssb.append(textIntro); + + if (missingUserIds != null && missingUserIds.size() > 0) { + ssb.append("\n\n"); + ssb.append(getString(R.string.api_select_pub_keys_missing_text)); + ssb.append("\n"); + for (String userId : missingUserIds) { + SpannableString ss = new SpannableString(userId + "\n"); + ss.setSpan(new BulletSpan(15, Color.BLACK), 0, ss.length(), + Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + ssb.append(ss); } - ); - - } else if (ACTION_SELECT_PUB_KEYS.equals(action)) { - long[] selectedMasterKeyIds = intent.getLongArrayExtra(EXTRA_SELECTED_MASTER_KEY_IDS); - boolean noUserIdsCheck = intent.getBooleanExtra(EXTRA_NO_USER_IDS_CHECK, true); - ArrayList missingUserIds = intent - .getStringArrayListExtra(EXTRA_MISSING_USER_IDS); - ArrayList dublicateUserIds = intent - .getStringArrayListExtra(EXTRA_DUPLICATE_USER_IDS); - - SpannableStringBuilder ssb = new SpannableStringBuilder(); - final SpannableString textIntro = new SpannableString( - noUserIdsCheck ? getString(R.string.api_select_pub_keys_text_no_user_ids) - : getString(R.string.api_select_pub_keys_text) - ); - textIntro.setSpan(new StyleSpan(Typeface.BOLD), 0, textIntro.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); - ssb.append(textIntro); - - if (missingUserIds != null && missingUserIds.size() > 0) { - ssb.append("\n\n"); - ssb.append(getString(R.string.api_select_pub_keys_missing_text)); - ssb.append("\n"); - for (String userId : missingUserIds) { - SpannableString ss = new SpannableString(userId + "\n"); - ss.setSpan(new BulletSpan(15, Color.BLACK), 0, ss.length(), - Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); - ssb.append(ss); } - } - if (dublicateUserIds != null && dublicateUserIds.size() > 0) { - ssb.append("\n\n"); - ssb.append(getString(R.string.api_select_pub_keys_dublicates_text)); - ssb.append("\n"); - for (String userId : dublicateUserIds) { - SpannableString ss = new SpannableString(userId + "\n"); - ss.setSpan(new BulletSpan(15, Color.BLACK), 0, ss.length(), - Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); - ssb.append(ss); + if (dublicateUserIds != null && dublicateUserIds.size() > 0) { + ssb.append("\n\n"); + ssb.append(getString(R.string.api_select_pub_keys_dublicates_text)); + ssb.append("\n"); + for (String userId : dublicateUserIds) { + SpannableString ss = new SpannableString(userId + "\n"); + ss.setSpan(new BulletSpan(15, Color.BLACK), 0, ss.length(), + Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + ssb.append(ss); + } } - } - setContentView(R.layout.api_remote_select_pub_keys); - initToolbar(); - - // Inflate a "Done"/"Cancel" custom action bar view - ActionBarHelper.setTwoButtonView(getSupportActionBar(), - R.string.btn_okay, R.drawable.ic_action_done, - new View.OnClickListener() { - @Override - public void onClick(View v) { - // add key ids to params Bundle for new request - Intent resultData = extras.getParcelable(EXTRA_DATA); - resultData.putExtra(OpenPgpApi.EXTRA_KEY_IDS, - mSelectFragment.getSelectedMasterKeyIds()); - - RemoteServiceActivity.this.setResult(RESULT_OK, resultData); - RemoteServiceActivity.this.finish(); - } - }, R.string.btn_do_not_save, R.drawable.ic_action_cancel, new View.OnClickListener() { - @Override - public void onClick(View v) { - // cancel - RemoteServiceActivity.this.setResult(RESULT_CANCELED); - RemoteServiceActivity.this.finish(); + setContentView(R.layout.api_remote_select_pub_keys); + initToolbar(); + + // Inflate a "Done"/"Cancel" custom action bar view + ActionBarHelper.setTwoButtonView(getSupportActionBar(), + R.string.btn_okay, R.drawable.ic_action_done, + new View.OnClickListener() { + @Override + public void onClick(View v) { + // add key ids to params Bundle for new request + Intent resultData = extras.getParcelable(EXTRA_DATA); + resultData.putExtra(OpenPgpApi.EXTRA_KEY_IDS, + mSelectFragment.getSelectedMasterKeyIds()); + + RemoteServiceActivity.this.setResult(RESULT_OK, resultData); + RemoteServiceActivity.this.finish(); + } + }, R.string.btn_do_not_save, R.drawable.ic_action_cancel, new View.OnClickListener() { + @Override + public void onClick(View v) { + // cancel + RemoteServiceActivity.this.setResult(RESULT_CANCELED); + RemoteServiceActivity.this.finish(); + } } - } - ); + ); - // set text on view - TextView textView = (TextView) findViewById(R.id.api_select_pub_keys_text); - textView.setText(ssb, TextView.BufferType.SPANNABLE); + // set text on view + TextView textView = (TextView) findViewById(R.id.api_select_pub_keys_text); + textView.setText(ssb, TextView.BufferType.SPANNABLE); - /* Load select pub keys fragment */ - // Check that the activity is using the layout version with - // the fragment_container FrameLayout - if (findViewById(R.id.api_select_pub_keys_fragment_container) != null) { + /* Load select pub keys fragment */ + // Check that the activity is using the layout version with + // the fragment_container FrameLayout + if (findViewById(R.id.api_select_pub_keys_fragment_container) != null) { - // However, if we're being restored from a previous state, - // then we don't need to do anything and should return or else - // we could end up with overlapping fragments. - if (savedInstanceState != null) { - return; - } + // However, if we're being restored from a previous state, + // then we don't need to do anything and should return or else + // we could end up with overlapping fragments. + if (savedInstanceState != null) { + return; + } - // Create an instance of the fragment - mSelectFragment = SelectPublicKeyFragment.newInstance(selectedMasterKeyIds); + // Create an instance of the fragment + mSelectFragment = SelectPublicKeyFragment.newInstance(selectedMasterKeyIds); - // Add the fragment to the 'fragment_container' FrameLayout - getSupportFragmentManager().beginTransaction() - .add(R.id.api_select_pub_keys_fragment_container, mSelectFragment).commit(); + // Add the fragment to the 'fragment_container' FrameLayout + getSupportFragmentManager().beginTransaction() + .add(R.id.api_select_pub_keys_fragment_container, mSelectFragment).commit(); + } + break; } - } else if (ACTION_ERROR_MESSAGE.equals(action)) { - String errorMessage = intent.getStringExtra(EXTRA_ERROR_MESSAGE); + case ACTION_ERROR_MESSAGE: { + String errorMessage = intent.getStringExtra(EXTRA_ERROR_MESSAGE); - Spannable redErrorMessage = new SpannableString(errorMessage); - redErrorMessage.setSpan(new ForegroundColorSpan(Color.RED), 0, errorMessage.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + Spannable redErrorMessage = new SpannableString(errorMessage); + redErrorMessage.setSpan(new ForegroundColorSpan(Color.RED), 0, errorMessage.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); - setContentView(R.layout.api_remote_error_message); - initToolbar(); + setContentView(R.layout.api_remote_error_message); + initToolbar(); - // Inflate a "Done" custom action bar view - ActionBarHelper.setOneButtonView(getSupportActionBar(), - R.string.btn_okay, R.drawable.ic_action_done, - new View.OnClickListener() { + // Inflate a "Done" custom action bar view + ActionBarHelper.setOneButtonView(getSupportActionBar(), + R.string.btn_okay, R.drawable.ic_action_done, + new View.OnClickListener() { - @Override - public void onClick(View v) { - RemoteServiceActivity.this.setResult(RESULT_CANCELED); - RemoteServiceActivity.this.finish(); + @Override + public void onClick(View v) { + RemoteServiceActivity.this.setResult(RESULT_CANCELED); + RemoteServiceActivity.this.finish(); + } } - } - ); - - // set text on view - TextView textView = (TextView) findViewById(R.id.api_app_error_message_text); - textView.setText(redErrorMessage); - } else { - Log.e(Constants.TAG, "Action does not exist!"); - setResult(RESULT_CANCELED); - finish(); + ); + + // set text on view + TextView textView = (TextView) findViewById(R.id.api_app_error_message_text); + textView.setText(redErrorMessage); + break; + } + default: + Log.e(Constants.TAG, "Action does not exist!"); + setResult(RESULT_CANCELED); + finish(); + break; } } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/CertifyActionsParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/CertifyActionsParcel.java index dd9c0d769..f0dbf0820 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/CertifyActionsParcel.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/CertifyActionsParcel.java @@ -34,7 +34,7 @@ public class CertifyActionsParcel implements Parcelable { final public long mMasterKeyId; public CertifyLevel mLevel; - public ArrayList mCertifyActions = new ArrayList(); + public ArrayList mCertifyActions = new ArrayList<>(); public CertifyActionsParcel(long masterKeyId) { mMasterKeyId = masterKeyId; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java index a2172171a..b96d8945c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -34,7 +34,6 @@ import org.sufficientlysecure.keychain.operations.PromoteKeyOperation; import org.sufficientlysecure.keychain.operations.results.DeleteResult; import org.sufficientlysecure.keychain.operations.results.EditKeyResult; import org.sufficientlysecure.keychain.operations.results.ExportResult; -import org.sufficientlysecure.keychain.operations.results.PgpEditKeyResult; import org.sufficientlysecure.keychain.operations.results.PromoteKeyResult; import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.operations.results.CertifyResult; @@ -232,313 +231,331 @@ public class KeychainIntentService extends IntentService implements Progressable String action = intent.getAction(); // executeServiceMethod action from extra bundle - if (ACTION_CERTIFY_KEYRING.equals(action)) { + switch (action) { + case ACTION_CERTIFY_KEYRING: { - // Input - CertifyActionsParcel parcel = data.getParcelable(CERTIFY_PARCEL); - String keyServerUri = data.getString(UPLOAD_KEY_SERVER); - - // Operation - CertifyOperation op = new CertifyOperation(this, providerHelper, this, mActionCanceled); - CertifyResult result = op.certify(parcel, keyServerUri); + // Input + CertifyActionsParcel parcel = data.getParcelable(CERTIFY_PARCEL); + String keyServerUri = data.getString(UPLOAD_KEY_SERVER); - // Result - sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result); + // Operation + CertifyOperation op = new CertifyOperation(this, providerHelper, this, mActionCanceled); + CertifyResult result = op.certify(parcel, keyServerUri); - } else if (ACTION_CONSOLIDATE.equals(action)) { + // Result + sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result); - // Operation - ConsolidateResult result; - if (data.containsKey(CONSOLIDATE_RECOVERY) && data.getBoolean(CONSOLIDATE_RECOVERY)) { - result = new ProviderHelper(this).consolidateDatabaseStep2(this); - } else { - result = new ProviderHelper(this).consolidateDatabaseStep1(this); + break; } + case ACTION_CONSOLIDATE: { - // Result - sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result); + // Operation + ConsolidateResult result; + if (data.containsKey(CONSOLIDATE_RECOVERY) && data.getBoolean(CONSOLIDATE_RECOVERY)) { + result = new ProviderHelper(this).consolidateDatabaseStep2(this); + } else { + result = new ProviderHelper(this).consolidateDatabaseStep1(this); + } + + // Result + sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result); - } else if (ACTION_DECRYPT_METADATA.equals(action)) { + break; + } + case ACTION_DECRYPT_METADATA: - try { + try { /* Input */ - String passphrase = data.getString(DECRYPT_PASSPHRASE); - byte[] nfcDecryptedSessionKey = data.getByteArray(DECRYPT_NFC_DECRYPTED_SESSION_KEY); + String passphrase = data.getString(DECRYPT_PASSPHRASE); + byte[] nfcDecryptedSessionKey = data.getByteArray(DECRYPT_NFC_DECRYPTED_SESSION_KEY); - InputData inputData = createDecryptInputData(data); + InputData inputData = createDecryptInputData(data); /* Operation */ - Bundle resultData = new Bundle(); + Bundle resultData = new Bundle(); - // verifyText and decrypt returning additional resultData values for the - // verification of signatures - PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder( - this, new ProviderHelper(this), this, inputData, null - ); - builder.setAllowSymmetricDecryption(true) - .setPassphrase(passphrase) - .setDecryptMetadataOnly(true) - .setNfcState(nfcDecryptedSessionKey); + // verifyText and decrypt returning additional resultData values for the + // verification of signatures + PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder( + this, new ProviderHelper(this), this, inputData, null + ); + builder.setAllowSymmetricDecryption(true) + .setPassphrase(passphrase) + .setDecryptMetadataOnly(true) + .setNfcState(nfcDecryptedSessionKey); - DecryptVerifyResult decryptVerifyResult = builder.build().execute(); + DecryptVerifyResult decryptVerifyResult = builder.build().execute(); - sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, decryptVerifyResult); - } catch (Exception e) { - sendErrorToHandler(e); - } + sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, decryptVerifyResult); + } catch (Exception e) { + sendErrorToHandler(e); + } - } else if (ACTION_DECRYPT_VERIFY.equals(action)) { + break; + case ACTION_DECRYPT_VERIFY: - try { + try { /* Input */ - String passphrase = data.getString(DECRYPT_PASSPHRASE); - byte[] nfcDecryptedSessionKey = data.getByteArray(DECRYPT_NFC_DECRYPTED_SESSION_KEY); + String passphrase = data.getString(DECRYPT_PASSPHRASE); + byte[] nfcDecryptedSessionKey = data.getByteArray(DECRYPT_NFC_DECRYPTED_SESSION_KEY); - InputData inputData = createDecryptInputData(data); - OutputStream outStream = createCryptOutputStream(data); + InputData inputData = createDecryptInputData(data); + OutputStream outStream = createCryptOutputStream(data); /* Operation */ - Bundle resultData = new Bundle(); + Bundle resultData = new Bundle(); - // verifyText and decrypt returning additional resultData values for the - // verification of signatures - PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder( - this, new ProviderHelper(this), this, - inputData, outStream - ); - builder.setAllowSymmetricDecryption(true) - .setPassphrase(passphrase) - .setNfcState(nfcDecryptedSessionKey); + // verifyText and decrypt returning additional resultData values for the + // verification of signatures + PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder( + this, new ProviderHelper(this), this, + inputData, outStream + ); + builder.setAllowSymmetricDecryption(true) + .setPassphrase(passphrase) + .setNfcState(nfcDecryptedSessionKey); - DecryptVerifyResult decryptVerifyResult = builder.build().execute(); + DecryptVerifyResult decryptVerifyResult = builder.build().execute(); - outStream.close(); + outStream.close(); - resultData.putParcelable(DecryptVerifyResult.EXTRA_RESULT, decryptVerifyResult); + resultData.putParcelable(DecryptVerifyResult.EXTRA_RESULT, decryptVerifyResult); /* Output */ - finalizeDecryptOutputStream(data, resultData, outStream); + finalizeDecryptOutputStream(data, resultData, outStream); - Log.logDebugBundle(resultData, "resultData"); + Log.logDebugBundle(resultData, "resultData"); - sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, resultData); - } catch (Exception e) { - sendErrorToHandler(e); - } - - } else if (ACTION_DELETE.equals(action)) { - - // Input - long[] masterKeyIds = data.getLongArray(DELETE_KEY_LIST); - boolean isSecret = data.getBoolean(DELETE_IS_SECRET); - - // Operation - DeleteOperation op = new DeleteOperation(this, new ProviderHelper(this), this); - DeleteResult result = op.execute(masterKeyIds, isSecret); + sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, resultData); + } catch (Exception e) { + sendErrorToHandler(e); + } - // Result - sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result); + break; + case ACTION_DELETE: { - } else if (ACTION_EDIT_KEYRING.equals(action)) { + // Input + long[] masterKeyIds = data.getLongArray(DELETE_KEY_LIST); + boolean isSecret = data.getBoolean(DELETE_IS_SECRET); - // Input - SaveKeyringParcel saveParcel = data.getParcelable(EDIT_KEYRING_PARCEL); - String passphrase = data.getString(EDIT_KEYRING_PASSPHRASE); + // Operation + DeleteOperation op = new DeleteOperation(this, new ProviderHelper(this), this); + DeleteResult result = op.execute(masterKeyIds, isSecret); - // Operation - EditKeyOperation op = new EditKeyOperation(this, providerHelper, this, mActionCanceled); - EditKeyResult result = op.execute(saveParcel, passphrase); + // Result + sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result); - // Result - sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result); + break; + } + case ACTION_EDIT_KEYRING: { - } else if (ACTION_PROMOTE_KEYRING.equals(action)) { + // Input + SaveKeyringParcel saveParcel = data.getParcelable(EDIT_KEYRING_PARCEL); + String passphrase = data.getString(EDIT_KEYRING_PASSPHRASE); - // Input - long keyRingId = data.getInt(EXPORT_KEY_RING_MASTER_KEY_ID); + // Operation + EditKeyOperation op = new EditKeyOperation(this, providerHelper, this, mActionCanceled); + EditKeyResult result = op.execute(saveParcel, passphrase); - // Operation - PromoteKeyOperation op = new PromoteKeyOperation(this, providerHelper, this, mActionCanceled); - PromoteKeyResult result = op.execute(keyRingId); + // Result + sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result); - // Result - sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result); + break; + } + case ACTION_PROMOTE_KEYRING: { - } else if (ACTION_EXPORT_KEYRING.equals(action)) { + // Input + long keyRingId = data.getInt(EXPORT_KEY_RING_MASTER_KEY_ID); - // Input - boolean exportSecret = data.getBoolean(EXPORT_SECRET, false); - String outputFile = data.getString(EXPORT_FILENAME); - Uri outputUri = data.getParcelable(EXPORT_URI); + // Operation + PromoteKeyOperation op = new PromoteKeyOperation(this, providerHelper, this, mActionCanceled); + PromoteKeyResult result = op.execute(keyRingId); - boolean exportAll = data.getBoolean(EXPORT_ALL); - long[] masterKeyIds = exportAll ? null : data.getLongArray(EXPORT_KEY_RING_MASTER_KEY_ID); + // Result + sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result); - // Operation - ImportExportOperation importExportOperation = new ImportExportOperation(this, new ProviderHelper(this), this); - ExportResult result; - if (outputFile != null) { - result = importExportOperation.exportToFile(masterKeyIds, exportSecret, outputFile); - } else { - result = importExportOperation.exportToUri(masterKeyIds, exportSecret, outputUri); + break; } - - // Result - sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result); - - } else if (ACTION_IMPORT_KEYRING.equals(action)) { - - try { + case ACTION_EXPORT_KEYRING: { // Input - String keyServer = data.getString(IMPORT_KEY_SERVER); - Iterator entries; - int numEntries; - if (data.containsKey(IMPORT_KEY_LIST)) { - // get entries from intent - ArrayList list = data.getParcelableArrayList(IMPORT_KEY_LIST); - entries = list.iterator(); - numEntries = list.size(); - } else { - // get entries from cached file - ParcelableFileCache cache = - new ParcelableFileCache(this, "key_import.pcl"); - IteratorWithSize it = cache.readCache(); - entries = it; - numEntries = it.getSize(); - } + boolean exportSecret = data.getBoolean(EXPORT_SECRET, false); + String outputFile = data.getString(EXPORT_FILENAME); + Uri outputUri = data.getParcelable(EXPORT_URI); + + boolean exportAll = data.getBoolean(EXPORT_ALL); + long[] masterKeyIds = exportAll ? null : data.getLongArray(EXPORT_KEY_RING_MASTER_KEY_ID); // Operation - ImportExportOperation importExportOperation = new ImportExportOperation( - this, providerHelper, this, mActionCanceled); - ImportKeyResult result = importExportOperation.importKeyRings(entries, numEntries, keyServer); - - // Special: consolidate on secret key import (cannot be cancelled!) - if (result.mSecret > 0) { - // TODO move this into the import operation - providerHelper.consolidateDatabaseStep1(this); + ImportExportOperation importExportOperation = new ImportExportOperation(this, new ProviderHelper(this), this); + ExportResult result; + if (outputFile != null) { + result = importExportOperation.exportToFile(masterKeyIds, exportSecret, outputFile); + } else { + result = importExportOperation.exportToUri(masterKeyIds, exportSecret, outputUri); } - // Special: make sure new data is synced into contacts - ContactSyncAdapterService.requestSync(); - // Result sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result); - } catch (Exception e) { - sendErrorToHandler(e); + + break; } + case ACTION_IMPORT_KEYRING: - } else if (ACTION_SIGN_ENCRYPT.equals(action)) { + try { - try { - /* Input */ - int source = data.get(SOURCE) != null ? data.getInt(SOURCE) : data.getInt(TARGET); - Bundle resultData = new Bundle(); + // Input + String keyServer = data.getString(IMPORT_KEY_SERVER); + Iterator entries; + int numEntries; + if (data.containsKey(IMPORT_KEY_LIST)) { + // get entries from intent + ArrayList list = data.getParcelableArrayList(IMPORT_KEY_LIST); + entries = list.iterator(); + numEntries = list.size(); + } else { + // get entries from cached file + ParcelableFileCache cache = + new ParcelableFileCache<>(this, "key_import.pcl"); + IteratorWithSize it = cache.readCache(); + entries = it; + numEntries = it.getSize(); + } - long sigMasterKeyId = data.getLong(ENCRYPT_SIGNATURE_MASTER_ID); - String sigKeyPassphrase = data.getString(ENCRYPT_SIGNATURE_KEY_PASSPHRASE); + // Operation + ImportExportOperation importExportOperation = new ImportExportOperation( + this, providerHelper, this, mActionCanceled); + ImportKeyResult result = importExportOperation.importKeyRings(entries, numEntries, keyServer); - byte[] nfcHash = data.getByteArray(ENCRYPT_SIGNATURE_NFC_HASH); - Date nfcTimestamp = (Date) data.getSerializable(ENCRYPT_SIGNATURE_NFC_TIMESTAMP); + // Special: consolidate on secret key import (cannot be cancelled!) + if (result.mSecret > 0) { + // TODO move this into the import operation + providerHelper.consolidateDatabaseStep1(this); + } - String symmetricPassphrase = data.getString(ENCRYPT_SYMMETRIC_PASSPHRASE); + // Special: make sure new data is synced into contacts + ContactSyncAdapterService.requestSync(); - boolean useAsciiArmor = data.getBoolean(ENCRYPT_USE_ASCII_ARMOR); - long encryptionKeyIds[] = data.getLongArray(ENCRYPT_ENCRYPTION_KEYS_IDS); - int compressionId = data.getInt(ENCRYPT_COMPRESSION_ID); - int urisCount = data.containsKey(ENCRYPT_INPUT_URIS) ? data.getParcelableArrayList(ENCRYPT_INPUT_URIS).size() : 1; - for (int i = 0; i < urisCount; i++) { - data.putInt(SELECTED_URI, i); - InputData inputData = createEncryptInputData(data); - OutputStream outStream = createCryptOutputStream(data); - String originalFilename = getOriginalFilename(data); + // Result + sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result); + } catch (Exception e) { + sendErrorToHandler(e); + } - /* Operation */ - PgpSignEncrypt.Builder builder = new PgpSignEncrypt.Builder( - this, new ProviderHelper(this), this, inputData, outStream - ); - builder.setEnableAsciiArmorOutput(useAsciiArmor) - .setVersionHeader(PgpHelper.getVersionForHeader(this)) - .setCompressionId(compressionId) - .setSymmetricEncryptionAlgorithm( - Preferences.getPreferences(this).getDefaultEncryptionAlgorithm()) - .setEncryptionMasterKeyIds(encryptionKeyIds) - .setSymmetricPassphrase(symmetricPassphrase) - .setOriginalFilename(originalFilename); + break; + case ACTION_SIGN_ENCRYPT: - try { + try { + /* Input */ + int source = data.get(SOURCE) != null ? data.getInt(SOURCE) : data.getInt(TARGET); + Bundle resultData = new Bundle(); - // Find the appropriate subkey to sign with - CachedPublicKeyRing signingRing = - new ProviderHelper(this).getCachedPublicKeyRing(sigMasterKeyId); - long sigSubKeyId = signingRing.getSecretSignId(); - - // Set signature settings - builder.setSignatureMasterKeyId(sigMasterKeyId) - .setSignatureSubKeyId(sigSubKeyId) - .setSignaturePassphrase(sigKeyPassphrase) - .setSignatureHashAlgorithm( - Preferences.getPreferences(this).getDefaultHashAlgorithm()) - .setAdditionalEncryptId(sigMasterKeyId); - if (nfcHash != null && nfcTimestamp != null) { - builder.setNfcState(nfcHash, nfcTimestamp); - } + long sigMasterKeyId = data.getLong(ENCRYPT_SIGNATURE_MASTER_ID); + String sigKeyPassphrase = data.getString(ENCRYPT_SIGNATURE_KEY_PASSPHRASE); - } catch (PgpKeyNotFoundException e) { - // encrypt-only - // TODO Just silently drop the requested signature? Shouldn't we throw here? - } + byte[] nfcHash = data.getByteArray(ENCRYPT_SIGNATURE_NFC_HASH); + Date nfcTimestamp = (Date) data.getSerializable(ENCRYPT_SIGNATURE_NFC_TIMESTAMP); - // this assumes that the bytes are cleartext (valid for current implementation!) - if (source == IO_BYTES) { - builder.setCleartextInput(true); - } + String symmetricPassphrase = data.getString(ENCRYPT_SYMMETRIC_PASSPHRASE); - SignEncryptResult result = builder.build().execute(); - resultData.putParcelable(SignEncryptResult.EXTRA_RESULT, result); + boolean useAsciiArmor = data.getBoolean(ENCRYPT_USE_ASCII_ARMOR); + long encryptionKeyIds[] = data.getLongArray(ENCRYPT_ENCRYPTION_KEYS_IDS); + int compressionId = data.getInt(ENCRYPT_COMPRESSION_ID); + int urisCount = data.containsKey(ENCRYPT_INPUT_URIS) ? data.getParcelableArrayList(ENCRYPT_INPUT_URIS).size() : 1; + for (int i = 0; i < urisCount; i++) { + data.putInt(SELECTED_URI, i); + InputData inputData = createEncryptInputData(data); + OutputStream outStream = createCryptOutputStream(data); + String originalFilename = getOriginalFilename(data); - outStream.close(); + /* Operation */ + PgpSignEncrypt.Builder builder = new PgpSignEncrypt.Builder( + this, new ProviderHelper(this), this, inputData, outStream + ); + builder.setEnableAsciiArmorOutput(useAsciiArmor) + .setVersionHeader(PgpHelper.getVersionForHeader(this)) + .setCompressionId(compressionId) + .setSymmetricEncryptionAlgorithm( + Preferences.getPreferences(this).getDefaultEncryptionAlgorithm()) + .setEncryptionMasterKeyIds(encryptionKeyIds) + .setSymmetricPassphrase(symmetricPassphrase) + .setOriginalFilename(originalFilename); + + try { + + // Find the appropriate subkey to sign with + CachedPublicKeyRing signingRing = + new ProviderHelper(this).getCachedPublicKeyRing(sigMasterKeyId); + long sigSubKeyId = signingRing.getSecretSignId(); + + // Set signature settings + builder.setSignatureMasterKeyId(sigMasterKeyId) + .setSignatureSubKeyId(sigSubKeyId) + .setSignaturePassphrase(sigKeyPassphrase) + .setSignatureHashAlgorithm( + Preferences.getPreferences(this).getDefaultHashAlgorithm()) + .setAdditionalEncryptId(sigMasterKeyId); + if (nfcHash != null && nfcTimestamp != null) { + builder.setNfcState(nfcHash, nfcTimestamp); + } + + } catch (PgpKeyNotFoundException e) { + // encrypt-only + // TODO Just silently drop the requested signature? Shouldn't we throw here? + } + + // this assumes that the bytes are cleartext (valid for current implementation!) + if (source == IO_BYTES) { + builder.setCleartextInput(true); + } + + SignEncryptResult result = builder.build().execute(); + resultData.putParcelable(SignEncryptResult.EXTRA_RESULT, result); + + outStream.close(); /* Output */ - finalizeEncryptOutputStream(data, resultData, outStream); + finalizeEncryptOutputStream(data, resultData, outStream); - } + } - Log.logDebugBundle(resultData, "resultData"); + Log.logDebugBundle(resultData, "resultData"); - sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, resultData); - } catch (Exception e) { - sendErrorToHandler(e); - } + sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, resultData); + } catch (Exception e) { + sendErrorToHandler(e); + } - } else if (ACTION_UPLOAD_KEYRING.equals(action)) { + break; + case ACTION_UPLOAD_KEYRING: - try { + try { /* Input */ - String keyServer = data.getString(UPLOAD_KEY_SERVER); - // and dataUri! + String keyServer = data.getString(UPLOAD_KEY_SERVER); + // and dataUri! /* Operation */ - HkpKeyserver server = new HkpKeyserver(keyServer); + HkpKeyserver server = new HkpKeyserver(keyServer); - CanonicalizedPublicKeyRing keyring = providerHelper.getCanonicalizedPublicKeyRing(dataUri); - ImportExportOperation importExportOperation = new ImportExportOperation(this, new ProviderHelper(this), this); + CanonicalizedPublicKeyRing keyring = providerHelper.getCanonicalizedPublicKeyRing(dataUri); + ImportExportOperation importExportOperation = new ImportExportOperation(this, new ProviderHelper(this), this); - try { - importExportOperation.uploadKeyRingToServer(server, keyring); - } catch (Keyserver.AddKeyException e) { - throw new PgpGeneralException("Unable to export key to selected server"); - } + try { + importExportOperation.uploadKeyRingToServer(server, keyring); + } catch (Keyserver.AddKeyException e) { + throw new PgpGeneralException("Unable to export key to selected server"); + } - sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY); - } catch (Exception e) { - sendErrorToHandler(e); - } + sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY); + } catch (Exception e) { + sendErrorToHandler(e); + } + break; } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java index 869d2e71b..142814d99 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java @@ -39,7 +39,6 @@ import android.support.v4.util.LongSparseArray; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.util.Preferences; import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType; import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing; @@ -103,7 +102,7 @@ public class PassphraseCacheService extends Service { private BroadcastReceiver mIntentReceiver; - private LongSparseArray mPassphraseCache = new LongSparseArray(); + private LongSparseArray mPassphraseCache = new LongSparseArray<>(); Context mContext; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java index 3c78f2c40..f5df5858c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java @@ -71,13 +71,13 @@ public class SaveKeyringParcel implements Parcelable { public void reset() { mNewUnlock = null; - mAddUserIds = new ArrayList(); - mAddUserAttribute = new ArrayList(); - mAddSubKeys = new ArrayList(); + mAddUserIds = new ArrayList<>(); + mAddUserAttribute = new ArrayList<>(); + mAddSubKeys = new ArrayList<>(); mChangePrimaryUserId = null; - mChangeSubKeys = new ArrayList(); - mRevokeUserIds = new ArrayList(); - mRevokeSubKeys = new ArrayList(); + mChangeSubKeys = new ArrayList<>(); + mRevokeUserIds = new ArrayList<>(); + mRevokeSubKeys = new ArrayList<>(); } /** Returns true iff this parcel does not contain any operations which require a passphrase. */ @@ -173,7 +173,7 @@ public class SaveKeyringParcel implements Parcelable { out += "mFlags: " + mFlags + ", "; out += "mExpiry: " + mExpiry + ", "; out += "mDummyStrip: " + mDummyStrip + ", "; - out += "mDummyDivert: " + mDummyDivert; + out += "mDummyDivert: [" + (mDummyDivert == null ? 0 : mDummyDivert.length) + " bytes]"; return out; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java index 6850eca13..1fb88b182 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyActivity.java @@ -18,9 +18,6 @@ package org.sufficientlysecure.keychain.ui; -import android.os.Bundle; -import android.support.v7.app.ActionBarActivity; - import org.sufficientlysecure.keychain.R; /** diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java index 841485c7c..50d5e3229 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java @@ -234,7 +234,7 @@ public class CertifyKeyFragment extends LoaderFragment long lastMasterKeyId = 0; String lastName = ""; - ArrayList uids = new ArrayList(); + ArrayList uids = new ArrayList<>(); boolean header = true; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java index 82d3279f4..62c38d136 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyActivity.java @@ -20,7 +20,6 @@ package org.sufficientlysecure.keychain.ui; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentTransaction; -import android.support.v7.app.ActionBarActivity; import org.sufficientlysecure.keychain.R; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java index 2804a5ce6..377a9d1f4 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java @@ -44,7 +44,6 @@ import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.service.SaveKeyringParcel; import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm; -import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult; import org.sufficientlysecure.keychain.util.Log; public class CreateKeyFinalFragment extends Fragment { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyInputFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyInputFragment.java index 6079062a7..8aa9fa6db 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyInputFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyInputFragment.java @@ -89,7 +89,7 @@ public class CreateKeyInputFragment extends Fragment { mEmailEdit.setThreshold(1); // Start working from first character mEmailEdit.setAdapter( - new ArrayAdapter + new ArrayAdapter<> (getActivity(), android.R.layout.simple_spinner_dropdown_item, ContactHelper.getPossibleUserEmails(getActivity()) ) @@ -124,7 +124,7 @@ public class CreateKeyInputFragment extends Fragment { mNameEdit.setThreshold(1); // Start working from first character mNameEdit.setAdapter( - new ArrayAdapter + new ArrayAdapter<> (getActivity(), android.R.layout.simple_spinner_dropdown_item, ContactHelper.getPossibleUserNames(getActivity()) ) diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesActivity.java index 59159929c..7e91889b3 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesActivity.java @@ -20,7 +20,6 @@ package org.sufficientlysecure.keychain.ui; import android.content.Intent; import android.net.Uri; import android.os.Bundle; -import android.support.v7.app.ActionBarActivity; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextActivity.java index 285078dbf..2afc4b7b3 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextActivity.java @@ -20,7 +20,6 @@ package org.sufficientlysecure.keychain.ui; import android.content.Intent; import android.os.Bundle; -import android.support.v7.app.ActionBarActivity; import android.text.TextUtils; import org.sufficientlysecure.keychain.Constants; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java index 492c81758..6dc2994cf 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyActivity.java @@ -19,7 +19,6 @@ package org.sufficientlysecure.keychain.ui; import android.net.Uri; import android.os.Bundle; -import android.support.v7.app.ActionBarActivity; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java index febda16c3..2e2d26bf0 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java @@ -231,10 +231,7 @@ public class EditKeyFragment extends LoaderFragment implements mSaveKeyringParcel = new SaveKeyringParcel(masterKeyId, keyRing.getFingerprint()); mPrimaryUserId = keyRing.getPrimaryUserIdWithFallback(); - } catch (PgpKeyNotFoundException e) { - finishWithError(LogType.MSG_EK_ERROR_NOT_FOUND); - return; - } catch (NotFoundException e) { + } catch (PgpKeyNotFoundException | NotFoundException e) { finishWithError(LogType.MSG_EK_ERROR_NOT_FOUND); return; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java index 2d1b66daa..c5404094a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptAsymmetricFragment.java @@ -28,7 +28,6 @@ import com.tokenautocomplete.TokenCompleteTextView; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; @@ -164,8 +163,8 @@ public class EncryptAsymmetricFragment extends Fragment implements EncryptActivi private void updateEncryptionKeys() { List objects = mEncryptKeyView.getObjects(); - List keyIds = new ArrayList(); - List userIds = new ArrayList(); + List keyIds = new ArrayList<>(); + List userIds = new ArrayList<>(); for (Object object : objects) { if (object instanceof EncryptKeyCompletionView.EncryptionKey) { keyIds.add(((EncryptKeyCompletionView.EncryptionKey) object).getKeyId()); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java index 1494d05e1..b1da1f2c5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java @@ -122,13 +122,13 @@ public class EncryptFilesActivity extends EncryptActivity implements EncryptActi @Override public ArrayList getInputUris() { - if (mInputUris == null) mInputUris = new ArrayList(); + if (mInputUris == null) mInputUris = new ArrayList<>(); return mInputUris; } @Override public ArrayList getOutputUris() { - if (mOutputUris == null) mOutputUris = new ArrayList(); + if (mOutputUris == null) mOutputUris = new ArrayList<>(); return mOutputUris; } @@ -252,7 +252,7 @@ public class EncryptFilesActivity extends EncryptActivity implements EncryptActi sendIntent.setType("application/octet-stream"); if (!isModeSymmetric() && mEncryptionUserIds != null) { - Set users = new HashSet(); + Set users = new HashSet<>(); for (String user : mEncryptionUserIds) { String[] userId = KeyRing.splitUserId(user); if (userId[1] != null) { @@ -382,7 +382,7 @@ public class EncryptFilesActivity extends EncryptActivity implements EncryptActi String action = intent.getAction(); Bundle extras = intent.getExtras(); String type = intent.getType(); - ArrayList uris = new ArrayList(); + ArrayList uris = new ArrayList<>(); if (extras == null) { extras = new Bundle(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java index 6961f5ee7..be305cc58 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java @@ -59,7 +59,7 @@ public class EncryptFilesFragment extends Fragment implements EncryptActivityInt private View mShareFile; private ListView mSelectedFiles; private SelectedFilesAdapter mAdapter = new SelectedFilesAdapter(); - private final Map thumbnailCache = new HashMap(); + private final Map thumbnailCache = new HashMap<>(); @Override public void onAttach(Activity activity) { @@ -224,7 +224,7 @@ public class EncryptFilesFragment extends Fragment implements EncryptActivityInt @Override public void onNotifyUpdate() { // Clear cache if needed - for (Uri uri : new HashSet(thumbnailCache.keySet())) { + for (Uri uri : new HashSet<>(thumbnailCache.keySet())) { if (!mEncryptInterface.getInputUris().contains(uri)) { thumbnailCache.remove(uri); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java index 9b06a0b75..dabd5ddd5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java @@ -121,13 +121,13 @@ public class EncryptTextActivity extends EncryptActivity implements EncryptActiv @Override public ArrayList getInputUris() { - if (mInputUris == null) mInputUris = new ArrayList(); + if (mInputUris == null) mInputUris = new ArrayList<>(); return mInputUris; } @Override public ArrayList getOutputUris() { - if (mOutputUris == null) mOutputUris = new ArrayList(); + if (mOutputUris == null) mOutputUris = new ArrayList<>(); return mOutputUris; } @@ -240,7 +240,7 @@ public class EncryptTextActivity extends EncryptActivity implements EncryptActiv sendIntent.putExtra(Intent.EXTRA_TEXT, new String(message.getData().getByteArray(KeychainIntentService.RESULT_BYTES))); if (!isModeSymmetric() && mEncryptionUserIds != null) { - Set users = new HashSet(); + Set users = new HashSet<>(); for (String user : mEncryptionUserIds) { String[] userId = KeyRing.splitUserId(user); if (userId[1] != null) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/FirstTimeActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/FirstTimeActivity.java index e487c8947..ce2a049f5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/FirstTimeActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/FirstTimeActivity.java @@ -19,7 +19,6 @@ package org.sufficientlysecure.keychain.ui; import android.content.Intent; import android.os.Bundle; -import android.support.v7.app.ActionBarActivity; import android.view.KeyEvent; import android.view.View; import android.view.Window; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java index f1677cb67..e72e265d4 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java @@ -29,7 +29,6 @@ import android.os.Message; import android.os.Messenger; import android.os.Parcelable; import android.support.v4.app.Fragment; -import android.support.v7.app.ActionBarActivity; import android.view.View; import android.view.View.OnClickListener; @@ -122,95 +121,102 @@ public class ImportKeysActivity extends BaseActivity { action = ACTION_IMPORT_KEY; } - if (ACTION_IMPORT_KEY.equals(action)) { + switch (action) { + case ACTION_IMPORT_KEY: /* Keychain's own Actions */ - startFileFragment(savedInstanceState); + startFileFragment(savedInstanceState); - if (dataUri != null) { - // action: directly load data - startListFragment(savedInstanceState, null, dataUri, null); - } else if (extras.containsKey(EXTRA_KEY_BYTES)) { - byte[] importData = extras.getByteArray(EXTRA_KEY_BYTES); + if (dataUri != null) { + // action: directly load data + startListFragment(savedInstanceState, null, dataUri, null); + } else if (extras.containsKey(EXTRA_KEY_BYTES)) { + byte[] importData = extras.getByteArray(EXTRA_KEY_BYTES); - // action: directly load data - startListFragment(savedInstanceState, importData, null, null); - } - } else if (ACTION_IMPORT_KEY_FROM_KEYSERVER.equals(action) - || ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_TO_SERVICE.equals(action) - || ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_RESULT.equals(action)) { - - // only used for OpenPgpService - if (extras.containsKey(EXTRA_PENDING_INTENT_DATA)) { - mPendingIntentData = extras.getParcelable(EXTRA_PENDING_INTENT_DATA); - } - if (extras.containsKey(EXTRA_QUERY) || extras.containsKey(EXTRA_KEY_ID)) { + // action: directly load data + startListFragment(savedInstanceState, importData, null, null); + } + break; + case ACTION_IMPORT_KEY_FROM_KEYSERVER: + case ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_TO_SERVICE: + case ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_RESULT: + + // only used for OpenPgpService + if (extras.containsKey(EXTRA_PENDING_INTENT_DATA)) { + mPendingIntentData = extras.getParcelable(EXTRA_PENDING_INTENT_DATA); + } + if (extras.containsKey(EXTRA_QUERY) || extras.containsKey(EXTRA_KEY_ID)) { /* simple search based on query or key id */ - String query = null; - if (extras.containsKey(EXTRA_QUERY)) { - query = extras.getString(EXTRA_QUERY); - } else if (extras.containsKey(EXTRA_KEY_ID)) { - long keyId = extras.getLong(EXTRA_KEY_ID, 0); - if (keyId != 0) { - query = KeyFormattingUtils.convertKeyIdToHex(keyId); + String query = null; + if (extras.containsKey(EXTRA_QUERY)) { + query = extras.getString(EXTRA_QUERY); + } else if (extras.containsKey(EXTRA_KEY_ID)) { + long keyId = extras.getLong(EXTRA_KEY_ID, 0); + if (keyId != 0) { + query = KeyFormattingUtils.convertKeyIdToHex(keyId); + } } - } - if (query != null && query.length() > 0) { - // display keyserver fragment with query - startCloudFragment(savedInstanceState, query, false); + if (query != null && query.length() > 0) { + // display keyserver fragment with query + startCloudFragment(savedInstanceState, query, false); - // action: search immediately - startListFragment(savedInstanceState, null, null, query); - } else { - Log.e(Constants.TAG, "Query is empty!"); - return; - } - } else if (extras.containsKey(EXTRA_FINGERPRINT)) { + // action: search immediately + startListFragment(savedInstanceState, null, null, query); + } else { + Log.e(Constants.TAG, "Query is empty!"); + return; + } + } else if (extras.containsKey(EXTRA_FINGERPRINT)) { /* * search based on fingerprint, here we can enforce a check in the end * if the right key has been downloaded */ - String fingerprint = extras.getString(EXTRA_FINGERPRINT); - if (isFingerprintValid(fingerprint)) { - String query = "0x" + fingerprint; + String fingerprint = extras.getString(EXTRA_FINGERPRINT); + if (isFingerprintValid(fingerprint)) { + String query = "0x" + fingerprint; - // display keyserver fragment with query - startCloudFragment(savedInstanceState, query, true); + // display keyserver fragment with query + startCloudFragment(savedInstanceState, query, true); - // action: search immediately - startListFragment(savedInstanceState, null, null, query); + // action: search immediately + startListFragment(savedInstanceState, null, null, query); + } + } else { + Log.e(Constants.TAG, + "IMPORT_KEY_FROM_KEYSERVER action needs to contain the 'query', 'key_id', or " + + "'fingerprint' extra!" + ); + return; } - } else { - Log.e(Constants.TAG, - "IMPORT_KEY_FROM_KEYSERVER action needs to contain the 'query', 'key_id', or " + - "'fingerprint' extra!" - ); - return; - } - } else if (ACTION_IMPORT_KEY_FROM_FILE.equals(action)) { - // NOTE: this only displays the appropriate fragment, no actions are taken - startFileFragment(savedInstanceState); - - // no immediate actions! - startListFragment(savedInstanceState, null, null, null); - } else if (ACTION_IMPORT_KEY_FROM_FILE_AND_RETURN.equals(action)) { - // NOTE: this only displays the appropriate fragment, no actions are taken - startFileFragment(savedInstanceState); - - // no immediate actions! - startListFragment(savedInstanceState, null, null, null); - } else if (ACTION_IMPORT_KEY_FROM_NFC.equals(action)) { - // NOTE: this only displays the appropriate fragment, no actions are taken - startFileFragment(savedInstanceState); - // TODO!!!!! - - // no immediate actions! - startListFragment(savedInstanceState, null, null, null); - } else { - startCloudFragment(savedInstanceState, null, false); - startListFragment(savedInstanceState, null, null, null); + break; + case ACTION_IMPORT_KEY_FROM_FILE: + // NOTE: this only displays the appropriate fragment, no actions are taken + startFileFragment(savedInstanceState); + + // no immediate actions! + startListFragment(savedInstanceState, null, null, null); + break; + case ACTION_IMPORT_KEY_FROM_FILE_AND_RETURN: + // NOTE: this only displays the appropriate fragment, no actions are taken + startFileFragment(savedInstanceState); + + // no immediate actions! + startListFragment(savedInstanceState, null, null, null); + break; + case ACTION_IMPORT_KEY_FROM_NFC: + // NOTE: this only displays the appropriate fragment, no actions are taken + startFileFragment(savedInstanceState); + // TODO!!!!! + + // no immediate actions! + startListFragment(savedInstanceState, null, null, null); + break; + default: + startCloudFragment(savedInstanceState, null, false); + startListFragment(savedInstanceState, null, null, null); + break; } } @@ -356,7 +362,7 @@ public class ImportKeysActivity extends BaseActivity { // We parcel this iteratively into a file - anything we can // display here, we should be able to import. ParcelableFileCache cache = - new ParcelableFileCache(this, "key_import.pcl"); + new ParcelableFileCache<>(this, "key_import.pcl"); cache.writeCache(selectedEntries); intent.putExtra(KeychainIntentService.EXTRA_DATA, data); @@ -388,7 +394,7 @@ public class ImportKeysActivity extends BaseActivity { data.putString(KeychainIntentService.IMPORT_KEY_SERVER, sls.mCloudPrefs.keyserver); // get selected key entries - ArrayList keys = new ArrayList(); + ArrayList keys = new ArrayList<>(); { // change the format into ParcelableKeyRing ArrayList entries = mListFragment.getSelectedEntries(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysCloudFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysCloudFragment.java index 89826b8e9..1d12f49f9 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysCloudFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysCloudFragment.java @@ -81,7 +81,7 @@ public class ImportKeysCloudFragment extends Fragment { namesAndEmails.addAll(ContactHelper.getContactMails(getActivity())); mQueryEditText.setThreshold(3); mQueryEditText.setAdapter( - new ArrayAdapter + new ArrayAdapter<> (getActivity(), android.R.layout.simple_spinner_dropdown_item, namesAndEmails ) diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java index 4fe53fb09..6a6140892 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysListFragment.java @@ -113,7 +113,7 @@ public class ImportKeysListFragment extends ListFragment implements return mAdapter.getSelectedEntries(); } else { Log.e(Constants.TAG, "Adapter not initialized, returning empty list"); - return new ArrayList(); + return new ArrayList<>(); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java index 7fa403485..fdc598394 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java @@ -19,7 +19,6 @@ package org.sufficientlysecure.keychain.ui; import android.annotation.TargetApi; -import android.app.ProgressDialog; import android.content.Context; import android.content.Intent; import android.database.Cursor; @@ -31,7 +30,6 @@ import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.os.Messenger; -import android.support.v4.app.FragmentActivity; import android.support.v4.app.LoaderManager; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; @@ -52,7 +50,6 @@ import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.AbsListView.MultiChoiceModeListener; import android.widget.AdapterView; -import android.widget.Button; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.ListView; @@ -60,16 +57,9 @@ import android.widget.TextView; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing; import org.sufficientlysecure.keychain.operations.results.DeleteResult; -import org.sufficientlysecure.keychain.provider.KeychainContract; -import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.service.KeychainIntentService; -import org.sufficientlysecure.keychain.operations.results.ImportKeyResult; -import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.util.ExportHelper; -import org.sufficientlysecure.keychain.util.KeyUpdateHelper; import org.sufficientlysecure.keychain.pgp.KeyRing; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; @@ -78,15 +68,10 @@ import org.sufficientlysecure.keychain.ui.widget.ListAwareSwipeRefreshLayout; import org.sufficientlysecure.keychain.ui.util.Highlighter; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.ui.util.Notify; -import org.sufficientlysecure.keychain.util.ParcelableFileCache; -import java.io.IOException; -import java.util.ArrayList; import java.util.Date; import java.util.HashMap; -import edu.cmu.cylab.starslinger.exchange.ExchangeActivity; -import edu.cmu.cylab.starslinger.exchange.ExchangeConfig; import se.emilsjolander.stickylistheaders.StickyListHeadersAdapter; import se.emilsjolander.stickylistheaders.StickyListHeadersListView; @@ -517,7 +502,7 @@ public class KeyListFragment extends LoaderFragment private String mQuery; private LayoutInflater mInflater; - private HashMap mSelection = new HashMap(); + private HashMap mSelection = new HashMap<>(); public KeyListAdapter(Context context, Cursor c, int flags) { super(context, c, flags); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayActivity.java index fd74e1654..21113fb2f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayActivity.java @@ -19,7 +19,6 @@ package org.sufficientlysecure.keychain.ui; import android.os.Bundle; -import android.support.v7.app.ActionBarActivity; import android.view.View; import org.sufficientlysecure.keychain.R; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcActivity.java index 3a70502ea..7311f4879 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcActivity.java @@ -15,7 +15,6 @@ import android.nfc.Tag; import android.nfc.tech.IsoDep; import android.os.Build; import android.os.Bundle; -import android.support.v7.app.ActionBarActivity; import android.view.WindowManager; import android.widget.Toast; @@ -23,13 +22,11 @@ import org.spongycastle.bcpg.HashAlgorithmTags; import org.spongycastle.util.encoders.Hex; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.util.Iso7816TLV; import org.sufficientlysecure.keychain.util.Log; import java.io.IOException; import java.nio.ByteBuffer; -import java.util.Locale; /** * This class provides a communication interface to OpenPGP applications on ISO SmartCard compliant @@ -91,33 +88,38 @@ public class NfcActivity extends BaseActivity { mKeyId = data.getLong(EXTRA_KEY_ID); } - if (ACTION_SIGN_HASH.equals(action)) { - mAction = action; - mPin = data.getString(EXTRA_PIN); - mHashToSign = data.getByteArray(EXTRA_NFC_HASH_TO_SIGN); - mHashAlgo = data.getInt(EXTRA_NFC_HASH_ALGO); - mServiceIntent = data.getParcelable(EXTRA_DATA); - - Log.d(Constants.TAG, "NfcActivity mAction: " + mAction); - Log.d(Constants.TAG, "NfcActivity mPin: " + mPin); - Log.d(Constants.TAG, "NfcActivity mHashToSign as hex: " + getHex(mHashToSign)); - Log.d(Constants.TAG, "NfcActivity mServiceIntent: " + mServiceIntent.toString()); - } else if (ACTION_DECRYPT_SESSION_KEY.equals(action)) { - mAction = action; - mPin = data.getString(EXTRA_PIN); - mEncryptedSessionKey = data.getByteArray(EXTRA_NFC_ENC_SESSION_KEY); - mServiceIntent = data.getParcelable(EXTRA_DATA); - - Log.d(Constants.TAG, "NfcActivity mAction: " + mAction); - Log.d(Constants.TAG, "NfcActivity mPin: " + mPin); - Log.d(Constants.TAG, "NfcActivity mEncryptedSessionKey as hex: " + getHex(mEncryptedSessionKey)); - Log.d(Constants.TAG, "NfcActivity mServiceIntent: " + mServiceIntent.toString()); - } else if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(action)) { - Log.e(Constants.TAG, "This should not happen! NfcActivity.onCreate() is being called instead of onNewIntent()!"); - toast("This should not happen! Please create a new bug report that the NFC screen is restarted!"); - finish(); - } else { - Log.d(Constants.TAG, "Action not supported: " + action); + switch (action) { + case ACTION_SIGN_HASH: + mAction = action; + mPin = data.getString(EXTRA_PIN); + mHashToSign = data.getByteArray(EXTRA_NFC_HASH_TO_SIGN); + mHashAlgo = data.getInt(EXTRA_NFC_HASH_ALGO); + mServiceIntent = data.getParcelable(EXTRA_DATA); + + Log.d(Constants.TAG, "NfcActivity mAction: " + mAction); + Log.d(Constants.TAG, "NfcActivity mPin: " + mPin); + Log.d(Constants.TAG, "NfcActivity mHashToSign as hex: " + getHex(mHashToSign)); + Log.d(Constants.TAG, "NfcActivity mServiceIntent: " + mServiceIntent.toString()); + break; + case ACTION_DECRYPT_SESSION_KEY: + mAction = action; + mPin = data.getString(EXTRA_PIN); + mEncryptedSessionKey = data.getByteArray(EXTRA_NFC_ENC_SESSION_KEY); + mServiceIntent = data.getParcelable(EXTRA_DATA); + + Log.d(Constants.TAG, "NfcActivity mAction: " + mAction); + Log.d(Constants.TAG, "NfcActivity mPin: " + mPin); + Log.d(Constants.TAG, "NfcActivity mEncryptedSessionKey as hex: " + getHex(mEncryptedSessionKey)); + Log.d(Constants.TAG, "NfcActivity mServiceIntent: " + mServiceIntent.toString()); + break; + case NfcAdapter.ACTION_TAG_DISCOVERED: + Log.e(Constants.TAG, "This should not happen! NfcActivity.onCreate() is being called instead of onNewIntent()!"); + toast("This should not happen! Please create a new bug report that the NFC screen is restarted!"); + finish(); + break; + default: + Log.d(Constants.TAG, "Action not supported: " + action); + break; } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcIntentActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcIntentActivity.java index 945d98379..3e8d688fa 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcIntentActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcIntentActivity.java @@ -15,7 +15,6 @@ import android.nfc.Tag; import android.nfc.tech.IsoDep; import android.os.Build; import android.os.Bundle; -import android.support.v7.app.ActionBarActivity; import android.view.WindowManager; import android.widget.Toast; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseWizardActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseWizardActivity.java index 93778fd0c..872e888a8 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseWizardActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseWizardActivity.java @@ -209,9 +209,7 @@ public class PassphraseWizardActivity extends FragmentActivity implements LockPa FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); transaction.replace(R.id.fragmentContainer, lpf).addToBackStack(null).commit(); } - } catch (IOException e) { - e.printStackTrace(); - } catch (FormatException e) { + } catch (IOException | FormatException e) { e.printStackTrace(); } @@ -236,9 +234,7 @@ public class PassphraseWizardActivity extends FragmentActivity implements LockPa nfc.setText(R.string.nfc_wrong_tag); } } - } catch (IOException e) { - e.printStackTrace(); - } catch (FormatException e) { + } catch (IOException | FormatException e) { e.printStackTrace(); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeScanActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeScanActivity.java index 28488879b..1a7a028c6 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeScanActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeScanActivity.java @@ -203,7 +203,7 @@ public class QrCodeScanActivity extends FragmentActivity { data.putString(KeychainIntentService.IMPORT_KEY_SERVER, cloudPrefs.keyserver); ParcelableKeyRing keyEntry = new ParcelableKeyRing(fingerprint, null, null); - ArrayList selectedEntries = new ArrayList(); + ArrayList selectedEntries = new ArrayList<>(); selectedEntries.add(keyEntry); data.putParcelableArrayList(KeychainIntentService.IMPORT_KEY_LIST, selectedEntries); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeViewActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeViewActivity.java index 42ad2258a..74ca19106 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeViewActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeViewActivity.java @@ -20,7 +20,6 @@ package org.sufficientlysecure.keychain.ui; import android.graphics.Bitmap; import android.net.Uri; import android.os.Bundle; -import android.support.v7.app.ActionBarActivity; import android.view.View; import android.view.ViewTreeObserver.OnGlobalLayoutListener; import android.widget.ImageView; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SafeSlingerActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SafeSlingerActivity.java index d5193b2a2..f95644aff 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SafeSlingerActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SafeSlingerActivity.java @@ -27,13 +27,9 @@ import android.os.Bundle; import android.os.Message; import android.os.Messenger; import android.support.v4.app.FragmentActivity; -import android.support.v7.app.ActionBarActivity; import android.view.View; -import android.widget.AdapterView; -import android.widget.ArrayAdapter; import android.widget.ImageView; import android.widget.NumberPicker; -import android.widget.Spinner; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; @@ -50,7 +46,6 @@ import org.sufficientlysecure.keychain.util.ParcelableFileCache; import java.io.IOException; import java.util.ArrayList; -import java.util.List; import edu.cmu.cylab.starslinger.exchange.ExchangeActivity; import edu.cmu.cylab.starslinger.exchange.ExchangeConfig; @@ -192,7 +187,7 @@ public class SafeSlingerActivity extends BaseActivity { // We parcel this iteratively into a file - anything we can // display here, we should be able to import. ParcelableFileCache cache = - new ParcelableFileCache(activity, "key_import.pcl"); + new ParcelableFileCache<>(activity, "key_import.pcl"); cache.writeCache(it.size(), it.iterator()); // fill values for this action @@ -220,7 +215,7 @@ public class SafeSlingerActivity extends BaseActivity { } private static ArrayList getSlingedKeys(Bundle extras) { - ArrayList list = new ArrayList(); + ArrayList list = new ArrayList<>(); if (extras != null) { byte[] d; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyActivity.java index f7e19706e..33c4abba3 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyActivity.java @@ -20,7 +20,6 @@ package org.sufficientlysecure.keychain.ui; import android.content.Intent; import android.os.Bundle; -import android.support.v7.app.ActionBarActivity; import android.view.View; import org.sufficientlysecure.keychain.Constants; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyFragment.java index af583bf89..afec3bf06 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyFragment.java @@ -42,7 +42,6 @@ import android.widget.TextView; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.compatibility.ListFragmentWorkaround; -import org.sufficientlysecure.keychain.pgp.KeyRing; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables; import org.sufficientlysecure.keychain.ui.adapter.SelectKeyCursorAdapter; @@ -216,7 +215,7 @@ public class SelectPublicKeyFragment extends ListFragmentWorkaround implements T public long[] getSelectedMasterKeyIds() { // mListView.getCheckedItemIds() would give the row ids of the KeyRings not the master key // ids! - Vector vector = new Vector(); + Vector vector = new Vector<>(); for (int i = 0; i < getListView().getCount(); ++i) { if (getListView().isItemChecked(i)) { vector.add(mAdapter.getMasterKeyId(i)); @@ -238,7 +237,7 @@ public class SelectPublicKeyFragment extends ListFragmentWorkaround implements T * @return */ public String[] getSelectedUserIds() { - Vector userIds = new Vector(); + Vector userIds = new Vector<>(); for (int i = 0; i < getListView().getCount(); ++i) { if (getListView().isItemChecked(i)) { userIds.add(mAdapter.getUserId(i)); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsKeyServerActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsKeyServerActivity.java index 365e8026c..60346c16d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsKeyServerActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsKeyServerActivity.java @@ -20,7 +20,6 @@ package org.sufficientlysecure.keychain.ui; import android.content.Context; import android.content.Intent; import android.os.Bundle; -import android.support.v7.app.ActionBarActivity; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; @@ -140,7 +139,7 @@ public class SettingsKeyServerActivity extends BaseActivity implements OnClickLi } private Vector serverList() { - Vector servers = new Vector(); + Vector servers = new Vector<>(); for (int i = 0; i < mEditors.getChildCount(); ++i) { KeyServerEditor editor = (KeyServerEditor) mEditors.getChildAt(i); String tmp = editor.getValue(); @@ -153,7 +152,7 @@ public class SettingsKeyServerActivity extends BaseActivity implements OnClickLi private void okClicked() { Intent data = new Intent(); - Vector servers = new Vector(); + Vector servers = new Vector<>(); for (int i = 0; i < mEditors.getChildCount(); ++i) { KeyServerEditor editor = (KeyServerEditor) mEditors.getChildAt(i); String tmp = editor.getValue(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java index 6cf346c97..ed86fea0a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java @@ -24,7 +24,6 @@ import android.os.Bundle; import android.os.Message; import android.os.Messenger; import android.support.v4.app.NavUtils; -import android.support.v7.app.ActionBarActivity; import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; @@ -57,7 +56,7 @@ public class UploadKeyActivity extends BaseActivity { mUploadButton = findViewById(R.id.upload_key_action_upload); mKeyServerSpinner = (Spinner) findViewById(R.id.upload_key_keyserver); - ArrayAdapter adapter = new ArrayAdapter(this, + ArrayAdapter adapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, Preferences.getPreferences(this) .getKeyServers() ); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java index a88b0f7cf..05d9dd58e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java @@ -27,9 +27,6 @@ import android.support.v4.app.NavUtils; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; import android.support.v7.app.ActionBar; -import android.support.v7.app.ActionBarActivity; -import android.text.SpannableString; -import android.text.SpannableStringBuilder; import android.text.format.DateFormat; import android.view.MenuItem; import android.view.View; @@ -37,7 +34,6 @@ import android.widget.TextView; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing; import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.pgp.WrappedSignature; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvancedActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvancedActivity.java index 7176232c5..4e3c6d2a6 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvancedActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvancedActivity.java @@ -20,8 +20,6 @@ package org.sufficientlysecure.keychain.ui; import android.net.Uri; import android.os.Bundle; -import android.support.v7.app.ActionBar; -import android.support.v7.app.ActionBarActivity; import android.view.View; import org.sufficientlysecure.keychain.Constants; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyShareFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyShareFragment.java index aa260b654..7c47cbd0d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyShareFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyShareFragment.java @@ -228,10 +228,7 @@ public class ViewKeyShareFragment extends LoaderFragment implements } startActivity(Intent.createChooser(sendIntent, title)); } - } catch (PgpGeneralException e) { - Log.e(Constants.TAG, "error processing key!", e); - Notify.showNotify(getActivity(), R.string.error_key_processing, Notify.Style.ERROR); - } catch (IOException e) { + } catch (PgpGeneralException | IOException e) { Log.e(Constants.TAG, "error processing key!", e); Notify.showNotify(getActivity(), R.string.error_key_processing, Notify.Style.ERROR); } catch (ProviderHelper.NotFoundException e) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java index 6c81e9193..8e82dd7d0 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java @@ -95,8 +95,8 @@ public class ImportKeysAdapter extends ArrayAdapter { * @see org.sufficientlysecure.keychain.operations.ImportExportOperation */ public ArrayList getSelectedEntries() { - ArrayList result = new ArrayList(); - ArrayList secrets = new ArrayList(); + ArrayList result = new ArrayList<>(); + ArrayList secrets = new ArrayList<>(); if (mData == null) { return result; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListCloudLoader.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListCloudLoader.java index 176c3ff5b..235fdf1d5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListCloudLoader.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListCloudLoader.java @@ -39,7 +39,7 @@ public class ImportKeysListCloudLoader Preferences.CloudSearchPrefs mCloudPrefs; String mServerQuery; - private ArrayList mEntryList = new ArrayList(); + private ArrayList mEntryList = new ArrayList<>(); private AsyncTaskResultWrapper> mEntryListWrapper; public ImportKeysListCloudLoader(Context context, String serverQuery, Preferences.CloudSearchPrefs cloudPrefs) { @@ -51,7 +51,7 @@ public class ImportKeysListCloudLoader @Override public AsyncTaskResultWrapper> loadInBackground() { - mEntryListWrapper = new AsyncTaskResultWrapper>(mEntryList, null); + mEntryListWrapper = new AsyncTaskResultWrapper<>(mEntryList, null); if (mServerQuery == null) { Log.e(Constants.TAG, "mServerQuery is null!"); @@ -119,7 +119,7 @@ public class ImportKeysListCloudLoader mEntryList.addAll(searchResult); } GetKeyResult getKeyResult = new GetKeyResult(GetKeyResult.RESULT_OK, null); - mEntryListWrapper = new AsyncTaskResultWrapper>(mEntryList, getKeyResult); + mEntryListWrapper = new AsyncTaskResultWrapper<>(mEntryList, getKeyResult); } catch (Keyserver.CloudSearchFailureException e) { // convert exception to result parcel int error = GetKeyResult.RESULT_ERROR; @@ -140,7 +140,7 @@ public class ImportKeysListCloudLoader OperationResult.OperationLog log = new OperationResult.OperationLog(); log.add(logType, 0); GetKeyResult getKeyResult = new GetKeyResult(error, log); - mEntryListWrapper = new AsyncTaskResultWrapper>(mEntryList, getKeyResult); + mEntryListWrapper = new AsyncTaskResultWrapper<>(mEntryList, getKeyResult); } } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java index cecad2716..9d1e8468c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java @@ -35,7 +35,6 @@ import org.sufficientlysecure.keychain.util.PositionAwareInputStream; import java.io.BufferedInputStream; import java.io.IOException; import java.util.ArrayList; -import java.util.Iterator; public class ImportKeysListLoader extends AsyncTaskLoader>> { @@ -55,8 +54,8 @@ public class ImportKeysListLoader final Context mContext; final InputData mInputData; - ArrayList mData = new ArrayList(); - LongSparseArray mParcelableRings = new LongSparseArray(); + ArrayList mData = new ArrayList<>(); + LongSparseArray mParcelableRings = new LongSparseArray<>(); AsyncTaskResultWrapper> mEntryListWrapper; public ImportKeysListLoader(Context context, InputData inputData) { @@ -73,7 +72,7 @@ public class ImportKeysListLoader } GetKeyResult getKeyResult = new GetKeyResult(GetKeyResult.RESULT_OK, null); - mEntryListWrapper = new AsyncTaskResultWrapper>(mData, getKeyResult); + mEntryListWrapper = new AsyncTaskResultWrapper<>(mData, getKeyResult); if (mInputData == null) { Log.e(Constants.TAG, "Input data is null!"); @@ -140,7 +139,7 @@ public class ImportKeysListLoader OperationResult.OperationLog log = new OperationResult.OperationLog(); log.add(OperationResult.LogType.MSG_GET_NO_VALID_KEYS, 0); GetKeyResult getKeyResult = new GetKeyResult(GetKeyResult.RESULT_ERROR_NO_VALID_KEYS, log); - mEntryListWrapper = new AsyncTaskResultWrapper> + mEntryListWrapper = new AsyncTaskResultWrapper<> (mData, getKeyResult); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyValueSpinnerAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyValueSpinnerAdapter.java index 80d605fb9..b8fe21941 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyValueSpinnerAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/KeyValueSpinnerAdapter.java @@ -33,7 +33,7 @@ public class KeyValueSpinnerAdapter extends ArrayAdapter { static > SortedSet> entriesSortedByValues( Map map) { - SortedSet> sortedEntries = new TreeSet>( + SortedSet> sortedEntries = new TreeSet<>( new Comparator>() { @Override public int compare(Map.Entry e1, Map.Entry e2) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/MultiUserIdsAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/MultiUserIdsAdapter.java index 9f29826ef..47ad5e664 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/MultiUserIdsAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/MultiUserIdsAdapter.java @@ -44,7 +44,7 @@ public class MultiUserIdsAdapter extends CursorAdapter { public MultiUserIdsAdapter(Context context, Cursor c, int flags) { super(context, c, flags); mInflater = LayoutInflater.from(context); - mCheckStates = new ArrayList(); + mCheckStates = new ArrayList<>(); } @Override @@ -148,7 +148,7 @@ public class MultiUserIdsAdapter extends CursorAdapter { } public ArrayList getSelectedCertifyActions() { - LongSparseArray actions = new LongSparseArray(); + LongSparseArray actions = new LongSparseArray<>(); for (int i = 0; i < mCheckStates.size(); i++) { if (mCheckStates.get(i)) { mCursor.moveToPosition(i); @@ -171,7 +171,7 @@ public class MultiUserIdsAdapter extends CursorAdapter { } } - ArrayList result = new ArrayList(actions.size()); + ArrayList result = new ArrayList<>(actions.size()); for (int i = 0; i < actions.size(); i++) { result.add(actions.valueAt(i)); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/PagerTabStripAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/PagerTabStripAdapter.java index 330254a8f..963e77fe9 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/PagerTabStripAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/PagerTabStripAdapter.java @@ -27,7 +27,7 @@ import java.util.ArrayList; public class PagerTabStripAdapter extends FragmentPagerAdapter { protected final Activity mActivity; - protected final ArrayList mTabs = new ArrayList(); + protected final ArrayList mTabs = new ArrayList<>(); static final class TabInfo { public final Class clss; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java index a8fa3f1aa..431cdc845 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java @@ -36,7 +36,6 @@ import android.widget.TextView; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.service.SaveKeyringParcel.SubkeyChange; -import org.sufficientlysecure.keychain.ui.util.FormattingUtils; import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.provider.KeychainContract.Keys; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/TabsAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/TabsAdapter.java index 9ddfa90be..44afed351 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/TabsAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/TabsAdapter.java @@ -33,7 +33,7 @@ public class TabsAdapter extends FragmentStatePagerAdapter implements ActionBar. private final Context mContext; private final ActionBar mActionBar; private final ViewPager mViewPager; - private final ArrayList mTabs = new ArrayList(); + private final ArrayList mTabs = new ArrayList<>(); static final class TabInfo { public final Class clss; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java index a778c7fa7..52c21e253 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java @@ -221,7 +221,7 @@ public class UserIdsAdapter extends CursorAdapter implements AdapterView.OnItemC } public ArrayList getSelectedUserIds() { - ArrayList result = new ArrayList(); + ArrayList result = new ArrayList<>(); for (int i = 0; i < mCheckStates.size(); i++) { if (mCheckStates.get(i)) { mCursor.moveToPosition(i); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddSubkeyDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddSubkeyDialogFragment.java index b4119a5eb..d5376cbdc 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddSubkeyDialogFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddSubkeyDialogFragment.java @@ -145,20 +145,20 @@ public class AddSubkeyDialogFragment extends DialogFragment { } { - ArrayList> choices = new ArrayList>(); - choices.add(new Choice(Algorithm.DSA, getResources().getString( + ArrayList> choices = new ArrayList<>(); + choices.add(new Choice<>(Algorithm.DSA, getResources().getString( R.string.dsa))); if (!mWillBeMasterKey) { - choices.add(new Choice(Algorithm.ELGAMAL, getResources().getString( + choices.add(new Choice<>(Algorithm.ELGAMAL, getResources().getString( R.string.elgamal))); } - choices.add(new Choice(Algorithm.RSA, getResources().getString( + choices.add(new Choice<>(Algorithm.RSA, getResources().getString( R.string.rsa))); - choices.add(new Choice(Algorithm.ECDSA, getResources().getString( + choices.add(new Choice<>(Algorithm.ECDSA, getResources().getString( R.string.ecdsa))); - choices.add(new Choice(Algorithm.ECDH, getResources().getString( + choices.add(new Choice<>(Algorithm.ECDH, getResources().getString( R.string.ecdh))); - ArrayAdapter> adapter = new ArrayAdapter>(context, + ArrayAdapter> adapter = new ArrayAdapter<>(context, android.R.layout.simple_spinner_item, choices); adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); mAlgorithmSpinner.setAdapter(adapter); @@ -172,20 +172,20 @@ public class AddSubkeyDialogFragment extends DialogFragment { } // dynamic ArrayAdapter must be created (instead of ArrayAdapter.getFromResource), because it's content may change - ArrayAdapter keySizeAdapter = new ArrayAdapter(context, android.R.layout.simple_spinner_item, + ArrayAdapter keySizeAdapter = new ArrayAdapter<>(context, android.R.layout.simple_spinner_item, new ArrayList(Arrays.asList(getResources().getStringArray(R.array.rsa_key_size_spinner_values)))); keySizeAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); mKeySizeSpinner.setAdapter(keySizeAdapter); mKeySizeSpinner.setSelection(1); // Default to 4096 for the key length { - ArrayList> choices = new ArrayList>(); + ArrayList> choices = new ArrayList<>(); - choices.add(new Choice(Curve.NIST_P256, getResources().getString( + choices.add(new Choice<>(Curve.NIST_P256, getResources().getString( R.string.key_curve_nist_p256))); - choices.add(new Choice(Curve.NIST_P384, getResources().getString( + choices.add(new Choice<>(Curve.NIST_P384, getResources().getString( R.string.key_curve_nist_p384))); - choices.add(new Choice(Curve.NIST_P521, getResources().getString( + choices.add(new Choice<>(Curve.NIST_P521, getResources().getString( R.string.key_curve_nist_p521))); /* @see SaveKeyringParcel @@ -197,7 +197,7 @@ public class AddSubkeyDialogFragment extends DialogFragment { R.string.key_curve_bp_p512))); */ - ArrayAdapter> adapter = new ArrayAdapter>(context, + ArrayAdapter> adapter = new ArrayAdapter<>(context, android.R.layout.simple_spinner_item, choices); mCurveSpinner.setAdapter(adapter); // make NIST P-256 the default diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddUserIdDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddUserIdDialogFragment.java index 3eef04aa7..a4ecc7c27 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddUserIdDialogFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddUserIdDialogFragment.java @@ -85,7 +85,7 @@ public class AddUserIdDialogFragment extends DialogFragment implements OnEditorA mMessenger = getArguments().getParcelable(ARG_MESSENGER); String predefinedName = getArguments().getString(ARG_NAME); - ArrayAdapter autoCompleteEmailAdapter = new ArrayAdapter + ArrayAdapter autoCompleteEmailAdapter = new ArrayAdapter<> (getActivity(), android.R.layout.simple_spinner_dropdown_item, ContactHelper.getPossibleUserEmails(getActivity()) ); @@ -150,7 +150,7 @@ public class AddUserIdDialogFragment extends DialogFragment implements OnEditorA mName.setThreshold(1); // Start working from first character mName.setAdapter( - new ArrayAdapter + new ArrayAdapter<> (getActivity(), android.R.layout.simple_spinner_dropdown_item, ContactHelper.getPossibleUserNames(getActivity()) ) diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteFileDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteFileDialogFragment.java index 0926de1d0..879e3f6da 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteFileDialogFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteFileDialogFragment.java @@ -28,7 +28,6 @@ import android.support.v4.app.DialogFragment; import android.support.v4.app.FragmentActivity; import android.widget.Toast; -import org.apache.http.conn.scheme.Scheme; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.util.FileHelper; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/QrCodeUtils.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/QrCodeUtils.java index 36f38045f..0bb4100c5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/QrCodeUtils.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/QrCodeUtils.java @@ -47,7 +47,7 @@ public class QrCodeUtils { */ public static Bitmap getQRCodeBitmap(final String input, final int size) { try { - final Hashtable hints = new Hashtable(); + final Hashtable hints = new Hashtable<>(); hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M); final BitMatrix result = new QRCodeWriter().encode(input, BarcodeFormat.QR_CODE, size, size, hints); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/CertifyKeySpinner.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/CertifyKeySpinner.java index 14f42eb04..904cde47e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/CertifyKeySpinner.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/CertifyKeySpinner.java @@ -29,7 +29,6 @@ import android.widget.ImageView; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainDatabase; -import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; public class CertifyKeySpinner extends KeySpinner { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EncryptKeyCompletionView.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EncryptKeyCompletionView.java index e03a14989..5f6f13181 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EncryptKeyCompletionView.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EncryptKeyCompletionView.java @@ -28,7 +28,6 @@ import android.support.v4.app.FragmentActivity; import android.support.v4.app.LoaderManager; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; -import android.text.SpannableStringBuilder; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; @@ -46,7 +45,6 @@ import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.util.ContactHelper; import org.sufficientlysecure.keychain.pgp.KeyRing; -import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables; @@ -165,7 +163,7 @@ public class EncryptKeyCompletionView extends TokenCompleteTextView { setAdapter(new EncryptKeyAdapter(Collections.emptyList())); return; } - ArrayList keys = new ArrayList(); + ArrayList keys = new ArrayList<>(); while (cursor.moveToNext()) { try { EncryptionKey key = new EncryptionKey(cursor); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/ListAwareSwipeRefreshLayout.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/ListAwareSwipeRefreshLayout.java index b3c3eb417..3403208d7 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/ListAwareSwipeRefreshLayout.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/ListAwareSwipeRefreshLayout.java @@ -20,13 +20,8 @@ package org.sufficientlysecure.keychain.ui.widget; import android.content.Context; import android.support.v4.widget.NoScrollableSwipeRefreshLayout; import android.util.AttributeSet; -import android.view.InputDevice; -import android.view.InputDevice.MotionRange; import android.view.MotionEvent; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.util.Log; - import se.emilsjolander.stickylistheaders.StickyListHeadersListView; public class ListAwareSwipeRefreshLayout extends NoScrollableSwipeRefreshLayout { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SignKeySpinner.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SignKeySpinner.java index 59d05a62e..9c8e4aedb 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SignKeySpinner.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SignKeySpinner.java @@ -26,7 +26,6 @@ import android.support.v4.content.Loader; import android.util.AttributeSet; import android.widget.ImageView; -import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/AlgorithmNames.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/AlgorithmNames.java index 99db634ac..c1955f75b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/AlgorithmNames.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/AlgorithmNames.java @@ -23,7 +23,6 @@ import android.app.Activity; import org.spongycastle.bcpg.CompressionAlgorithmTags; import org.spongycastle.bcpg.HashAlgorithmTags; import org.spongycastle.openpgp.PGPEncryptedData; -import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import java.util.HashMap; @@ -32,9 +31,9 @@ import java.util.HashMap; public class AlgorithmNames { Activity mActivity; - HashMap mEncryptionNames = new HashMap(); - HashMap mHashNames = new HashMap(); - HashMap mCompressionNames = new HashMap(); + HashMap mEncryptionNames = new HashMap<>(); + HashMap mHashNames = new HashMap<>(); + HashMap mCompressionNames = new HashMap<>(); public AlgorithmNames(Activity context) { super(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ContactHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ContactHelper.java index 4ce7a1bac..11b29f521 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ContactHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ContactHelper.java @@ -73,20 +73,20 @@ public class ContactHelper { ContactsContract.Data.RAW_CONTACT_ID + "=? AND " + ContactsContract.Data.MIMETYPE + "=?"; public static final String ID_SELECTION = ContactsContract.RawContacts._ID + "=?"; - private static final Map photoCache = new HashMap(); + private static final Map photoCache = new HashMap<>(); public static List getPossibleUserEmails(Context context) { Set accountMails = getAccountEmails(context); accountMails.addAll(getMainProfileContactEmails(context)); // now return the Set (without duplicates) as a List - return new ArrayList(accountMails); + return new ArrayList<>(accountMails); } public static List getPossibleUserNames(Context context) { Set accountMails = getAccountEmails(context); Set names = getContactNamesFromEmails(context, accountMails); names.addAll(getMainProfileContactName(context)); - return new ArrayList(names); + return new ArrayList<>(names); } /** @@ -97,7 +97,7 @@ public class ContactHelper { */ private static Set getAccountEmails(Context context) { final Account[] accounts = AccountManager.get(context).getAccounts(); - final Set emailSet = new HashSet(); + final Set emailSet = new HashSet<>(); for (Account account : accounts) { if (Patterns.EMAIL_ADDRESS.matcher(account.name).matches()) { emailSet.add(account.name); @@ -116,7 +116,7 @@ public class ContactHelper { */ private static Set getContactNamesFromEmails(Context context, Set emails) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { - Set names = new HashSet(); + Set names = new HashSet<>(); for (String email : emails) { ContentResolver resolver = context.getContentResolver(); Cursor profileCursor = resolver.query( @@ -128,7 +128,7 @@ public class ContactHelper { ); if (profileCursor == null) return null; - Set currNames = new HashSet(); + Set currNames = new HashSet<>(); while (profileCursor.moveToNext()) { String name = profileCursor.getString(1); if (name != null) { @@ -140,7 +140,7 @@ public class ContactHelper { } return names; } else { - return new HashSet(); + return new HashSet<>(); } } @@ -172,7 +172,7 @@ public class ContactHelper { ); if (profileCursor == null) return null; - Set emails = new HashSet(); + Set emails = new HashSet<>(); while (profileCursor.moveToNext()) { String email = profileCursor.getString(0); if (email != null) { @@ -182,7 +182,7 @@ public class ContactHelper { profileCursor.close(); return emails; } else { - return new HashSet(); + return new HashSet<>(); } } @@ -201,7 +201,7 @@ public class ContactHelper { null, null, null); if (profileCursor == null) return null; - Set names = new HashSet(); + Set names = new HashSet<>(); // should only contain one entry! while (profileCursor.moveToNext()) { String name = profileCursor.getString(0); @@ -210,9 +210,9 @@ public class ContactHelper { } } profileCursor.close(); - return new ArrayList(names); + return new ArrayList<>(names); } else { - return new ArrayList(); + return new ArrayList<>(); } } @@ -221,9 +221,9 @@ public class ContactHelper { Cursor mailCursor = resolver.query(ContactsContract.CommonDataKinds.Email.CONTENT_URI, new String[]{ContactsContract.CommonDataKinds.Email.DATA}, null, null, null); - if (mailCursor == null) return new ArrayList(); + if (mailCursor == null) return new ArrayList<>(); - Set mails = new HashSet(); + Set mails = new HashSet<>(); while (mailCursor.moveToNext()) { String email = mailCursor.getString(0); if (email != null) { @@ -231,7 +231,7 @@ public class ContactHelper { } } mailCursor.close(); - return new ArrayList(mails); + return new ArrayList<>(mails); } public static List getContactNames(Context context) { @@ -239,9 +239,9 @@ public class ContactHelper { Cursor cursor = resolver.query(ContactsContract.Contacts.CONTENT_URI, new String[]{ContactsContract.Contacts.DISPLAY_NAME}, null, null, null); - if (cursor == null) return new ArrayList(); + if (cursor == null) return new ArrayList<>(); - Set names = new HashSet(); + Set names = new HashSet<>(); while (cursor.moveToNext()) { String name = cursor.getString(0); if (name != null) { @@ -249,7 +249,7 @@ public class ContactHelper { } } cursor.close(); - return new ArrayList(names); + return new ArrayList<>(names); } @TargetApi(Build.VERSION_CODES.JELLY_BEAN) @@ -309,7 +309,7 @@ public class ContactHelper { boolean isExpired = !cursor.isNull(4) && new Date(cursor.getLong(4) * 1000).before(new Date()); boolean isRevoked = cursor.getInt(5) > 0; int rawContactId = findRawContactId(resolver, fingerprint); - ArrayList ops = new ArrayList(); + ArrayList ops = new ArrayList<>(); // Do not store expired or revoked keys in contact db - and remove them if they already exist if (isExpired || isRevoked) { @@ -351,7 +351,7 @@ public class ContactHelper { * @return a set of all key fingerprints currently present in the contact db */ private static Set getRawContactFingerprints(ContentResolver resolver) { - HashSet result = new HashSet(); + HashSet result = new HashSet<>(); Cursor fingerprints = resolver.query(ContactsContract.RawContacts.CONTENT_URI, SOURCE_ID_PROJECTION, ACCOUNT_TYPE_SELECTION, new String[]{Constants.ACCOUNT_TYPE}, null); if (fingerprints != null) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/EmailKeyHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/EmailKeyHelper.java index 49d4d8bf8..8334b37ec 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/EmailKeyHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/EmailKeyHelper.java @@ -42,13 +42,13 @@ public class EmailKeyHelper { public static void importAll(Context context, Messenger messenger, List mails) { // Collect all candidates as ImportKeysListEntry (set for deduplication) - Set entries = new HashSet(); + Set entries = new HashSet<>(); for (String mail : mails) { entries.addAll(getEmailKeys(context, mail)); } // Put them in a list and import - ArrayList keys = new ArrayList(entries.size()); + ArrayList keys = new ArrayList<>(entries.size()); for (ImportKeysListEntry entry : entries) { keys.add(new ParcelableKeyRing(entry.getFingerprintHex(), entry.getKeyIdHex(), null)); } @@ -56,7 +56,7 @@ public class EmailKeyHelper { } public static Set getEmailKeys(Context context, String mail) { - Set keys = new HashSet(); + Set keys = new HashSet<>(); // Try _hkp._tcp SRV record first String[] mailparts = mail.split("@"); @@ -90,7 +90,7 @@ public class EmailKeyHelper { } public static List getEmailKeys(String mail, Keyserver keyServer) { - Set keys = new HashSet(); + Set keys = new HashSet<>(); try { for (ImportKeysListEntry key : keyServer.search(mail)) { if (key.isRevoked() || key.isExpired()) continue; @@ -103,6 +103,6 @@ public class EmailKeyHelper { } catch (Keyserver.QueryFailedException ignored) { } catch (Keyserver.QueryNeedsRepairException ignored) { } - return new ArrayList(keys); + return new ArrayList<>(keys); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ExportHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ExportHelper.java index 7492d95b2..fee9ff487 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ExportHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ExportHelper.java @@ -25,12 +25,10 @@ import android.os.Handler; import android.os.Message; import android.os.Messenger; import android.support.v7.app.ActionBarActivity; -import android.widget.Toast; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.operations.results.ExportResult; -import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.service.KeychainIntentService; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Iso7816TLV.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Iso7816TLV.java index 90afd3bc0..c0483ad04 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Iso7816TLV.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Iso7816TLV.java @@ -125,7 +125,7 @@ public class Iso7816TLV { public static Iso7816TLV[] readList(byte[] data, boolean recursive) throws IOException { ByteBuffer buf = ByteBuffer.wrap(data); - ArrayList result = new ArrayList(); + ArrayList result = new ArrayList<>(); // read while data is available. this will fail if there is trailing data! while (buf.hasRemaining()) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/KeyUpdateHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/KeyUpdateHelper.java index 76ec9f75f..943b913d7 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/KeyUpdateHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/KeyUpdateHelper.java @@ -17,21 +17,6 @@ package org.sufficientlysecure.keychain.util; -import android.content.Context; -import android.content.Intent; -import android.os.AsyncTask; -import android.os.Bundle; -import android.os.Messenger; - -import org.sufficientlysecure.keychain.keyimport.ImportKeysListEntry; -import org.sufficientlysecure.keychain.provider.KeychainContract; -import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.service.KeychainIntentService; -import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; - -import java.util.ArrayList; -import java.util.List; - public class KeyUpdateHelper { /* diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Log.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Log.java index b4f7c5767..8b165cd57 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Log.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Log.java @@ -21,9 +21,6 @@ import android.os.Bundle; import org.sufficientlysecure.keychain.Constants; -import java.io.IOException; -import java.io.StreamTokenizer; -import java.io.StringReader; import java.util.Iterator; import java.util.Set; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ParcelableFileCache.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ParcelableFileCache.java index 3081021cf..5de682fe6 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ParcelableFileCache.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ParcelableFileCache.java @@ -32,9 +32,7 @@ import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; -import java.util.ArrayList; import java.util.Iterator; -import java.util.List; /** * When sending large data (over 1MB) through Androids Binder IPC you get diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Preferences.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Preferences.java index 5efd6c419..8d4af58d7 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Preferences.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Preferences.java @@ -200,7 +200,7 @@ public class Preferences { public String[] getKeyServers() { String rawData = mSharedPreferences.getString(Constants.Pref.KEY_SERVERS, Constants.Defaults.KEY_SERVERS); - Vector servers = new Vector(); + Vector servers = new Vector<>(); String chunks[] = rawData.split(","); for (String c : chunks) { String tmp = c.trim(); @@ -281,7 +281,7 @@ public class Preferences { case 3: { // migrate keyserver to hkps String[] serversArray = getKeyServers(); - ArrayList servers = new ArrayList(Arrays.asList(serversArray)); + ArrayList servers = new ArrayList<>(Arrays.asList(serversArray)); ListIterator it = servers.listIterator(); while (it.hasNext()) { String server = it.next(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ShareHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ShareHelper.java index e97438772..120b84a3b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ShareHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ShareHelper.java @@ -51,10 +51,10 @@ public class ShareHelper { return Intent.createChooser(prototype, title); } - List targetedShareIntents = new ArrayList(); + List targetedShareIntents = new ArrayList<>(); List resInfoList = mContext.getPackageManager().queryIntentActivities(prototype, 0); - List resInfoListFiltered = new ArrayList(); + List resInfoListFiltered = new ArrayList<>(); if (!resInfoList.isEmpty()) { for (ResolveInfo resolveInfo : resInfoList) { // do not add blacklisted ones diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/TlsHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/TlsHelper.java index 9946d81aa..7e318281d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/TlsHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/TlsHelper.java @@ -50,7 +50,7 @@ public class TlsHelper { } } - private static Map sStaticCA = new HashMap(); + private static Map sStaticCA = new HashMap<>(); public static void addStaticCA(String domain, byte[] certificate) { sStaticCA.put(domain, certificate); @@ -120,13 +120,7 @@ public class TlsHelper { urlConnection.setSSLSocketFactory(context.getSocketFactory()); return urlConnection; - } catch (CertificateException e) { - throw new TlsHelperException(e); - } catch (NoSuchAlgorithmException e) { - throw new TlsHelperException(e); - } catch (KeyStoreException e) { - throw new TlsHelperException(e); - } catch (KeyManagementException e) { + } catch (CertificateException | KeyManagementException | KeyStoreException | NoSuchAlgorithmException e) { throw new TlsHelperException(e); } } -- cgit v1.2.3 From e4e2d647c8cd8bf2d1e318c85d41173caf18adf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Mon, 26 Jan 2015 00:50:35 +0100 Subject: Material Design: Full screen dialogs --- .../remote/ui/AccountSettingsActivity.java | 16 ++-- .../keychain/remote/ui/RemoteServiceActivity.java | 28 +++--- .../keychain/ui/BaseActivity.java | 80 ++++++++++++++++- .../keychain/ui/EditKeyFragment.java | 19 ++--- .../keychain/ui/LogDisplayActivity.java | 4 +- .../keychain/ui/QrCodeViewActivity.java | 4 +- .../keychain/ui/SelectPublicKeyActivity.java | 11 +-- .../keychain/ui/SettingsKeyServerActivity.java | 11 +-- .../keychain/ui/ViewKeyAdvancedActivity.java | 4 +- .../keychain/ui/adapter/SubkeysAdapter.java | 2 +- .../keychain/ui/util/ActionBarHelper.java | 99 ---------------------- .../keychain/ui/widget/FoldableLinearLayout.java | 39 +++++---- 12 files changed, 136 insertions(+), 181 deletions(-) delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/ActionBarHelper.java (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsActivity.java index 2751db370..e5edd6a0f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsActivity.java @@ -27,7 +27,6 @@ import android.view.View; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.ui.BaseActivity; -import org.sufficientlysecure.keychain.ui.util.ActionBarHelper; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.remote.AccountSettings; import org.sufficientlysecure.keychain.operations.results.OperationResult; @@ -45,14 +44,18 @@ public class AccountSettingsActivity extends BaseActivity { super.onCreate(savedInstanceState); // Inflate a "Done" custom action bar - ActionBarHelper.setOneButtonView(getSupportActionBar(), - R.string.api_settings_save, R.drawable.ic_action_done, + setFullScreenDialogDoneClose(R.string.api_settings_save, new View.OnClickListener() { @Override public void onClick(View v) { - // "Done" save(); } + }, + new View.OnClickListener() { + @Override + public void onClick(View v) { + finish(); + } }); @@ -129,9 +132,4 @@ public class AccountSettingsActivity extends BaseActivity { } } - @Override - public void onBackPressed() { - save(); - super.onBackPressed(); - } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/RemoteServiceActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/RemoteServiceActivity.java index 447f02b55..cbc593b0a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/RemoteServiceActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/RemoteServiceActivity.java @@ -40,7 +40,6 @@ import org.sufficientlysecure.keychain.remote.AccountSettings; import org.sufficientlysecure.keychain.remote.AppSettings; import org.sufficientlysecure.keychain.ui.BaseActivity; import org.sufficientlysecure.keychain.ui.SelectPublicKeyFragment; -import org.sufficientlysecure.keychain.ui.util.ActionBarHelper; import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.util.Log; @@ -123,8 +122,8 @@ public class RemoteServiceActivity extends BaseActivity { mAppSettingsFragment.setAppSettings(settings); // Inflate a "Done"/"Cancel" custom action bar view - ActionBarHelper.setTwoButtonView(getSupportActionBar(), - R.string.api_register_allow, R.drawable.ic_action_done, + setFullScreenDialogTwoButtons( + R.string.api_register_allow, R.drawable.ic_check_white_24dp, new View.OnClickListener() { @Override public void onClick(View v) { @@ -137,7 +136,7 @@ public class RemoteServiceActivity extends BaseActivity { RemoteServiceActivity.this.setResult(RESULT_OK, resultData); RemoteServiceActivity.this.finish(); } - }, R.string.api_register_disallow, R.drawable.ic_action_cancel, + }, R.string.api_register_disallow, R.drawable.ic_close_white_24dp, new View.OnClickListener() { @Override public void onClick(View v) { @@ -179,8 +178,7 @@ public class RemoteServiceActivity extends BaseActivity { mAccSettingsFragment.setAccSettings(settings); // Inflate a "Done"/"Cancel" custom action bar view - ActionBarHelper.setTwoButtonView(getSupportActionBar(), - R.string.api_settings_save, R.drawable.ic_action_done, + setFullScreenDialogDoneClose(R.string.api_settings_save, new View.OnClickListener() { @Override public void onClick(View v) { @@ -208,7 +206,7 @@ public class RemoteServiceActivity extends BaseActivity { RemoteServiceActivity.this.finish(); } } - }, R.string.api_settings_cancel, R.drawable.ic_action_cancel, + }, new View.OnClickListener() { @Override public void onClick(View v) { @@ -216,8 +214,7 @@ public class RemoteServiceActivity extends BaseActivity { RemoteServiceActivity.this.setResult(RESULT_CANCELED); RemoteServiceActivity.this.finish(); } - } - ); + }); break; } @@ -264,8 +261,7 @@ public class RemoteServiceActivity extends BaseActivity { initToolbar(); // Inflate a "Done"/"Cancel" custom action bar view - ActionBarHelper.setTwoButtonView(getSupportActionBar(), - R.string.btn_okay, R.drawable.ic_action_done, + setFullScreenDialogDoneClose(R.string.btn_okay, new View.OnClickListener() { @Override public void onClick(View v) { @@ -277,16 +273,15 @@ public class RemoteServiceActivity extends BaseActivity { RemoteServiceActivity.this.setResult(RESULT_OK, resultData); RemoteServiceActivity.this.finish(); } - }, R.string.btn_do_not_save, R.drawable.ic_action_cancel, new View.OnClickListener() { + }, + new View.OnClickListener() { @Override public void onClick(View v) { // cancel RemoteServiceActivity.this.setResult(RESULT_CANCELED); RemoteServiceActivity.this.finish(); } - } - ); - + }); // set text on view TextView textView = (TextView) findViewById(R.id.api_select_pub_keys_text); @@ -323,8 +318,7 @@ public class RemoteServiceActivity extends BaseActivity { initToolbar(); // Inflate a "Done" custom action bar view - ActionBarHelper.setOneButtonView(getSupportActionBar(), - R.string.btn_okay, R.drawable.ic_action_done, + setFullScreenDialogClose( new View.OnClickListener() { @Override diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BaseActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BaseActivity.java index c38d126d7..7423e6828 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BaseActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BaseActivity.java @@ -17,14 +17,21 @@ package org.sufficientlysecure.keychain.ui; +import android.app.Activity; import android.os.Bundle; +import android.support.v7.app.ActionBar; import android.support.v7.app.ActionBarActivity; import android.support.v7.widget.Toolbar; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; import org.sufficientlysecure.keychain.R; /** - * Sets action bar + * Setups Toolbar */ public abstract class BaseActivity extends ActionBarActivity { protected Toolbar mToolbar; @@ -49,4 +56,75 @@ public abstract class BaseActivity extends ActionBarActivity { protected void setActionBarIcon(int iconRes) { mToolbar.setNavigationIcon(iconRes); } + + /** + * Inflate custom design to look like a full screen dialog, as specified in Material Design Guidelines + * see http://www.google.com/design/spec/components/dialogs.html#dialogs-full-screen-dialogs + */ + protected void setFullScreenDialogDoneClose(int doneText, View.OnClickListener doneOnClickListener, + View.OnClickListener cancelOnClickListener) { + setActionBarIcon(R.drawable.ic_close_white_24dp); + + // Inflate the custom action bar view + final LayoutInflater inflater = (LayoutInflater) getSupportActionBar().getThemedContext() + .getSystemService(Activity.LAYOUT_INFLATER_SERVICE); + final View customActionBarView = inflater.inflate(R.layout.full_screen_dialog, null); + + TextView firstTextView = ((TextView) customActionBarView.findViewById(R.id.full_screen_dialog_done_text)); + firstTextView.setText(doneText); + customActionBarView.findViewById(R.id.full_screen_dialog_done).setOnClickListener( + doneOnClickListener); + + getSupportActionBar().setDisplayShowCustomEnabled(true); + getSupportActionBar().setDisplayShowTitleEnabled(true); + getSupportActionBar().setCustomView(customActionBarView, new ActionBar.LayoutParams( + ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT, + Gravity.END)); + mToolbar.setNavigationOnClickListener(cancelOnClickListener); + } + + /** + * Close button only + */ + protected void setFullScreenDialogClose(View.OnClickListener cancelOnClickListener) { + setActionBarIcon(R.drawable.ic_close_white_24dp); + getSupportActionBar().setDisplayShowTitleEnabled(true); + mToolbar.setNavigationOnClickListener(cancelOnClickListener); + } + + /** + * Inflate custom design with two buttons using drawables. + * This does not conform to the Material Design Guidelines, but we deviate here as this is used + * to indicate "Allow access"/"Disallow access" to the API, which must be clearly indicated + */ + protected void setFullScreenDialogTwoButtons(int firstText, int firstDrawableId, View.OnClickListener firstOnClickListener, + int secondText, int secondDrawableId, View.OnClickListener secondOnClickListener) { + + // Inflate the custom action bar view + final LayoutInflater inflater = (LayoutInflater) getSupportActionBar().getThemedContext() + .getSystemService(Activity.LAYOUT_INFLATER_SERVICE); + final View customActionBarView = inflater.inflate( + R.layout.full_screen_dialog_2, null); + + TextView firstTextView = ((TextView) customActionBarView.findViewById(R.id.actionbar_done_text)); + firstTextView.setText(firstText); + firstTextView.setCompoundDrawablesWithIntrinsicBounds(firstDrawableId, 0, 0, 0); + customActionBarView.findViewById(R.id.actionbar_done).setOnClickListener( + firstOnClickListener); + TextView secondTextView = ((TextView) customActionBarView.findViewById(R.id.actionbar_cancel_text)); + secondTextView.setText(secondText); + secondTextView.setCompoundDrawablesWithIntrinsicBounds(secondDrawableId, 0, 0, 0); + customActionBarView.findViewById(R.id.actionbar_cancel).setOnClickListener( + secondOnClickListener); + + // Show the custom action bar view and hide the normal Home icon and title. + getSupportActionBar().setDisplayShowTitleEnabled(false); + getSupportActionBar().setDisplayShowHomeEnabled(false); + getSupportActionBar().setDisplayHomeAsUpEnabled(false); + getSupportActionBar().setDisplayShowCustomEnabled(true); + getSupportActionBar().setCustomView(customActionBarView, new ActionBar.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); + } + + } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java index 2e2d26bf0..25ca6e8fd 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EditKeyFragment.java @@ -29,7 +29,6 @@ import android.os.Messenger; import android.support.v4.app.LoaderManager; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; -import android.support.v7.app.ActionBarActivity; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; @@ -66,7 +65,6 @@ import org.sufficientlysecure.keychain.ui.dialog.EditSubkeyDialogFragment; import org.sufficientlysecure.keychain.ui.dialog.EditSubkeyExpiryDialogFragment; import org.sufficientlysecure.keychain.ui.dialog.EditUserIdDialogFragment; import org.sufficientlysecure.keychain.ui.dialog.SetPassphraseDialogFragment; -import org.sufficientlysecure.keychain.ui.util.ActionBarHelper; import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.util.Log; @@ -148,10 +146,8 @@ public class EditKeyFragment extends LoaderFragment implements @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); - - // Inflate a "Done"/"Cancel" custom action bar view - ActionBarHelper.setTwoButtonView(((ActionBarActivity) getActivity()).getSupportActionBar(), - R.string.btn_save, R.drawable.ic_action_save, + ((EditKeyActivity) getActivity()).setFullScreenDialogDoneClose( + R.string.btn_save, new OnClickListener() { @Override public void onClick(View v) { @@ -162,16 +158,13 @@ public class EditKeyFragment extends LoaderFragment implements saveInDatabase(mCurrentPassphrase); } } - }, R.string.menu_key_edit_cancel, R.drawable.ic_action_cancel, - new OnClickListener() { + }, new OnClickListener() { @Override public void onClick(View v) { - // cancel getActivity().setResult(Activity.RESULT_CANCELED); getActivity().finish(); } - } - ); + }); Uri dataUri = getArguments().getParcelable(ARG_DATA_URI); SaveKeyringParcel saveKeyringParcel = getArguments().getParcelable(ARG_SAVE_KEYRING_PARCEL); @@ -393,8 +386,8 @@ public class EditKeyFragment extends LoaderFragment implements // cache new returned passphrase! mSaveKeyringParcel.mNewUnlock = new ChangeUnlockParcel( - data.getString(SetPassphraseDialogFragment.MESSAGE_NEW_PASSPHRASE), - null + data.getString(SetPassphraseDialogFragment.MESSAGE_NEW_PASSPHRASE), + null ); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayActivity.java index 21113fb2f..0de7bb391 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayActivity.java @@ -22,7 +22,6 @@ import android.os.Bundle; import android.view.View; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.ui.util.ActionBarHelper; public class LogDisplayActivity extends BaseActivity { @@ -31,8 +30,7 @@ public class LogDisplayActivity extends BaseActivity { super.onCreate(savedInstanceState); // Inflate a "Done" custom action bar - ActionBarHelper.setOneButtonView(getSupportActionBar(), - R.string.btn_okay, R.drawable.ic_action_done, + setFullScreenDialogClose( new View.OnClickListener() { @Override public void onClick(View v) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeViewActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeViewActivity.java index 74ca19106..ef1d797be 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeViewActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeViewActivity.java @@ -26,7 +26,6 @@ import android.widget.ImageView; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.ui.util.ActionBarHelper; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.ProviderHelper; @@ -44,8 +43,7 @@ public class QrCodeViewActivity extends BaseActivity { super.onCreate(savedInstanceState); // Inflate a "Done" custom action bar - ActionBarHelper.setOneButtonView(getSupportActionBar(), - R.string.btn_okay, R.drawable.ic_action_done, + setFullScreenDialogClose( new View.OnClickListener() { @Override public void onClick(View v) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyActivity.java index 33c4abba3..0e3374833 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyActivity.java @@ -24,7 +24,6 @@ import android.view.View; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.ui.util.ActionBarHelper; public class SelectPublicKeyActivity extends BaseActivity { @@ -46,21 +45,19 @@ public class SelectPublicKeyActivity extends BaseActivity { super.onCreate(savedInstanceState); // Inflate a "Done"/"Cancel" custom action bar view - ActionBarHelper.setTwoButtonView(getSupportActionBar(), R.string.btn_okay, R.drawable.ic_action_done, + setFullScreenDialogDoneClose(R.string.btn_okay, new View.OnClickListener() { @Override public void onClick(View v) { - // ok okClicked(); } - }, R.string.btn_do_not_save, R.drawable.ic_action_cancel, new View.OnClickListener() { + }, + new View.OnClickListener() { @Override public void onClick(View v) { - // cancel cancelClicked(); } - } - ); + }); setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsKeyServerActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsKeyServerActivity.java index 60346c16d..080dc2495 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsKeyServerActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsKeyServerActivity.java @@ -27,7 +27,6 @@ import android.view.ViewGroup; import android.widget.TextView; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.ui.util.ActionBarHelper; import org.sufficientlysecure.keychain.ui.widget.Editor; import org.sufficientlysecure.keychain.ui.widget.Editor.EditorListener; import org.sufficientlysecure.keychain.ui.widget.KeyServerEditor; @@ -51,21 +50,19 @@ public class SettingsKeyServerActivity extends BaseActivity implements OnClickLi super.onCreate(savedInstanceState); // Inflate a "Done"/"Cancel" custom action bar view - ActionBarHelper.setTwoButtonView(getSupportActionBar(), R.string.btn_okay, R.drawable.ic_action_done, + setFullScreenDialogDoneClose(R.string.btn_save, new View.OnClickListener() { @Override public void onClick(View v) { - // ok okClicked(); } - }, R.string.btn_do_not_save, R.drawable.ic_action_cancel, new View.OnClickListener() { + }, + new View.OnClickListener() { @Override public void onClick(View v) { - // cancel cancelClicked(); } - } - ); + }); mInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvancedActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvancedActivity.java index 4e3c6d2a6..471f55c47 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvancedActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvancedActivity.java @@ -25,7 +25,6 @@ import android.view.View; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.ui.util.ActionBarHelper; import org.sufficientlysecure.keychain.util.ExportHelper; import org.sufficientlysecure.keychain.util.Log; @@ -42,8 +41,7 @@ public class ViewKeyAdvancedActivity extends BaseActivity { mProviderHelper = new ProviderHelper(this); // Inflate a "Done" custom action bar - ActionBarHelper.setOneButtonView(getSupportActionBar(), - R.string.btn_okay, R.drawable.ic_action_done, + setFullScreenDialogClose( new View.OnClickListener() { @Override public void onClick(View v) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java index 431cdc845..5ba09be7e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java @@ -164,7 +164,7 @@ public class SubkeysAdapter extends CursorAdapter { ? mSaveKeyringParcel.getSubkeyChange(keyId) : null; - if (change.mDummyStrip) { + if (change != null && change.mDummyStrip) { algorithmStr.append(", "); final SpannableString boldStripped = new SpannableString( context.getString(R.string.key_stripped) diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/ActionBarHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/ActionBarHelper.java deleted file mode 100644 index edd12ec73..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/ActionBarHelper.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (C) 2013-2014 Dominik Schürmann - * - * 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 . - */ - -package org.sufficientlysecure.keychain.ui.util; - -import android.app.Activity; -import android.support.v7.app.ActionBar; -import android.view.LayoutInflater; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.ViewGroup; -import android.widget.TextView; - -import org.sufficientlysecure.keychain.R; - -public class ActionBarHelper { - - /** - * Sets custom view on ActionBar for Done/Cancel activities - * - * @param actionBar - * @param firstText - * @param firstDrawableId - * @param firstOnClickListener - * @param secondText - * @param secondDrawableId - * @param secondOnClickListener - */ - public static void setTwoButtonView(ActionBar actionBar, - int firstText, int firstDrawableId, OnClickListener firstOnClickListener, - int secondText, int secondDrawableId, OnClickListener secondOnClickListener) { - - // Inflate the custom action bar view - final LayoutInflater inflater = (LayoutInflater) actionBar.getThemedContext() - .getSystemService(Activity.LAYOUT_INFLATER_SERVICE); - final View customActionBarView = inflater.inflate( - R.layout.actionbar_custom_view_done_cancel, null); - - TextView firstTextView = ((TextView) customActionBarView.findViewById(R.id.actionbar_done_text)); - firstTextView.setText(firstText); - firstTextView.setCompoundDrawablesWithIntrinsicBounds(firstDrawableId, 0, 0, 0); - customActionBarView.findViewById(R.id.actionbar_done).setOnClickListener( - firstOnClickListener); - TextView secondTextView = ((TextView) customActionBarView.findViewById(R.id.actionbar_cancel_text)); - secondTextView.setText(secondText); - secondTextView.setCompoundDrawablesWithIntrinsicBounds(secondDrawableId, 0, 0, 0); - customActionBarView.findViewById(R.id.actionbar_cancel).setOnClickListener( - secondOnClickListener); - - // Show the custom action bar view and hide the normal Home icon and title. - actionBar.setDisplayShowTitleEnabled(false); - actionBar.setDisplayShowHomeEnabled(false); - actionBar.setDisplayShowCustomEnabled(true); - actionBar.setCustomView(customActionBarView, new ActionBar.LayoutParams( - ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); - } - - /** - * Sets custom view on ActionBar for Done activities - * - * @param actionBar - * @param firstText - * @param firstOnClickListener - */ - public static void setOneButtonView(ActionBar actionBar, int firstText, int firstDrawableId, - OnClickListener firstOnClickListener) { - // Inflate a "Done" custom action bar view to serve as the "Up" affordance. - final LayoutInflater inflater = (LayoutInflater) actionBar.getThemedContext() - .getSystemService(Activity.LAYOUT_INFLATER_SERVICE); - final View customActionBarView = inflater - .inflate(R.layout.actionbar_custom_view_done, null); - - TextView firstTextView = ((TextView) customActionBarView.findViewById(R.id.actionbar_done_text)); - firstTextView.setText(firstText); - firstTextView.setCompoundDrawablesWithIntrinsicBounds(firstDrawableId, 0, 0, 0); - customActionBarView.findViewById(R.id.actionbar_done).setOnClickListener( - firstOnClickListener); - - // Show the custom action bar view and hide the normal Home icon and title. - actionBar.setDisplayShowTitleEnabled(false); - actionBar.setDisplayShowHomeEnabled(false); - actionBar.setDisplayShowCustomEnabled(true); - actionBar.setCustomView(customActionBarView); - } -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/FoldableLinearLayout.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/FoldableLinearLayout.java index b456b61ab..34e7b639a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/FoldableLinearLayout.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/FoldableLinearLayout.java @@ -33,17 +33,16 @@ import org.sufficientlysecure.keychain.R; /** * Class representing a LinearLayout that can fold and hide it's content when pressed * To use just add the following to your xml layout - - - - - - - + *

+ * + *

+ * + *

+ * */ public class FoldableLinearLayout extends LinearLayout { @@ -75,6 +74,7 @@ public class FoldableLinearLayout extends LinearLayout { /** * Load given attributes to inner variables, + * * @param context * @param attrs */ @@ -87,8 +87,8 @@ public class FoldableLinearLayout extends LinearLayout { a.recycle(); } // If any attribute isn't found then set a default one - mFoldedLabel = (mFoldedLabel == null) ? context.getString(R.id.none) : mFoldedLabel; - mUnFoldedLabel = (mUnFoldedLabel == null) ? context.getString(R.id.none) : mUnFoldedLabel; + mFoldedLabel = (mFoldedLabel == null) ? context.getString(R.string.none) : mFoldedLabel; + mUnFoldedLabel = (mUnFoldedLabel == null) ? context.getString(R.string.none) : mUnFoldedLabel; } @Override @@ -138,7 +138,7 @@ public class FoldableLinearLayout extends LinearLayout { private void initialiseInnerViews() { mFoldableIcon = (ImageView) mFoldableLayout.findViewById(R.id.foldableIcon); - mFoldableIcon.setImageResource(R.drawable.ic_action_expand); + mFoldableIcon.setImageResource(R.drawable.ic_expand_more_black_24dp); mFoldableTextView = (TextView) mFoldableLayout.findViewById(R.id.foldableText); mFoldableTextView.setText(mFoldedLabel); @@ -151,7 +151,7 @@ public class FoldableLinearLayout extends LinearLayout { public void onClick(View view) { mFolded = !mFolded; if (mFolded) { - mFoldableIcon.setImageResource(R.drawable.ic_action_collapse); + mFoldableIcon.setImageResource(R.drawable.ic_expand_less_black_24dp); mFoldableContainer.setVisibility(View.VISIBLE); AlphaAnimation animation = new AlphaAnimation(0f, 1f); animation.setDuration(mShortAnimationDuration); @@ -159,12 +159,13 @@ public class FoldableLinearLayout extends LinearLayout { mFoldableTextView.setText(mUnFoldedLabel); } else { - mFoldableIcon.setImageResource(R.drawable.ic_action_expand); + mFoldableIcon.setImageResource(R.drawable.ic_expand_more_black_24dp); AlphaAnimation animation = new AlphaAnimation(1f, 0f); animation.setDuration(mShortAnimationDuration); animation.setAnimationListener(new Animation.AnimationListener() { @Override - public void onAnimationStart(Animation animation) { } + public void onAnimationStart(Animation animation) { + } @Override public void onAnimationEnd(Animation animation) { @@ -173,7 +174,8 @@ public class FoldableLinearLayout extends LinearLayout { } @Override - public void onAnimationRepeat(Animation animation) { } + public void onAnimationRepeat(Animation animation) { + } }); mFoldableContainer.startAnimation(animation); mFoldableTextView.setText(mFoldedLabel); @@ -185,6 +187,7 @@ public class FoldableLinearLayout extends LinearLayout { /** * Adds provided child view to foldableContainer View + * * @param child */ @Override -- cgit v1.2.3 From e049895b9f8f5f9996ac678acf6810768e859695 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Mon, 26 Jan 2015 15:24:42 +0100 Subject: Material Design Drawer --- .../keychain/remote/ui/AppsListActivity.java | 24 +++++++---- .../keychain/ui/EncryptActivity.java | 2 +- .../keychain/ui/EncryptFilesActivity.java | 12 +++--- .../keychain/ui/EncryptTextActivity.java | 12 +++--- .../keychain/ui/KeyListActivity.java | 20 +++++---- .../keychain/ui/NavDrawerActivity.java | 47 ++++++++++++++++++++++ 6 files changed, 88 insertions(+), 29 deletions(-) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NavDrawerActivity.java (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppsListActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppsListActivity.java index 079b3065e..3b4cc654e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppsListActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppsListActivity.java @@ -21,19 +21,27 @@ import android.os.Bundle; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.ui.DrawerActivity; +import org.sufficientlysecure.keychain.ui.NavDrawerActivity; -public class AppsListActivity extends DrawerActivity { +public class AppsListActivity extends NavDrawerActivity { - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - activateDrawerNavigation(savedInstanceState); - } +// @Override +// protected void onCreate(Bundle savedInstanceState) { +// super.onCreate(savedInstanceState); +// +// activateDrawerNavigation(savedInstanceState); +// } @Override - protected void initLayout() { + public void init(Bundle savedInstanceState) { + super.init(savedInstanceState); setContentView(R.layout.api_apps_list_activity); } + +// @Override +// protected void initLayout() { +// setContentView(R.layout.api_apps_list_activity); +// } + } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java index b9058a37d..11780e761 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java @@ -14,7 +14,7 @@ import org.sufficientlysecure.keychain.operations.results.SignEncryptResult; import java.util.Date; -public abstract class EncryptActivity extends DrawerActivity { +public abstract class EncryptActivity extends NavDrawerActivity { public static final int REQUEST_CODE_PASSPHRASE = 0x00008001; public static final int REQUEST_CODE_NFC = 0x00008002; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java index b1da1f2c5..6a5eaa26c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java @@ -312,10 +312,10 @@ public class EncryptFilesActivity extends EncryptActivity implements EncryptActi // if called with an intent action, do not init drawer navigation if (ACTION_ENCRYPT_DATA.equals(getIntent().getAction())) { // lock drawer - deactivateDrawerNavigation(); +// deactivateDrawerNavigation(); // TODO: back button to key? } else { - activateDrawerNavigation(savedInstanceState); +// activateDrawerNavigation(savedInstanceState); } // Handle intent actions @@ -325,10 +325,10 @@ public class EncryptFilesActivity extends EncryptActivity implements EncryptActi mUseArmor = Preferences.getPreferences(this).getDefaultAsciiArmor(); } - @Override - protected void initLayout() { - setContentView(R.layout.encrypt_files_activity); - } +// @Override +// protected void initLayout() { +// setContentView(R.layout.encrypt_files_activity); +// } @Override public boolean onCreateOptionsMenu(Menu menu) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java index dabd5ddd5..f9faf683d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java @@ -292,10 +292,10 @@ public class EncryptTextActivity extends EncryptActivity implements EncryptActiv // if called with an intent action, do not init drawer navigation if (ACTION_ENCRYPT_TEXT.equals(getIntent().getAction())) { // lock drawer - deactivateDrawerNavigation(); +// deactivateDrawerNavigation(); // TODO: back button to key? } else { - activateDrawerNavigation(savedInstanceState); +// activateDrawerNavigation(savedInstanceState); } // Handle intent actions @@ -303,10 +303,10 @@ public class EncryptTextActivity extends EncryptActivity implements EncryptActiv updateModeFragment(); } - @Override - protected void initLayout() { - setContentView(R.layout.encrypt_text_activity); - } +// @Override +// protected void initLayout() { +// setContentView(R.layout.encrypt_text_activity); +// } @Override public boolean onCreateOptionsMenu(Menu menu) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java index 1d9a9cf64..b7f3588eb 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java @@ -41,15 +41,19 @@ import org.sufficientlysecure.keychain.util.Preferences; import java.io.IOException; -public class KeyListActivity extends DrawerActivity { +import it.neokree.materialnavigationdrawer.MaterialNavigationDrawer; + +public class KeyListActivity extends NavDrawerActivity { public static final int REQUEST_CODE_RESULT_TO_LIST = 1; ExportHelper mExportHelper; @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); +// public void onCreate(Bundle savedInstanceState) { + public void init(Bundle savedInstanceState) { + super.init(savedInstanceState); +// super.onCreate(savedInstanceState); // setActionBarIcon(R.drawable.ic_ab_drawer); setTitle(R.string.nav_keys); @@ -72,13 +76,13 @@ public class KeyListActivity extends DrawerActivity { } // now setup navigation drawer in DrawerActivity... - activateDrawerNavigation(savedInstanceState); +// activateDrawerNavigation(savedInstanceState); } - @Override - protected void initLayout() { - setContentView(R.layout.key_list_activity); - } +// @Override +// protected void initLayout() { +// setContentView(R.layout.key_list_activity); +// } @Override public boolean onCreateOptionsMenu(Menu menu) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NavDrawerActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NavDrawerActivity.java new file mode 100644 index 000000000..092334ac3 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NavDrawerActivity.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2015 Dominik Schürmann + * + * 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 . + */ + +package org.sufficientlysecure.keychain.ui; + +import android.content.Intent; +import android.os.Bundle; + +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.remote.ui.AppsListActivity; + +import it.neokree.materialnavigationdrawer.MaterialNavigationDrawer; + +public abstract class NavDrawerActivity extends MaterialNavigationDrawer { + + @Override + public void init(Bundle savedInstanceState) { + + // set the header image + this.setDrawerHeaderImage(R.drawable.mat2); + + // create sections + this.addSection(newSection(getString(R.string.app_name), R.drawable.ic_vpn_key_black_24dp, new KeyListFragment())); + + this.addSection(newSection(getString(R.string.title_encrypt_text), R.drawable.ic_lock_outline_black_24dp, new Intent(this, EncryptTextActivity.class))); + this.addSection(newSection(getString(R.string.title_encrypt_files), R.drawable.ic_lock_outline_black_24dp, new Intent(this, EncryptFilesActivity.class))); + this.addSection(newSection(getString(R.string.title_decrypt), R.drawable.ic_lock_open_black_24dp, new Intent(this, DecryptActivity.class))); + this.addSection(newSection(getString(R.string.title_api_registered_apps), R.drawable.ic_apps_black_24dp, new Intent(this, AppsListActivity.class))); + + // create bottom section + this.addBottomSection(newSection(getString(R.string.menu_preferences), R.drawable.ic_settings_black_24dp, new Intent(this, SettingsActivity.class))); + } +} -- cgit v1.2.3 From 2bb7c3bcef695519c58d33253b74393caf7f14a0 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Sun, 25 Jan 2015 15:25:49 +0100 Subject: move last parts of import logic from kis into operation --- .../keychain/operations/ImportExportOperation.java | 48 +++++++++++++++++-- .../operations/results/ImportKeyResult.java | 4 ++ .../operations/results/OperationResult.java | 1 + .../keychain/service/KeychainIntentService.java | 55 +++++++--------------- 4 files changed, 67 insertions(+), 41 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportExportOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportExportOperation.java index cd8a33c20..3f3e0a432 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportExportOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportExportOperation.java @@ -30,6 +30,7 @@ import org.sufficientlysecure.keychain.keyimport.KeybaseKeyserver; import org.sufficientlysecure.keychain.keyimport.Keyserver; import org.sufficientlysecure.keychain.keyimport.Keyserver.AddKeyException; import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing; +import org.sufficientlysecure.keychain.operations.results.ConsolidateResult; import org.sufficientlysecure.keychain.operations.results.ExportResult; import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing; import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing; @@ -44,9 +45,12 @@ import org.sufficientlysecure.keychain.operations.results.OperationResult.LogTyp import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; import org.sufficientlysecure.keychain.operations.results.ImportKeyResult; import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult; +import org.sufficientlysecure.keychain.service.ContactSyncAdapterService; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.util.FileHelper; import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.ParcelableFileCache; +import org.sufficientlysecure.keychain.util.ParcelableFileCache.IteratorWithSize; import org.sufficientlysecure.keychain.util.ProgressScaler; import java.io.BufferedOutputStream; @@ -58,6 +62,7 @@ import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; import java.util.Iterator; +import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; /** An operation class which implements high level import and export @@ -123,6 +128,35 @@ public class ImportExportOperation extends BaseOperation { } } + public ImportKeyResult importKeyRings(List entries, String keyServerUri) { + + Iterator it = entries.iterator(); + int numEntries = entries.size(); + + return importKeyRings(it, numEntries, keyServerUri); + + } + + public ImportKeyResult importKeyRings(ParcelableFileCache cache, String keyServerUri) { + + // get entries from cached file + try { + IteratorWithSize it = cache.readCache(); + int numEntries = it.getSize(); + + return importKeyRings(it, numEntries, keyServerUri); + } catch (IOException e) { + + // Special treatment here, we need a lot + OperationLog log = new OperationLog(); + log.add(LogType.MSG_IMPORT, 0, 0); + log.add(LogType.MSG_IMPORT_ERROR_IO, 0, 0); + + return new ImportKeyResult(ImportKeyResult.RESULT_ERROR, log); + } + + } + public ImportKeyResult importKeyRings(Iterator entries, int num, String keyServerUri) { updateProgress(R.string.progress_importing, 0, 100); @@ -131,9 +165,7 @@ public class ImportExportOperation extends BaseOperation { // If there aren't even any keys, do nothing here. if (entries == null || !entries.hasNext()) { - return new ImportKeyResult( - ImportKeyResult.RESULT_FAIL_NOTHING, log, 0, 0, 0, 0, - new long[]{}); + return new ImportKeyResult(ImportKeyResult.RESULT_FAIL_NOTHING, log); } int newKeys = 0, oldKeys = 0, badKeys = 0, secret = 0; @@ -293,6 +325,16 @@ public class ImportExportOperation extends BaseOperation { position++; } + // Special: consolidate on secret key import (cannot be cancelled!) + if (secret > 0) { + setPreventCancel(); + ConsolidateResult result = mProviderHelper.consolidateDatabaseStep1(mProgressable); + log.add(result, 1); + } + + // Special: make sure new data is synced into contacts + ContactSyncAdapterService.requestSync(); + // convert to long array long[] importedMasterKeyIdsArray = new long[importedMasterKeyIds.size()]; for (int i = 0; i < importedMasterKeyIds.size(); ++i) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/ImportKeyResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/ImportKeyResult.java index 1dd038a23..91b53fd78 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/ImportKeyResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/ImportKeyResult.java @@ -83,6 +83,10 @@ public class ImportKeyResult extends OperationResult { mImportedMasterKeyIds = source.createLongArray(); } + public ImportKeyResult(int result, OperationLog log) { + this(result, log, 0, 0, 0, 0, new long[] { }); + } + public ImportKeyResult(int result, OperationLog log, int newKeys, int updatedKeys, int badKeys, int secret, long[] importedMasterKeyIds) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java index d025727b5..eba8f13af 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java @@ -654,6 +654,7 @@ public abstract class OperationResult implements Parcelable { MSG_IMPORT_FINGERPRINT_ERROR (LogLevel.ERROR, R.string.msg_import_fingerprint_error), MSG_IMPORT_FINGERPRINT_OK (LogLevel.DEBUG, R.string.msg_import_fingerprint_ok), MSG_IMPORT_ERROR (LogLevel.ERROR, R.string.msg_import_error), + MSG_IMPORT_ERROR_IO (LogLevel.ERROR, R.string.msg_import_error_io), MSG_IMPORT_PARTIAL (LogLevel.ERROR, R.string.msg_import_partial), MSG_IMPORT_SUCCESS (LogLevel.OK, R.string.msg_import_success), diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java index b96d8945c..c88e0bd8d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -403,49 +403,28 @@ public class KeychainIntentService extends IntentService implements Progressable break; } - case ACTION_IMPORT_KEYRING: + case ACTION_IMPORT_KEYRING: { - try { - - // Input - String keyServer = data.getString(IMPORT_KEY_SERVER); - Iterator entries; - int numEntries; - if (data.containsKey(IMPORT_KEY_LIST)) { - // get entries from intent - ArrayList list = data.getParcelableArrayList(IMPORT_KEY_LIST); - entries = list.iterator(); - numEntries = list.size(); - } else { - // get entries from cached file - ParcelableFileCache cache = - new ParcelableFileCache<>(this, "key_import.pcl"); - IteratorWithSize it = cache.readCache(); - entries = it; - numEntries = it.getSize(); - } - - // Operation - ImportExportOperation importExportOperation = new ImportExportOperation( - this, providerHelper, this, mActionCanceled); - ImportKeyResult result = importExportOperation.importKeyRings(entries, numEntries, keyServer); - - // Special: consolidate on secret key import (cannot be cancelled!) - if (result.mSecret > 0) { - // TODO move this into the import operation - providerHelper.consolidateDatabaseStep1(this); - } + // Input + String keyServer = data.getString(IMPORT_KEY_SERVER); + ArrayList list = data.getParcelableArrayList(IMPORT_KEY_LIST); + ParcelableFileCache cache = + new ParcelableFileCache<>(this, "key_import.pcl"); - // Special: make sure new data is synced into contacts - ContactSyncAdapterService.requestSync(); + // Operation + ImportExportOperation importExportOperation = new ImportExportOperation( + this, providerHelper, this, mActionCanceled); + // Either list or cache must be null, no guarantees otherwise. + ImportKeyResult result = list != null + ? importExportOperation.importKeyRings(list, keyServer) + : importExportOperation.importKeyRings(cache, keyServer); - // Result - sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result); - } catch (Exception e) { - sendErrorToHandler(e); - } + // Result + sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result); break; + + } case ACTION_SIGN_ENCRYPT: try { -- cgit v1.2.3 From efe5c80b1cd4cecb313f399fb5d3b994e690a708 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Mon, 26 Jan 2015 16:32:23 +0100 Subject: remove unused NonPgpPartException --- .../keychain/ui/adapter/ImportKeysListLoader.java | 12 ------------ 1 file changed, 12 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java index 9d1e8468c..144a16a48 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java @@ -39,18 +39,6 @@ import java.util.ArrayList; public class ImportKeysListLoader extends AsyncTaskLoader>> { - public static class NonPgpPartException extends Exception { - private int mCount; - - public NonPgpPartException(int count) { - this.mCount = count; - } - - public int getCount() { - return mCount; - } - } - final Context mContext; final InputData mInputData; -- cgit v1.2.3 From fc786280fdd7187f1828a4c7fa4d719de902a374 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Mon, 26 Jan 2015 17:33:40 +0100 Subject: Fixes for detached signatures --- .../keychain/pgp/PgpSignEncrypt.java | 35 ++++++++++++++++------ .../keychain/remote/OpenPgpService.java | 12 ++++++-- 2 files changed, 36 insertions(+), 11 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java index 3c6c86338..5282deca4 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java @@ -428,6 +428,7 @@ public class PgpSignEncrypt extends BaseOperation { BCPGOutputStream bcpgOut; ByteArrayOutputStream detachedByteOut = null; + ArmoredOutputStream detachedArmorOut = null; BCPGOutputStream detachedBcpgOut = null; try { @@ -535,7 +536,12 @@ public class PgpSignEncrypt extends BaseOperation { detachedByteOut = new ByteArrayOutputStream(); OutputStream detachedOut = detachedByteOut; if (mEnableAsciiArmorOutput) { - detachedOut = new ArmoredOutputStream(detachedOut); + detachedArmorOut = new ArmoredOutputStream(detachedOut); + if (mVersionHeader != null) { + detachedArmorOut.setHeader("Version", mVersionHeader); + } + + detachedOut = detachedArmorOut; } detachedBcpgOut = new BCPGOutputStream(detachedOut); @@ -614,27 +620,38 @@ public class PgpSignEncrypt extends BaseOperation { // Note that the checked key here is the master key, not the signing key // (although these are always the same on Yubikeys) result.setNfcData(mSignatureSubKeyId, e.hashToSign, e.hashAlgo, e.creationTimestamp, mSignaturePassphrase); - Log.d(Constants.TAG, "e.hashToSign"+ Hex.toHexString(e.hashToSign)); + Log.d(Constants.TAG, "e.hashToSign" + Hex.toHexString(e.hashToSign)); return result; } } // closing outputs // NOTE: closing needs to be done in the correct order! - // TODO: closing bcpgOut and pOut??? - if (enableEncryption) { - if (enableCompression) { + if (encryptionOut != null) { + if (compressGen != null) { compressGen.close(); } encryptionOut.close(); } - if (mEnableAsciiArmorOutput) { + // Note: Closing ArmoredOutputStream does not close the underlying stream + if (armorOut != null) { armorOut.close(); } - - out.close(); - mOutStream.close(); + // Note: Closing ArmoredOutputStream does not close the underlying stream + if (detachedArmorOut != null) { + detachedArmorOut.close(); + } + // Also closes detachedBcpgOut + if (detachedByteOut != null) { + detachedByteOut.close(); + } + if (out != null) { + out.close(); + } + if (mOutStream != null) { + mOutStream.close(); + } } catch (SignatureException e) { log.add(LogType.MSG_SE_ERROR_SIG, indent); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java index f2af43b6f..6c36e1ab8 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java @@ -244,7 +244,12 @@ public class OpenPgpService extends RemoteService { // Get Input- and OutputStream from ParcelFileDescriptor InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(input); - OutputStream os = new ParcelFileDescriptor.AutoCloseOutputStream(output); + OutputStream os = null; + if (cleartextSign) { + // output stream only needed for cleartext signatures, + // detached signatures are returned as extra + os = new ParcelFileDescriptor.AutoCloseOutputStream(output); + } try { long inputLength = is.available(); InputData inputData = new InputData(is, inputLength); @@ -325,7 +330,9 @@ public class OpenPgpService extends RemoteService { } } finally { is.close(); - os.close(); + if (os != null) { + os.close(); + } } } catch (Exception e) { Log.d(Constants.TAG, "signImpl", e); @@ -720,6 +727,7 @@ public class OpenPgpService extends RemoteService { return signImpl(data, input, output, accSettings, true); } else if (OpenPgpApi.ACTION_SIGN.equals(action)) { // DEPRECATED: same as ACTION_CLEARTEXT_SIGN + Log.w(Constants.TAG, "You are using a deprecated API call, please use ACTION_CLEARTEXT_SIGN instead of ACTION_SIGN!"); return signImpl(data, input, output, accSettings, true); } else if (OpenPgpApi.ACTION_DETACHED_SIGN.equals(action)) { return signImpl(data, input, output, accSettings, false); -- cgit v1.2.3 From 6c80025ead59b558ebb2d6a9f802ef046e673388 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Tue, 27 Jan 2015 09:17:23 +0100 Subject: backend support for charset in ascii-armored streams --- .../operations/results/DecryptVerifyResult.java | 11 ++++++++++ .../operations/results/OperationResult.java | 1 + .../keychain/pgp/PgpDecryptVerify.java | 24 +++++++++++++++++++--- .../keychain/pgp/PgpSignEncrypt.java | 12 +++++++++++ .../keychain/remote/OpenPgpService.java | 6 ++++++ .../keychain/ui/DecryptTextFragment.java | 15 +++++++++++++- 6 files changed, 65 insertions(+), 4 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DecryptVerifyResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DecryptVerifyResult.java index d81577102..86b37fea6 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DecryptVerifyResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DecryptVerifyResult.java @@ -41,6 +41,9 @@ public class DecryptVerifyResult extends OperationResult { OpenPgpSignatureResult mSignatureResult; OpenPgpMetadata mDecryptMetadata; + // This holds the charset which was specified in the ascii armor, if specified + // https://tools.ietf.org/html/rfc4880#page56 + String mCharset; public long getKeyIdPassphraseNeeded() { return mKeyIdPassphraseNeeded; @@ -84,6 +87,14 @@ public class DecryptVerifyResult extends OperationResult { mDecryptMetadata = decryptMetadata; } + public String getCharset () { + return mCharset; + } + + public void setCharset(String charset) { + mCharset = charset; + } + public boolean isPending() { return (mResult & RESULT_PENDING) == RESULT_PENDING; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java index eba8f13af..5b28f0f5a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java @@ -564,6 +564,7 @@ public abstract class OperationResult implements Parcelable { MSG_DC_ASKIP_NO_KEY (LogLevel.DEBUG, R.string.msg_dc_askip_no_key), MSG_DC_ASKIP_NOT_ALLOWED (LogLevel.DEBUG, R.string.msg_dc_askip_not_allowed), MSG_DC_ASYM (LogLevel.DEBUG, R.string.msg_dc_asym), + MSG_DC_CHARSET (LogLevel.DEBUG, R.string.msg_dc_charset), MSG_DC_CLEAR_DATA (LogLevel.DEBUG, R.string.msg_dc_clear_data), MSG_DC_CLEAR_DECOMPRESS (LogLevel.DEBUG, R.string.msg_dc_clear_decompress), MSG_DC_CLEAR_META_FILE (LogLevel.DEBUG, R.string.msg_dc_clear_meta_file), diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java index b58df085f..6c987f484 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java @@ -234,6 +234,22 @@ public class PgpDecryptVerify extends BaseOperation { boolean symmetricPacketFound = false; boolean anyPacketFound = false; + // If the input stream is armored, and there is a charset specified, take a note for later + // https://tools.ietf.org/html/rfc4880#page56 + String charset = null; + if (in instanceof ArmoredInputStream) { + for (String header : ((ArmoredInputStream) in).getArmorHeaders()) { + String[] pieces = header.split(":", 2); + if (pieces.length == 2 && "charset".equalsIgnoreCase(pieces[0])) { + charset = pieces[1].trim(); + break; + } + } + if (charset != null) { + log.add(LogType.MSG_DC_CHARSET, indent, charset); + } + } + // go through all objects and find one we can decrypt while (it.hasNext()) { Object obj = it.next(); @@ -550,6 +566,7 @@ public class PgpDecryptVerify extends BaseOperation { log.add(LogType.MSG_DC_OK_META_ONLY, indent); DecryptVerifyResult result = new DecryptVerifyResult(DecryptVerifyResult.RESULT_OK, log); + result.setCharset(charset); result.setDecryptMetadata(metadata); return result; } @@ -647,6 +664,7 @@ public class PgpDecryptVerify extends BaseOperation { new DecryptVerifyResult(DecryptVerifyResult.RESULT_OK, log); result.setDecryptMetadata(metadata); result.setSignatureResult(signatureResultBuilder.build()); + result.setCharset(charset); return result; } @@ -807,7 +825,7 @@ public class PgpDecryptVerify extends BaseOperation { while ((ch = fIn.read()) >= 0) { bOut.write(ch); if (ch == '\r' || ch == '\n') { - lookAhead = readPassedEOL(bOut, ch, fIn); + lookAhead = readPastEOL(bOut, ch, fIn); break; } } @@ -824,7 +842,7 @@ public class PgpDecryptVerify extends BaseOperation { do { bOut.write(ch); if (ch == '\r' || ch == '\n') { - lookAhead = readPassedEOL(bOut, ch, fIn); + lookAhead = readPastEOL(bOut, ch, fIn); break; } } while ((ch = fIn.read()) >= 0); @@ -836,7 +854,7 @@ public class PgpDecryptVerify extends BaseOperation { return lookAhead; } - private static int readPassedEOL(ByteArrayOutputStream bOut, int lastCh, InputStream fIn) + private static int readPastEOL(ByteArrayOutputStream bOut, int lastCh, InputStream fIn) throws IOException { int lookAhead = fIn.read(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java index 3c3bcc890..c2fa811bd 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java @@ -81,6 +81,7 @@ public class PgpSignEncrypt extends BaseOperation { private boolean mCleartextInput; private String mOriginalFilename; private boolean mFailOnMissingEncryptionKeyIds; + private String mCharset; private byte[] mNfcSignedHash = null; private Date mNfcCreationTimestamp = null; @@ -118,6 +119,7 @@ public class PgpSignEncrypt extends BaseOperation { this.mNfcCreationTimestamp = builder.mNfcCreationTimestamp; this.mOriginalFilename = builder.mOriginalFilename; this.mFailOnMissingEncryptionKeyIds = builder.mFailOnMissingEncryptionKeyIds; + this.mCharset = builder.mCharset; } public static class Builder { @@ -145,6 +147,7 @@ public class PgpSignEncrypt extends BaseOperation { private byte[] mNfcSignedHash = null; private Date mNfcCreationTimestamp = null; private boolean mFailOnMissingEncryptionKeyIds = false; + private String mCharset = null; public Builder(Context context, ProviderHelper providerHelper, Progressable progressable, InputData data, OutputStream outStream) { @@ -211,6 +214,11 @@ public class PgpSignEncrypt extends BaseOperation { return this; } + public Builder setCharset(String charset) { + mCharset = charset; + return this; + } + /** * Also encrypt with the signing keyring * @@ -283,6 +291,10 @@ public class PgpSignEncrypt extends BaseOperation { if (mVersionHeader != null) { armorOut.setHeader("Version", mVersionHeader); } + // if we have a charset, put it in the header + if (mCharset != null) { + armorOut.setHeader("Charset", mCharset); + } out = armorOut; } else { out = mOutStream; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java index 9534cc49d..68677fb9c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java @@ -557,6 +557,12 @@ public class OpenPgpService extends RemoteService { result.putExtra(OpenPgpApi.RESULT_METADATA, metadata); } } + + String charset = pgpResult.getCharset(); + if (charset != null) { + result.putExtra(OpenPgpApi.RESULT_CHARSET, charset); + } + } else { LogEntryParcel errorMsg = pgpResult.getLog().getLast(); throw new Exception(getString(errorMsg.mType.getMsgId())); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextFragment.java index 83ba64ce2..78333a8d8 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextFragment.java @@ -41,6 +41,8 @@ import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.ShareHelper; +import java.io.UnsupportedEncodingException; + public class DecryptTextFragment extends DecryptFragment { public static final String ARG_CIPHERTEXT = "ciphertext"; @@ -194,7 +196,18 @@ public class DecryptTextFragment extends DecryptFragment { byte[] decryptedMessage = returnData .getByteArray(KeychainIntentService.RESULT_DECRYPTED_BYTES); - mText.setText(new String(decryptedMessage)); + String displayMessage; + if (pgpResult.getCharset() != null) { + try { + displayMessage = new String(decryptedMessage, pgpResult.getCharset()); + } catch (UnsupportedEncodingException e) { + // if we can't decode properly, just fall back to utf-8 + displayMessage = new String(decryptedMessage); + } + } else { + displayMessage = new String(decryptedMessage); + } + mText.setText(displayMessage); pgpResult.createNotify(getActivity()).show(); -- cgit v1.2.3 From fd29d27e61e531378f0c37c78028fb2e86989dea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Tue, 27 Jan 2015 09:37:07 +0100 Subject: Temporary nav drawer fixes --- .../keychain/ui/DecryptActivity.java | 4 ++-- .../keychain/ui/EncryptActivity.java | 2 +- .../keychain/ui/EncryptFilesActivity.java | 8 ++++---- .../keychain/ui/EncryptTextActivity.java | 8 ++++---- .../keychain/ui/NavDrawerActivity.java | 23 +++++++++++++++------- 5 files changed, 27 insertions(+), 18 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java index a84461a92..21377bcd2 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java @@ -34,13 +34,13 @@ import org.sufficientlysecure.keychain.ui.util.SubtleAttentionSeeker; import java.util.regex.Matcher; -public class DecryptActivity extends DrawerActivity { +public class DecryptActivity extends BaseActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - activateDrawerNavigation(savedInstanceState); +// activateDrawerNavigation(savedInstanceState); View actionFile = findViewById(R.id.decrypt_files); View actionFromClipboard = findViewById(R.id.decrypt_from_clipboard); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java index 11780e761..611078f95 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java @@ -14,7 +14,7 @@ import org.sufficientlysecure.keychain.operations.results.SignEncryptResult; import java.util.Date; -public abstract class EncryptActivity extends NavDrawerActivity { +public abstract class EncryptActivity extends BaseActivity { public static final int REQUEST_CODE_PASSPHRASE = 0x00008001; public static final int REQUEST_CODE_NFC = 0x00008002; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java index 6a5eaa26c..63708ae8e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java @@ -325,10 +325,10 @@ public class EncryptFilesActivity extends EncryptActivity implements EncryptActi mUseArmor = Preferences.getPreferences(this).getDefaultAsciiArmor(); } -// @Override -// protected void initLayout() { -// setContentView(R.layout.encrypt_files_activity); -// } + @Override + protected void initLayout() { + setContentView(R.layout.encrypt_files_activity); + } @Override public boolean onCreateOptionsMenu(Menu menu) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java index f9faf683d..b4c12996e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java @@ -303,10 +303,10 @@ public class EncryptTextActivity extends EncryptActivity implements EncryptActiv updateModeFragment(); } -// @Override -// protected void initLayout() { -// setContentView(R.layout.encrypt_text_activity); -// } + @Override + protected void initLayout() { + setContentView(R.layout.encrypt_text_activity); + } @Override public boolean onCreateOptionsMenu(Menu menu) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NavDrawerActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NavDrawerActivity.java index 092334ac3..5381b1ab3 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NavDrawerActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NavDrawerActivity.java @@ -19,9 +19,12 @@ package org.sufficientlysecure.keychain.ui; import android.content.Intent; import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.remote.ui.AppsListActivity; +import org.sufficientlysecure.keychain.remote.ui.AppsListFragment; import it.neokree.materialnavigationdrawer.MaterialNavigationDrawer; @@ -29,19 +32,25 @@ public abstract class NavDrawerActivity extends MaterialNavigationDrawer { @Override public void init(Bundle savedInstanceState) { + // don't open drawer on first run + disableLearningPattern(); + +// addMultiPaneSupport(); // set the header image - this.setDrawerHeaderImage(R.drawable.mat2); + // create and set the header + View view = LayoutInflater.from(this).inflate(R.layout.custom_drawer, null); + setDrawerHeaderCustom(view); // create sections - this.addSection(newSection(getString(R.string.app_name), R.drawable.ic_vpn_key_black_24dp, new KeyListFragment())); + addSection(newSection(getString(R.string.title_keys), R.drawable.ic_vpn_key_black_24dp, new KeyListFragment())); - this.addSection(newSection(getString(R.string.title_encrypt_text), R.drawable.ic_lock_outline_black_24dp, new Intent(this, EncryptTextActivity.class))); - this.addSection(newSection(getString(R.string.title_encrypt_files), R.drawable.ic_lock_outline_black_24dp, new Intent(this, EncryptFilesActivity.class))); - this.addSection(newSection(getString(R.string.title_decrypt), R.drawable.ic_lock_open_black_24dp, new Intent(this, DecryptActivity.class))); - this.addSection(newSection(getString(R.string.title_api_registered_apps), R.drawable.ic_apps_black_24dp, new Intent(this, AppsListActivity.class))); + addSection(newSection(getString(R.string.title_encrypt_text), R.drawable.ic_lock_outline_black_24dp, new Intent(this, EncryptTextActivity.class))); + addSection(newSection(getString(R.string.title_encrypt_files), R.drawable.ic_lock_outline_black_24dp, new Intent(this, EncryptFilesActivity.class))); + addSection(newSection(getString(R.string.title_decrypt), R.drawable.ic_lock_open_black_24dp, new Intent(this, DecryptActivity.class))); + addSection(newSection(getString(R.string.title_api_registered_apps), R.drawable.ic_apps_black_24dp, new AppsListFragment())); // create bottom section - this.addBottomSection(newSection(getString(R.string.menu_preferences), R.drawable.ic_settings_black_24dp, new Intent(this, SettingsActivity.class))); + addBottomSection(newSection(getString(R.string.menu_preferences), R.drawable.ic_settings_black_24dp, new Intent(this, SettingsActivity.class))); } } -- cgit v1.2.3 From ae7ba2639f1ade3953c8b96fb32a17df0d3aaf8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Tue, 27 Jan 2015 13:00:28 +0100 Subject: Support verification of detached signatures --- .../keychain/pgp/PgpDecryptVerify.java | 305 ++++++++++++++------- .../keychain/remote/OpenPgpService.java | 16 +- 2 files changed, 223 insertions(+), 98 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java index 6c987f484..a69c5fe36 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java @@ -28,7 +28,6 @@ import org.spongycastle.openpgp.PGPEncryptedData; import org.spongycastle.openpgp.PGPEncryptedDataList; import org.spongycastle.openpgp.PGPException; import org.spongycastle.openpgp.PGPLiteralData; -import org.spongycastle.openpgp.PGPObjectFactory; import org.spongycastle.openpgp.PGPOnePassSignature; import org.spongycastle.openpgp.PGPOnePassSignatureList; import org.spongycastle.openpgp.PGPPBEEncryptedData; @@ -36,6 +35,7 @@ import org.spongycastle.openpgp.PGPPublicKeyEncryptedData; import org.spongycastle.openpgp.PGPSignature; import org.spongycastle.openpgp.PGPSignatureList; import org.spongycastle.openpgp.PGPUtil; +import org.spongycastle.openpgp.jcajce.JcaPGPObjectFactory; import org.spongycastle.openpgp.operator.PBEDataDecryptorFactory; import org.spongycastle.openpgp.operator.PGPDigestCalculatorProvider; import org.spongycastle.openpgp.operator.PublicKeyDataDecryptorFactory; @@ -83,6 +83,7 @@ public class PgpDecryptVerify extends BaseOperation { private Set mAllowedKeyIds; private boolean mDecryptMetadataOnly; private byte[] mDecryptedSessionKey; + private byte[] mDetachedSignature; protected PgpDecryptVerify(Builder builder) { super(builder.mContext, builder.mProviderHelper, builder.mProgressable); @@ -96,6 +97,7 @@ public class PgpDecryptVerify extends BaseOperation { this.mAllowedKeyIds = builder.mAllowedKeyIds; this.mDecryptMetadataOnly = builder.mDecryptMetadataOnly; this.mDecryptedSessionKey = builder.mDecryptedSessionKey; + this.mDetachedSignature = builder.mDetachedSignature; } public static class Builder { @@ -103,15 +105,16 @@ public class PgpDecryptVerify extends BaseOperation { private Context mContext; private ProviderHelper mProviderHelper; private InputData mData; - private OutputStream mOutStream; // optional + private OutputStream mOutStream = null; private Progressable mProgressable = null; private boolean mAllowSymmetricDecryption = true; private String mPassphrase = null; private Set mAllowedKeyIds = null; private boolean mDecryptMetadataOnly = false; private byte[] mDecryptedSessionKey = null; + private byte[] mDetachedSignature = null; public Builder(Context context, ProviderHelper providerHelper, Progressable progressable, @@ -156,6 +159,17 @@ public class PgpDecryptVerify extends BaseOperation { return this; } + /** + * If detachedSignature != null, it will be used exclusively to verify the signature + * + * @param detachedSignature + * @return + */ + public Builder setDetachedSignature(byte[] detachedSignature) { + mDetachedSignature = detachedSignature; + return this; + } + public PgpDecryptVerify build() { return new PgpDecryptVerify(this); } @@ -166,22 +180,30 @@ public class PgpDecryptVerify extends BaseOperation { */ public DecryptVerifyResult execute() { try { - // automatically works with ascii armor input and binary - InputStream in = PGPUtil.getDecoderStream(mData.getInputStream()); + if (mDetachedSignature != null) { + Log.d(Constants.TAG, "Detached signature present, verifying with this signature only"); - if (in instanceof ArmoredInputStream) { - ArmoredInputStream aIn = (ArmoredInputStream) in; - // it is ascii armored - Log.d(Constants.TAG, "ASCII Armor Header Line: " + aIn.getArmorHeaderLine()); - - if (aIn.isClearText()) { - // a cleartext signature, verify it with the other method - return verifyCleartextSignature(aIn, 0); + return verifyDetachedSignature(mData.getInputStream(), 0); + } else { + // automatically works with PGP ascii armor and PGP binary + InputStream in = PGPUtil.getDecoderStream(mData.getInputStream()); + + if (in instanceof ArmoredInputStream) { + ArmoredInputStream aIn = (ArmoredInputStream) in; + // it is ascii armored + Log.d(Constants.TAG, "ASCII Armor Header Line: " + aIn.getArmorHeaderLine()); + + if (aIn.isClearText()) { + // a cleartext signature, verify it with the other method + return verifyCleartextSignature(aIn, 0); + } else { + // else: ascii armored encryption! go on... + return decryptVerify(in, 0); + } + } else { + return decryptVerify(in, 0); } - // else: ascii armored encryption! go on... } - - return decryptVerify(in, 0); } catch (PGPException e) { Log.d(Constants.TAG, "PGPException", e); OperationLog log = new OperationLog(); @@ -205,7 +227,7 @@ public class PgpDecryptVerify extends BaseOperation { log.add(LogType.MSG_DC, indent); indent += 1; - PGPObjectFactory pgpF = new PGPObjectFactory(in, new JcaKeyFingerprintCalculator()); + JcaPGPObjectFactory pgpF = new JcaPGPObjectFactory(in); PGPEncryptedDataList enc; Object o = pgpF.nextObject(); @@ -238,15 +260,18 @@ public class PgpDecryptVerify extends BaseOperation { // https://tools.ietf.org/html/rfc4880#page56 String charset = null; if (in instanceof ArmoredInputStream) { - for (String header : ((ArmoredInputStream) in).getArmorHeaders()) { - String[] pieces = header.split(":", 2); - if (pieces.length == 2 && "charset".equalsIgnoreCase(pieces[0])) { - charset = pieces[1].trim(); - break; + ArmoredInputStream aIn = (ArmoredInputStream) in; + if (aIn.getArmorHeaders() != null) { + for (String header : aIn.getArmorHeaders()) { + String[] pieces = header.split(":", 2); + if (pieces.length == 2 && "charset".equalsIgnoreCase(pieces[0])) { + charset = pieces[1].trim(); + break; + } + } + if (charset != null) { + log.add(LogType.MSG_DC_CHARSET, indent, charset); } - } - if (charset != null) { - log.add(LogType.MSG_DC_CHARSET, indent, charset); } } @@ -273,19 +298,19 @@ public class PgpDecryptVerify extends BaseOperation { ); } catch (ProviderHelper.NotFoundException e) { // continue with the next packet in the while loop - log.add(LogType.MSG_DC_ASKIP_NO_KEY, indent +1); + log.add(LogType.MSG_DC_ASKIP_NO_KEY, indent + 1); continue; } if (secretKeyRing == null) { // continue with the next packet in the while loop - log.add(LogType.MSG_DC_ASKIP_NO_KEY, indent +1); + log.add(LogType.MSG_DC_ASKIP_NO_KEY, indent + 1); continue; } // get subkey which has been used for this encryption packet secretEncryptionKey = secretKeyRing.getSecretKey(subKeyId); if (secretEncryptionKey == null) { // should actually never happen, so no need to be more specific. - log.add(LogType.MSG_DC_ASKIP_NO_KEY, indent +1); + log.add(LogType.MSG_DC_ASKIP_NO_KEY, indent + 1); continue; } @@ -299,7 +324,7 @@ public class PgpDecryptVerify extends BaseOperation { if (!mAllowedKeyIds.contains(masterKeyId)) { // this key is in our db, but NOT allowed! // continue with the next packet in the while loop - log.add(LogType.MSG_DC_ASKIP_NOT_ALLOWED, indent +1); + log.add(LogType.MSG_DC_ASKIP_NOT_ALLOWED, indent + 1); continue; } } @@ -314,15 +339,15 @@ public class PgpDecryptVerify extends BaseOperation { try { // returns "" if key has no passphrase mPassphrase = getCachedPassphrase(subKeyId); - log.add(LogType.MSG_DC_PASS_CACHED, indent +1); + log.add(LogType.MSG_DC_PASS_CACHED, indent + 1); } catch (PassphraseCacheInterface.NoSecretKeyException e) { - log.add(LogType.MSG_DC_ERROR_NO_KEY, indent +1); + log.add(LogType.MSG_DC_ERROR_NO_KEY, indent + 1); return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log); } // if passphrase was not cached, return here indicating that a passphrase is missing! if (mPassphrase == null) { - log.add(LogType.MSG_DC_PENDING_PASSPHRASE, indent +1); + log.add(LogType.MSG_DC_PENDING_PASSPHRASE, indent + 1); DecryptVerifyResult result = new DecryptVerifyResult(DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE, log); result.setKeyIdPassphraseNeeded(subKeyId); @@ -338,8 +363,8 @@ public class PgpDecryptVerify extends BaseOperation { log.add(LogType.MSG_DC_SYM, indent); - if (! mAllowSymmetricDecryption) { - log.add(LogType.MSG_DC_SYM_SKIP, indent +1); + if (!mAllowSymmetricDecryption) { + log.add(LogType.MSG_DC_SYM_SKIP, indent + 1); continue; } @@ -354,7 +379,7 @@ public class PgpDecryptVerify extends BaseOperation { // if no passphrase is given, return here // indicating that a passphrase is missing! if (mPassphrase == null) { - log.add(LogType.MSG_DC_PENDING_PASSPHRASE, indent +1); + log.add(LogType.MSG_DC_PENDING_PASSPHRASE, indent + 1); return new DecryptVerifyResult(DecryptVerifyResult.RESULT_PENDING_SYM_PASSPHRASE, log); } @@ -399,13 +424,13 @@ public class PgpDecryptVerify extends BaseOperation { updateProgress(R.string.progress_extracting_key, currentProgress, 100); try { - log.add(LogType.MSG_DC_UNLOCKING, indent +1); + log.add(LogType.MSG_DC_UNLOCKING, indent + 1); if (!secretEncryptionKey.unlock(mPassphrase)) { - log.add(LogType.MSG_DC_ERROR_BAD_PASSPHRASE, indent +1); + log.add(LogType.MSG_DC_ERROR_BAD_PASSPHRASE, indent + 1); return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log); } } catch (PgpGeneralException e) { - log.add(LogType.MSG_DC_ERROR_EXTRACT_KEY, indent +1); + log.add(LogType.MSG_DC_ERROR_EXTRACT_KEY, indent + 1); return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log); } @@ -417,7 +442,7 @@ public class PgpDecryptVerify extends BaseOperation { = secretEncryptionKey.getDecryptorFactory(mDecryptedSessionKey); clear = encryptedDataAsymmetric.getDataStream(decryptorFactory); } catch (NfcSyncPublicKeyDataDecryptorFactoryBuilder.NfcInteractionNeeded e) { - log.add(LogType.MSG_DC_PENDING_NFC, indent +1); + log.add(LogType.MSG_DC_PENDING_NFC, indent + 1); DecryptVerifyResult result = new DecryptVerifyResult(DecryptVerifyResult.RESULT_PENDING_NFC, log); result.setNfcState(secretEncryptionKey.getKeyId(), e.encryptedSessionKey, mPassphrase); @@ -428,11 +453,11 @@ public class PgpDecryptVerify extends BaseOperation { // If we didn't find any useful data, error out // no packet has been found where we have the corresponding secret key in our db log.add( - anyPacketFound ? LogType.MSG_DC_ERROR_NO_KEY : LogType.MSG_DC_ERROR_NO_DATA, indent +1); + anyPacketFound ? LogType.MSG_DC_ERROR_NO_KEY : LogType.MSG_DC_ERROR_NO_DATA, indent + 1); return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log); } - PGPObjectFactory plainFact = new PGPObjectFactory(clear, new JcaKeyFingerprintCalculator()); + JcaPGPObjectFactory plainFact = new JcaPGPObjectFactory(clear); Object dataChunk = plainFact.nextObject(); OpenPgpSignatureResultBuilder signatureResultBuilder = new OpenPgpSignatureResultBuilder(); int signatureIndex = -1; @@ -443,25 +468,27 @@ public class PgpDecryptVerify extends BaseOperation { indent += 1; if (dataChunk instanceof PGPCompressedData) { - log.add(LogType.MSG_DC_CLEAR_DECOMPRESS, indent +1); + log.add(LogType.MSG_DC_CLEAR_DECOMPRESS, indent + 1); currentProgress += 2; updateProgress(R.string.progress_decompressing_data, currentProgress, 100); PGPCompressedData compressedData = (PGPCompressedData) dataChunk; - PGPObjectFactory fact = new PGPObjectFactory(compressedData.getDataStream(), new JcaKeyFingerprintCalculator()); + JcaPGPObjectFactory fact = new JcaPGPObjectFactory(compressedData.getDataStream()); dataChunk = fact.nextObject(); plainFact = fact; } PGPOnePassSignature signature = null; if (dataChunk instanceof PGPOnePassSignatureList) { - log.add(LogType.MSG_DC_CLEAR_SIGNATURE, indent +1); + log.add(LogType.MSG_DC_CLEAR_SIGNATURE, indent + 1); currentProgress += 2; updateProgress(R.string.progress_processing_signature, currentProgress, 100); PGPOnePassSignatureList sigList = (PGPOnePassSignatureList) dataChunk; + // NOTE: following code is similar to processSignature, but for PGPOnePassSignature + // go through all signatures // and find out for which signature we have a key in our database for (int i = 0; i < sigList.size(); ++i) { @@ -507,7 +534,7 @@ public class PgpDecryptVerify extends BaseOperation { OpenPgpMetadata metadata; if (dataChunk instanceof PGPLiteralData) { - log.add(LogType.MSG_DC_CLEAR_DATA, indent +1); + log.add(LogType.MSG_DC_CLEAR_DATA, indent + 1); indent += 2; currentProgress += 4; updateProgress(R.string.progress_decrypting, currentProgress, 100); @@ -549,12 +576,12 @@ public class PgpDecryptVerify extends BaseOperation { literalData.getModificationTime().getTime(), originalSize); - if ( ! originalFilename.equals("")) { + if (!originalFilename.equals("")) { log.add(LogType.MSG_DC_CLEAR_META_FILE, indent + 1, originalFilename); } - log.add(LogType.MSG_DC_CLEAR_META_MIME, indent +1, + log.add(LogType.MSG_DC_CLEAR_META_MIME, indent + 1, mimeType); - log.add(LogType.MSG_DC_CLEAR_META_TIME, indent +1, + log.add(LogType.MSG_DC_CLEAR_META_TIME, indent + 1, new Date(literalData.getModificationTime().getTime()).toString()); if (originalSize != 0) { log.add(LogType.MSG_DC_CLEAR_META_SIZE, indent + 1, @@ -589,7 +616,9 @@ public class PgpDecryptVerify extends BaseOperation { int length; byte[] buffer = new byte[1 << 16]; while ((length = dataIn.read(buffer)) > 0) { - mOutStream.write(buffer, 0, length); + if (mOutStream != null) { + mOutStream.write(buffer, 0, length); + } // update signature buffer if signature is also present if (signature != null) { @@ -623,9 +652,9 @@ public class PgpDecryptVerify extends BaseOperation { // Verify signature and check binding signatures boolean validSignature = signature.verify(messageSignature); if (validSignature) { - log.add(LogType.MSG_DC_CLEAR_SIGNATURE_OK, indent +1); + log.add(LogType.MSG_DC_CLEAR_SIGNATURE_OK, indent + 1); } else { - log.add(LogType.MSG_DC_CLEAR_SIGNATURE_BAD, indent +1); + log.add(LogType.MSG_DC_CLEAR_SIGNATURE_BAD, indent + 1); } signatureResultBuilder.setValidSignature(validSignature); } @@ -687,7 +716,7 @@ public class PgpDecryptVerify extends BaseOperation { ByteArrayOutputStream out = new ByteArrayOutputStream(); - updateProgress(R.string.progress_done, 0, 100); + updateProgress(R.string.progress_reading_data, 0, 100); ByteArrayOutputStream lineOut = new ByteArrayOutputStream(); int lookAhead = readInputLine(lineOut, aIn); @@ -707,10 +736,12 @@ public class PgpDecryptVerify extends BaseOperation { out.close(); byte[] clearText = out.toByteArray(); - mOutStream.write(clearText); + if (mOutStream != null) { + mOutStream.write(clearText); + } updateProgress(R.string.progress_processing_signature, 60, 100); - PGPObjectFactory pgpFact = new PGPObjectFactory(aIn, new JcaKeyFingerprintCalculator()); + JcaPGPObjectFactory pgpFact = new JcaPGPObjectFactory(aIn); PGPSignatureList sigList = (PGPSignatureList) pgpFact.nextObject(); if (sigList == null) { @@ -718,45 +749,7 @@ public class PgpDecryptVerify extends BaseOperation { return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log); } - CanonicalizedPublicKeyRing signingRing = null; - CanonicalizedPublicKey signingKey = null; - int signatureIndex = -1; - - // go through all signatures - // and find out for which signature we have a key in our database - for (int i = 0; i < sigList.size(); ++i) { - try { - long sigKeyId = sigList.get(i).getKeyID(); - signingRing = mProviderHelper.getCanonicalizedPublicKeyRing( - KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(sigKeyId) - ); - signingKey = signingRing.getPublicKey(sigKeyId); - signatureIndex = i; - } catch (ProviderHelper.NotFoundException e) { - Log.d(Constants.TAG, "key not found, trying next signature..."); - } - } - - PGPSignature signature = null; - - if (signingKey != null) { - // key found in our database! - signature = sigList.get(signatureIndex); - - signatureResultBuilder.initValid(signingRing, signingKey); - - JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = - new JcaPGPContentVerifierBuilderProvider() - .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); - signature.init(contentVerifierBuilderProvider, signingKey.getPublicKey()); - } else { - // no key in our database -> return "unknown pub key" status including the first key id - if (!sigList.isEmpty()) { - signatureResultBuilder.setSignatureAvailable(true); - signatureResultBuilder.setKnownKey(false); - signatureResultBuilder.setKeyId(sigList.get(0).getKeyID()); - } - } + PGPSignature signature = processPGPSignatureList(sigList, signatureResultBuilder); if (signature != null) { try { @@ -804,6 +797,134 @@ public class PgpDecryptVerify extends BaseOperation { return result; } + private DecryptVerifyResult verifyDetachedSignature(InputStream in, int indent) + throws IOException, PGPException { + + OperationLog log = new OperationLog(); + + OpenPgpSignatureResultBuilder signatureResultBuilder = new OpenPgpSignatureResultBuilder(); + // detached signatures are never encrypted + signatureResultBuilder.setSignatureOnly(true); + + updateProgress(R.string.progress_processing_signature, 0, 100); + InputStream detachedSigIn = new ByteArrayInputStream(mDetachedSignature); + detachedSigIn = PGPUtil.getDecoderStream(detachedSigIn); + + JcaPGPObjectFactory pgpFact = new JcaPGPObjectFactory(detachedSigIn); + + PGPSignatureList sigList; + Object o = pgpFact.nextObject(); + if (o instanceof PGPCompressedData) { + PGPCompressedData c1 = (PGPCompressedData) o; + pgpFact = new JcaPGPObjectFactory(c1.getDataStream()); + sigList = (PGPSignatureList) pgpFact.nextObject(); + } else if (o instanceof PGPSignatureList) { + sigList = (PGPSignatureList) o; + } else { + log.add(LogType.MSG_DC_ERROR_INVALID_SIGLIST, 0); + return new DecryptVerifyResult(DecryptVerifyResult.RESULT_ERROR, log); + } + + PGPSignature signature = processPGPSignatureList(sigList, signatureResultBuilder); + + if (signature != null) { + updateProgress(R.string.progress_reading_data, 60, 100); + + ProgressScaler progressScaler = new ProgressScaler(mProgressable, 60, 90, 100); + long alreadyWritten = 0; + long wholeSize = mData.getSize() - mData.getStreamPosition(); + int length; + byte[] buffer = new byte[1 << 16]; + while ((length = in.read(buffer)) > 0) { + if (mOutStream != null) { + mOutStream.write(buffer, 0, length); + } + + // update signature buffer if signature is also present + signature.update(buffer, 0, length); + + alreadyWritten += length; + if (wholeSize > 0) { + long progress = 100 * alreadyWritten / wholeSize; + // stop at 100% for wrong file sizes... + if (progress > 100) { + progress = 100; + } + progressScaler.setProgress((int) progress, 100); + } else { + // TODO: slow annealing to fake a progress? + } + } + + updateProgress(R.string.progress_verifying_signature, 90, 100); + log.add(LogType.MSG_DC_CLEAR_SIGNATURE_CHECK, indent); + + // these are not cleartext signatures! + signatureResultBuilder.setSignatureOnly(false); + + // Verify signature and check binding signatures + boolean validSignature = signature.verify(); + if (validSignature) { + log.add(LogType.MSG_DC_CLEAR_SIGNATURE_OK, indent + 1); + } else { + log.add(LogType.MSG_DC_CLEAR_SIGNATURE_BAD, indent + 1); + } + signatureResultBuilder.setValidSignature(validSignature); + } + + updateProgress(R.string.progress_done, 100, 100); + + log.add(LogType.MSG_DC_OK, indent); + + DecryptVerifyResult result = new DecryptVerifyResult(DecryptVerifyResult.RESULT_OK, log); + result.setSignatureResult(signatureResultBuilder.build()); + return result; + } + + private PGPSignature processPGPSignatureList(PGPSignatureList sigList, OpenPgpSignatureResultBuilder signatureResultBuilder) throws PGPException { + CanonicalizedPublicKeyRing signingRing = null; + CanonicalizedPublicKey signingKey = null; + int signatureIndex = -1; + + // go through all signatures + // and find out for which signature we have a key in our database + for (int i = 0; i < sigList.size(); ++i) { + try { + long sigKeyId = sigList.get(i).getKeyID(); + signingRing = mProviderHelper.getCanonicalizedPublicKeyRing( + KeyRings.buildUnifiedKeyRingsFindBySubkeyUri(sigKeyId) + ); + signingKey = signingRing.getPublicKey(sigKeyId); + signatureIndex = i; + } catch (ProviderHelper.NotFoundException e) { + Log.d(Constants.TAG, "key not found, trying next signature..."); + } + } + + PGPSignature signature = null; + + if (signingKey != null) { + // key found in our database! + signature = sigList.get(signatureIndex); + + signatureResultBuilder.initValid(signingRing, signingKey); + + JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = + new JcaPGPContentVerifierBuilderProvider() + .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); + signature.init(contentVerifierBuilderProvider, signingKey.getPublicKey()); + } else { + // no key in our database -> return "unknown pub key" status including the first key id + if (!sigList.isEmpty()) { + signatureResultBuilder.setSignatureAvailable(true); + signatureResultBuilder.setKnownKey(false); + signatureResultBuilder.setKeyId(sigList.get(0).getKeyID()); + } + } + + return signature; + } + /** * Mostly taken from ClearSignedFileProcessor in Bouncy Castle */ diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java index e1d15e2d3..d967931ce 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java @@ -481,7 +481,8 @@ public class OpenPgpService extends RemoteService { InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(input); OutputStream os; - if (decryptMetadataOnly) { + // output is optional, e.g., for verifying detached signatures + if (decryptMetadataOnly || output == null) { os = null; } else { os = new ParcelFileDescriptor.AutoCloseOutputStream(output); @@ -498,15 +499,17 @@ public class OpenPgpService extends RemoteService { byte[] nfcDecryptedSessionKey = data.getByteArrayExtra(OpenPgpApi.EXTRA_NFC_DECRYPTED_SESSION_KEY); + byte[] detachedSignature = data.getByteArrayExtra(OpenPgpApi.EXTRA_DETACHED_SIGNATURE); + // allow only private keys associated with accounts of this app // no support for symmetric encryption builder.setPassphrase(passphrase) .setAllowSymmetricDecryption(false) .setAllowedKeyIds(allowedKeyIds) .setDecryptMetadataOnly(decryptMetadataOnly) - .setNfcState(nfcDecryptedSessionKey); + .setNfcState(nfcDecryptedSessionKey) + .setDetachedSignature(detachedSignature); - // TODO: currently does not support binary signed-only content DecryptVerifyResult pgpResult = builder.build().execute(); if (pgpResult.isPending()) { @@ -678,15 +681,16 @@ public class OpenPgpService extends RemoteService { // version code is required and needs to correspond to version code of service! // History of versions in org.openintents.openpgp.util.OpenPgpApi - // we support 3, 4, 5 + // we support 3, 4, 5, 6 if (data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) != 3 && data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) != 4 - && data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) != 5) { + && data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) != 5 + && data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) != 6) { Intent result = new Intent(); OpenPgpError error = new OpenPgpError (OpenPgpError.INCOMPATIBLE_API_VERSIONS, "Incompatible API versions!\n" + "used API version: " + data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) + "\n" - + "supported API versions: 3, 4"); + + "supported API versions: 3, 4, 5, 6"); result.putExtra(OpenPgpApi.RESULT_ERROR, error); result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR); return result; -- cgit v1.2.3 From 5a1187b7816f108d514eb718993553d38b66ea54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Tue, 27 Jan 2015 13:15:24 +0100 Subject: Fix nullpointer in ImportKeysActivity --- .../keychain/ui/ImportKeysActivity.java | 37 ++++++++++++++-------- 1 file changed, 24 insertions(+), 13 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java index e72e265d4..6638c9944 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java @@ -115,6 +115,12 @@ public class ImportKeysActivity extends BaseActivity { extras = new Bundle(); } + if (action == null) { + startCloudFragment(savedInstanceState, null, false); + startListFragment(savedInstanceState, null, null, null); + return; + } + if (Intent.ACTION_VIEW.equals(action)) { // Android's Action when opening file associated to Keychain (see AndroidManifest.xml) // delegate action to ACTION_IMPORT_KEY @@ -122,8 +128,8 @@ public class ImportKeysActivity extends BaseActivity { } switch (action) { - case ACTION_IMPORT_KEY: - /* Keychain's own Actions */ + case ACTION_IMPORT_KEY: { + /* Keychain's own Actions */ startFileFragment(savedInstanceState); if (dataUri != null) { @@ -136,16 +142,17 @@ public class ImportKeysActivity extends BaseActivity { startListFragment(savedInstanceState, importData, null, null); } break; + } case ACTION_IMPORT_KEY_FROM_KEYSERVER: case ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_TO_SERVICE: - case ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_RESULT: + case ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_RESULT: { // only used for OpenPgpService if (extras.containsKey(EXTRA_PENDING_INTENT_DATA)) { mPendingIntentData = extras.getParcelable(EXTRA_PENDING_INTENT_DATA); } if (extras.containsKey(EXTRA_QUERY) || extras.containsKey(EXTRA_KEY_ID)) { - /* simple search based on query or key id */ + /* simple search based on query or key id */ String query = null; if (extras.containsKey(EXTRA_QUERY)) { @@ -168,10 +175,10 @@ public class ImportKeysActivity extends BaseActivity { return; } } else if (extras.containsKey(EXTRA_FINGERPRINT)) { - /* - * search based on fingerprint, here we can enforce a check in the end - * if the right key has been downloaded - */ + /* + * search based on fingerprint, here we can enforce a check in the end + * if the right key has been downloaded + */ String fingerprint = extras.getString(EXTRA_FINGERPRINT); if (isFingerprintValid(fingerprint)) { @@ -191,21 +198,24 @@ public class ImportKeysActivity extends BaseActivity { return; } break; - case ACTION_IMPORT_KEY_FROM_FILE: + } + case ACTION_IMPORT_KEY_FROM_FILE: { // NOTE: this only displays the appropriate fragment, no actions are taken startFileFragment(savedInstanceState); // no immediate actions! startListFragment(savedInstanceState, null, null, null); break; - case ACTION_IMPORT_KEY_FROM_FILE_AND_RETURN: + } + case ACTION_IMPORT_KEY_FROM_FILE_AND_RETURN: { // NOTE: this only displays the appropriate fragment, no actions are taken startFileFragment(savedInstanceState); // no immediate actions! startListFragment(savedInstanceState, null, null, null); break; - case ACTION_IMPORT_KEY_FROM_NFC: + } + case ACTION_IMPORT_KEY_FROM_NFC: { // NOTE: this only displays the appropriate fragment, no actions are taken startFileFragment(savedInstanceState); // TODO!!!!! @@ -213,14 +223,15 @@ public class ImportKeysActivity extends BaseActivity { // no immediate actions! startListFragment(savedInstanceState, null, null, null); break; - default: + } + default: { startCloudFragment(savedInstanceState, null, false); startListFragment(savedInstanceState, null, null, null); break; + } } } - private void startListFragment(Bundle savedInstanceState, byte[] bytes, Uri dataUri, String serverQuery) { // However, if we're being restored from a previous state, // then we don't need to do anything and should return or else -- cgit v1.2.3 From 6c6201f1292951fdc25b355c1693045d94186ff2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Tue, 27 Jan 2015 17:13:54 +0100 Subject: Fix cleartext signatures internally --- .../keychain/service/KeychainIntentService.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java index 515711d1f..264b45035 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -428,7 +428,7 @@ public class KeychainIntentService extends IntentService implements Progressable case ACTION_SIGN_ENCRYPT: try { - /* Input */ + /* Input */ int source = data.get(SOURCE) != null ? data.getInt(SOURCE) : data.getInt(TARGET); Bundle resultData = new Bundle(); @@ -450,11 +450,12 @@ public class KeychainIntentService extends IntentService implements Progressable OutputStream outStream = createCryptOutputStream(data); String originalFilename = getOriginalFilename(data); - /* Operation */ + /* Operation */ PgpSignEncrypt.Builder builder = new PgpSignEncrypt.Builder( this, new ProviderHelper(this), this, inputData, outStream ); builder.setEnableAsciiArmorOutput(useAsciiArmor) + .setCleartextSignature(true) .setVersionHeader(PgpHelper.getVersionForHeader(this)) .setCompressionId(compressionId) .setSymmetricEncryptionAlgorithm( @@ -491,10 +492,8 @@ public class KeychainIntentService extends IntentService implements Progressable outStream.close(); - /* Output */ - + /* Output */ finalizeEncryptOutputStream(data, resultData, outStream); - } Log.logDebugBundle(resultData, "resultData"); -- cgit v1.2.3 From 43930ed8f2d890585b5b85cd963d4f564cdb736f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Thu, 29 Jan 2015 10:10:07 +0100 Subject: Move key list logic into fragment, UI fixes for nav drawer --- .../org/sufficientlysecure/keychain/Constants.java | 7 +- .../remote/ui/AccountSettingsActivity.java | 3 - .../keychain/remote/ui/AppSettingsActivity.java | 7 - .../keychain/remote/ui/AppsListActivity.java | 47 ---- .../keychain/ui/FirstTimeActivity.java | 2 +- .../keychain/ui/KeyListActivity.java | 237 --------------------- .../keychain/ui/MainActivity.java | 52 +++++ .../keychain/ui/NavDrawerActivity.java | 2 +- .../keychain/ui/SafeSlingerActivity.java | 2 +- .../keychain/ui/ViewKeyActivity.java | 2 +- 10 files changed, 59 insertions(+), 302 deletions(-) delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppsListActivity.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java index 04a932658..b3b433a63 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java @@ -20,11 +20,10 @@ package org.sufficientlysecure.keychain; import android.os.Environment; import org.spongycastle.jce.provider.BouncyCastleProvider; -import org.sufficientlysecure.keychain.remote.ui.AppsListActivity; import org.sufficientlysecure.keychain.ui.DecryptActivity; import org.sufficientlysecure.keychain.ui.EncryptFilesActivity; import org.sufficientlysecure.keychain.ui.EncryptTextActivity; -import org.sufficientlysecure.keychain.ui.KeyListActivity; +import org.sufficientlysecure.keychain.ui.MainActivity; import java.io.File; @@ -92,11 +91,11 @@ public final class Constants { } public static final class DrawerItems { - public static final Class KEY_LIST = KeyListActivity.class; + public static final Class KEY_LIST = MainActivity.class; public static final Class ENCRYPT_TEXT = EncryptTextActivity.class; public static final Class ENCRYPT_FILE = EncryptFilesActivity.class; public static final Class DECRYPT = DecryptActivity.class; - public static final Class REGISTERED_APPS_LIST = AppsListActivity.class; + public static final Class REGISTERED_APPS_LIST = MainActivity.class; public static final Class[] ARRAY = new Class[]{ KEY_LIST, ENCRYPT_TEXT, diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsActivity.java index e5edd6a0f..f4cd553d0 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsActivity.java @@ -92,9 +92,6 @@ public class AccountSettingsActivity extends BaseActivity { case R.id.menu_account_settings_delete: deleteAccount(); return true; - case R.id.menu_account_settings_cancel: - finish(); - return true; } return super.onOptionsItemSelected(item); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java index e91482e28..36d6ad888 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java @@ -47,13 +47,6 @@ public class AppSettingsActivity extends BaseActivity { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - // let the actionbar look like Android's contact app -// ActionBar actionBar = getSupportActionBar(); -// actionBar.setDisplayHomeAsUpEnabled(true); -// actionBar.setIcon(android.R.color.transparent); -// actionBar.setHomeButtonEnabled(true); - - mSettingsFragment = (AppSettingsFragment) getSupportFragmentManager().findFragmentById( R.id.api_app_settings_fragment); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppsListActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppsListActivity.java deleted file mode 100644 index 3b4cc654e..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppsListActivity.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2013-2014 Dominik Schürmann - * - * 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 . - */ - -package org.sufficientlysecure.keychain.remote.ui; - -import android.os.Bundle; - -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.ui.DrawerActivity; -import org.sufficientlysecure.keychain.ui.NavDrawerActivity; - -public class AppsListActivity extends NavDrawerActivity { - -// @Override -// protected void onCreate(Bundle savedInstanceState) { -// super.onCreate(savedInstanceState); -// -// activateDrawerNavigation(savedInstanceState); -// } - - @Override - public void init(Bundle savedInstanceState) { - super.init(savedInstanceState); - setContentView(R.layout.api_apps_list_activity); - } - - -// @Override -// protected void initLayout() { -// setContentView(R.layout.api_apps_list_activity); -// } - -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/FirstTimeActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/FirstTimeActivity.java index ce2a049f5..4e51c62d2 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/FirstTimeActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/FirstTimeActivity.java @@ -92,7 +92,7 @@ public class FirstTimeActivity extends BaseActivity { private void finishSetup(Intent srcData) { Preferences prefs = Preferences.getPreferences(this); prefs.setFirstTime(false); - Intent intent = new Intent(this, KeyListActivity.class); + Intent intent = new Intent(this, MainActivity.class); // give intent through to display notify if (srcData != null) { intent.putExtras(srcData); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java deleted file mode 100644 index b7f3588eb..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListActivity.java +++ /dev/null @@ -1,237 +0,0 @@ -/* - * Copyright (C) 2012-2014 Dominik Schürmann - * Copyright (C) 2014 Vincent Breitmoser - * - * 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 . - */ - -package org.sufficientlysecure.keychain.ui; - -import android.app.ProgressDialog; -import android.content.Intent; -import android.os.Bundle; -import android.os.Message; -import android.os.Messenger; -import android.view.Menu; -import android.view.MenuItem; - -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.operations.results.ConsolidateResult; -import org.sufficientlysecure.keychain.operations.results.OperationResult; -import org.sufficientlysecure.keychain.provider.KeychainContract; -import org.sufficientlysecure.keychain.provider.KeychainDatabase; -import org.sufficientlysecure.keychain.service.KeychainIntentService; -import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; -import org.sufficientlysecure.keychain.ui.util.Notify; -import org.sufficientlysecure.keychain.util.ExportHelper; -import org.sufficientlysecure.keychain.util.Log; -import org.sufficientlysecure.keychain.util.Preferences; - -import java.io.IOException; - -import it.neokree.materialnavigationdrawer.MaterialNavigationDrawer; - -public class KeyListActivity extends NavDrawerActivity { - - public static final int REQUEST_CODE_RESULT_TO_LIST = 1; - - ExportHelper mExportHelper; - - @Override -// public void onCreate(Bundle savedInstanceState) { - public void init(Bundle savedInstanceState) { - super.init(savedInstanceState); -// super.onCreate(savedInstanceState); -// setActionBarIcon(R.drawable.ic_ab_drawer); - - setTitle(R.string.nav_keys); - - // if this is the first time show first time activity - Preferences prefs = Preferences.getPreferences(this); - if (prefs.isFirstTime()) { - startActivity(new Intent(this, FirstTimeActivity.class)); - finish(); - return; - } - - mExportHelper = new ExportHelper(this); - - Intent data = getIntent(); - // If we got an EXTRA_RESULT in the intent, show the notification - if (data != null && data.hasExtra(OperationResult.EXTRA_RESULT)) { - OperationResult result = data.getParcelableExtra(OperationResult.EXTRA_RESULT); - result.createNotify(this).show(); - } - - // now setup navigation drawer in DrawerActivity... -// activateDrawerNavigation(savedInstanceState); - } - -// @Override -// protected void initLayout() { -// setContentView(R.layout.key_list_activity); -// } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - super.onCreateOptionsMenu(menu); - getMenuInflater().inflate(R.menu.key_list, menu); - - if (Constants.DEBUG) { - menu.findItem(R.id.menu_key_list_debug_cons).setVisible(true); - menu.findItem(R.id.menu_key_list_debug_read).setVisible(true); - menu.findItem(R.id.menu_key_list_debug_write).setVisible(true); - menu.findItem(R.id.menu_key_list_debug_first_time).setVisible(true); - } - - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.menu_key_list_add: - Intent scanQrCode = new Intent(this, QrCodeScanActivity.class); - scanQrCode.setAction(QrCodeScanActivity.ACTION_SCAN_WITH_RESULT); - startActivityForResult(scanQrCode, 0); - return true; - - case R.id.menu_key_list_search_cloud: - searchCloud(); - return true; - - case R.id.menu_key_list_create: - createKey(); - return true; - - case R.id.menu_key_list_import_existing_key: - Intent intentImportExisting = new Intent(this, ImportKeysActivity.class); - intentImportExisting.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_FILE_AND_RETURN); - startActivityForResult(intentImportExisting, 0); - return true; - - case R.id.menu_key_list_export: - mExportHelper.showExportKeysDialog(null, Constants.Path.APP_DIR_FILE, true); - return true; - - case R.id.menu_key_list_debug_cons: - consolidate(); - return true; - - case R.id.menu_key_list_debug_read: - try { - KeychainDatabase.debugBackup(this, true); - Notify.showNotify(this, "Restored debug_backup.db", Notify.Style.INFO); - getContentResolver().notifyChange(KeychainContract.KeyRings.CONTENT_URI, null); - } catch (IOException e) { - Log.e(Constants.TAG, "IO Error", e); - Notify.showNotify(this, "IO Error " + e.getMessage(), Notify.Style.ERROR); - } - return true; - - case R.id.menu_key_list_debug_write: - try { - KeychainDatabase.debugBackup(this, false); - Notify.showNotify(this, "Backup to debug_backup.db completed", Notify.Style.INFO); - } catch (IOException e) { - Log.e(Constants.TAG, "IO Error", e); - Notify.showNotify(this, "IO Error: " + e.getMessage(), Notify.Style.ERROR); - } - return true; - - case R.id.menu_key_list_debug_first_time: - Preferences prefs = Preferences.getPreferences(this); - prefs.setFirstTime(true); - Intent intent = new Intent(this, FirstTimeActivity.class); - startActivity(intent); - finish(); - return true; - - default: - return super.onOptionsItemSelected(item); - } - } - - private void searchCloud() { - Intent importIntent = new Intent(this, ImportKeysActivity.class); - importIntent.putExtra(ImportKeysActivity.EXTRA_QUERY, (String) null); // hack to show only cloud tab - startActivity(importIntent); - } - - private void createKey() { - Intent intent = new Intent(this, CreateKeyActivity.class); - startActivityForResult(intent, 0); - } - - private void consolidate() { - // Message is received after importing is done in KeychainIntentService - KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler( - this, - getString(R.string.progress_importing), - ProgressDialog.STYLE_HORIZONTAL) { - public void handleMessage(Message message) { - // handle messages by standard KeychainIntentServiceHandler first - super.handleMessage(message); - - if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) { - // get returned data bundle - Bundle returnData = message.getData(); - if (returnData == null) { - return; - } - final ConsolidateResult result = - returnData.getParcelable(OperationResult.EXTRA_RESULT); - if (result == null) { - return; - } - - result.createNotify(KeyListActivity.this).show(); - } - } - }; - - // Send all information needed to service to import key in other thread - Intent intent = new Intent(this, KeychainIntentService.class); - - intent.setAction(KeychainIntentService.ACTION_CONSOLIDATE); - - // fill values for this action - Bundle data = new Bundle(); - - intent.putExtra(KeychainIntentService.EXTRA_DATA, data); - - // Create a new Messenger for the communication back - Messenger messenger = new Messenger(saveHandler); - intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger); - - // show progress dialog - saveHandler.showProgressDialog(this); - - // start service with intent - startService(intent); - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - // if a result has been returned, display a notify - if (data != null && data.hasExtra(OperationResult.EXTRA_RESULT)) { - OperationResult result = data.getParcelableExtra(OperationResult.EXTRA_RESULT); - result.createNotify(this).show(); - } else { - super.onActivityResult(requestCode, resultCode, data); - } - } - -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java new file mode 100644 index 000000000..f3bf337c9 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2012-2014 Dominik Schürmann + * Copyright (C) 2014 Vincent Breitmoser + * + * 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 . + */ + +package org.sufficientlysecure.keychain.ui; + +import android.content.Intent; +import android.os.Bundle; + +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.operations.results.OperationResult; +import org.sufficientlysecure.keychain.util.Preferences; + +public class MainActivity extends NavDrawerActivity { + + @Override + public void init(Bundle savedInstanceState) { + super.init(savedInstanceState); + + setTitle(R.string.nav_keys); + + // if this is the first time show first time activity + Preferences prefs = Preferences.getPreferences(this); + if (prefs.isFirstTime()) { + startActivity(new Intent(this, FirstTimeActivity.class)); + finish(); + return; + } + + Intent data = getIntent(); + // If we got an EXTRA_RESULT in the intent, show the notification + if (data != null && data.hasExtra(OperationResult.EXTRA_RESULT)) { + OperationResult result = data.getParcelableExtra(OperationResult.EXTRA_RESULT); + result.createNotify(this).show(); + } + } + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NavDrawerActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NavDrawerActivity.java index 5381b1ab3..57910af5e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NavDrawerActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NavDrawerActivity.java @@ -23,7 +23,6 @@ import android.view.LayoutInflater; import android.view.View; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.remote.ui.AppsListActivity; import org.sufficientlysecure.keychain.remote.ui.AppsListFragment; import it.neokree.materialnavigationdrawer.MaterialNavigationDrawer; @@ -52,5 +51,6 @@ public abstract class NavDrawerActivity extends MaterialNavigationDrawer { // create bottom section addBottomSection(newSection(getString(R.string.menu_preferences), R.drawable.ic_settings_black_24dp, new Intent(this, SettingsActivity.class))); + addBottomSection(newSection(getString(R.string.menu_help), R.drawable.ic_help_black_24dp, new Intent(this, HelpActivity.class))); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SafeSlingerActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SafeSlingerActivity.java index f95644aff..d1df2906d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SafeSlingerActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SafeSlingerActivity.java @@ -163,7 +163,7 @@ public class SafeSlingerActivity extends BaseActivity { certifyIntent.putExtra(CertifyKeyActivity.EXTRA_RESULT, result); certifyIntent.putExtra(CertifyKeyActivity.EXTRA_KEY_IDS, result.getImportedMasterKeyIds()); certifyIntent.putExtra(CertifyKeyActivity.EXTRA_CERTIFY_KEY_ID, mMasterKeyId); - startActivityForResult(certifyIntent, KeyListActivity.REQUEST_CODE_RESULT_TO_LIST); + startActivityForResult(certifyIntent, 0); // mExchangeMasterKeyId = null; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java index 3bb0695a0..575df01b7 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java @@ -188,7 +188,7 @@ public class ViewKeyActivity extends BaseActivity implements try { switch (item.getItemId()) { case android.R.id.home: { - Intent homeIntent = new Intent(this, KeyListActivity.class); + Intent homeIntent = new Intent(this, MainActivity.class); homeIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); startActivity(homeIntent); return true; -- cgit v1.2.3 From c4ef86b38a5c8b98e5ee2934e0a0c1184f2baf07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Thu, 29 Jan 2015 12:03:00 +0100 Subject: Refactor DecryptActivity into DecryptOverviewFragment for nav drawer --- .../org/sufficientlysecure/keychain/Constants.java | 3 +- .../keychain/ui/DecryptActivity.java | 128 -------------------- .../keychain/ui/DecryptOverviewFragment.java | 130 +++++++++++++++++++++ .../keychain/ui/NavDrawerActivity.java | 2 +- 4 files changed, 132 insertions(+), 131 deletions(-) delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptOverviewFragment.java (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java index b3b433a63..6c3e702c5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java @@ -20,7 +20,6 @@ package org.sufficientlysecure.keychain; import android.os.Environment; import org.spongycastle.jce.provider.BouncyCastleProvider; -import org.sufficientlysecure.keychain.ui.DecryptActivity; import org.sufficientlysecure.keychain.ui.EncryptFilesActivity; import org.sufficientlysecure.keychain.ui.EncryptTextActivity; import org.sufficientlysecure.keychain.ui.MainActivity; @@ -94,7 +93,7 @@ public final class Constants { public static final Class KEY_LIST = MainActivity.class; public static final Class ENCRYPT_TEXT = EncryptTextActivity.class; public static final Class ENCRYPT_FILE = EncryptFilesActivity.class; - public static final Class DECRYPT = DecryptActivity.class; + public static final Class DECRYPT = MainActivity.class; public static final Class REGISTERED_APPS_LIST = MainActivity.class; public static final Class[] ARRAY = new Class[]{ KEY_LIST, diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java deleted file mode 100644 index 21377bcd2..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptActivity.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright (C) 2014 Dominik Schürmann - * Copyright (C) 2014 Vincent Breitmoser - * - * 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 . - */ - -package org.sufficientlysecure.keychain.ui; - -import android.annotation.TargetApi; -import android.content.Intent; -import android.os.AsyncTask; -import android.os.Build; -import android.os.Build.VERSION_CODES; -import android.os.Bundle; -import android.view.View; - -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.compatibility.ClipboardReflection; -import org.sufficientlysecure.keychain.pgp.PgpHelper; -import org.sufficientlysecure.keychain.operations.results.OperationResult; -import org.sufficientlysecure.keychain.ui.util.SubtleAttentionSeeker; - -import java.util.regex.Matcher; - -public class DecryptActivity extends BaseActivity { - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - -// activateDrawerNavigation(savedInstanceState); - - View actionFile = findViewById(R.id.decrypt_files); - View actionFromClipboard = findViewById(R.id.decrypt_from_clipboard); - - actionFile.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - Intent filesDecrypt = new Intent(DecryptActivity.this, DecryptFilesActivity.class); - filesDecrypt.setAction(DecryptFilesActivity.ACTION_DECRYPT_DATA_OPEN); - startActivity(filesDecrypt); - } - }); - - actionFromClipboard.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - Intent clipboardDecrypt = new Intent(DecryptActivity.this, DecryptTextActivity.class); - clipboardDecrypt.setAction(DecryptTextActivity.ACTION_DECRYPT_FROM_CLIPBOARD); - startActivityForResult(clipboardDecrypt, 0); - } - }); - } - - @Override - protected void initLayout() { - setContentView(R.layout.decrypt_activity); - } - - @TargetApi(VERSION_CODES.HONEYCOMB) - @Override - protected void onResume() { - super.onResume(); - - // This is an eye candy ice cream sandwich feature, nvm on versions below - if (Build.VERSION.SDK_INT >= VERSION_CODES.ICE_CREAM_SANDWICH) { - - // get text from clipboard - final CharSequence clipboardText = - ClipboardReflection.getClipboardText(DecryptActivity.this); - - // if it's null, nothing to do here /o/ - if (clipboardText == null) { - return; - } - - new AsyncTask() { - @Override - protected Boolean doInBackground(String... clipboardText) { - - // see if it looks like a pgp thing - Matcher matcher = PgpHelper.PGP_MESSAGE.matcher(clipboardText[0]); - boolean animate = matcher.matches(); - - // see if it looks like another pgp thing - if (!animate) { - matcher = PgpHelper.PGP_CLEARTEXT_SIGNATURE.matcher(clipboardText[0]); - animate = matcher.matches(); - } - return animate; - } - - @Override - protected void onPostExecute(Boolean animate) { - super.onPostExecute(animate); - - // if so, animate the clipboard icon just a bit~ - if (animate) { - SubtleAttentionSeeker.tada(findViewById(R.id.clipboard_icon), 1.5f).start(); - } - } - }.execute(clipboardText.toString()); - } - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - // if a result has been returned, display a notify - if (data != null && data.hasExtra(OperationResult.EXTRA_RESULT)) { - OperationResult result = data.getParcelableExtra(OperationResult.EXTRA_RESULT); - result.createNotify(this).show(); - } else { - super.onActivityResult(requestCode, resultCode, data); - } - } -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptOverviewFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptOverviewFragment.java new file mode 100644 index 000000000..8407a8ca7 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptOverviewFragment.java @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2014-2015 Dominik Schürmann + * Copyright (C) 2014 Vincent Breitmoser + * + * 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 . + */ + +package org.sufficientlysecure.keychain.ui; + +import android.content.Intent; +import android.os.AsyncTask; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.compatibility.ClipboardReflection; +import org.sufficientlysecure.keychain.operations.results.OperationResult; +import org.sufficientlysecure.keychain.pgp.PgpHelper; +import org.sufficientlysecure.keychain.ui.util.SubtleAttentionSeeker; + +import java.util.regex.Matcher; + +public class DecryptOverviewFragment extends Fragment { + + View mActionFile; + View mActionFromClipboard; + View mClipboardIcon; + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + } + + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.decrypt_overview_fragment, container, false); + + mActionFile = view.findViewById(R.id.decrypt_files); + mActionFromClipboard = view.findViewById(R.id.decrypt_from_clipboard); + mClipboardIcon = view.findViewById(R.id.clipboard_icon); + + mActionFile.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent filesDecrypt = new Intent(getActivity(), DecryptFilesActivity.class); + filesDecrypt.setAction(DecryptFilesActivity.ACTION_DECRYPT_DATA_OPEN); + startActivity(filesDecrypt); + } + }); + + mActionFromClipboard.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent clipboardDecrypt = new Intent(getActivity(), DecryptTextActivity.class); + clipboardDecrypt.setAction(DecryptTextActivity.ACTION_DECRYPT_FROM_CLIPBOARD); + startActivityForResult(clipboardDecrypt, 0); + } + }); + + return view; + } + + @Override + public void onResume() { + super.onResume(); + + // get text from clipboard + final CharSequence clipboardText = + ClipboardReflection.getClipboardText(getActivity()); + + // if it's null, nothing to do here /o/ + if (clipboardText == null) { + return; + } + + new AsyncTask() { + @Override + protected Boolean doInBackground(String... clipboardText) { + + // see if it looks like a pgp thing + Matcher matcher = PgpHelper.PGP_MESSAGE.matcher(clipboardText[0]); + boolean animate = matcher.matches(); + + // see if it looks like another pgp thing + if (!animate) { + matcher = PgpHelper.PGP_CLEARTEXT_SIGNATURE.matcher(clipboardText[0]); + animate = matcher.matches(); + } + return animate; + } + + @Override + protected void onPostExecute(Boolean animate) { + super.onPostExecute(animate); + + // if so, animate the clipboard icon just a bit~ + if (animate) { + SubtleAttentionSeeker.tada(mClipboardIcon, 1.5f).start(); + } + } + }.execute(clipboardText.toString()); + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + // if a result has been returned, display a notify + if (data != null && data.hasExtra(OperationResult.EXTRA_RESULT)) { + OperationResult result = data.getParcelableExtra(OperationResult.EXTRA_RESULT); + result.createNotify(getActivity()).show(); + } else { + super.onActivityResult(requestCode, resultCode, data); + } + } +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NavDrawerActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NavDrawerActivity.java index 57910af5e..200ee382b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NavDrawerActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NavDrawerActivity.java @@ -46,7 +46,7 @@ public abstract class NavDrawerActivity extends MaterialNavigationDrawer { addSection(newSection(getString(R.string.title_encrypt_text), R.drawable.ic_lock_outline_black_24dp, new Intent(this, EncryptTextActivity.class))); addSection(newSection(getString(R.string.title_encrypt_files), R.drawable.ic_lock_outline_black_24dp, new Intent(this, EncryptFilesActivity.class))); - addSection(newSection(getString(R.string.title_decrypt), R.drawable.ic_lock_open_black_24dp, new Intent(this, DecryptActivity.class))); + addSection(newSection(getString(R.string.title_decrypt), R.drawable.ic_lock_open_black_24dp, new DecryptOverviewFragment())); addSection(newSection(getString(R.string.title_api_registered_apps), R.drawable.ic_apps_black_24dp, new AppsListFragment())); // create bottom section -- cgit v1.2.3 From a346b58db720c78c83714a0c5b1780029753dbd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Thu, 29 Jan 2015 12:44:06 +0100 Subject: Close FileDescriptors and input, output streams when possible --- .../keychain/remote/OpenPgpService.java | 620 +++++++++++---------- 1 file changed, 335 insertions(+), 285 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java index d967931ce..d4f1e248c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java @@ -55,6 +55,7 @@ import org.sufficientlysecure.keychain.ui.ViewKeyActivity; import org.sufficientlysecure.keychain.util.InputData; import org.sufficientlysecure.keychain.util.Log; +import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; @@ -224,6 +225,8 @@ public class OpenPgpService extends RemoteService { private Intent signImpl(Intent data, ParcelFileDescriptor input, ParcelFileDescriptor output, AccountSettings accSettings, boolean cleartextSign) { + InputStream is = null; + OutputStream os = null; try { boolean asciiArmor = cleartextSign || data.getBooleanExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true); @@ -243,96 +246,88 @@ public class OpenPgpService extends RemoteService { } // Get Input- and OutputStream from ParcelFileDescriptor - InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(input); - OutputStream os = null; + is = new ParcelFileDescriptor.AutoCloseInputStream(input); if (cleartextSign) { // output stream only needed for cleartext signatures, // detached signatures are returned as extra os = new ParcelFileDescriptor.AutoCloseOutputStream(output); } + long inputLength = is.available(); + InputData inputData = new InputData(is, inputLength); + + // Find the appropriate subkey to sign with + long sigSubKeyId; try { - long inputLength = is.available(); - InputData inputData = new InputData(is, inputLength); + CachedPublicKeyRing signingRing = + new ProviderHelper(this).getCachedPublicKeyRing(accSettings.getKeyId()); + sigSubKeyId = signingRing.getSecretSignId(); + } catch (PgpKeyNotFoundException e) { + // secret key that is set for this account is deleted? + // show account config again! + return getCreateAccountIntent(data, getAccountName(data)); + } - // Find the appropriate subkey to sign with - long sigSubKeyId; + // get passphrase from cache, if key has "no" passphrase, this returns an empty String + String passphrase; + if (data.hasExtra(OpenPgpApi.EXTRA_PASSPHRASE)) { + passphrase = data.getStringExtra(OpenPgpApi.EXTRA_PASSPHRASE); + } else { try { - CachedPublicKeyRing signingRing = - new ProviderHelper(this).getCachedPublicKeyRing(accSettings.getKeyId()); - sigSubKeyId = signingRing.getSecretSignId(); - } catch (PgpKeyNotFoundException e) { - // secret key that is set for this account is deleted? - // show account config again! + passphrase = PassphraseCacheService.getCachedPassphrase(getContext(), + accSettings.getKeyId(), sigSubKeyId); + } catch (PassphraseCacheService.KeyNotFoundException e) { + // should happen earlier, but return again here if it happens return getCreateAccountIntent(data, getAccountName(data)); } + } + if (passphrase == null) { + // get PendingIntent for passphrase input, add it to given params and return to client + return getPassphraseIntent(data, sigSubKeyId); + } - // get passphrase from cache, if key has "no" passphrase, this returns an empty String - String passphrase; - if (data.hasExtra(OpenPgpApi.EXTRA_PASSPHRASE)) { - passphrase = data.getStringExtra(OpenPgpApi.EXTRA_PASSPHRASE); - } else { - try { - passphrase = PassphraseCacheService.getCachedPassphrase(getContext(), - accSettings.getKeyId(), sigSubKeyId); - } catch (PassphraseCacheService.KeyNotFoundException e) { - // should happen earlier, but return again here if it happens - return getCreateAccountIntent(data, getAccountName(data)); - } - } - if (passphrase == null) { - // get PendingIntent for passphrase input, add it to given params and return to client - return getPassphraseIntent(data, sigSubKeyId); - } - - // sign-only - PgpSignEncrypt.Builder builder = new PgpSignEncrypt.Builder( - this, new ProviderHelper(getContext()), null, - inputData, os - ); - builder.setEnableAsciiArmorOutput(asciiArmor) - .setCleartextSignature(cleartextSign) - .setDetachedSignature(!cleartextSign) - .setVersionHeader(PgpHelper.getVersionForHeader(this)) - .setSignatureHashAlgorithm(accSettings.getHashAlgorithm()) - .setSignatureMasterKeyId(accSettings.getKeyId()) - .setSignatureSubKeyId(sigSubKeyId) - .setSignaturePassphrase(passphrase) - .setNfcState(nfcSignedHash, nfcCreationDate); - - // execute PGP operation! - SignEncryptResult pgpResult = builder.build().execute(); - - if (pgpResult.isPending()) { - if ((pgpResult.getResult() & SignEncryptResult.RESULT_PENDING_PASSPHRASE) == - SignEncryptResult.RESULT_PENDING_PASSPHRASE) { - return getPassphraseIntent(data, pgpResult.getKeyIdPassphraseNeeded()); - } else if ((pgpResult.getResult() & SignEncryptResult.RESULT_PENDING_NFC) == - SignEncryptResult.RESULT_PENDING_NFC) { - // return PendingIntent to execute NFC activity - // pass through the signature creation timestamp to be used again on second execution - // of PgpSignEncrypt when we have the signed hash! - data.putExtra(OpenPgpApi.EXTRA_NFC_SIG_CREATION_TIMESTAMP, pgpResult.getNfcTimestamp().getTime()); - return getNfcSignIntent(data, pgpResult.getNfcKeyId(), pgpResult.getNfcPassphrase(), pgpResult.getNfcHash(), pgpResult.getNfcAlgo()); - } else { - throw new PgpGeneralException( - "Encountered unhandled type of pending action not supported by API!"); - } - } else if (pgpResult.success()) { - Intent result = new Intent(); - if (!cleartextSign) { - result.putExtra(OpenPgpApi.RESULT_DETACHED_SIGNATURE, pgpResult.getDetachedSignature()); - } - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS); - return result; + // sign-only + PgpSignEncrypt.Builder builder = new PgpSignEncrypt.Builder( + this, new ProviderHelper(getContext()), null, + inputData, os + ); + builder.setEnableAsciiArmorOutput(asciiArmor) + .setCleartextSignature(cleartextSign) + .setDetachedSignature(!cleartextSign) + .setVersionHeader(PgpHelper.getVersionForHeader(this)) + .setSignatureHashAlgorithm(accSettings.getHashAlgorithm()) + .setSignatureMasterKeyId(accSettings.getKeyId()) + .setSignatureSubKeyId(sigSubKeyId) + .setSignaturePassphrase(passphrase) + .setNfcState(nfcSignedHash, nfcCreationDate); + + // execute PGP operation! + SignEncryptResult pgpResult = builder.build().execute(); + + if (pgpResult.isPending()) { + if ((pgpResult.getResult() & SignEncryptResult.RESULT_PENDING_PASSPHRASE) == + SignEncryptResult.RESULT_PENDING_PASSPHRASE) { + return getPassphraseIntent(data, pgpResult.getKeyIdPassphraseNeeded()); + } else if ((pgpResult.getResult() & SignEncryptResult.RESULT_PENDING_NFC) == + SignEncryptResult.RESULT_PENDING_NFC) { + // return PendingIntent to execute NFC activity + // pass through the signature creation timestamp to be used again on second execution + // of PgpSignEncrypt when we have the signed hash! + data.putExtra(OpenPgpApi.EXTRA_NFC_SIG_CREATION_TIMESTAMP, pgpResult.getNfcTimestamp().getTime()); + return getNfcSignIntent(data, pgpResult.getNfcKeyId(), pgpResult.getNfcPassphrase(), pgpResult.getNfcHash(), pgpResult.getNfcAlgo()); } else { - LogEntryParcel errorMsg = pgpResult.getLog().getLast(); - throw new Exception(getString(errorMsg.mType.getMsgId())); + throw new PgpGeneralException( + "Encountered unhandled type of pending action not supported by API!"); } - } finally { - is.close(); - if (os != null) { - os.close(); + } else if (pgpResult.success()) { + Intent result = new Intent(); + if (!cleartextSign) { + result.putExtra(OpenPgpApi.RESULT_DETACHED_SIGNATURE, pgpResult.getDetachedSignature()); } + result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS); + return result; + } else { + LogEntryParcel errorMsg = pgpResult.getLog().getLast(); + throw new Exception(getString(errorMsg.mType.getMsgId())); } } catch (Exception e) { Log.d(Constants.TAG, "signImpl", e); @@ -341,12 +336,29 @@ public class OpenPgpService extends RemoteService { new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage())); result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR); return result; + } finally { + if (is != null) { + try { + is.close(); + } catch (IOException e) { + Log.e(Constants.TAG, "IOException when closing InputStream", e); + } + } + if (os != null) { + try { + os.close(); + } catch (IOException e) { + Log.e(Constants.TAG, "IOException when closing OutputStream", e); + } + } } } private Intent encryptAndSignImpl(Intent data, ParcelFileDescriptor input, ParcelFileDescriptor output, AccountSettings accSettings, boolean sign) { + InputStream is = null; + OutputStream os = null; try { boolean asciiArmor = data.getBooleanExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true); String originalFilename = data.getStringExtra(OpenPgpApi.EXTRA_ORIGINAL_FILENAME); @@ -372,96 +384,91 @@ public class OpenPgpService extends RemoteService { // build InputData and write into OutputStream // Get Input- and OutputStream from ParcelFileDescriptor - InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(input); - OutputStream os = new ParcelFileDescriptor.AutoCloseOutputStream(output); - try { - long inputLength = is.available(); - InputData inputData = new InputData(is, inputLength); - - PgpSignEncrypt.Builder builder = new PgpSignEncrypt.Builder( - this, new ProviderHelper(getContext()), null, inputData, os - ); - builder.setEnableAsciiArmorOutput(asciiArmor) - .setVersionHeader(PgpHelper.getVersionForHeader(this)) - .setCompressionId(accSettings.getCompression()) - .setSymmetricEncryptionAlgorithm(accSettings.getEncryptionAlgorithm()) - .setEncryptionMasterKeyIds(keyIds) - .setFailOnMissingEncryptionKeyIds(true) - .setOriginalFilename(originalFilename) - .setAdditionalEncryptId(accSettings.getKeyId()); // add acc key for encryption - - if (sign) { - - // Find the appropriate subkey to sign with - long sigSubKeyId; - try { - CachedPublicKeyRing signingRing = - new ProviderHelper(this).getCachedPublicKeyRing(accSettings.getKeyId()); - sigSubKeyId = signingRing.getSecretSignId(); - } catch (PgpKeyNotFoundException e) { - // secret key that is set for this account is deleted? - // show account config again! - return getCreateAccountIntent(data, getAccountName(data)); - } + is = new ParcelFileDescriptor.AutoCloseInputStream(input); + os = new ParcelFileDescriptor.AutoCloseOutputStream(output); + + long inputLength = is.available(); + InputData inputData = new InputData(is, inputLength); + + PgpSignEncrypt.Builder builder = new PgpSignEncrypt.Builder( + this, new ProviderHelper(getContext()), null, inputData, os + ); + builder.setEnableAsciiArmorOutput(asciiArmor) + .setVersionHeader(PgpHelper.getVersionForHeader(this)) + .setCompressionId(accSettings.getCompression()) + .setSymmetricEncryptionAlgorithm(accSettings.getEncryptionAlgorithm()) + .setEncryptionMasterKeyIds(keyIds) + .setFailOnMissingEncryptionKeyIds(true) + .setOriginalFilename(originalFilename) + .setAdditionalEncryptId(accSettings.getKeyId()); // add acc key for encryption + + if (sign) { - String passphrase; - if (data.hasExtra(OpenPgpApi.EXTRA_PASSPHRASE)) { - passphrase = data.getStringExtra(OpenPgpApi.EXTRA_PASSPHRASE); - } else { - passphrase = PassphraseCacheService.getCachedPassphrase(getContext(), - accSettings.getKeyId(), sigSubKeyId); - } - if (passphrase == null) { - // get PendingIntent for passphrase input, add it to given params and return to client - return getPassphraseIntent(data, sigSubKeyId); - } + // Find the appropriate subkey to sign with + long sigSubKeyId; + try { + CachedPublicKeyRing signingRing = + new ProviderHelper(this).getCachedPublicKeyRing(accSettings.getKeyId()); + sigSubKeyId = signingRing.getSecretSignId(); + } catch (PgpKeyNotFoundException e) { + // secret key that is set for this account is deleted? + // show account config again! + return getCreateAccountIntent(data, getAccountName(data)); + } - byte[] nfcSignedHash = data.getByteArrayExtra(OpenPgpApi.EXTRA_NFC_SIGNED_HASH); - // carefully: only set if timestamp exists - Date nfcCreationDate = null; - long nfcCreationTimestamp = data.getLongExtra(OpenPgpApi.EXTRA_NFC_SIG_CREATION_TIMESTAMP, -1); - if (nfcCreationTimestamp != -1) { - nfcCreationDate = new Date(nfcCreationTimestamp); - } + String passphrase; + if (data.hasExtra(OpenPgpApi.EXTRA_PASSPHRASE)) { + passphrase = data.getStringExtra(OpenPgpApi.EXTRA_PASSPHRASE); + } else { + passphrase = PassphraseCacheService.getCachedPassphrase(getContext(), + accSettings.getKeyId(), sigSubKeyId); + } + if (passphrase == null) { + // get PendingIntent for passphrase input, add it to given params and return to client + return getPassphraseIntent(data, sigSubKeyId); + } - // sign and encrypt - builder.setSignatureHashAlgorithm(accSettings.getHashAlgorithm()) - .setSignatureMasterKeyId(accSettings.getKeyId()) - .setSignatureSubKeyId(sigSubKeyId) - .setSignaturePassphrase(passphrase) - .setNfcState(nfcSignedHash, nfcCreationDate); + byte[] nfcSignedHash = data.getByteArrayExtra(OpenPgpApi.EXTRA_NFC_SIGNED_HASH); + // carefully: only set if timestamp exists + Date nfcCreationDate = null; + long nfcCreationTimestamp = data.getLongExtra(OpenPgpApi.EXTRA_NFC_SIG_CREATION_TIMESTAMP, -1); + if (nfcCreationTimestamp != -1) { + nfcCreationDate = new Date(nfcCreationTimestamp); } - // execute PGP operation! - SignEncryptResult pgpResult = builder.build().execute(); - - if (pgpResult.isPending()) { - if ((pgpResult.getResult() & SignEncryptResult.RESULT_PENDING_PASSPHRASE) == - SignEncryptResult.RESULT_PENDING_PASSPHRASE) { - return getPassphraseIntent(data, pgpResult.getKeyIdPassphraseNeeded()); - } else if ((pgpResult.getResult() & SignEncryptResult.RESULT_PENDING_NFC) == - SignEncryptResult.RESULT_PENDING_NFC) { - // return PendingIntent to execute NFC activity - // pass through the signature creation timestamp to be used again on second execution - // of PgpSignEncrypt when we have the signed hash! - data.putExtra(OpenPgpApi.EXTRA_NFC_SIG_CREATION_TIMESTAMP, pgpResult.getNfcTimestamp().getTime()); - return getNfcSignIntent(data, pgpResult.getNfcKeyId(), pgpResult.getNfcPassphrase(), pgpResult.getNfcHash(), pgpResult.getNfcAlgo()); - } else { - throw new PgpGeneralException( - "Encountered unhandled type of pending action not supported by API!"); - } - } else if (pgpResult.success()) { - Intent result = new Intent(); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS); - return result; + // sign and encrypt + builder.setSignatureHashAlgorithm(accSettings.getHashAlgorithm()) + .setSignatureMasterKeyId(accSettings.getKeyId()) + .setSignatureSubKeyId(sigSubKeyId) + .setSignaturePassphrase(passphrase) + .setNfcState(nfcSignedHash, nfcCreationDate); + } + + // execute PGP operation! + SignEncryptResult pgpResult = builder.build().execute(); + + if (pgpResult.isPending()) { + if ((pgpResult.getResult() & SignEncryptResult.RESULT_PENDING_PASSPHRASE) == + SignEncryptResult.RESULT_PENDING_PASSPHRASE) { + return getPassphraseIntent(data, pgpResult.getKeyIdPassphraseNeeded()); + } else if ((pgpResult.getResult() & SignEncryptResult.RESULT_PENDING_NFC) == + SignEncryptResult.RESULT_PENDING_NFC) { + // return PendingIntent to execute NFC activity + // pass through the signature creation timestamp to be used again on second execution + // of PgpSignEncrypt when we have the signed hash! + data.putExtra(OpenPgpApi.EXTRA_NFC_SIG_CREATION_TIMESTAMP, pgpResult.getNfcTimestamp().getTime()); + return getNfcSignIntent(data, pgpResult.getNfcKeyId(), pgpResult.getNfcPassphrase(), pgpResult.getNfcHash(), pgpResult.getNfcAlgo()); } else { - LogEntryParcel errorMsg = pgpResult.getLog().getLast(); - throw new Exception(getString(errorMsg.mType.getMsgId())); + throw new PgpGeneralException( + "Encountered unhandled type of pending action not supported by API!"); } - - } finally { - is.close(); - os.close(); + } else if (pgpResult.success()) { + Intent result = new Intent(); + result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS); + return result; + } else { + LogEntryParcel errorMsg = pgpResult.getLog().getLast(); + throw new Exception(getString(errorMsg.mType.getMsgId())); } } catch (Exception e) { Log.d(Constants.TAG, "encryptAndSignImpl", e); @@ -470,17 +477,33 @@ public class OpenPgpService extends RemoteService { new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage())); result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR); return result; + } finally { + if (is != null) { + try { + is.close(); + } catch (IOException e) { + Log.e(Constants.TAG, "IOException when closing InputStream", e); + } + } + if (os != null) { + try { + os.close(); + } catch (IOException e) { + Log.e(Constants.TAG, "IOException when closing OutputStream", e); + } + } } } private Intent decryptAndVerifyImpl(Intent data, ParcelFileDescriptor input, ParcelFileDescriptor output, Set allowedKeyIds, boolean decryptMetadataOnly) { + InputStream is = null; + OutputStream os = null; try { // Get Input- and OutputStream from ParcelFileDescriptor - InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(input); + is = new ParcelFileDescriptor.AutoCloseInputStream(input); - OutputStream os; // output is optional, e.g., for verifying detached signatures if (decryptMetadataOnly || output == null) { os = null; @@ -488,101 +511,95 @@ public class OpenPgpService extends RemoteService { os = new ParcelFileDescriptor.AutoCloseOutputStream(output); } - try { - String passphrase = data.getStringExtra(OpenPgpApi.EXTRA_PASSPHRASE); - long inputLength = is.available(); - InputData inputData = new InputData(is, inputLength); - - PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder( - this, new ProviderHelper(getContext()), null, inputData, os - ); - - byte[] nfcDecryptedSessionKey = data.getByteArrayExtra(OpenPgpApi.EXTRA_NFC_DECRYPTED_SESSION_KEY); - - byte[] detachedSignature = data.getByteArrayExtra(OpenPgpApi.EXTRA_DETACHED_SIGNATURE); - - // allow only private keys associated with accounts of this app - // no support for symmetric encryption - builder.setPassphrase(passphrase) - .setAllowSymmetricDecryption(false) - .setAllowedKeyIds(allowedKeyIds) - .setDecryptMetadataOnly(decryptMetadataOnly) - .setNfcState(nfcDecryptedSessionKey) - .setDetachedSignature(detachedSignature); - - DecryptVerifyResult pgpResult = builder.build().execute(); - - if (pgpResult.isPending()) { - if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE) == - DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE) { - return getPassphraseIntent(data, pgpResult.getKeyIdPassphraseNeeded()); - } else if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_SYM_PASSPHRASE) == - DecryptVerifyResult.RESULT_PENDING_SYM_PASSPHRASE) { - throw new PgpGeneralException( - "Decryption of symmetric content not supported by API!"); - } else if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_NFC) == - DecryptVerifyResult.RESULT_PENDING_NFC) { - return getNfcDecryptIntent( - data, pgpResult.getNfcSubKeyId(), pgpResult.getNfcPassphrase(), pgpResult.getNfcEncryptedSessionKey()); - } else { - throw new PgpGeneralException( - "Encountered unhandled type of pending action not supported by API!"); - } - } else if (pgpResult.success()) { - Intent result = new Intent(); - - OpenPgpSignatureResult signatureResult = pgpResult.getSignatureResult(); - if (signatureResult != null) { - result.putExtra(OpenPgpApi.RESULT_SIGNATURE, signatureResult); - - if (data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) < 5) { - // SIGNATURE_KEY_REVOKED and SIGNATURE_KEY_EXPIRED have been added in version 5 - if (signatureResult.getStatus() == OpenPgpSignatureResult.SIGNATURE_KEY_REVOKED - || signatureResult.getStatus() == OpenPgpSignatureResult.SIGNATURE_KEY_EXPIRED) { - signatureResult.setStatus(OpenPgpSignatureResult.SIGNATURE_ERROR); - } - } - - if (signatureResult.getStatus() == OpenPgpSignatureResult.SIGNATURE_KEY_MISSING) { - // If signature is unknown we return an _additional_ PendingIntent - // to retrieve the missing key - Intent intent = new Intent(getBaseContext(), ImportKeysActivity.class); - intent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_TO_SERVICE); - intent.putExtra(ImportKeysActivity.EXTRA_KEY_ID, signatureResult.getKeyId()); - intent.putExtra(ImportKeysActivity.EXTRA_PENDING_INTENT_DATA, data); + String passphrase = data.getStringExtra(OpenPgpApi.EXTRA_PASSPHRASE); + long inputLength = is.available(); + InputData inputData = new InputData(is, inputLength); + + PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder( + this, new ProviderHelper(getContext()), null, inputData, os + ); + + byte[] nfcDecryptedSessionKey = data.getByteArrayExtra(OpenPgpApi.EXTRA_NFC_DECRYPTED_SESSION_KEY); + + byte[] detachedSignature = data.getByteArrayExtra(OpenPgpApi.EXTRA_DETACHED_SIGNATURE); + + // allow only private keys associated with accounts of this app + // no support for symmetric encryption + builder.setPassphrase(passphrase) + .setAllowSymmetricDecryption(false) + .setAllowedKeyIds(allowedKeyIds) + .setDecryptMetadataOnly(decryptMetadataOnly) + .setNfcState(nfcDecryptedSessionKey) + .setDetachedSignature(detachedSignature); + + DecryptVerifyResult pgpResult = builder.build().execute(); + + if (pgpResult.isPending()) { + if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE) == + DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE) { + return getPassphraseIntent(data, pgpResult.getKeyIdPassphraseNeeded()); + } else if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_SYM_PASSPHRASE) == + DecryptVerifyResult.RESULT_PENDING_SYM_PASSPHRASE) { + throw new PgpGeneralException( + "Decryption of symmetric content not supported by API!"); + } else if ((pgpResult.getResult() & DecryptVerifyResult.RESULT_PENDING_NFC) == + DecryptVerifyResult.RESULT_PENDING_NFC) { + return getNfcDecryptIntent( + data, pgpResult.getNfcSubKeyId(), pgpResult.getNfcPassphrase(), pgpResult.getNfcEncryptedSessionKey()); + } else { + throw new PgpGeneralException( + "Encountered unhandled type of pending action not supported by API!"); + } + } else if (pgpResult.success()) { + Intent result = new Intent(); - PendingIntent pi = PendingIntent.getActivity(getBaseContext(), 0, - intent, - PendingIntent.FLAG_CANCEL_CURRENT); + OpenPgpSignatureResult signatureResult = pgpResult.getSignatureResult(); + if (signatureResult != null) { + result.putExtra(OpenPgpApi.RESULT_SIGNATURE, signatureResult); - result.putExtra(OpenPgpApi.RESULT_INTENT, pi); + if (data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) < 5) { + // SIGNATURE_KEY_REVOKED and SIGNATURE_KEY_EXPIRED have been added in version 5 + if (signatureResult.getStatus() == OpenPgpSignatureResult.SIGNATURE_KEY_REVOKED + || signatureResult.getStatus() == OpenPgpSignatureResult.SIGNATURE_KEY_EXPIRED) { + signatureResult.setStatus(OpenPgpSignatureResult.SIGNATURE_ERROR); } } - if (data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) >= 4) { - OpenPgpMetadata metadata = pgpResult.getDecryptMetadata(); - if (metadata != null) { - result.putExtra(OpenPgpApi.RESULT_METADATA, metadata); - } - } + if (signatureResult.getStatus() == OpenPgpSignatureResult.SIGNATURE_KEY_MISSING) { + // If signature is unknown we return an _additional_ PendingIntent + // to retrieve the missing key + Intent intent = new Intent(getBaseContext(), ImportKeysActivity.class); + intent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_TO_SERVICE); + intent.putExtra(ImportKeysActivity.EXTRA_KEY_ID, signatureResult.getKeyId()); + intent.putExtra(ImportKeysActivity.EXTRA_PENDING_INTENT_DATA, data); - String charset = pgpResult.getCharset(); - if (charset != null) { - result.putExtra(OpenPgpApi.RESULT_CHARSET, charset); + PendingIntent pi = PendingIntent.getActivity(getBaseContext(), 0, + intent, + PendingIntent.FLAG_CANCEL_CURRENT); + + result.putExtra(OpenPgpApi.RESULT_INTENT, pi); } + } - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS); - return result; - } else { - LogEntryParcel errorMsg = pgpResult.getLog().getLast(); - throw new Exception(getString(errorMsg.mType.getMsgId())); + if (data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) >= 4) { + OpenPgpMetadata metadata = pgpResult.getDecryptMetadata(); + if (metadata != null) { + result.putExtra(OpenPgpApi.RESULT_METADATA, metadata); + } } - } finally { - is.close(); - if (os != null) { - os.close(); + + String charset = pgpResult.getCharset(); + if (charset != null) { + result.putExtra(OpenPgpApi.RESULT_CHARSET, charset); } + + result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS); + return result; + } else { + LogEntryParcel errorMsg = pgpResult.getLog().getLast(); + throw new Exception(getString(errorMsg.mType.getMsgId())); } + } catch (Exception e) { Log.d(Constants.TAG, "decryptAndVerifyImpl", e); Intent result = new Intent(); @@ -590,6 +607,21 @@ public class OpenPgpService extends RemoteService { new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage())); result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR); return result; + } finally { + if (is != null) { + try { + is.close(); + } catch (IOException e) { + Log.e(Constants.TAG, "IOException when closing InputStream", e); + } + } + if (os != null) { + try { + os.close(); + } catch (IOException e) { + Log.e(Constants.TAG, "IOException when closing OutputStream", e); + } + } } } @@ -720,48 +752,66 @@ public class OpenPgpService extends RemoteService { @Override public Intent execute(Intent data, ParcelFileDescriptor input, ParcelFileDescriptor output) { - Intent errorResult = checkRequirements(data); - if (errorResult != null) { - return errorResult; - } + try { + Intent errorResult = checkRequirements(data); + if (errorResult != null) { + return errorResult; + } - String accName = getAccountName(data); - final AccountSettings accSettings = getAccSettings(accName); - if (accSettings == null) { - return getCreateAccountIntent(data, accName); - } + String accName = getAccountName(data); + final AccountSettings accSettings = getAccSettings(accName); + if (accSettings == null) { + return getCreateAccountIntent(data, accName); + } - String action = data.getAction(); - if (OpenPgpApi.ACTION_CLEARTEXT_SIGN.equals(action)) { - return signImpl(data, input, output, accSettings, true); - } else if (OpenPgpApi.ACTION_SIGN.equals(action)) { - // DEPRECATED: same as ACTION_CLEARTEXT_SIGN - Log.w(Constants.TAG, "You are using a deprecated API call, please use ACTION_CLEARTEXT_SIGN instead of ACTION_SIGN!"); - return signImpl(data, input, output, accSettings, true); - } else if (OpenPgpApi.ACTION_DETACHED_SIGN.equals(action)) { - return signImpl(data, input, output, accSettings, false); - } else if (OpenPgpApi.ACTION_ENCRYPT.equals(action)) { - return encryptAndSignImpl(data, input, output, accSettings, false); - } else if (OpenPgpApi.ACTION_SIGN_AND_ENCRYPT.equals(action)) { - return encryptAndSignImpl(data, input, output, accSettings, true); - } else if (OpenPgpApi.ACTION_DECRYPT_VERIFY.equals(action)) { - String currentPkg = getCurrentCallingPackage(); - Set allowedKeyIds = - mProviderHelper.getAllKeyIdsForApp( - ApiAccounts.buildBaseUri(currentPkg)); - return decryptAndVerifyImpl(data, input, output, allowedKeyIds, false); - } else if (OpenPgpApi.ACTION_DECRYPT_METADATA.equals(action)) { - String currentPkg = getCurrentCallingPackage(); - Set allowedKeyIds = - mProviderHelper.getAllKeyIdsForApp( - ApiAccounts.buildBaseUri(currentPkg)); - return decryptAndVerifyImpl(data, input, output, allowedKeyIds, true); - } 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; + String action = data.getAction(); + if (OpenPgpApi.ACTION_CLEARTEXT_SIGN.equals(action)) { + return signImpl(data, input, output, accSettings, true); + } else if (OpenPgpApi.ACTION_SIGN.equals(action)) { + // DEPRECATED: same as ACTION_CLEARTEXT_SIGN + Log.w(Constants.TAG, "You are using a deprecated API call, please use ACTION_CLEARTEXT_SIGN instead of ACTION_SIGN!"); + return signImpl(data, input, output, accSettings, true); + } else if (OpenPgpApi.ACTION_DETACHED_SIGN.equals(action)) { + return signImpl(data, input, output, accSettings, false); + } else if (OpenPgpApi.ACTION_ENCRYPT.equals(action)) { + return encryptAndSignImpl(data, input, output, accSettings, false); + } else if (OpenPgpApi.ACTION_SIGN_AND_ENCRYPT.equals(action)) { + return encryptAndSignImpl(data, input, output, accSettings, true); + } else if (OpenPgpApi.ACTION_DECRYPT_VERIFY.equals(action)) { + String currentPkg = getCurrentCallingPackage(); + Set allowedKeyIds = + mProviderHelper.getAllKeyIdsForApp( + ApiAccounts.buildBaseUri(currentPkg)); + return decryptAndVerifyImpl(data, input, output, allowedKeyIds, false); + } else if (OpenPgpApi.ACTION_DECRYPT_METADATA.equals(action)) { + String currentPkg = getCurrentCallingPackage(); + Set allowedKeyIds = + mProviderHelper.getAllKeyIdsForApp( + ApiAccounts.buildBaseUri(currentPkg)); + return decryptAndVerifyImpl(data, input, output, allowedKeyIds, true); + } 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; + } + } finally { + // always close input and output file descriptors even in error cases + if (input != null) { + try { + input.close(); + } catch (IOException e) { + Log.e(Constants.TAG, "IOException when closing input ParcelFileDescriptor", e); + } + } + if (output != null) { + try { + output.close(); + } catch (IOException e) { + Log.e(Constants.TAG, "IOException when closing output ParcelFileDescriptor", e); + } + } } } -- cgit v1.2.3 From 34b01e9f2b07eef512e5fb453891f7233a685ae8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Thu, 29 Jan 2015 13:36:38 +0100 Subject: Remove files related to old nav drawer --- .../org/sufficientlysecure/keychain/Constants.java | 18 -- .../keychain/ui/DrawerActivity.java | 305 --------------------- .../keychain/ui/NavDrawerActivity.java | 2 +- 3 files changed, 1 insertion(+), 324 deletions(-) delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DrawerActivity.java (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java index 6c3e702c5..67fa30a44 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/Constants.java @@ -20,9 +20,6 @@ package org.sufficientlysecure.keychain; import android.os.Environment; import org.spongycastle.jce.provider.BouncyCastleProvider; -import org.sufficientlysecure.keychain.ui.EncryptFilesActivity; -import org.sufficientlysecure.keychain.ui.EncryptTextActivity; -import org.sufficientlysecure.keychain.ui.MainActivity; import java.io.File; @@ -89,21 +86,6 @@ public final class Constants { public static final int PREF_VERSION = 4; } - public static final class DrawerItems { - public static final Class KEY_LIST = MainActivity.class; - public static final Class ENCRYPT_TEXT = EncryptTextActivity.class; - public static final Class ENCRYPT_FILE = EncryptFilesActivity.class; - public static final Class DECRYPT = MainActivity.class; - public static final Class REGISTERED_APPS_LIST = MainActivity.class; - public static final Class[] ARRAY = new Class[]{ - KEY_LIST, - ENCRYPT_TEXT, - ENCRYPT_FILE, - DECRYPT, - REGISTERED_APPS_LIST - }; - } - public static final class key { public static final int none = 0; public static final int symmetric = -1; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DrawerActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DrawerActivity.java deleted file mode 100644 index 712516b8d..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DrawerActivity.java +++ /dev/null @@ -1,305 +0,0 @@ -/* - * Copyright (C) 2014 Dominik Schürmann - * - * 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 . - */ - -package org.sufficientlysecure.keychain.ui; - -import android.app.Activity; -import android.content.Context; -import android.content.Intent; -import android.content.res.Configuration; -import android.graphics.Color; -import android.os.Bundle; -import android.support.v4.app.ActionBarDrawerToggle; -import android.support.v4.view.GravityCompat; -import android.support.v4.widget.DrawerLayout; -import android.support.v4.widget.FixedDrawerLayout; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.widget.AdapterView; -import android.widget.ArrayAdapter; -import android.widget.ImageView; -import android.widget.ListView; -import android.widget.TextView; - -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; - -public abstract class DrawerActivity extends BaseActivity { - private FixedDrawerLayout mDrawerLayout; - private ListView mDrawerList; - private ActionBarDrawerToggle mDrawerToggle; - - private CharSequence mDrawerTitle; - private CharSequence mTitle; - private boolean mIsDrawerLocked = false; - - private Class mSelectedItem; - - private static final int MENU_ID_PREFERENCE = 222; - private static final int MENU_ID_HELP = 223; - - protected void deactivateDrawerNavigation() { - ((DrawerLayout) findViewById(R.id.drawer_layout)).setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED); - } - - protected void activateDrawerNavigation(Bundle savedInstanceState) { - mDrawerTitle = getString(R.string.app_name); - mDrawerLayout = (FixedDrawerLayout) findViewById(R.id.drawer_layout); - mDrawerList = (ListView) findViewById(R.id.left_drawer); - ViewGroup viewGroup = (ViewGroup) findViewById(R.id.content_frame); - int leftMarginLoaded = ((ViewGroup.MarginLayoutParams) viewGroup.getLayoutParams()).leftMargin; - int leftMarginInTablets = (int) getResources().getDimension(R.dimen.drawer_size); - int errorInMarginAllowed = 5; - - // if the left margin of the loaded layout is close to the - // one used in tablets then set drawer as open and locked - if (Math.abs(leftMarginLoaded - leftMarginInTablets) < errorInMarginAllowed) { - mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_OPEN, mDrawerList); - mDrawerLayout.setScrimColor(Color.TRANSPARENT); - mIsDrawerLocked = true; - } else { - // set a custom shadow that overlays the main content when the drawer opens - mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START); - mIsDrawerLocked = false; - } - - NavItem mItemIconTexts[] = new NavItem[]{ - new NavItem(R.drawable.ic_action_accounts, getString(R.string.nav_keys)), - new NavItem(R.drawable.ic_action_secure, getString(R.string.nav_encrypt_text)), - new NavItem(R.drawable.ic_action_secure, getString(R.string.nav_encrypt_files)), - new NavItem(R.drawable.ic_action_not_secure, getString(R.string.nav_decrypt)), - new NavItem(R.drawable.ic_action_view_as_list, getString(R.string.nav_apps))}; - - mDrawerList.setAdapter(new NavigationDrawerAdapter(this, R.layout.drawer_list_item, - mItemIconTexts)); - - mDrawerList.setOnItemClickListener(new DrawerItemClickListener()); - - // enable ActionBar app icon to behave as action to toggle nav drawer - // if the drawer is not locked - if (!mIsDrawerLocked) { - getSupportActionBar().setDisplayHomeAsUpEnabled(true); - getSupportActionBar().setHomeButtonEnabled(true); - } - - // ActionBarDrawerToggle ties together the the proper interactions - // between the sliding drawer and the action bar app icon - mDrawerToggle = new ActionBarDrawerToggle(this, /* host Activity */ - mDrawerLayout, /* DrawerLayout object */ - R.drawable.ic_drawer, /* nav drawer image to replace 'Up' caret */ - R.string.drawer_open, /* "open drawer" description for accessibility */ - R.string.drawer_close /* "close drawer" description for accessibility */ - ) { - public void onDrawerClosed(View view) { - getSupportActionBar().setTitle(mTitle); - - callIntentForDrawerItem(mSelectedItem); - } - - public void onDrawerOpened(View drawerView) { - mTitle = getSupportActionBar().getTitle(); - getSupportActionBar().setTitle(mDrawerTitle); - // creates call to onPrepareOptionsMenu() - supportInvalidateOptionsMenu(); - } - }; - - if (!mIsDrawerLocked) { - mDrawerLayout.setDrawerListener(mDrawerToggle); - } else { - // If the drawer is locked open make it un-focusable - // so that it doesn't consume all the Back button presses - mDrawerLayout.setFocusableInTouchMode(false); - } - } - - /** - * Uses startActivity to call the Intent of the given class - * - * @param drawerItem the class of the drawer item you want to load. Based on Constants.DrawerItems.* - */ - public void callIntentForDrawerItem(Class drawerItem) { - // creates call to onPrepareOptionsMenu() - supportInvalidateOptionsMenu(); - - // call intent activity if selected - if (drawerItem != null) { - finish(); - overridePendingTransition(0, 0); - - Intent intent = new Intent(this, drawerItem); - startActivity(intent); - - // disable animation of activity start - overridePendingTransition(0, 0); - } - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - if (mDrawerToggle == null) { - return super.onCreateOptionsMenu(menu); - } - - menu.add(42, MENU_ID_PREFERENCE, 100, R.string.menu_preferences); - menu.add(42, MENU_ID_HELP, 101, R.string.menu_help); - - return super.onCreateOptionsMenu(menu); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - if (mDrawerToggle == null) { - return super.onOptionsItemSelected(item); - } - - // The action bar home/up action should open or close the drawer. - // ActionBarDrawerToggle will take care of this. - if (mDrawerToggle.onOptionsItemSelected(item)) { - return true; - } - - switch (item.getItemId()) { - case MENU_ID_PREFERENCE: { - Intent intent = new Intent(this, SettingsActivity.class); - startActivity(intent); - return true; - } - case MENU_ID_HELP: { - Intent intent = new Intent(this, HelpActivity.class); - startActivity(intent); - return true; - } - default: - return super.onOptionsItemSelected(item); - } - } - - /** - * The click listener for ListView in the navigation drawer - */ - private class DrawerItemClickListener implements ListView.OnItemClickListener { - @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { - selectItem(position); - } - } - - private void selectItem(int position) { - // update selected item and title, then close the drawer - mDrawerList.setItemChecked(position, true); - // set selected class - mSelectedItem = Constants.DrawerItems.ARRAY[position]; - - // setTitle(mDrawerTitles[position]); - // If drawer isn't locked just close the drawer and - // it will move to the selected item by itself (via drawer toggle listener) - if (!mIsDrawerLocked) { - mDrawerLayout.closeDrawer(mDrawerList); - // else move to the selected item yourself - } else { - callIntentForDrawerItem(mSelectedItem); - } - } - - /** - * When using the ActionBarDrawerToggle, you must call it during onPostCreate() and - * onConfigurationChanged()... - */ - @Override - protected void onPostCreate(Bundle savedInstanceState) { - super.onPostCreate(savedInstanceState); - // Sync the toggle state after onRestoreInstanceState has occurred. - if (mDrawerToggle != null) { - mDrawerToggle.syncState(); - } - } - - @Override - public void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - // Pass any configuration change to the drawer toggles - if (mDrawerToggle != null) { - mDrawerToggle.onConfigurationChanged(newConfig); - } - } - - private class NavItem { - public int icon; // res-id - public String title; - - /** - * NavItem constructor - * - * @param icon The icons resource-id - * @param title The title of the menu entry - */ - public NavItem(int icon, String title) { - super(); - this.icon = icon; - this.title = title; - } - } - - private class NavigationDrawerAdapter extends ArrayAdapter { - Context mContext; - int mLayoutResourceId; - NavItem mData[] = null; - - public NavigationDrawerAdapter(Context context, int layoutResourceId, NavItem[] data) { - super(context, layoutResourceId, data); - this.mLayoutResourceId = layoutResourceId; - this.mContext = context; - this.mData = data; - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - View row = convertView; - NavItemHolder holder; - - if (row == null) { - LayoutInflater inflater = ((Activity) mContext).getLayoutInflater(); - row = inflater.inflate(mLayoutResourceId, parent, false); - - holder = new NavItemHolder(); - holder.mImg = (ImageView) row.findViewById(R.id.drawer_item_icon); - holder.mTxtTitle = (TextView) row.findViewById(R.id.drawer_item_text); - - row.setTag(holder); - } else { - holder = (NavItemHolder) row.getTag(); - } - - NavItem item = mData[position]; - holder.mTxtTitle.setText(item.title); - holder.mImg.setImageResource(item.icon); - - return row; - } - - } - - static class NavItemHolder { - ImageView mImg; - TextView mTxtTitle; - } - -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NavDrawerActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NavDrawerActivity.java index 200ee382b..9f96d9ff8 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NavDrawerActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NavDrawerActivity.java @@ -38,7 +38,7 @@ public abstract class NavDrawerActivity extends MaterialNavigationDrawer { // set the header image // create and set the header - View view = LayoutInflater.from(this).inflate(R.layout.custom_drawer, null); + View view = LayoutInflater.from(this).inflate(R.layout.drawer_custom_header, null); setDrawerHeaderCustom(view); // create sections -- cgit v1.2.3 From e0369a2f14864cc16bb46488cd25df294bec91c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Thu, 29 Jan 2015 17:02:01 +0100 Subject: Header image tryout --- .../java/org/sufficientlysecure/keychain/ui/NavDrawerActivity.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NavDrawerActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NavDrawerActivity.java index 9f96d9ff8..bc9c36a2e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NavDrawerActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NavDrawerActivity.java @@ -38,8 +38,7 @@ public abstract class NavDrawerActivity extends MaterialNavigationDrawer { // set the header image // create and set the header - View view = LayoutInflater.from(this).inflate(R.layout.drawer_custom_header, null); - setDrawerHeaderCustom(view); + setDrawerHeaderImage(R.drawable.drawer_header); // create sections addSection(newSection(getString(R.string.title_keys), R.drawable.ic_vpn_key_black_24dp, new KeyListFragment())); -- cgit v1.2.3 From d6e4936fa54dc3577296dbadaeb556178dcad2c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Thu, 29 Jan 2015 17:46:27 +0100 Subject: Introduce allowed keys table per API client --- .../keychain/provider/KeychainContract.java | 28 ++++++++++++++++++++++ .../keychain/provider/KeychainDatabase.java | 24 ++++++++++++++++++- .../keychain/provider/KeychainProvider.java | 22 ++++++++++++++--- .../remote/ui/AccountSettingsActivity.java | 1 - 4 files changed, 70 insertions(+), 5 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java index f4e00c36c..e0313074c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java @@ -85,6 +85,11 @@ public class KeychainContract { String PACKAGE_NAME = "package_name"; // foreign key to api_apps.package_name } + interface ApiAppsAllowedKeysColumns { + String KEY_ID = "key_id"; // not a database id + String PACKAGE_NAME = "package_name"; // foreign key to api_apps.package_name + } + public static final String CONTENT_AUTHORITY = Constants.PACKAGE_NAME + ".provider"; private static final Uri BASE_CONTENT_URI_INTERNAL = Uri @@ -106,6 +111,7 @@ public class KeychainContract { public static final String BASE_API_APPS = "api_apps"; public static final String PATH_ACCOUNTS = "accounts"; + public static final String PATH_ALLOWED_KEYS = "allowed_keys"; public static class KeyRings implements BaseColumns, KeysColumns, UserPacketsColumns { public static final String MASTER_KEY_ID = KeysColumns.MASTER_KEY_ID; @@ -305,6 +311,28 @@ public class KeychainContract { } } + public static class ApiAllowedKeys implements ApiAppsAllowedKeysColumns, BaseColumns { + public static final Uri CONTENT_URI = BASE_CONTENT_URI_INTERNAL.buildUpon() + .appendPath(BASE_API_APPS).build(); + + /** + * Use if multiple items get returned + */ + public static final String CONTENT_TYPE + = "vnd.android.cursor.dir/vnd.org.sufficientlysecure.keychain.provider.api_apps.allowed_keys"; + + /** + * Use if a single item is returned + */ + public static final String CONTENT_ITEM_TYPE + = "vnd.android.cursor.item/vnd.org.sufficientlysecure.keychain.provider.api_apps.allowed_keys"; + + public static Uri buildBaseUri(String packageName) { + return CONTENT_URI.buildUpon().appendEncodedPath(packageName).appendPath(PATH_ALLOWED_KEYS) + .build(); + } + } + public static class Certs implements CertsColumns, BaseColumns { public static final String USER_ID = UserPacketsColumns.USER_ID; public static final String SIGNER_UID = "signer_user_id"; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java index 5ce5eec17..9e8f03a66 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java @@ -28,6 +28,7 @@ import android.provider.BaseColumns; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; +import org.sufficientlysecure.keychain.provider.KeychainContract.ApiAppsAllowedKeysColumns; import org.sufficientlysecure.keychain.provider.KeychainContract.ApiAppsAccountsColumns; import org.sufficientlysecure.keychain.provider.KeychainContract.ApiAppsColumns; import org.sufficientlysecure.keychain.provider.KeychainContract.CertsColumns; @@ -52,7 +53,7 @@ import java.io.IOException; */ public class KeychainDatabase extends SQLiteOpenHelper { private static final String DATABASE_NAME = "openkeychain.db"; - private static final int DATABASE_VERSION = 7; + private static final int DATABASE_VERSION = 8; static Boolean apgHack = false; private Context mContext; @@ -64,6 +65,7 @@ public class KeychainDatabase extends SQLiteOpenHelper { String CERTS = "certs"; String API_APPS = "api_apps"; String API_ACCOUNTS = "api_accounts"; + String API_ALLOWED_KEYS = "api_allowed_keys"; } private static final String CREATE_KEYRINGS_PUBLIC = @@ -166,6 +168,17 @@ public class KeychainDatabase extends SQLiteOpenHelper { + Tables.API_APPS + "(" + ApiAppsColumns.PACKAGE_NAME + ") ON DELETE CASCADE" + ")"; + private static final String CREATE_API_APPS_ALLOWED_KEYS = + "CREATE TABLE IF NOT EXISTS " + Tables.API_ALLOWED_KEYS + " (" + + BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + + ApiAppsAllowedKeysColumns.KEY_ID + " INTEGER, " + + ApiAppsAllowedKeysColumns.PACKAGE_NAME + " TEXT NOT NULL, " + + + "UNIQUE(" + ApiAppsAllowedKeysColumns.PACKAGE_NAME + "), " + + "FOREIGN KEY(" + ApiAppsAllowedKeysColumns.PACKAGE_NAME + ") REFERENCES " + + Tables.API_APPS + "(" + ApiAppsAllowedKeysColumns.PACKAGE_NAME + ") ON DELETE CASCADE" + + ")"; + KeychainDatabase(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); mContext = context; @@ -243,6 +256,15 @@ public class KeychainDatabase extends SQLiteOpenHelper { case 6: db.execSQL("ALTER TABLE user_ids ADD COLUMN type INTEGER"); db.execSQL("ALTER TABLE user_ids ADD COLUMN attribute_data BLOB"); + case 7: + // consolidate + case 8: + // new table for allowed key ids in API + try { + db.execSQL(CREATE_API_APPS_ALLOWED_KEYS); + } catch (Exception e) { + // never mind, the column probably already existed + } } // always do consolidate after upgrade diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java index 72475472e..4f263afc4 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java @@ -31,6 +31,7 @@ import android.net.Uri; import android.text.TextUtils; import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.provider.KeychainContract.ApiAllowedKeys; import org.sufficientlysecure.keychain.provider.KeychainContract.ApiAccounts; import org.sufficientlysecure.keychain.provider.KeychainContract.ApiApps; import org.sufficientlysecure.keychain.provider.KeychainContract.Certs; @@ -63,9 +64,10 @@ public class KeychainProvider extends ContentProvider { private static final int KEY_RING_CERTS_SPECIFIC = 206; private static final int API_APPS = 301; - private static final int API_APPS_BY_PACKAGE_NAME = 303; - private static final int API_ACCOUNTS = 304; - private static final int API_ACCOUNTS_BY_ACCOUNT_NAME = 306; + private static final int API_APPS_BY_PACKAGE_NAME = 302; + private static final int API_ACCOUNTS = 303; + private static final int API_ACCOUNTS_BY_ACCOUNT_NAME = 304; + private static final int API_ALLOWED_KEYS = 305; private static final int KEY_RINGS_FIND_BY_EMAIL = 400; private static final int KEY_RINGS_FIND_BY_SUBKEY = 401; @@ -162,6 +164,8 @@ public class KeychainProvider extends ContentProvider { * * api_apps/_/accounts * api_apps/_/accounts/_ (account name) + * + * api_apps/_/allowed_keys * */ matcher.addURI(authority, KeychainContract.BASE_API_APPS, API_APPS); @@ -172,6 +176,9 @@ public class KeychainProvider extends ContentProvider { matcher.addURI(authority, KeychainContract.BASE_API_APPS + "/*/" + KeychainContract.PATH_ACCOUNTS + "/*", API_ACCOUNTS_BY_ACCOUNT_NAME); + matcher.addURI(authority, KeychainContract.BASE_API_APPS + "/*/" + + KeychainContract.PATH_ALLOWED_KEYS, API_ALLOWED_KEYS); + return matcher; } @@ -223,6 +230,9 @@ public class KeychainProvider extends ContentProvider { case API_ACCOUNTS_BY_ACCOUNT_NAME: return ApiAccounts.CONTENT_ITEM_TYPE; + case API_ALLOWED_KEYS: + return ApiAllowedKeys.CONTENT_ITEM_TYPE; + default: throw new UnsupportedOperationException("Unknown uri: " + uri); } @@ -613,6 +623,12 @@ public class KeychainProvider extends ContentProvider { qb.appendWhere(" AND " + Tables.API_ACCOUNTS + "." + ApiAccounts.ACCOUNT_NAME + " = "); qb.appendWhereEscapeString(uri.getLastPathSegment()); + break; + case API_ALLOWED_KEYS: + qb.setTables(Tables.API_ALLOWED_KEYS); + qb.appendWhere(Tables.API_ALLOWED_KEYS + "." + ApiAccounts.PACKAGE_NAME + " = "); + qb.appendWhereEscapeString(uri.getPathSegments().get(1)); + break; default: throw new IllegalArgumentException("Unknown URI " + uri + " (" + match + ")"); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsActivity.java index f4cd553d0..02bf98b12 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsActivity.java @@ -58,7 +58,6 @@ public class AccountSettingsActivity extends BaseActivity { } }); - mAccountSettingsFragment = (AccountSettingsFragment) getSupportFragmentManager().findFragmentById( R.id.api_account_settings_fragment); -- cgit v1.2.3 From fcd91d881eda698e69ca00ed6cdedc1e0a9d2394 Mon Sep 17 00:00:00 2001 From: ligi Date: Thu, 29 Jan 2015 20:30:26 +0100 Subject: Add explicit casting to be able to compile with java8 --- .../java/org/sufficientlysecure/keychain/provider/KeychainProvider.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java index 72475472e..1fc14e59f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java @@ -683,7 +683,7 @@ public class KeychainProvider extends ContentProvider { )) { throw new AssertionError("Incorrect type for user packet! This is a bug!"); } - if (values.get(UserPacketsColumns.RANK) == 0 && values.get(UserPacketsColumns.USER_ID) == null) { + if (((Number)values.get(UserPacketsColumns.RANK)).intValue() == 0 && values.get(UserPacketsColumns.USER_ID) == null) { throw new AssertionError("Rank 0 user packet must be a user id!"); } db.insertOrThrow(Tables.USER_PACKETS, null, values); -- cgit v1.2.3 From 38f7950d90c49ff27dcf2afb651337c2f4f2b663 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Thu, 29 Jan 2015 21:00:58 +0100 Subject: Saving of allowed keys --- .../keychain/provider/KeychainContract.java | 6 - .../keychain/provider/KeychainDatabase.java | 4 +- .../keychain/provider/KeychainProvider.java | 30 ++- .../keychain/provider/ProviderHelper.java | 40 +++ .../keychain/remote/ui/AppSettingsActivity.java | 32 ++- .../keychain/remote/ui/AppSettingsAllowedKeys.java | 292 +++++++++++++++++++++ .../keychain/ui/KeyListFragment.java | 133 +++++----- .../keychain/ui/SelectPublicKeyActivity.java | 144 ---------- 8 files changed, 454 insertions(+), 227 deletions(-) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsAllowedKeys.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyActivity.java (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java index e0313074c..5856589c4 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainContract.java @@ -321,12 +321,6 @@ public class KeychainContract { public static final String CONTENT_TYPE = "vnd.android.cursor.dir/vnd.org.sufficientlysecure.keychain.provider.api_apps.allowed_keys"; - /** - * Use if a single item is returned - */ - public static final String CONTENT_ITEM_TYPE - = "vnd.android.cursor.item/vnd.org.sufficientlysecure.keychain.provider.api_apps.allowed_keys"; - public static Uri buildBaseUri(String packageName) { return CONTENT_URI.buildUpon().appendEncodedPath(packageName).appendPath(PATH_ALLOWED_KEYS) .build(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java index 9e8f03a66..d34cc74a3 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java @@ -174,7 +174,8 @@ public class KeychainDatabase extends SQLiteOpenHelper { + ApiAppsAllowedKeysColumns.KEY_ID + " INTEGER, " + ApiAppsAllowedKeysColumns.PACKAGE_NAME + " TEXT NOT NULL, " - + "UNIQUE(" + ApiAppsAllowedKeysColumns.PACKAGE_NAME + "), " + + "UNIQUE(" + ApiAppsAllowedKeysColumns.KEY_ID + ", " + + ApiAppsAllowedKeysColumns.PACKAGE_NAME + "), " + "FOREIGN KEY(" + ApiAppsAllowedKeysColumns.PACKAGE_NAME + ") REFERENCES " + Tables.API_APPS + "(" + ApiAppsAllowedKeysColumns.PACKAGE_NAME + ") ON DELETE CASCADE" + ")"; @@ -208,6 +209,7 @@ public class KeychainDatabase extends SQLiteOpenHelper { db.execSQL(CREATE_CERTS); db.execSQL(CREATE_API_APPS); db.execSQL(CREATE_API_APPS_ACCOUNTS); + db.execSQL(CREATE_API_APPS_ALLOWED_KEYS); } @Override diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java index 4f263afc4..6bd88570f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java @@ -231,7 +231,7 @@ public class KeychainProvider extends ContentProvider { return ApiAccounts.CONTENT_ITEM_TYPE; case API_ALLOWED_KEYS: - return ApiAllowedKeys.CONTENT_ITEM_TYPE; + return ApiAllowedKeys.CONTENT_TYPE; default: throw new UnsupportedOperationException("Unknown uri: " + uri); @@ -717,7 +717,7 @@ public class KeychainProvider extends ContentProvider { db.insertOrThrow(Tables.API_APPS, null, values); break; - case API_ACCOUNTS: + case API_ACCOUNTS: { // set foreign key automatically based on given uri // e.g., api_apps/com.example.app/accounts/ String packageName = uri.getPathSegments().get(1); @@ -725,12 +725,21 @@ public class KeychainProvider extends ContentProvider { db.insertOrThrow(Tables.API_ACCOUNTS, null, values); break; + } + case API_ALLOWED_KEYS: { + // set foreign key automatically based on given uri + // e.g., api_apps/com.example.app/allowed_keys/ + String packageName = uri.getPathSegments().get(1); + values.put(ApiAllowedKeys.PACKAGE_NAME, packageName); + db.insertOrThrow(Tables.API_ALLOWED_KEYS, null, values); + break; + } default: throw new UnsupportedOperationException("Unknown uri: " + uri); } - if(keyId != null) { + if (keyId != null) { uri = KeyRings.buildGenericKeyRingUri(keyId); rowUri = uri; } @@ -793,6 +802,10 @@ public class KeychainProvider extends ContentProvider { count = db.delete(Tables.API_ACCOUNTS, buildDefaultApiAccountsSelection(uri, additionalSelection), selectionArgs); break; + case API_ALLOWED_KEYS: + count = db.delete(Tables.API_ALLOWED_KEYS, buildDefaultApiAllowedKeysSelection(uri, additionalSelection), + selectionArgs); + break; default: throw new UnsupportedOperationException("Unknown uri: " + uri); } @@ -885,4 +898,15 @@ public class KeychainProvider extends ContentProvider { + andSelection; } + private String buildDefaultApiAllowedKeysSelection(Uri uri, String selection) { + String packageName = DatabaseUtils.sqlEscapeString(uri.getPathSegments().get(1)); + + String andSelection = ""; + if (!TextUtils.isEmpty(selection)) { + andSelection = " AND (" + selection + ")"; + } + + return ApiAllowedKeys.PACKAGE_NAME + "=" + packageName + andSelection; + } + } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java index a229f454f..db458254c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java @@ -33,6 +33,7 @@ import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.operations.results.ImportKeyResult; import org.sufficientlysecure.keychain.pgp.WrappedUserAttribute; import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets; +import org.sufficientlysecure.keychain.remote.ui.AppSettingsAllowedKeys; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.util.ParcelableFileCache.IteratorWithSize; import org.sufficientlysecure.keychain.util.Preferences; @@ -50,6 +51,7 @@ import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; import org.sufficientlysecure.keychain.pgp.UncachedPublicKey; import org.sufficientlysecure.keychain.pgp.WrappedSignature; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; +import org.sufficientlysecure.keychain.provider.KeychainContract.ApiAllowedKeys; import org.sufficientlysecure.keychain.provider.KeychainContract.ApiApps; import org.sufficientlysecure.keychain.provider.KeychainContract.Certs; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData; @@ -1504,6 +1506,44 @@ public class ProviderHelper { return keyIds; } + public Set getAllowedKeyIdsForApp(Uri uri) { + Set keyIds = new HashSet<>(); + + Cursor cursor = mContentResolver.query(uri, null, null, null, null); + try { + if (cursor != null) { + int keyIdColumn = cursor.getColumnIndex(KeychainContract.ApiAllowedKeys.KEY_ID); + while (cursor.moveToNext()) { + keyIds.add(cursor.getLong(keyIdColumn)); + } + } + } finally { + if (cursor != null) { + cursor.close(); + } + } + + return keyIds; + } + + public void saveAllowedKeyIdsForApp(Uri uri, Set allowedKeyIds) + throws RemoteException, OperationApplicationException { + ArrayList ops = new ArrayList<>(); + + // clear table + ops.add(ContentProviderOperation.newDelete(uri) + .build()); + + // re-insert allowed key ids + for (Long keyId : allowedKeyIds) { + ops.add(ContentProviderOperation.newInsert(uri) + .withValue(ApiAllowedKeys.KEY_ID, keyId) + .build()); + } + + getContentResolver().applyBatch(KeychainContract.CONTENT_AUTHORITY, ops); + } + public Set getAllFingerprints(Uri uri) { Set fingerprints = new HashSet<>(); String[] projection = new String[]{KeyRings.FINGERPRINT}; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java index 36d6ad888..b73055670 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java @@ -24,6 +24,7 @@ import android.net.Uri; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; +import android.view.View; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; @@ -39,6 +40,7 @@ public class AppSettingsActivity extends BaseActivity { private AppSettingsFragment mSettingsFragment; private AccountsListFragment mAccountsListFragment; + private AppSettingsAllowedKeys mAllowedKeysFragment; // model AppSettings mAppSettings; @@ -47,6 +49,20 @@ public class AppSettingsActivity extends BaseActivity { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + setFullScreenDialogDoneClose(R.string.api_settings_save, + new View.OnClickListener() { + @Override + public void onClick(View v) { + save(); + } + }, + new View.OnClickListener() { + @Override + public void onClick(View v) { + finish(); + } + }); + mSettingsFragment = (AppSettingsFragment) getSupportFragmentManager().findFragmentById( R.id.api_app_settings_fragment); @@ -62,6 +78,10 @@ public class AppSettingsActivity extends BaseActivity { } } + private void save() { + mAllowedKeysFragment.saveAllowedKeys(); + } + @Override protected void initLayout() { setContentView(R.layout.api_app_settings_activity); @@ -120,10 +140,12 @@ public class AppSettingsActivity extends BaseActivity { Uri accountsUri = appUri.buildUpon().appendPath(KeychainContract.PATH_ACCOUNTS).build(); Log.d(Constants.TAG, "accountsUri: " + accountsUri); - startListFragment(savedInstanceState, accountsUri); + Uri allowedKeysUri = appUri.buildUpon().appendPath(KeychainContract.PATH_ALLOWED_KEYS).build(); + Log.d(Constants.TAG, "allowedKeysUri: " + allowedKeysUri); + startListFragments(savedInstanceState, accountsUri, allowedKeysUri); } - private void startListFragment(Bundle savedInstanceState, Uri dataUri) { + private void startListFragments(Bundle savedInstanceState, Uri accountsUri, Uri allowedKeysUri) { // However, if we're being restored from a previous state, // then we don't need to do anything and should return or else // we could end up with overlapping fragments. @@ -132,13 +154,17 @@ public class AppSettingsActivity extends BaseActivity { } // Create an instance of the fragment - mAccountsListFragment = AccountsListFragment.newInstance(dataUri); + mAccountsListFragment = AccountsListFragment.newInstance(accountsUri); + mAllowedKeysFragment = AppSettingsAllowedKeys.newInstance(allowedKeysUri); // Add the fragment to the 'fragment_container' FrameLayout // NOTE: We use commitAllowingStateLoss() to prevent weird crashes! getSupportFragmentManager().beginTransaction() .replace(R.id.api_accounts_list_fragment, mAccountsListFragment) .commitAllowingStateLoss(); + getSupportFragmentManager().beginTransaction() + .replace(R.id.api_allowed_keys_list_fragment, mAllowedKeysFragment) + .commitAllowingStateLoss(); // do it immediately! getSupportFragmentManager().executePendingTransactions(); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsAllowedKeys.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsAllowedKeys.java new file mode 100644 index 000000000..3e4394264 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsAllowedKeys.java @@ -0,0 +1,292 @@ +/* + * Copyright (C) 2015 Dominik Schürmann + * + * 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 . + */ + +package org.sufficientlysecure.keychain.remote.ui; + +import android.content.Context; +import android.content.OperationApplicationException; +import android.database.Cursor; +import android.database.DatabaseUtils; +import android.net.Uri; +import android.os.Bundle; +import android.os.RemoteException; +import android.support.v4.app.LoaderManager; +import android.support.v4.content.CursorLoader; +import android.support.v4.content.Loader; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ListView; + +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.compatibility.ListFragmentWorkaround; +import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; +import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables; +import org.sufficientlysecure.keychain.provider.ProviderHelper; +import org.sufficientlysecure.keychain.ui.adapter.SelectKeyCursorAdapter; +import org.sufficientlysecure.keychain.ui.widget.FixedListView; +import org.sufficientlysecure.keychain.util.Log; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; +import java.util.Vector; + +public class AppSettingsAllowedKeys extends ListFragmentWorkaround implements LoaderManager.LoaderCallbacks { + private static final String ARG_DATA_URI = "uri"; + + private SelectKeyCursorAdapter mAdapter; + private Set mSelectedMasterKeyIds; + private ProviderHelper mProviderHelper; + + private Uri mDataUri; + + /** + * Creates new instance of this fragment + */ + public static AppSettingsAllowedKeys newInstance(Uri dataUri) { + AppSettingsAllowedKeys frag = new AppSettingsAllowedKeys(); + Bundle args = new Bundle(); + + args.putParcelable(ARG_DATA_URI, dataUri); + + frag.setArguments(args); + + return frag; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + mProviderHelper = new ProviderHelper(getActivity()); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View layout = super.onCreateView(inflater, container, + savedInstanceState); + ListView lv = (ListView) layout.findViewById(android.R.id.list); + ViewGroup parent = (ViewGroup) lv.getParent(); + + /* + * http://stackoverflow.com/a/15880684 + * Remove ListView and add FixedListView in its place. + * This is done here programatically to be still able to use the progressBar of ListFragment. + * + * We want FixedListView to be able to put this ListFragment inside a ScrollView + */ + int lvIndex = parent.indexOfChild(lv); + parent.removeViewAt(lvIndex); + FixedListView newLv = new FixedListView(getActivity()); + newLv.setId(android.R.id.list); + parent.addView(newLv, lvIndex, lv.getLayoutParams()); + return layout; + } + + /** + * Define Adapter and Loader on create of Activity + */ + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + mDataUri = getArguments().getParcelable(ARG_DATA_URI); + + getListView().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)); + + mAdapter = new SecretKeyCursorAdapter(getActivity(), null, 0, getListView()); + + setListAdapter(mAdapter); + + // Start out with a progress indicator. + setListShown(false); + + mSelectedMasterKeyIds = mProviderHelper.getAllKeyIdsForApp(mDataUri); + Log.d(Constants.TAG, "allowed: " + mSelectedMasterKeyIds.toString()); + + // Prepare the loader. Either re-connect with an existing one, + // or start a new one. + getLoaderManager().initLoader(0, null, this); + } + + /** + * Selects items based on master key ids in list view + * + * @param masterKeyIds + */ + private void preselectMasterKeyIds(Set masterKeyIds) { + for (int i = 0; i < getListView().getCount(); ++i) { + long listKeyId = mAdapter.getMasterKeyId(i); + for (long keyId : masterKeyIds) { + if (listKeyId == keyId) { + getListView().setItemChecked(i, true); + break; + } + } + } + } + + /** + * Returns all selected master key ids + * + * @return + */ + public Set getSelectedMasterKeyIds() { + // mListView.getCheckedItemIds() would give the row ids of the KeyRings not the master key + // ids! + Set keyIds = new HashSet<>(); + for (int i = 0; i < getListView().getCount(); ++i) { + if (getListView().isItemChecked(i)) { + keyIds.add(mAdapter.getMasterKeyId(i)); + } + } + + return keyIds; + } + + /** + * Returns all selected user ids + * + * @return + */ + public String[] getSelectedUserIds() { + Vector userIds = new Vector<>(); + for (int i = 0; i < getListView().getCount(); ++i) { + if (getListView().isItemChecked(i)) { + userIds.add(mAdapter.getUserId(i)); + } + } + + // make empty array to not return null + String userIdArray[] = new String[0]; + return userIds.toArray(userIdArray); + } + + public void saveAllowedKeys() { + try { + mProviderHelper.saveAllowedKeyIdsForApp(mDataUri, getSelectedMasterKeyIds()); + } catch (RemoteException | OperationApplicationException e) { + Log.e(Constants.TAG, "Problem saving allowed key ids!", e); + } + } + + @Override + public Loader onCreateLoader(int id, Bundle args) { + Uri baseUri = KeyRings.buildUnifiedKeyRingsUri(); + + // These are the rows that we will retrieve. + String[] projection = new String[]{ + KeyRings._ID, + KeyRings.MASTER_KEY_ID, + KeyRings.USER_ID, + KeyRings.IS_EXPIRED, + KeyRings.IS_REVOKED, + KeyRings.HAS_ENCRYPT, + KeyRings.VERIFIED, + KeyRings.HAS_ANY_SECRET, + }; + + String inMasterKeyList = null; + if (mSelectedMasterKeyIds != null && mSelectedMasterKeyIds.size() > 0) { + inMasterKeyList = Tables.KEYS + "." + KeyRings.MASTER_KEY_ID + " IN ("; + Iterator iter = mSelectedMasterKeyIds.iterator(); + while (iter.hasNext()) { + inMasterKeyList += DatabaseUtils.sqlEscapeString("" + iter.next()); + if (iter.hasNext()) { + inMasterKeyList += ", "; + } + } + inMasterKeyList += ")"; + } + + String selection = KeyRings.HAS_ANY_SECRET + " != 0"; + + String orderBy = KeyRings.USER_ID + " ASC"; + if (inMasterKeyList != null) { + // sort by selected master keys + orderBy = inMasterKeyList + " DESC, " + orderBy; + } + // 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, selection, null, orderBy); + } + + @Override + public void onLoadFinished(Loader loader, Cursor data) { + // Swap the new cursor in. (The framework will take care of closing the + // old cursor once we return.) + mAdapter.swapCursor(data); + + // The list should now be shown. + if (isResumed()) { + setListShown(true); + } else { + setListShownNoAnimation(true); + } + + // preselect given master keys + preselectMasterKeyIds(mSelectedMasterKeyIds); + } + + @Override + public void onLoaderReset(Loader loader) { + // This is called when the last Cursor provided to onLoadFinished() + // above is about to be closed. We need to make sure we are no + // longer using it. + mAdapter.swapCursor(null); + } + + private class SecretKeyCursorAdapter extends SelectKeyCursorAdapter { + + public SecretKeyCursorAdapter(Context context, Cursor c, int flags, ListView listView) { + super(context, c, flags, listView); + } + + @Override + protected void initIndex(Cursor cursor) { + super.initIndex(cursor); + } + + @Override + public void bindView(View view, Context context, Cursor cursor) { + super.bindView(view, context, cursor); + ViewHolderItem h = (ViewHolderItem) view.getTag(); + + // We care about the checkbox + h.selected.setVisibility(View.VISIBLE); + // the getListView works because this is not a static subclass! + h.selected.setChecked(getListView().isItemChecked(cursor.getPosition())); + + boolean enabled = false; + if ((Boolean) h.statusIcon.getTag()) { + h.statusIcon.setVisibility(View.GONE); + enabled = true; + } + + h.setEnabled(enabled); + } + + } + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java index 4e5e8c631..8abb381f8 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java @@ -110,7 +110,6 @@ public class KeyListFragment extends LoaderFragment super.onCreate(savedInstanceState); mExportHelper = new ExportHelper(getActivity()); - } /** @@ -205,84 +204,82 @@ public class KeyListFragment extends LoaderFragment mStickyList.setFastScrollEnabled(true); /* - * Multi-selection is only available for Android >= 3.0 + * Multi-selection */ - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { - mStickyList.setFastScrollAlwaysVisible(true); + mStickyList.setFastScrollAlwaysVisible(true); - mStickyList.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL); - mStickyList.getWrappedList().setMultiChoiceModeListener(new MultiChoiceModeListener() { + mStickyList.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL); + mStickyList.getWrappedList().setMultiChoiceModeListener(new MultiChoiceModeListener() { - @Override - public boolean onCreateActionMode(ActionMode mode, Menu menu) { - android.view.MenuInflater inflater = getActivity().getMenuInflater(); - inflater.inflate(R.menu.key_list_multi, menu); - mActionMode = mode; - return true; - } + @Override + public boolean onCreateActionMode(ActionMode mode, Menu menu) { + android.view.MenuInflater inflater = getActivity().getMenuInflater(); + inflater.inflate(R.menu.key_list_multi, menu); + mActionMode = mode; + return true; + } - @Override - public boolean onPrepareActionMode(ActionMode mode, Menu menu) { - return false; - } + @Override + public boolean onPrepareActionMode(ActionMode mode, Menu menu) { + return false; + } - @Override - public boolean onActionItemClicked(ActionMode mode, MenuItem item) { + @Override + public boolean onActionItemClicked(ActionMode mode, MenuItem item) { - // get IDs for checked positions as long array - long[] ids; + // get IDs for checked positions as long array + long[] ids; - switch (item.getItemId()) { - case R.id.menu_key_list_multi_encrypt: { - ids = mAdapter.getCurrentSelectedMasterKeyIds(); - encrypt(mode, ids); - break; - } - case R.id.menu_key_list_multi_delete: { - ids = mAdapter.getCurrentSelectedMasterKeyIds(); - showDeleteKeyDialog(mode, ids, mAdapter.isAnySecretSelected()); - break; - } - case R.id.menu_key_list_multi_export: { - ids = mAdapter.getCurrentSelectedMasterKeyIds(); - ExportHelper mExportHelper = new ExportHelper((ActionBarActivity) getActivity()); - mExportHelper.showExportKeysDialog(ids, Constants.Path.APP_DIR_FILE, - mAdapter.isAnySecretSelected()); - break; - } - case R.id.menu_key_list_multi_select_all: { - // select all - for (int i = 0; i < mStickyList.getCount(); i++) { - mStickyList.setItemChecked(i, true); - } - break; + switch (item.getItemId()) { + case R.id.menu_key_list_multi_encrypt: { + ids = mAdapter.getCurrentSelectedMasterKeyIds(); + encrypt(mode, ids); + break; + } + case R.id.menu_key_list_multi_delete: { + ids = mAdapter.getCurrentSelectedMasterKeyIds(); + showDeleteKeyDialog(mode, ids, mAdapter.isAnySecretSelected()); + break; + } + case R.id.menu_key_list_multi_export: { + ids = mAdapter.getCurrentSelectedMasterKeyIds(); + ExportHelper mExportHelper = new ExportHelper((ActionBarActivity) getActivity()); + mExportHelper.showExportKeysDialog(ids, Constants.Path.APP_DIR_FILE, + mAdapter.isAnySecretSelected()); + break; + } + case R.id.menu_key_list_multi_select_all: { + // select all + for (int i = 0; i < mStickyList.getCount(); i++) { + mStickyList.setItemChecked(i, true); } + break; } - return true; } + return true; + } - @Override - public void onDestroyActionMode(ActionMode mode) { - mActionMode = null; - mAdapter.clearSelection(); - } + @Override + public void onDestroyActionMode(ActionMode mode) { + mActionMode = null; + mAdapter.clearSelection(); + } - @Override - public void onItemCheckedStateChanged(ActionMode mode, int position, long id, - boolean checked) { - if (checked) { - mAdapter.setNewSelection(position, checked); - } else { - mAdapter.removeSelection(position); - } - int count = mStickyList.getCheckedItemCount(); - String keysSelected = getResources().getQuantityString( - R.plurals.key_list_selected_keys, count, count); - mode.setTitle(keysSelected); + @Override + public void onItemCheckedStateChanged(ActionMode mode, int position, long id, + boolean checked) { + if (checked) { + mAdapter.setNewSelection(position, checked); + } else { + mAdapter.removeSelection(position); } + int count = mStickyList.getCheckedItemCount(); + String keysSelected = getResources().getQuantityString( + R.plurals.key_list_selected_keys, count, count); + mode.setTitle(keysSelected); + } - }); - } + }); // We have a menu item to show in action bar. setHasOptionsMenu(true); @@ -369,9 +366,7 @@ public class KeyListFragment extends LoaderFragment // end action mode, if any if (mActionMode != null) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { - mActionMode.finish(); - } + mActionMode.finish(); } // The list should now be shown. @@ -401,7 +396,6 @@ public class KeyListFragment extends LoaderFragment startActivity(viewIntent); } - @TargetApi(Build.VERSION_CODES.HONEYCOMB) protected void encrypt(ActionMode mode, long[] masterKeyIds) { Intent intent = new Intent(getActivity(), EncryptFilesActivity.class); intent.setAction(EncryptFilesActivity.ACTION_ENCRYPT_DATA); @@ -418,7 +412,6 @@ public class KeyListFragment extends LoaderFragment * @param masterKeyIds * @param hasSecret must contain whether the list of masterKeyIds contains a secret key or not */ - @TargetApi(Build.VERSION_CODES.HONEYCOMB) public void showDeleteKeyDialog(final ActionMode mode, long[] masterKeyIds, boolean hasSecret) { // Can only work on singular secret keys if (hasSecret && masterKeyIds.length > 1) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyActivity.java deleted file mode 100644 index 0e3374833..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SelectPublicKeyActivity.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (C) 2012-2014 Dominik Schürmann - * Copyright (C) 2010-2014 Thialfihar - * - * 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 . - */ - -package org.sufficientlysecure.keychain.ui; - -import android.content.Intent; -import android.os.Bundle; -import android.view.View; - -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; - -public class SelectPublicKeyActivity extends BaseActivity { - - // Actions for internal use only: - public static final String ACTION_SELECT_PUBLIC_KEYS = Constants.INTENT_PREFIX - + "SELECT_PUBLIC_KEYRINGS"; - - public static final String EXTRA_SELECTED_MASTER_KEY_IDS = "master_key_ids"; - - public static final String RESULT_EXTRA_MASTER_KEY_IDS = "master_key_ids"; - public static final String RESULT_EXTRA_USER_IDS = "user_ids"; - - SelectPublicKeyFragment mSelectFragment; - - long mSelectedMasterKeyIds[]; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - // Inflate a "Done"/"Cancel" custom action bar view - setFullScreenDialogDoneClose(R.string.btn_okay, - new View.OnClickListener() { - @Override - public void onClick(View v) { - okClicked(); - } - }, - new View.OnClickListener() { - @Override - public void onClick(View v) { - cancelClicked(); - } - }); - - setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL); - - handleIntent(getIntent()); - - // Check that the activity is using the layout version with - // the fragment_container FrameLayout - if (findViewById(R.id.select_public_key_fragment_container) != null) { - - // However, if we're being restored from a previous state, - // then we don't need to do anything and should return or else - // we could end up with overlapping fragments. - if (savedInstanceState != null) { - return; - } - - // Create an instance of the fragment - mSelectFragment = SelectPublicKeyFragment.newInstance(mSelectedMasterKeyIds); - - // Add the fragment to the 'fragment_container' FrameLayout - getSupportFragmentManager().beginTransaction() - .add(R.id.select_public_key_fragment_container, mSelectFragment).commit(); - } - - // TODO: reimplement! - // mFilterLayout = findViewById(R.id.layout_filter); - // mFilterInfo = (TextView) mFilterLayout.findViewById(R.id.filterInfo); - // mClearFilterButton = (Button) mFilterLayout.findViewById(R.id.btn_clear); - // - // mClearFilterButton.setOnClickListener(new OnClickListener() { - // public void onClick(View v) { - // handleIntent(new Intent()); - // } - // }); - - } - - @Override - protected void initLayout() { - setContentView(R.layout.select_public_key_activity); - } - - @Override - protected void onNewIntent(Intent intent) { - super.onNewIntent(intent); - handleIntent(intent); - } - - private void handleIntent(Intent intent) { - // TODO: reimplement search! - - // String searchString = null; - // if (Intent.ACTION_SEARCH.equals(intent.getAction())) { - // searchString = intent.getStringExtra(SearchManager.QUERY); - // if (searchString != null && searchString.trim().length() == 0) { - // searchString = null; - // } - // } - - // if (searchString == null) { - // mFilterLayout.setVisibility(View.GONE); - // } else { - // mFilterLayout.setVisibility(View.VISIBLE); - // mFilterInfo.setText(getString(R.string.filterInfo, searchString)); - // } - - // preselected master keys - mSelectedMasterKeyIds = intent.getLongArrayExtra(EXTRA_SELECTED_MASTER_KEY_IDS); - } - - private void cancelClicked() { - setResult(RESULT_CANCELED, null); - finish(); - } - - private void okClicked() { - Intent data = new Intent(); - data.putExtra(RESULT_EXTRA_MASTER_KEY_IDS, mSelectFragment.getSelectedMasterKeyIds()); - data.putExtra(RESULT_EXTRA_USER_IDS, mSelectFragment.getSelectedUserIds()); - setResult(RESULT_OK, data); - finish(); - } - -} -- cgit v1.2.3 From 464f7c671834cd01c83b5453437c0df451510a33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Fri, 30 Jan 2015 10:47:40 +0100 Subject: Fix saving of allowed keys --- .../keychain/provider/ProviderHelper.java | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java index db458254c..2bf62c2e0 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java @@ -1310,7 +1310,6 @@ public class ProviderHelper { progress.setProgress(100, 100); log.add(LogType.MSG_CON_SUCCESS, indent); - indent -= 1; return new ConsolidateResult(ConsolidateResult.RESULT_OK, log); @@ -1528,20 +1527,15 @@ public class ProviderHelper { public void saveAllowedKeyIdsForApp(Uri uri, Set allowedKeyIds) throws RemoteException, OperationApplicationException { - ArrayList ops = new ArrayList<>(); - - // clear table - ops.add(ContentProviderOperation.newDelete(uri) - .build()); + // wipe whole table of allowed keys for this account + mContentResolver.delete(uri, null, null); // re-insert allowed key ids for (Long keyId : allowedKeyIds) { - ops.add(ContentProviderOperation.newInsert(uri) - .withValue(ApiAllowedKeys.KEY_ID, keyId) - .build()); + ContentValues values = new ContentValues(); + values.put(ApiAllowedKeys.KEY_ID, keyId); + mContentResolver.insert(uri, values); } - - getContentResolver().applyBatch(KeychainContract.CONTENT_AUTHORITY, ops); } public Set getAllFingerprints(Uri uri) { -- cgit v1.2.3 From e651a392795caa395b060946b0cfaca5a5b41ded Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Fri, 30 Jan 2015 10:59:57 +0100 Subject: Rename app setting classes for consistency --- .../keychain/provider/ProviderHelper.java | 1 - .../keychain/remote/ui/AppSettingsActivity.java | 8 +- .../keychain/remote/ui/AppSettingsAllowedKeys.java | 292 --------------------- .../ui/AppSettingsAllowedKeysListFragment.java | 292 +++++++++++++++++++++ .../keychain/remote/ui/AppSettingsFragment.java | 108 -------- .../remote/ui/AppSettingsHeaderFragment.java | 108 ++++++++ .../keychain/remote/ui/RemoteServiceActivity.java | 8 +- 7 files changed, 408 insertions(+), 409 deletions(-) delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsAllowedKeys.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsAllowedKeysListFragment.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsFragment.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsHeaderFragment.java (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java index 2bf62c2e0..10e0c3dc8 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java @@ -33,7 +33,6 @@ import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.operations.results.ImportKeyResult; import org.sufficientlysecure.keychain.pgp.WrappedUserAttribute; import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets; -import org.sufficientlysecure.keychain.remote.ui.AppSettingsAllowedKeys; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.util.ParcelableFileCache.IteratorWithSize; import org.sufficientlysecure.keychain.util.Preferences; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java index b73055670..8f822a338 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java @@ -38,9 +38,9 @@ import org.sufficientlysecure.keychain.util.Log; public class AppSettingsActivity extends BaseActivity { private Uri mAppUri; - private AppSettingsFragment mSettingsFragment; + private AppSettingsHeaderFragment mSettingsFragment; private AccountsListFragment mAccountsListFragment; - private AppSettingsAllowedKeys mAllowedKeysFragment; + private AppSettingsAllowedKeysListFragment mAllowedKeysFragment; // model AppSettings mAppSettings; @@ -63,7 +63,7 @@ public class AppSettingsActivity extends BaseActivity { } }); - mSettingsFragment = (AppSettingsFragment) getSupportFragmentManager().findFragmentById( + mSettingsFragment = (AppSettingsHeaderFragment) getSupportFragmentManager().findFragmentById( R.id.api_app_settings_fragment); Intent intent = getIntent(); @@ -155,7 +155,7 @@ public class AppSettingsActivity extends BaseActivity { // Create an instance of the fragment mAccountsListFragment = AccountsListFragment.newInstance(accountsUri); - mAllowedKeysFragment = AppSettingsAllowedKeys.newInstance(allowedKeysUri); + mAllowedKeysFragment = AppSettingsAllowedKeysListFragment.newInstance(allowedKeysUri); // Add the fragment to the 'fragment_container' FrameLayout // NOTE: We use commitAllowingStateLoss() to prevent weird crashes! diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsAllowedKeys.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsAllowedKeys.java deleted file mode 100644 index 3e4394264..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsAllowedKeys.java +++ /dev/null @@ -1,292 +0,0 @@ -/* - * Copyright (C) 2015 Dominik Schürmann - * - * 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 . - */ - -package org.sufficientlysecure.keychain.remote.ui; - -import android.content.Context; -import android.content.OperationApplicationException; -import android.database.Cursor; -import android.database.DatabaseUtils; -import android.net.Uri; -import android.os.Bundle; -import android.os.RemoteException; -import android.support.v4.app.LoaderManager; -import android.support.v4.content.CursorLoader; -import android.support.v4.content.Loader; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ListView; - -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.compatibility.ListFragmentWorkaround; -import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; -import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables; -import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.ui.adapter.SelectKeyCursorAdapter; -import org.sufficientlysecure.keychain.ui.widget.FixedListView; -import org.sufficientlysecure.keychain.util.Log; - -import java.util.HashSet; -import java.util.Iterator; -import java.util.Set; -import java.util.Vector; - -public class AppSettingsAllowedKeys extends ListFragmentWorkaround implements LoaderManager.LoaderCallbacks { - private static final String ARG_DATA_URI = "uri"; - - private SelectKeyCursorAdapter mAdapter; - private Set mSelectedMasterKeyIds; - private ProviderHelper mProviderHelper; - - private Uri mDataUri; - - /** - * Creates new instance of this fragment - */ - public static AppSettingsAllowedKeys newInstance(Uri dataUri) { - AppSettingsAllowedKeys frag = new AppSettingsAllowedKeys(); - Bundle args = new Bundle(); - - args.putParcelable(ARG_DATA_URI, dataUri); - - frag.setArguments(args); - - return frag; - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - mProviderHelper = new ProviderHelper(getActivity()); - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - View layout = super.onCreateView(inflater, container, - savedInstanceState); - ListView lv = (ListView) layout.findViewById(android.R.id.list); - ViewGroup parent = (ViewGroup) lv.getParent(); - - /* - * http://stackoverflow.com/a/15880684 - * Remove ListView and add FixedListView in its place. - * This is done here programatically to be still able to use the progressBar of ListFragment. - * - * We want FixedListView to be able to put this ListFragment inside a ScrollView - */ - int lvIndex = parent.indexOfChild(lv); - parent.removeViewAt(lvIndex); - FixedListView newLv = new FixedListView(getActivity()); - newLv.setId(android.R.id.list); - parent.addView(newLv, lvIndex, lv.getLayoutParams()); - return layout; - } - - /** - * Define Adapter and Loader on create of Activity - */ - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - - mDataUri = getArguments().getParcelable(ARG_DATA_URI); - - getListView().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)); - - mAdapter = new SecretKeyCursorAdapter(getActivity(), null, 0, getListView()); - - setListAdapter(mAdapter); - - // Start out with a progress indicator. - setListShown(false); - - mSelectedMasterKeyIds = mProviderHelper.getAllKeyIdsForApp(mDataUri); - Log.d(Constants.TAG, "allowed: " + mSelectedMasterKeyIds.toString()); - - // Prepare the loader. Either re-connect with an existing one, - // or start a new one. - getLoaderManager().initLoader(0, null, this); - } - - /** - * Selects items based on master key ids in list view - * - * @param masterKeyIds - */ - private void preselectMasterKeyIds(Set masterKeyIds) { - for (int i = 0; i < getListView().getCount(); ++i) { - long listKeyId = mAdapter.getMasterKeyId(i); - for (long keyId : masterKeyIds) { - if (listKeyId == keyId) { - getListView().setItemChecked(i, true); - break; - } - } - } - } - - /** - * Returns all selected master key ids - * - * @return - */ - public Set getSelectedMasterKeyIds() { - // mListView.getCheckedItemIds() would give the row ids of the KeyRings not the master key - // ids! - Set keyIds = new HashSet<>(); - for (int i = 0; i < getListView().getCount(); ++i) { - if (getListView().isItemChecked(i)) { - keyIds.add(mAdapter.getMasterKeyId(i)); - } - } - - return keyIds; - } - - /** - * Returns all selected user ids - * - * @return - */ - public String[] getSelectedUserIds() { - Vector userIds = new Vector<>(); - for (int i = 0; i < getListView().getCount(); ++i) { - if (getListView().isItemChecked(i)) { - userIds.add(mAdapter.getUserId(i)); - } - } - - // make empty array to not return null - String userIdArray[] = new String[0]; - return userIds.toArray(userIdArray); - } - - public void saveAllowedKeys() { - try { - mProviderHelper.saveAllowedKeyIdsForApp(mDataUri, getSelectedMasterKeyIds()); - } catch (RemoteException | OperationApplicationException e) { - Log.e(Constants.TAG, "Problem saving allowed key ids!", e); - } - } - - @Override - public Loader onCreateLoader(int id, Bundle args) { - Uri baseUri = KeyRings.buildUnifiedKeyRingsUri(); - - // These are the rows that we will retrieve. - String[] projection = new String[]{ - KeyRings._ID, - KeyRings.MASTER_KEY_ID, - KeyRings.USER_ID, - KeyRings.IS_EXPIRED, - KeyRings.IS_REVOKED, - KeyRings.HAS_ENCRYPT, - KeyRings.VERIFIED, - KeyRings.HAS_ANY_SECRET, - }; - - String inMasterKeyList = null; - if (mSelectedMasterKeyIds != null && mSelectedMasterKeyIds.size() > 0) { - inMasterKeyList = Tables.KEYS + "." + KeyRings.MASTER_KEY_ID + " IN ("; - Iterator iter = mSelectedMasterKeyIds.iterator(); - while (iter.hasNext()) { - inMasterKeyList += DatabaseUtils.sqlEscapeString("" + iter.next()); - if (iter.hasNext()) { - inMasterKeyList += ", "; - } - } - inMasterKeyList += ")"; - } - - String selection = KeyRings.HAS_ANY_SECRET + " != 0"; - - String orderBy = KeyRings.USER_ID + " ASC"; - if (inMasterKeyList != null) { - // sort by selected master keys - orderBy = inMasterKeyList + " DESC, " + orderBy; - } - // 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, selection, null, orderBy); - } - - @Override - public void onLoadFinished(Loader loader, Cursor data) { - // Swap the new cursor in. (The framework will take care of closing the - // old cursor once we return.) - mAdapter.swapCursor(data); - - // The list should now be shown. - if (isResumed()) { - setListShown(true); - } else { - setListShownNoAnimation(true); - } - - // preselect given master keys - preselectMasterKeyIds(mSelectedMasterKeyIds); - } - - @Override - public void onLoaderReset(Loader loader) { - // This is called when the last Cursor provided to onLoadFinished() - // above is about to be closed. We need to make sure we are no - // longer using it. - mAdapter.swapCursor(null); - } - - private class SecretKeyCursorAdapter extends SelectKeyCursorAdapter { - - public SecretKeyCursorAdapter(Context context, Cursor c, int flags, ListView listView) { - super(context, c, flags, listView); - } - - @Override - protected void initIndex(Cursor cursor) { - super.initIndex(cursor); - } - - @Override - public void bindView(View view, Context context, Cursor cursor) { - super.bindView(view, context, cursor); - ViewHolderItem h = (ViewHolderItem) view.getTag(); - - // We care about the checkbox - h.selected.setVisibility(View.VISIBLE); - // the getListView works because this is not a static subclass! - h.selected.setChecked(getListView().isItemChecked(cursor.getPosition())); - - boolean enabled = false; - if ((Boolean) h.statusIcon.getTag()) { - h.statusIcon.setVisibility(View.GONE); - enabled = true; - } - - h.setEnabled(enabled); - } - - } - -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsAllowedKeysListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsAllowedKeysListFragment.java new file mode 100644 index 000000000..13b242a5e --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsAllowedKeysListFragment.java @@ -0,0 +1,292 @@ +/* + * Copyright (C) 2015 Dominik Schürmann + * + * 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 . + */ + +package org.sufficientlysecure.keychain.remote.ui; + +import android.content.Context; +import android.content.OperationApplicationException; +import android.database.Cursor; +import android.database.DatabaseUtils; +import android.net.Uri; +import android.os.Bundle; +import android.os.RemoteException; +import android.support.v4.app.LoaderManager; +import android.support.v4.content.CursorLoader; +import android.support.v4.content.Loader; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ListView; + +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.compatibility.ListFragmentWorkaround; +import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; +import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables; +import org.sufficientlysecure.keychain.provider.ProviderHelper; +import org.sufficientlysecure.keychain.ui.adapter.SelectKeyCursorAdapter; +import org.sufficientlysecure.keychain.ui.widget.FixedListView; +import org.sufficientlysecure.keychain.util.Log; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; +import java.util.Vector; + +public class AppSettingsAllowedKeysListFragment extends ListFragmentWorkaround implements LoaderManager.LoaderCallbacks { + private static final String ARG_DATA_URI = "uri"; + + private SelectKeyCursorAdapter mAdapter; + private Set mSelectedMasterKeyIds; + private ProviderHelper mProviderHelper; + + private Uri mDataUri; + + /** + * Creates new instance of this fragment + */ + public static AppSettingsAllowedKeysListFragment newInstance(Uri dataUri) { + AppSettingsAllowedKeysListFragment frag = new AppSettingsAllowedKeysListFragment(); + Bundle args = new Bundle(); + + args.putParcelable(ARG_DATA_URI, dataUri); + + frag.setArguments(args); + + return frag; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + mProviderHelper = new ProviderHelper(getActivity()); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View layout = super.onCreateView(inflater, container, + savedInstanceState); + ListView lv = (ListView) layout.findViewById(android.R.id.list); + ViewGroup parent = (ViewGroup) lv.getParent(); + + /* + * http://stackoverflow.com/a/15880684 + * Remove ListView and add FixedListView in its place. + * This is done here programatically to be still able to use the progressBar of ListFragment. + * + * We want FixedListView to be able to put this ListFragment inside a ScrollView + */ + int lvIndex = parent.indexOfChild(lv); + parent.removeViewAt(lvIndex); + FixedListView newLv = new FixedListView(getActivity()); + newLv.setId(android.R.id.list); + parent.addView(newLv, lvIndex, lv.getLayoutParams()); + return layout; + } + + /** + * Define Adapter and Loader on create of Activity + */ + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + mDataUri = getArguments().getParcelable(ARG_DATA_URI); + + getListView().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)); + + mAdapter = new SecretKeyCursorAdapter(getActivity(), null, 0, getListView()); + + setListAdapter(mAdapter); + + // Start out with a progress indicator. + setListShown(false); + + mSelectedMasterKeyIds = mProviderHelper.getAllKeyIdsForApp(mDataUri); + Log.d(Constants.TAG, "allowed: " + mSelectedMasterKeyIds.toString()); + + // Prepare the loader. Either re-connect with an existing one, + // or start a new one. + getLoaderManager().initLoader(0, null, this); + } + + /** + * Selects items based on master key ids in list view + * + * @param masterKeyIds + */ + private void preselectMasterKeyIds(Set masterKeyIds) { + for (int i = 0; i < getListView().getCount(); ++i) { + long listKeyId = mAdapter.getMasterKeyId(i); + for (long keyId : masterKeyIds) { + if (listKeyId == keyId) { + getListView().setItemChecked(i, true); + break; + } + } + } + } + + /** + * Returns all selected master key ids + * + * @return + */ + public Set getSelectedMasterKeyIds() { + // mListView.getCheckedItemIds() would give the row ids of the KeyRings not the master key + // ids! + Set keyIds = new HashSet<>(); + for (int i = 0; i < getListView().getCount(); ++i) { + if (getListView().isItemChecked(i)) { + keyIds.add(mAdapter.getMasterKeyId(i)); + } + } + + return keyIds; + } + + /** + * Returns all selected user ids + * + * @return + */ + public String[] getSelectedUserIds() { + Vector userIds = new Vector<>(); + for (int i = 0; i < getListView().getCount(); ++i) { + if (getListView().isItemChecked(i)) { + userIds.add(mAdapter.getUserId(i)); + } + } + + // make empty array to not return null + String userIdArray[] = new String[0]; + return userIds.toArray(userIdArray); + } + + public void saveAllowedKeys() { + try { + mProviderHelper.saveAllowedKeyIdsForApp(mDataUri, getSelectedMasterKeyIds()); + } catch (RemoteException | OperationApplicationException e) { + Log.e(Constants.TAG, "Problem saving allowed key ids!", e); + } + } + + @Override + public Loader onCreateLoader(int id, Bundle args) { + Uri baseUri = KeyRings.buildUnifiedKeyRingsUri(); + + // These are the rows that we will retrieve. + String[] projection = new String[]{ + KeyRings._ID, + KeyRings.MASTER_KEY_ID, + KeyRings.USER_ID, + KeyRings.IS_EXPIRED, + KeyRings.IS_REVOKED, + KeyRings.HAS_ENCRYPT, + KeyRings.VERIFIED, + KeyRings.HAS_ANY_SECRET, + }; + + String inMasterKeyList = null; + if (mSelectedMasterKeyIds != null && mSelectedMasterKeyIds.size() > 0) { + inMasterKeyList = Tables.KEYS + "." + KeyRings.MASTER_KEY_ID + " IN ("; + Iterator iter = mSelectedMasterKeyIds.iterator(); + while (iter.hasNext()) { + inMasterKeyList += DatabaseUtils.sqlEscapeString("" + iter.next()); + if (iter.hasNext()) { + inMasterKeyList += ", "; + } + } + inMasterKeyList += ")"; + } + + String selection = KeyRings.HAS_ANY_SECRET + " != 0"; + + String orderBy = KeyRings.USER_ID + " ASC"; + if (inMasterKeyList != null) { + // sort by selected master keys + orderBy = inMasterKeyList + " DESC, " + orderBy; + } + // 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, selection, null, orderBy); + } + + @Override + public void onLoadFinished(Loader loader, Cursor data) { + // Swap the new cursor in. (The framework will take care of closing the + // old cursor once we return.) + mAdapter.swapCursor(data); + + // The list should now be shown. + if (isResumed()) { + setListShown(true); + } else { + setListShownNoAnimation(true); + } + + // preselect given master keys + preselectMasterKeyIds(mSelectedMasterKeyIds); + } + + @Override + public void onLoaderReset(Loader loader) { + // This is called when the last Cursor provided to onLoadFinished() + // above is about to be closed. We need to make sure we are no + // longer using it. + mAdapter.swapCursor(null); + } + + private class SecretKeyCursorAdapter extends SelectKeyCursorAdapter { + + public SecretKeyCursorAdapter(Context context, Cursor c, int flags, ListView listView) { + super(context, c, flags, listView); + } + + @Override + protected void initIndex(Cursor cursor) { + super.initIndex(cursor); + } + + @Override + public void bindView(View view, Context context, Cursor cursor) { + super.bindView(view, context, cursor); + ViewHolderItem h = (ViewHolderItem) view.getTag(); + + // We care about the checkbox + h.selected.setVisibility(View.VISIBLE); + // the getListView works because this is not a static subclass! + h.selected.setChecked(getListView().isItemChecked(cursor.getPosition())); + + boolean enabled = false; + if ((Boolean) h.statusIcon.getTag()) { + h.statusIcon.setVisibility(View.GONE); + enabled = true; + } + + h.setEnabled(enabled); + } + + } + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsFragment.java deleted file mode 100644 index a6db02708..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsFragment.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (C) 2013-2014 Dominik Schürmann - * - * 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 . - */ - -package org.sufficientlysecure.keychain.remote.ui; - -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; -import android.content.pm.PackageManager.NameNotFoundException; -import android.graphics.drawable.Drawable; -import android.os.Bundle; -import android.support.v4.app.Fragment; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.TextView; - -import org.spongycastle.util.encoders.Hex; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.remote.AppSettings; -import org.sufficientlysecure.keychain.util.Log; - -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; - -public class AppSettingsFragment extends Fragment { - - // model - private AppSettings mAppSettings; - - // view - private TextView mAppNameView; - private ImageView mAppIconView; - private TextView mPackageName; - private TextView mPackageSignature; - - public AppSettings getAppSettings() { - return mAppSettings; - } - - public void setAppSettings(AppSettings appSettings) { - this.mAppSettings = appSettings; - updateView(appSettings); - } - - /** - * Inflate the layout for this fragment - */ - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.api_app_settings_fragment, container, false); - mAppNameView = (TextView) view.findViewById(R.id.api_app_settings_app_name); - mAppIconView = (ImageView) view.findViewById(R.id.api_app_settings_app_icon); - mPackageName = (TextView) view.findViewById(R.id.api_app_settings_package_name); - mPackageSignature = (TextView) view.findViewById(R.id.api_app_settings_package_signature); - return view; - } - - private void updateView(AppSettings appSettings) { - // get application name and icon from package manager - String appName; - Drawable appIcon = null; - PackageManager pm = getActivity().getApplicationContext().getPackageManager(); - try { - ApplicationInfo ai = pm.getApplicationInfo(appSettings.getPackageName(), 0); - - appName = (String) pm.getApplicationLabel(ai); - appIcon = pm.getApplicationIcon(ai); - } catch (NameNotFoundException e) { - // fallback - appName = appSettings.getPackageName(); - } - mAppNameView.setText(appName); - mAppIconView.setImageDrawable(appIcon); - - // advanced info: package name - mPackageName.setText(appSettings.getPackageName()); - - // advanced info: package signature SHA-256 - try { - MessageDigest md = MessageDigest.getInstance("SHA-256"); - md.update(appSettings.getPackageSignature()); - byte[] digest = md.digest(); - String signature = new String(Hex.encode(digest)); - - mPackageSignature.setText(signature); - } catch (NoSuchAlgorithmException e) { - Log.e(Constants.TAG, "Should not happen!", e); - } - } - - -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsHeaderFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsHeaderFragment.java new file mode 100644 index 000000000..7beac8973 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsHeaderFragment.java @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2013-2014 Dominik Schürmann + * + * 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 . + */ + +package org.sufficientlysecure.keychain.remote.ui; + +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import org.spongycastle.util.encoders.Hex; +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.remote.AppSettings; +import org.sufficientlysecure.keychain.util.Log; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +public class AppSettingsHeaderFragment extends Fragment { + + // model + private AppSettings mAppSettings; + + // view + private TextView mAppNameView; + private ImageView mAppIconView; + private TextView mPackageName; + private TextView mPackageSignature; + + public AppSettings getAppSettings() { + return mAppSettings; + } + + public void setAppSettings(AppSettings appSettings) { + this.mAppSettings = appSettings; + updateView(appSettings); + } + + /** + * Inflate the layout for this fragment + */ + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.api_app_settings_fragment, container, false); + mAppNameView = (TextView) view.findViewById(R.id.api_app_settings_app_name); + mAppIconView = (ImageView) view.findViewById(R.id.api_app_settings_app_icon); + mPackageName = (TextView) view.findViewById(R.id.api_app_settings_package_name); + mPackageSignature = (TextView) view.findViewById(R.id.api_app_settings_package_signature); + return view; + } + + private void updateView(AppSettings appSettings) { + // get application name and icon from package manager + String appName; + Drawable appIcon = null; + PackageManager pm = getActivity().getApplicationContext().getPackageManager(); + try { + ApplicationInfo ai = pm.getApplicationInfo(appSettings.getPackageName(), 0); + + appName = (String) pm.getApplicationLabel(ai); + appIcon = pm.getApplicationIcon(ai); + } catch (NameNotFoundException e) { + // fallback + appName = appSettings.getPackageName(); + } + mAppNameView.setText(appName); + mAppIconView.setImageDrawable(appIcon); + + // advanced info: package name + mPackageName.setText(appSettings.getPackageName()); + + // advanced info: package signature SHA-256 + try { + MessageDigest md = MessageDigest.getInstance("SHA-256"); + md.update(appSettings.getPackageSignature()); + byte[] digest = md.digest(); + String signature = new String(Hex.encode(digest)); + + mPackageSignature.setText(signature); + } catch (NoSuchAlgorithmException e) { + Log.e(Constants.TAG, "Should not happen!", e); + } + } + + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/RemoteServiceActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/RemoteServiceActivity.java index cbc593b0a..2c5c78161 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/RemoteServiceActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/RemoteServiceActivity.java @@ -75,7 +75,7 @@ public class RemoteServiceActivity extends BaseActivity { public static final String EXTRA_ERROR_MESSAGE = "error_message"; // register view - private AppSettingsFragment mAppSettingsFragment; + private AppSettingsHeaderFragment mAppSettingsHeaderFragment; // create acc view private AccountSettingsFragment mAccSettingsFragment; // select pub keys view @@ -115,11 +115,11 @@ public class RemoteServiceActivity extends BaseActivity { setContentView(R.layout.api_remote_register_app); initToolbar(); - mAppSettingsFragment = (AppSettingsFragment) getSupportFragmentManager().findFragmentById( + mAppSettingsHeaderFragment = (AppSettingsHeaderFragment) getSupportFragmentManager().findFragmentById( R.id.api_app_settings_fragment); AppSettings settings = new AppSettings(packageName, packageSignature); - mAppSettingsFragment.setAppSettings(settings); + mAppSettingsHeaderFragment.setAppSettings(settings); // Inflate a "Done"/"Cancel" custom action bar view setFullScreenDialogTwoButtons( @@ -129,7 +129,7 @@ public class RemoteServiceActivity extends BaseActivity { public void onClick(View v) { // Allow - mProviderHelper.insertApiApp(mAppSettingsFragment.getAppSettings()); + mProviderHelper.insertApiApp(mAppSettingsHeaderFragment.getAppSettings()); // give data through for new service call Intent resultData = extras.getParcelable(EXTRA_DATA); -- cgit v1.2.3 From 5466d1e9802815726d713bca2aeabaff2861519c Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Sat, 31 Jan 2015 18:26:20 +0100 Subject: prevent recursive consolidate --- .../keychain/operations/results/OperationResult.java | 1 + .../sufficientlysecure/keychain/provider/ProviderHelper.java | 12 ++++++++---- .../keychain/service/KeychainIntentServiceHandler.java | 1 + .../keychain/util/ParcelableFileCache.java | 1 - 4 files changed, 10 insertions(+), 5 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java index 055028064..af4fcb071 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java @@ -520,6 +520,7 @@ public abstract class OperationResult implements Parcelable { MSG_CON_ERROR_PUBLIC (LogLevel.ERROR, R.string.msg_con_error_public), MSG_CON_ERROR_SECRET (LogLevel.ERROR, R.string.msg_con_error_secret), MSG_CON_RECOVER (LogLevel.DEBUG, R.string.msg_con_recover), + MSG_CON_RECURSIVE (LogLevel.OK, R.string.msg_con_recursive), MSG_CON_REIMPORT_PUBLIC (LogLevel.DEBUG, R.plurals.msg_con_reimport_public), MSG_CON_REIMPORT_PUBLIC_SKIP (LogLevel.DEBUG, R.string.msg_con_reimport_public_skip), MSG_CON_REIMPORT_SECRET (LogLevel.DEBUG, R.plurals.msg_con_reimport_secret), diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java index a229f454f..f23006a94 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java @@ -1053,6 +1053,11 @@ public class ProviderHelper { log.add(LogType.MSG_CON, indent); indent += 1; + if (mConsolidateCritical) { + log.add(LogType.MSG_CON_RECURSIVE, indent); + return new ConsolidateResult(ConsolidateResult.RESULT_OK, log); + } + progress.setProgress(R.string.progress_con_saving, 0, 100); // The consolidate operation can never be cancelled! @@ -1219,13 +1224,11 @@ public class ProviderHelper { log.add(LogType.MSG_CON_DB_CLEAR, indent); mContentResolver.delete(KeyRings.buildUnifiedKeyRingsUri(), null, null); - ParcelableFileCache cacheSecret = - new ParcelableFileCache<>(mContext, "consolidate_secret.pcl"); - ParcelableFileCache cachePublic = - new ParcelableFileCache<>(mContext, "consolidate_public.pcl"); + ParcelableFileCache cacheSecret, cachePublic; // Set flag that we have a cached consolidation here try { + cacheSecret = new ParcelableFileCache<>(mContext, "consolidate_secret.pcl"); IteratorWithSize itSecrets = cacheSecret.readCache(false); int numSecrets = itSecrets.getSize(); @@ -1253,6 +1256,7 @@ public class ProviderHelper { try { + cachePublic = new ParcelableFileCache<>(mContext, "consolidate_public.pcl"); IteratorWithSize itPublics = cachePublic.readCache(); int numPublics = itPublics.getSize(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java index 180020d0b..a6d5b02c9 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java @@ -131,6 +131,7 @@ public class KeychainIntentServiceHandler extends Handler { case MESSAGE_PREVENT_CANCEL: mProgressDialogFragment.setPreventCancel(true); + break; default: Log.e(Constants.TAG, "unknown handler message!"); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ParcelableFileCache.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ParcelableFileCache.java index 5de682fe6..6f9cb277e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ParcelableFileCache.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ParcelableFileCache.java @@ -104,7 +104,6 @@ public class ParcelableFileCache { throw new IOException(e); } - // yes this is sloppy data flow. WE WOULDN'T NEED THIS WITH TUPLE RETURN TYPES final int numEntries = ois.readInt(); return new IteratorWithSize() { -- cgit v1.2.3 From 7b24ee7b55db99467dd63e631ba55a27d08587d5 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Sun, 1 Feb 2015 23:14:26 +0100 Subject: rewrite PgpSignEncrypt data flow - introduce high-level SignEncryptOperation for uri to uri signing/encryption - use SignEncryptParcel for high-level operation parameters - use PgpSignEncryptInput plus streams for low-level operation parameters - get rid of all sign/encrypt logic in KeychainIntentService --- .../keychain/KeychainApplication.java | 4 +- .../keychain/keyimport/CloudSearch.java | 2 +- .../keychain/keyimport/HkpKeyserver.java | 4 +- .../keychain/keyimport/ImportKeysListEntry.java | 2 +- .../keychain/operations/CertifyOperation.java | 8 +- .../keychain/operations/EditKeyOperation.java | 6 +- .../keychain/operations/ImportExportOperation.java | 8 +- .../keychain/operations/PromoteKeyOperation.java | 2 +- .../keychain/operations/SignEncryptOperation.java | 136 ++++ .../keychain/operations/results/DeleteResult.java | 2 - .../operations/results/OperationResult.java | 65 +- .../operations/results/PgpSignEncryptResult.java | 139 ++++ .../operations/results/SignEncryptResult.java | 106 +-- .../operations/results/SingletonResult.java | 5 - .../keychain/pgp/PgpDecryptVerify.java | 8 +- .../sufficientlysecure/keychain/pgp/PgpHelper.java | 2 +- .../keychain/pgp/PgpSignEncrypt.java | 724 --------------------- .../keychain/pgp/PgpSignEncryptInput.java | 176 +++++ .../keychain/pgp/PgpSignEncryptOperation.java | 578 ++++++++++++++++ .../keychain/pgp/SignEncryptParcel.java | 135 ++++ .../keychain/pgp/UncachedKeyRing.java | 2 +- .../keychain/pgp/WrappedUserAttribute.java | 1 - .../keychain/provider/KeychainDatabase.java | 2 +- .../keychain/provider/KeychainProvider.java | 2 +- .../keychain/provider/ProviderHelper.java | 24 +- .../keychain/remote/OpenPgpService.java | 117 +--- .../remote/ui/AccountSettingsActivity.java | 6 +- .../remote/ui/AccountSettingsFragment.java | 4 +- .../keychain/remote/ui/AppSettingsActivity.java | 2 +- .../service/ContactSyncAdapterService.java | 2 +- .../keychain/service/KeychainIntentService.java | 175 +---- .../service/KeychainIntentServiceHandler.java | 2 +- .../keychain/service/PassphraseCacheService.java | 2 +- .../keychain/service/SaveKeyringParcel.java | 1 + .../keychain/ui/ConsolidateDialogActivity.java | 2 +- .../keychain/ui/CreateKeyFinalFragment.java | 6 +- .../keychain/ui/DecryptFilesActivity.java | 2 +- .../keychain/ui/DecryptFilesFragment.java | 6 +- .../keychain/ui/DecryptFragment.java | 2 +- .../keychain/ui/DecryptTextActivity.java | 4 +- .../keychain/ui/DecryptTextFragment.java | 2 +- .../keychain/ui/EncryptActivity.java | 36 +- .../keychain/ui/EncryptFilesActivity.java | 50 +- .../keychain/ui/EncryptFilesFragment.java | 2 +- .../keychain/ui/EncryptTextActivity.java | 55 +- .../keychain/ui/FirstTimeActivity.java | 2 +- .../keychain/ui/ImportKeysCloudFragment.java | 2 +- .../keychain/ui/KeyListFragment.java | 12 +- .../keychain/ui/NavDrawerActivity.java | 2 - .../keychain/ui/NfcIntentActivity.java | 2 +- .../keychain/ui/QrCodeViewActivity.java | 4 +- .../keychain/ui/UploadKeyActivity.java | 2 +- .../keychain/ui/ViewCertActivity.java | 4 +- .../keychain/ui/ViewKeyMainFragment.java | 6 +- .../ui/adapter/ImportKeysListCloudLoader.java | 6 +- .../keychain/ui/adapter/ImportKeysListLoader.java | 2 +- .../keychain/ui/adapter/MultiUserIdsAdapter.java | 2 +- .../ui/adapter/SelectKeyCursorAdapter.java | 2 +- .../keychain/ui/adapter/SubkeysAdapter.java | 4 +- .../keychain/ui/adapter/SubkeysAddedAdapter.java | 2 +- .../keychain/ui/adapter/UserIdsAdapter.java | 2 +- .../ui/dialog/AddUserIdDialogFragment.java | 2 +- .../keychain/ui/dialog/FileDialogFragment.java | 2 +- .../ui/widget/EncryptKeyCompletionView.java | 6 +- .../keychain/ui/widget/KeySpinner.java | 2 +- .../keychain/util/ContactHelper.java | 2 +- .../keychain/util/InputData.java | 12 + .../keychain/util/TlsHelper.java | 1 - 68 files changed, 1451 insertions(+), 1253 deletions(-) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/SignEncryptOperation.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/PgpSignEncryptResult.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptInput.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/SignEncryptParcel.java (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java index 446699a81..957ce4b23 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java @@ -32,12 +32,12 @@ import android.provider.ContactsContract; import android.widget.Toast; import org.spongycastle.jce.provider.BouncyCastleProvider; -import org.sufficientlysecure.keychain.util.Preferences; -import org.sufficientlysecure.keychain.util.TlsHelper; import org.sufficientlysecure.keychain.provider.TemporaryStorageProvider; import org.sufficientlysecure.keychain.ui.ConsolidateDialogActivity; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.PRNGFixes; +import org.sufficientlysecure.keychain.util.Preferences; +import org.sufficientlysecure.keychain.util.TlsHelper; import java.security.Security; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/CloudSearch.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/CloudSearch.java index 3b281876f..c0221fad3 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/CloudSearch.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/CloudSearch.java @@ -17,8 +17,8 @@ package org.sufficientlysecure.keychain.keyimport; import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.util.Preferences; import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.Preferences; import java.util.ArrayList; import java.util.Vector; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java index f39c552a3..480319081 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java @@ -19,10 +19,10 @@ package org.sufficientlysecure.keychain.keyimport; import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; -import org.sufficientlysecure.keychain.util.TlsHelper; import org.sufficientlysecure.keychain.pgp.PgpHelper; +import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.TlsHelper; import java.io.BufferedWriter; import java.io.IOException; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java index 1d5ee76a4..591408c8b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java @@ -23,9 +23,9 @@ import android.os.Parcelable; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.pgp.KeyRing; -import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; import org.sufficientlysecure.keychain.pgp.UncachedPublicKey; +import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import java.io.Serializable; import java.util.ArrayList; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/CertifyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/CertifyOperation.java index 3b391814e..025f45f7f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/CertifyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/CertifyOperation.java @@ -5,6 +5,10 @@ import android.content.Context; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.keyimport.HkpKeyserver; import org.sufficientlysecure.keychain.keyimport.Keyserver.AddKeyException; +import org.sufficientlysecure.keychain.operations.results.CertifyResult; +import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; +import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; +import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult; import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing; import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey; import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType; @@ -16,10 +20,6 @@ import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.provider.ProviderHelper.NotFoundException; import org.sufficientlysecure.keychain.service.CertifyActionsParcel; import org.sufficientlysecure.keychain.service.CertifyActionsParcel.CertifyAction; -import org.sufficientlysecure.keychain.operations.results.CertifyResult; -import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; -import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; -import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.util.Log; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java index 106c62688..7f14b08d9 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java @@ -4,16 +4,16 @@ import android.content.Context; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.operations.results.EditKeyResult; +import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; +import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; import org.sufficientlysecure.keychain.operations.results.PgpEditKeyResult; +import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult; import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKeyRing; import org.sufficientlysecure.keychain.pgp.PgpKeyOperation; import org.sufficientlysecure.keychain.pgp.Progressable; import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.provider.ProviderHelper.NotFoundException; -import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; -import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; -import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult; import org.sufficientlysecure.keychain.service.ContactSyncAdapterService; import org.sufficientlysecure.keychain.service.PassphraseCacheService; import org.sufficientlysecure.keychain.service.SaveKeyringParcel; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportExportOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportExportOperation.java index 3f3e0a432..8f10377cd 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportExportOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportExportOperation.java @@ -32,6 +32,10 @@ import org.sufficientlysecure.keychain.keyimport.Keyserver.AddKeyException; import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing; import org.sufficientlysecure.keychain.operations.results.ConsolidateResult; import org.sufficientlysecure.keychain.operations.results.ExportResult; +import org.sufficientlysecure.keychain.operations.results.ImportKeyResult; +import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; +import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; +import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult; import org.sufficientlysecure.keychain.pgp.CanonicalizedKeyRing; import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing; import org.sufficientlysecure.keychain.pgp.PgpHelper; @@ -41,10 +45,6 @@ import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables; import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; -import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; -import org.sufficientlysecure.keychain.operations.results.ImportKeyResult; -import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult; import org.sufficientlysecure.keychain.service.ContactSyncAdapterService; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.util.FileHelper; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/PromoteKeyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/PromoteKeyOperation.java index f10d11684..783b32477 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/PromoteKeyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/PromoteKeyOperation.java @@ -3,10 +3,10 @@ package org.sufficientlysecure.keychain.operations; import android.content.Context; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.operations.results.PromoteKeyResult; import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; import org.sufficientlysecure.keychain.operations.results.PgpEditKeyResult; +import org.sufficientlysecure.keychain.operations.results.PromoteKeyResult; import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult; import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing; import org.sufficientlysecure.keychain.pgp.Progressable; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/SignEncryptOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/SignEncryptOperation.java new file mode 100644 index 000000000..e98f6b150 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/SignEncryptOperation.java @@ -0,0 +1,136 @@ +package org.sufficientlysecure.keychain.operations; + +import android.content.Context; +import android.net.Uri; + +import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; +import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; +import org.sufficientlysecure.keychain.operations.results.PgpSignEncryptResult; +import org.sufficientlysecure.keychain.operations.results.SignEncryptResult; +import org.sufficientlysecure.keychain.pgp.PgpSignEncryptOperation; +import org.sufficientlysecure.keychain.pgp.Progressable; +import org.sufficientlysecure.keychain.pgp.SignEncryptParcel; +import org.sufficientlysecure.keychain.provider.ProviderHelper; +import org.sufficientlysecure.keychain.util.FileHelper; +import org.sufficientlysecure.keychain.util.InputData; +import org.sufficientlysecure.keychain.util.ProgressScaler; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.FileNotFoundException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.concurrent.atomic.AtomicBoolean; + +/** This is a high-level operation, which encapsulates one or more sign/encrypt + * operations, using URIs or byte arrays as input and output. + * + * This operation is fail-fast: If any sign/encrypt sub-operation fails or returns + * a pending result, it will terminate. + * + */ +public class SignEncryptOperation extends BaseOperation { + + public SignEncryptOperation(Context context, ProviderHelper providerHelper, + Progressable progressable, AtomicBoolean cancelled) { + super(context, providerHelper, progressable, cancelled); + } + + public SignEncryptResult execute(SignEncryptParcel input) { + + OperationLog log = new OperationLog(); + log.add(LogType.MSG_SE, 0); + + ArrayDeque inputUris = new ArrayDeque<>(input.getInputUris()); + ArrayDeque outputUris = new ArrayDeque<>(input.getOutputUris()); + byte[] inputBytes = input.getBytes(); + byte[] outputBytes = null; + + ArrayList results = new ArrayList<>(); + + do { + + if (checkCancelled()) { + log.add(LogType.MSG_OPERATION_CANCELLED, 0); + return new SignEncryptResult(SignEncryptResult.RESULT_CANCELLED, log, results); + } + + InputData inputData; + { + if (inputBytes != null) { + log.add(LogType.MSG_SE_INPUT_BYTES, 1); + InputStream is = new ByteArrayInputStream(inputBytes); + inputData = new InputData(is, inputBytes.length); + inputBytes = null; + } else { + if (inputUris.isEmpty()) { + log.add(LogType.MSG_SE_ERROR_NO_INPUT, 1); + return new SignEncryptResult(SignEncryptResult.RESULT_ERROR, log, results); + } + + log.add(LogType.MSG_SE_INPUT_URI, 1); + Uri uri = inputUris.removeFirst(); + try { + InputStream is = mContext.getContentResolver().openInputStream(uri); + long fileSize = FileHelper.getFileSize(mContext, uri, 0); + String filename = FileHelper.getFilename(mContext, uri); + inputData = new InputData(is, fileSize, filename); + } catch (FileNotFoundException e) { + log.add(LogType.MSG_SE_ERROR_INPUT_URI_NOT_FOUND, 1); + return new SignEncryptResult(SignEncryptResult.RESULT_ERROR, log, results); + } + } + } + + OutputStream outStream; + { + if (!outputUris.isEmpty()) { + try { + Uri outputUri = outputUris.removeFirst(); + outStream = mContext.getContentResolver().openOutputStream(outputUri); + } catch (FileNotFoundException e) { + log.add(LogType.MSG_SE_ERROR_OUTPUT_URI_NOT_FOUND, 1); + return new SignEncryptResult(SignEncryptResult.RESULT_ERROR, log, results); + } + } else { + if (outputBytes != null) { + log.add(LogType.MSG_SE_ERROR_TOO_MANY_INPUTS, 1); + return new SignEncryptResult(SignEncryptResult.RESULT_ERROR, log, results); + } + outStream = new ByteArrayOutputStream(); + } + } + + PgpSignEncryptOperation op = new PgpSignEncryptOperation(mContext, mProviderHelper, + new ProgressScaler(), mCancelled); + PgpSignEncryptResult result = op.execute(input, inputData, outStream); + results.add(result); + log.add(result, 2); + + if (result.isPending()) { + return new SignEncryptResult(SignEncryptResult.RESULT_PENDING, log, results); + } + + if (!result.success()) { + return new SignEncryptResult(SignEncryptResult.RESULT_ERROR, log, results); + } + + if (outStream instanceof ByteArrayOutputStream) { + outputBytes = ((ByteArrayOutputStream) outStream).toByteArray(); + } + + } while (!inputUris.isEmpty()); + + if (!outputUris.isEmpty()) { + // Any output URIs left are indicative of a programming error + log.add(LogType.MSG_SE_WARN_OUTPUT_LEFT, 1); + } + + log.add(LogType.MSG_SE_SUCCESS, 1); + return new SignEncryptResult(SignEncryptResult.RESULT_OK, log, results, outputBytes); + + } + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DeleteResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DeleteResult.java index e69fb59f2..62197541a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DeleteResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/DeleteResult.java @@ -21,8 +21,6 @@ package org.sufficientlysecure.keychain.operations.results; import android.app.Activity; import android.content.Intent; import android.os.Parcel; -import android.os.Parcelable; -import android.view.View; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.ui.LogDisplayActivity; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java index af4fcb071..078eb7354 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java @@ -20,15 +20,8 @@ package org.sufficientlysecure.keychain.operations.results; import android.app.Activity; import android.content.Intent; -import android.graphics.Color; import android.os.Parcel; import android.os.Parcelable; -import android.view.View; - -import com.nispok.snackbar.Snackbar; -import com.nispok.snackbar.Snackbar.SnackbarDuration; -import com.nispok.snackbar.SnackbarManager; -import com.nispok.snackbar.listeners.ActionClickListener; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; @@ -593,28 +586,42 @@ public abstract class OperationResult implements Parcelable { MSG_DC_UNLOCKING (LogLevel.INFO, R.string.msg_dc_unlocking), // signencrypt - MSG_SE_ASYMMETRIC (LogLevel.INFO, R.string.msg_se_asymmetric), - MSG_SE_CLEARSIGN_ONLY (LogLevel.DEBUG, R.string.msg_se_clearsign_only), - MSG_SE_COMPRESSING (LogLevel.DEBUG, R.string.msg_se_compressing), - MSG_SE_ENCRYPTING (LogLevel.DEBUG, R.string.msg_se_encrypting), - MSG_SE_ERROR_BAD_PASSPHRASE (LogLevel.ERROR, R.string.msg_se_error_bad_passphrase), - MSG_SE_ERROR_IO (LogLevel.ERROR, R.string.msg_se_error_io), - MSG_SE_ERROR_SIGN_KEY(LogLevel.ERROR, R.string.msg_se_error_sign_key), - MSG_SE_ERROR_KEY_SIGN (LogLevel.ERROR, R.string.msg_se_error_key_sign), - MSG_SE_ERROR_NFC (LogLevel.ERROR, R.string.msg_se_error_nfc), - MSG_SE_ERROR_PGP (LogLevel.ERROR, R.string.msg_se_error_pgp), - MSG_SE_ERROR_SIG (LogLevel.ERROR, R.string.msg_se_error_sig), - MSG_SE_ERROR_UNLOCK (LogLevel.ERROR, R.string.msg_se_error_unlock), - MSG_SE_KEY_OK (LogLevel.OK, R.string.msg_se_key_ok), - MSG_SE_KEY_UNKNOWN (LogLevel.DEBUG, R.string.msg_se_key_unknown), - MSG_SE_KEY_WARN (LogLevel.WARN, R.string.msg_se_key_warn), - MSG_SE_OK (LogLevel.OK, R.string.msg_se_ok), - MSG_SE_PENDING_NFC (LogLevel.INFO, R.string.msg_se_pending_nfc), - MSG_SE_PENDING_PASSPHRASE (LogLevel.INFO, R.string.msg_se_pending_passphrase), - MSG_SE (LogLevel.DEBUG, R.string.msg_se), - MSG_SE_SIGNING (LogLevel.DEBUG, R.string.msg_se_signing), - MSG_SE_SIGCRYPTING (LogLevel.DEBUG, R.string.msg_se_sigcrypting), - MSG_SE_SYMMETRIC (LogLevel.INFO, R.string.msg_se_symmetric), + MSG_SE (LogLevel.START, R.string.msg_se), + MSG_SE_INPUT_BYTES (LogLevel.INFO, R.string.msg_se_input_bytes), + MSG_SE_INPUT_URI (LogLevel.INFO, R.string.msg_se_input_uri), + MSG_SE_ERROR_NO_INPUT (LogLevel.DEBUG, R.string.msg_se_error_no_input), + MSG_SE_ERROR_INPUT_URI_NOT_FOUND (LogLevel.ERROR, R.string.msg_se_error_input_uri_not_found), + MSG_SE_ERROR_OUTPUT_URI_NOT_FOUND (LogLevel.ERROR, R.string.msg_se_error_output_uri_not_found), + MSG_SE_ERROR_TOO_MANY_INPUTS (LogLevel.ERROR, R.string.msg_se_error_too_many_inputs), + MSG_SE_WARN_OUTPUT_LEFT (LogLevel.WARN, R.string.msg_se_warn_output_left), + MSG_SE_SUCCESS (LogLevel.OK, R.string.msg_se_success), + + // pgpsignencrypt + MSG_PSE_ASYMMETRIC (LogLevel.INFO, R.string.msg_pse_asymmetric), + MSG_PSE_CLEARSIGN_ONLY (LogLevel.DEBUG, R.string.msg_pse_clearsign_only), + MSG_PSE_COMPRESSING (LogLevel.DEBUG, R.string.msg_pse_compressing), + MSG_PSE_ENCRYPTING (LogLevel.DEBUG, R.string.msg_pse_encrypting), + MSG_PSE_ERROR_BAD_PASSPHRASE (LogLevel.ERROR, R.string.msg_pse_error_bad_passphrase), + MSG_PSE_ERROR_HASH_ALGO (LogLevel.ERROR, R.string.msg_pse_error_hash_algo), + MSG_PSE_ERROR_IO (LogLevel.ERROR, R.string.msg_pse_error_io), + MSG_PSE_ERROR_SIGN_KEY(LogLevel.ERROR, R.string.msg_pse_error_sign_key), + MSG_PSE_ERROR_KEY_SIGN (LogLevel.ERROR, R.string.msg_pse_error_key_sign), + MSG_PSE_ERROR_NFC (LogLevel.ERROR, R.string.msg_pse_error_nfc), + MSG_PSE_ERROR_PGP (LogLevel.ERROR, R.string.msg_pse_error_pgp), + MSG_PSE_ERROR_SIG (LogLevel.ERROR, R.string.msg_pse_error_sig), + MSG_PSE_ERROR_UNLOCK (LogLevel.ERROR, R.string.msg_pse_error_unlock), + MSG_PSE_KEY_OK (LogLevel.OK, R.string.msg_pse_key_ok), + MSG_PSE_KEY_UNKNOWN (LogLevel.DEBUG, R.string.msg_pse_key_unknown), + MSG_PSE_KEY_WARN (LogLevel.WARN, R.string.msg_pse_key_warn), + MSG_PSE_OK (LogLevel.OK, R.string.msg_pse_ok), + MSG_PSE_PENDING_NFC (LogLevel.INFO, R.string.msg_pse_pending_nfc), + MSG_PSE_PENDING_PASSPHRASE (LogLevel.INFO, R.string.msg_pse_pending_passphrase), + MSG_PSE (LogLevel.DEBUG, R.string.msg_pse), + MSG_PSE_SIGNING (LogLevel.DEBUG, R.string.msg_pse_signing), + MSG_PSE_SIGNING_CLEARTEXT (LogLevel.DEBUG, R.string.msg_pse_signing_cleartext), + MSG_PSE_SIGNING_DETACHED (LogLevel.DEBUG, R.string.msg_pse_signing_detached), + MSG_PSE_SIGCRYPTING (LogLevel.DEBUG, R.string.msg_pse_sigcrypting), + MSG_PSE_SYMMETRIC (LogLevel.INFO, R.string.msg_pse_symmetric), MSG_CRT_CERTIFYING (LogLevel.DEBUG, R.string.msg_crt_certifying), MSG_CRT_CERTIFY_ALL (LogLevel.DEBUG, R.string.msg_crt_certify_all), diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/PgpSignEncryptResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/PgpSignEncryptResult.java new file mode 100644 index 000000000..de2f64404 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/PgpSignEncryptResult.java @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2014 Vincent Breitmoser + * + * 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 . + */ + +package org.sufficientlysecure.keychain.operations.results; + +import android.os.Parcel; + +import java.util.Date; + +public class PgpSignEncryptResult extends OperationResult { + + // the fourth bit indicates a "data pending" result! (it's also a form of non-success) + public static final int RESULT_PENDING = RESULT_ERROR + 8; + + // fifth to sixth bit in addition indicate specific type of pending + public static final int RESULT_PENDING_PASSPHRASE = RESULT_PENDING + 16; + public static final int RESULT_PENDING_NFC = RESULT_PENDING + 32; + + long mKeyIdPassphraseNeeded; + + long mNfcKeyId; + byte[] mNfcHash; + int mNfcAlgo; + Date mNfcTimestamp; + String mNfcPassphrase; + byte[] mDetachedSignature; + + public long getKeyIdPassphraseNeeded() { + return mKeyIdPassphraseNeeded; + } + + public void setKeyIdPassphraseNeeded(long keyIdPassphraseNeeded) { + mKeyIdPassphraseNeeded = keyIdPassphraseNeeded; + } + + public void setNfcData(long nfcKeyId, byte[] nfcHash, int nfcAlgo, Date nfcTimestamp, String passphrase) { + mNfcKeyId = nfcKeyId; + mNfcHash = nfcHash; + mNfcAlgo = nfcAlgo; + mNfcTimestamp = nfcTimestamp; + mNfcPassphrase = passphrase; + } + + public void setDetachedSignature(byte[] detachedSignature) { + mDetachedSignature = detachedSignature; + } + + public long getNfcKeyId() { + return mNfcKeyId; + } + + public byte[] getNfcHash() { + return mNfcHash; + } + + public int getNfcAlgo() { + return mNfcAlgo; + } + + public Date getNfcTimestamp() { + return mNfcTimestamp; + } + + public String getNfcPassphrase() { + return mNfcPassphrase; + } + + public byte[] getDetachedSignature() { + return mDetachedSignature; + } + + public boolean isPending() { + return (mResult & RESULT_PENDING) == RESULT_PENDING; + } + + public PgpSignEncryptResult(int result, OperationLog log) { + super(result, log); + } + + public PgpSignEncryptResult(Parcel source) { + super(source); + mNfcHash = source.readInt() != 0 ? source.createByteArray() : null; + mNfcAlgo = source.readInt(); + mNfcTimestamp = source.readInt() != 0 ? new Date(source.readLong()) : null; + mDetachedSignature = source.readInt() != 0 ? source.createByteArray() : null; + } + + public int describeContents() { + return 0; + } + + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + if (mNfcHash != null) { + dest.writeInt(1); + dest.writeByteArray(mNfcHash); + } else { + dest.writeInt(0); + } + dest.writeInt(mNfcAlgo); + if (mNfcTimestamp != null) { + dest.writeInt(1); + dest.writeLong(mNfcTimestamp.getTime()); + } else { + dest.writeInt(0); + } + if (mDetachedSignature != null) { + dest.writeInt(1); + dest.writeByteArray(mDetachedSignature); + } else { + dest.writeInt(0); + } + } + + public static final Creator CREATOR = new Creator() { + public PgpSignEncryptResult createFromParcel(final Parcel source) { + return new PgpSignEncryptResult(source); + } + + public PgpSignEncryptResult[] newArray(final int size) { + return new PgpSignEncryptResult[size]; + } + }; + +} \ No newline at end of file diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/SignEncryptResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/SignEncryptResult.java index c336f8502..ed0de65b0 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/SignEncryptResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/SignEncryptResult.java @@ -19,84 +19,42 @@ package org.sufficientlysecure.keychain.operations.results; import android.os.Parcel; -import java.util.Date; +import java.util.ArrayList; public class SignEncryptResult extends OperationResult { - // the fourth bit indicates a "data pending" result! (it's also a form of non-success) - public static final int RESULT_PENDING = RESULT_ERROR + 8; - - // fifth to sixth bit in addition indicate specific type of pending - public static final int RESULT_PENDING_PASSPHRASE = RESULT_PENDING + 16; - public static final int RESULT_PENDING_NFC = RESULT_PENDING + 32; - - long mKeyIdPassphraseNeeded; - - long mNfcKeyId; - byte[] mNfcHash; - int mNfcAlgo; - Date mNfcTimestamp; - String mNfcPassphrase; - byte[] mDetachedSignature; - - public long getKeyIdPassphraseNeeded() { - return mKeyIdPassphraseNeeded; - } - - public void setKeyIdPassphraseNeeded(long keyIdPassphraseNeeded) { - mKeyIdPassphraseNeeded = keyIdPassphraseNeeded; - } + ArrayList mResults; + byte[] mResultBytes; - public void setNfcData(long nfcKeyId, byte[] nfcHash, int nfcAlgo, Date nfcTimestamp, String passphrase) { - mNfcKeyId = nfcKeyId; - mNfcHash = nfcHash; - mNfcAlgo = nfcAlgo; - mNfcTimestamp = nfcTimestamp; - mNfcPassphrase = passphrase; - } - - public void setDetachedSignature(byte[] detachedSignature) { - mDetachedSignature = detachedSignature; - } - - public long getNfcKeyId() { - return mNfcKeyId; - } - - public byte[] getNfcHash() { - return mNfcHash; - } - - public int getNfcAlgo() { - return mNfcAlgo; - } - - public Date getNfcTimestamp() { - return mNfcTimestamp; - } - - public String getNfcPassphrase() { - return mNfcPassphrase; - } + public static final int RESULT_PENDING = RESULT_ERROR + 8; - public byte[] getDetachedSignature() { - return mDetachedSignature; + public PgpSignEncryptResult getPending() { + for (PgpSignEncryptResult sub : mResults) { + if (sub.isPending()) { + return sub; + } + } + return null; } - public boolean isPending() { - return (mResult & RESULT_PENDING) == RESULT_PENDING; + public SignEncryptResult(int result, OperationLog log, ArrayList results) { + super(result, log); + mResults = results; } - public SignEncryptResult(int result, OperationLog log) { + public SignEncryptResult(int result, OperationLog log, ArrayList results, byte[] resultBytes) { super(result, log); + mResults = results; + mResultBytes = resultBytes; } public SignEncryptResult(Parcel source) { super(source); - mNfcHash = source.readInt() != 0 ? source.createByteArray() : null; - mNfcAlgo = source.readInt(); - mNfcTimestamp = source.readInt() != 0 ? new Date(source.readLong()) : null; - mDetachedSignature = source.readInt() != 0 ? source.createByteArray() : null; + mResults = source.createTypedArrayList(PgpSignEncryptResult.CREATOR); + } + + public byte[] getResultBytes() { + return mResultBytes; } public int describeContents() { @@ -105,25 +63,7 @@ public class SignEncryptResult extends OperationResult { public void writeToParcel(Parcel dest, int flags) { super.writeToParcel(dest, flags); - if (mNfcHash != null) { - dest.writeInt(1); - dest.writeByteArray(mNfcHash); - } else { - dest.writeInt(0); - } - dest.writeInt(mNfcAlgo); - if (mNfcTimestamp != null) { - dest.writeInt(1); - dest.writeLong(mNfcTimestamp.getTime()); - } else { - dest.writeInt(0); - } - if (mDetachedSignature != null) { - dest.writeInt(1); - dest.writeByteArray(mDetachedSignature); - } else { - dest.writeInt(0); - } + dest.writeTypedList(mResults); } public static final Creator CREATOR = new Creator() { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/SingletonResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/SingletonResult.java index b53eda5f6..04cb241f9 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/SingletonResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/SingletonResult.java @@ -18,13 +18,8 @@ package org.sufficientlysecure.keychain.operations.results; -import android.app.Activity; import android.os.Parcel; -import com.github.johnpersano.supertoasts.SuperCardToast; -import com.github.johnpersano.supertoasts.SuperToast; -import com.github.johnpersano.supertoasts.util.Style; - /** This is a simple subclass meant to contain only a single log message. This log * message is also shown without a log button in the createNotify SuperToast. */ public class SingletonResult extends OperationResult { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java index a69c5fe36..ad9b1900e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java @@ -39,7 +39,6 @@ import org.spongycastle.openpgp.jcajce.JcaPGPObjectFactory; import org.spongycastle.openpgp.operator.PBEDataDecryptorFactory; import org.spongycastle.openpgp.operator.PGPDigestCalculatorProvider; import org.spongycastle.openpgp.operator.PublicKeyDataDecryptorFactory; -import org.spongycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator; import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider; import org.spongycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder; import org.spongycastle.openpgp.operator.jcajce.JcePBEDataDecryptorFactoryBuilder; @@ -47,12 +46,12 @@ import org.spongycastle.openpgp.operator.jcajce.NfcSyncPublicKeyDataDecryptorFac import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.operations.BaseOperation; -import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; -import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; -import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult; import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; +import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; +import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; +import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.util.InputData; import org.sufficientlysecure.keychain.util.Log; @@ -616,6 +615,7 @@ public class PgpDecryptVerify extends BaseOperation { int length; byte[] buffer = new byte[1 << 16]; while ((length = dataIn.read(buffer)) > 0) { + Log.d(Constants.TAG, "read bytes: " + length); if (mOutStream != null) { mOutStream.write(buffer, 0, length); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpHelper.java index 0a15fd98f..12de2f637 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpHelper.java @@ -24,8 +24,8 @@ import android.content.pm.PackageManager.NameNotFoundException; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.util.Preferences; import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.Preferences; import java.io.File; import java.io.IOException; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java deleted file mode 100644 index 060db96b4..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java +++ /dev/null @@ -1,724 +0,0 @@ -/* - * Copyright (C) 2012-2014 Dominik Schürmann - * Copyright (C) 2010-2014 Thialfihar - * Copyright (C) 2014 Vincent Breitmoser - * - * 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 . - */ - -package org.sufficientlysecure.keychain.pgp; - -import android.content.Context; - -import org.spongycastle.bcpg.ArmoredOutputStream; -import org.spongycastle.bcpg.BCPGOutputStream; -import org.spongycastle.bcpg.CompressionAlgorithmTags; -import org.spongycastle.openpgp.PGPCompressedDataGenerator; -import org.spongycastle.openpgp.PGPEncryptedDataGenerator; -import org.spongycastle.openpgp.PGPException; -import org.spongycastle.openpgp.PGPLiteralData; -import org.spongycastle.openpgp.PGPLiteralDataGenerator; -import org.spongycastle.openpgp.PGPSignatureGenerator; -import org.spongycastle.openpgp.operator.jcajce.JcePBEKeyEncryptionMethodGenerator; -import org.spongycastle.openpgp.operator.jcajce.JcePGPDataEncryptorBuilder; -import org.spongycastle.openpgp.operator.jcajce.NfcSyncPGPContentSignerBuilder; -import org.spongycastle.util.encoders.Hex; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.operations.BaseOperation; -import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; -import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; -import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; -import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; -import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; -import org.sufficientlysecure.keychain.operations.results.SignEncryptResult; -import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; -import org.sufficientlysecure.keychain.util.InputData; -import org.sufficientlysecure.keychain.util.Log; -import org.sufficientlysecure.keychain.util.ProgressScaler; - -import java.io.BufferedReader; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.UnsupportedEncodingException; -import java.security.SignatureException; -import java.util.Arrays; -import java.util.Date; -import java.util.LinkedList; - -/** - * This class uses a Builder pattern! - */ -public class PgpSignEncrypt extends BaseOperation { - private String mVersionHeader; - private InputData mData; - private OutputStream mOutStream; - - private boolean mEnableAsciiArmorOutput; - private int mCompressionId; - private long[] mEncryptionMasterKeyIds; - private String mSymmetricPassphrase; - private int mSymmetricEncryptionAlgorithm; - private long mSignatureMasterKeyId; - private Long mSignatureSubKeyId; - private int mSignatureHashAlgorithm; - private String mSignaturePassphrase; - private long mAdditionalEncryptId; - private boolean mCleartextSignature; - private boolean mDetachedSignature; - private String mOriginalFilename; - private boolean mFailOnMissingEncryptionKeyIds; - private String mCharset; - - private byte[] mNfcSignedHash = null; - private Date mNfcCreationTimestamp = null; - - private static byte[] NEW_LINE; - - static { - try { - NEW_LINE = "\r\n".getBytes("UTF-8"); - } catch (UnsupportedEncodingException e) { - Log.e(Constants.TAG, "UnsupportedEncodingException", e); - } - } - - protected PgpSignEncrypt(Builder builder) { - super(builder.mContext, builder.mProviderHelper, builder.mProgressable); - - // private Constructor can only be called from Builder - this.mVersionHeader = builder.mVersionHeader; - this.mData = builder.mData; - this.mOutStream = builder.mOutStream; - - this.mEnableAsciiArmorOutput = builder.mEnableAsciiArmorOutput; - this.mCompressionId = builder.mCompressionId; - this.mEncryptionMasterKeyIds = builder.mEncryptionMasterKeyIds; - this.mSymmetricPassphrase = builder.mSymmetricPassphrase; - this.mSymmetricEncryptionAlgorithm = builder.mSymmetricEncryptionAlgorithm; - this.mSignatureMasterKeyId = builder.mSignatureMasterKeyId; - this.mSignatureSubKeyId = builder.mSignatureSubKeyId; - this.mSignatureHashAlgorithm = builder.mSignatureHashAlgorithm; - this.mSignaturePassphrase = builder.mSignaturePassphrase; - this.mAdditionalEncryptId = builder.mAdditionalEncryptId; - this.mCleartextSignature = builder.mCleartextSignature; - this.mDetachedSignature = builder.mDetachedSignature; - this.mNfcSignedHash = builder.mNfcSignedHash; - this.mNfcCreationTimestamp = builder.mNfcCreationTimestamp; - this.mOriginalFilename = builder.mOriginalFilename; - this.mFailOnMissingEncryptionKeyIds = builder.mFailOnMissingEncryptionKeyIds; - this.mCharset = builder.mCharset; - } - - public static class Builder { - // mandatory parameter - private Context mContext; - private ProviderHelper mProviderHelper; - private Progressable mProgressable; - private InputData mData; - private OutputStream mOutStream; - - // optional - private String mVersionHeader = null; - private boolean mEnableAsciiArmorOutput = false; - private int mCompressionId = CompressionAlgorithmTags.UNCOMPRESSED; - private long[] mEncryptionMasterKeyIds = null; - private String mSymmetricPassphrase = null; - private int mSymmetricEncryptionAlgorithm = 0; - private long mSignatureMasterKeyId = Constants.key.none; - private Long mSignatureSubKeyId = null; - private int mSignatureHashAlgorithm = 0; - private String mSignaturePassphrase = null; - private long mAdditionalEncryptId = Constants.key.none; - private boolean mCleartextSignature = false; - private boolean mDetachedSignature = false; - private String mOriginalFilename = ""; - private byte[] mNfcSignedHash = null; - private Date mNfcCreationTimestamp = null; - private boolean mFailOnMissingEncryptionKeyIds = false; - private String mCharset = null; - - public Builder(Context context, ProviderHelper providerHelper, Progressable progressable, - InputData data, OutputStream outStream) { - mContext = context; - mProviderHelper = providerHelper; - mProgressable = progressable; - - mData = data; - mOutStream = outStream; - } - - public Builder setVersionHeader(String versionHeader) { - mVersionHeader = versionHeader; - return this; - } - - public Builder setEnableAsciiArmorOutput(boolean enableAsciiArmorOutput) { - mEnableAsciiArmorOutput = enableAsciiArmorOutput; - return this; - } - - public Builder setCompressionId(int compressionId) { - mCompressionId = compressionId; - return this; - } - - public Builder setEncryptionMasterKeyIds(long[] encryptionMasterKeyIds) { - mEncryptionMasterKeyIds = encryptionMasterKeyIds; - return this; - } - - public Builder setSymmetricPassphrase(String symmetricPassphrase) { - mSymmetricPassphrase = symmetricPassphrase; - return this; - } - - public Builder setSymmetricEncryptionAlgorithm(int symmetricEncryptionAlgorithm) { - mSymmetricEncryptionAlgorithm = symmetricEncryptionAlgorithm; - return this; - } - - public Builder setSignatureMasterKeyId(long signatureMasterKeyId) { - mSignatureMasterKeyId = signatureMasterKeyId; - return this; - } - - public Builder setSignatureSubKeyId(long signatureSubKeyId) { - mSignatureSubKeyId = signatureSubKeyId; - return this; - } - - public Builder setSignatureHashAlgorithm(int signatureHashAlgorithm) { - mSignatureHashAlgorithm = signatureHashAlgorithm; - return this; - } - - public Builder setSignaturePassphrase(String signaturePassphrase) { - mSignaturePassphrase = signaturePassphrase; - return this; - } - - public Builder setFailOnMissingEncryptionKeyIds(boolean failOnMissingEncryptionKeyIds) { - mFailOnMissingEncryptionKeyIds = failOnMissingEncryptionKeyIds; - return this; - } - - public Builder setCharset(String charset) { - mCharset = charset; - return this; - } - - /** - * Also encrypt with the signing keyring - * - * @param additionalEncryptId - * @return - */ - public Builder setAdditionalEncryptId(long additionalEncryptId) { - mAdditionalEncryptId = additionalEncryptId; - return this; - } - - public Builder setCleartextSignature(boolean cleartextSignature) { - mCleartextSignature = cleartextSignature; - return this; - } - - public Builder setDetachedSignature(boolean detachedSignature) { - mDetachedSignature = detachedSignature; - return this; - } - - public Builder setOriginalFilename(String originalFilename) { - mOriginalFilename = originalFilename; - return this; - } - - public Builder setNfcState(byte[] signedHash, Date creationTimestamp) { - mNfcSignedHash = signedHash; - mNfcCreationTimestamp = creationTimestamp; - return this; - } - - public PgpSignEncrypt build() { - return new PgpSignEncrypt(this); - } - } - - /** - * Signs and/or encrypts data based on parameters of class - */ - public SignEncryptResult execute() { - - int indent = 0; - OperationLog log = new OperationLog(); - - log.add(LogType.MSG_SE, indent); - indent += 1; - - boolean enableSignature = mSignatureMasterKeyId != Constants.key.none; - boolean enableEncryption = ((mEncryptionMasterKeyIds != null && mEncryptionMasterKeyIds.length > 0) - || mSymmetricPassphrase != null); - boolean enableCompression = (mCompressionId != CompressionAlgorithmTags.UNCOMPRESSED); - - Log.d(Constants.TAG, "enableSignature:" + enableSignature - + "\nenableEncryption:" + enableEncryption - + "\nenableCompression:" + enableCompression - + "\nenableAsciiArmorOutput:" + mEnableAsciiArmorOutput); - - // add additional key id to encryption ids (mostly to do self-encryption) - if (enableEncryption && mAdditionalEncryptId != Constants.key.none) { - mEncryptionMasterKeyIds = Arrays.copyOf(mEncryptionMasterKeyIds, mEncryptionMasterKeyIds.length + 1); - mEncryptionMasterKeyIds[mEncryptionMasterKeyIds.length - 1] = mAdditionalEncryptId; - } - - ArmoredOutputStream armorOut = null; - OutputStream out; - if (mEnableAsciiArmorOutput) { - armorOut = new ArmoredOutputStream(mOutStream); - if (mVersionHeader != null) { - armorOut.setHeader("Version", mVersionHeader); - } - // if we have a charset, put it in the header - if (mCharset != null) { - armorOut.setHeader("Charset", mCharset); - } - out = armorOut; - } else { - out = mOutStream; - } - - /* Get keys for signature generation for later usage */ - CanonicalizedSecretKey signingKey = null; - long signKeyId; - if (enableSignature) { - - try { - // fetch the indicated master key id (the one whose name we sign in) - CanonicalizedSecretKeyRing signingKeyRing = - mProviderHelper.getCanonicalizedSecretKeyRing(mSignatureMasterKeyId); - // fetch the specific subkey to sign with, or just use the master key if none specified - signKeyId = mSignatureSubKeyId != null ? mSignatureSubKeyId : mSignatureMasterKeyId; - signingKey = signingKeyRing.getSecretKey(signKeyId); - // make sure it's a signing key alright! - } catch (ProviderHelper.NotFoundException e) { - log.add(LogType.MSG_SE_ERROR_SIGN_KEY, indent); - return new SignEncryptResult(SignEncryptResult.RESULT_ERROR, log); - } - - // Make sure we are allowed to sign here! - if (!signingKey.canSign()) { - log.add(LogType.MSG_SE_ERROR_KEY_SIGN, indent); - return new SignEncryptResult(SignEncryptResult.RESULT_ERROR, log); - } - - // if no passphrase was explicitly set try to get it from the cache service - if (mSignaturePassphrase == null) { - try { - // returns "" if key has no passphrase - mSignaturePassphrase = getCachedPassphrase(signKeyId); - // TODO -// log.add(LogType.MSG_DC_PASS_CACHED, indent + 1); - } catch (PassphraseCacheInterface.NoSecretKeyException e) { - // TODO -// log.add(LogType.MSG_DC_ERROR_NO_KEY, indent + 1); - return new SignEncryptResult(SignEncryptResult.RESULT_ERROR, log); - } - - // if passphrase was not cached, return here indicating that a passphrase is missing! - if (mSignaturePassphrase == null) { - log.add(LogType.MSG_SE_PENDING_PASSPHRASE, indent + 1); - SignEncryptResult result = new SignEncryptResult(SignEncryptResult.RESULT_PENDING_PASSPHRASE, log); - result.setKeyIdPassphraseNeeded(signKeyId); - return result; - } - } - - updateProgress(R.string.progress_extracting_signature_key, 0, 100); - - try { - if (!signingKey.unlock(mSignaturePassphrase)) { - log.add(LogType.MSG_SE_ERROR_BAD_PASSPHRASE, indent); - return new SignEncryptResult(SignEncryptResult.RESULT_ERROR, log); - } - } catch (PgpGeneralException e) { - log.add(LogType.MSG_SE_ERROR_UNLOCK, indent); - return new SignEncryptResult(SignEncryptResult.RESULT_ERROR, log); - } - - // check if hash algo is supported - LinkedList supported = signingKey.getSupportedHashAlgorithms(); - if (!supported.contains(mSignatureHashAlgorithm)) { - // get most preferred - mSignatureHashAlgorithm = supported.getLast(); - } - } - updateProgress(R.string.progress_preparing_streams, 2, 100); - - /* Initialize PGPEncryptedDataGenerator for later usage */ - PGPEncryptedDataGenerator cPk = null; - if (enableEncryption) { - // has Integrity packet enabled! - JcePGPDataEncryptorBuilder encryptorBuilder = - new JcePGPDataEncryptorBuilder(mSymmetricEncryptionAlgorithm) - .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME) - .setWithIntegrityPacket(true); - - cPk = new PGPEncryptedDataGenerator(encryptorBuilder); - - if (mSymmetricPassphrase != null) { - // Symmetric encryption - log.add(LogType.MSG_SE_SYMMETRIC, indent); - - JcePBEKeyEncryptionMethodGenerator symmetricEncryptionGenerator = - new JcePBEKeyEncryptionMethodGenerator(mSymmetricPassphrase.toCharArray()); - cPk.addMethod(symmetricEncryptionGenerator); - } else { - log.add(LogType.MSG_SE_ASYMMETRIC, indent); - - // Asymmetric encryption - for (long id : mEncryptionMasterKeyIds) { - try { - CanonicalizedPublicKeyRing keyRing = mProviderHelper.getCanonicalizedPublicKeyRing( - KeyRings.buildUnifiedKeyRingUri(id)); - CanonicalizedPublicKey key = keyRing.getEncryptionSubKey(); - cPk.addMethod(key.getPubKeyEncryptionGenerator()); - log.add(LogType.MSG_SE_KEY_OK, indent + 1, - KeyFormattingUtils.convertKeyIdToHex(id)); - } catch (PgpKeyNotFoundException e) { - log.add(LogType.MSG_SE_KEY_WARN, indent + 1, - KeyFormattingUtils.convertKeyIdToHex(id)); - if (mFailOnMissingEncryptionKeyIds) { - return new SignEncryptResult(SignEncryptResult.RESULT_ERROR, log); - } - } catch (ProviderHelper.NotFoundException e) { - log.add(LogType.MSG_SE_KEY_UNKNOWN, indent + 1, - KeyFormattingUtils.convertKeyIdToHex(id)); - if (mFailOnMissingEncryptionKeyIds) { - return new SignEncryptResult(SignEncryptResult.RESULT_ERROR, log); - } - } - } - } - } - - /* Initialize signature generator object for later usage */ - PGPSignatureGenerator signatureGenerator = null; - if (enableSignature) { - updateProgress(R.string.progress_preparing_signature, 4, 100); - - try { - boolean cleartext = mCleartextSignature && mEnableAsciiArmorOutput && !enableEncryption; - signatureGenerator = signingKey.getSignatureGenerator( - mSignatureHashAlgorithm, cleartext, mNfcSignedHash, mNfcCreationTimestamp); - } catch (PgpGeneralException e) { - log.add(LogType.MSG_SE_ERROR_NFC, indent); - return new SignEncryptResult(SignEncryptResult.RESULT_ERROR, log); - } - } - - ProgressScaler progressScaler = - new ProgressScaler(mProgressable, 8, 95, 100); - PGPCompressedDataGenerator compressGen = null; - OutputStream pOut; - OutputStream encryptionOut = null; - BCPGOutputStream bcpgOut; - - ByteArrayOutputStream detachedByteOut = null; - ArmoredOutputStream detachedArmorOut = null; - BCPGOutputStream detachedBcpgOut = null; - - try { - - if (enableEncryption) { - /* actual encryption */ - updateProgress(R.string.progress_encrypting, 8, 100); - log.add(enableSignature - ? LogType.MSG_SE_SIGCRYPTING - : LogType.MSG_SE_ENCRYPTING, - indent - ); - indent += 1; - - encryptionOut = cPk.open(out, new byte[1 << 16]); - - if (enableCompression) { - log.add(LogType.MSG_SE_COMPRESSING, indent); - compressGen = new PGPCompressedDataGenerator(mCompressionId); - bcpgOut = new BCPGOutputStream(compressGen.open(encryptionOut)); - } else { - bcpgOut = new BCPGOutputStream(encryptionOut); - } - - if (enableSignature) { - signatureGenerator.generateOnePassVersion(false).encode(bcpgOut); - } - - PGPLiteralDataGenerator literalGen = new PGPLiteralDataGenerator(); - char literalDataFormatTag; - if (mCleartextSignature) { - literalDataFormatTag = PGPLiteralData.UTF8; - } else { - literalDataFormatTag = PGPLiteralData.BINARY; - } - pOut = literalGen.open(bcpgOut, literalDataFormatTag, mOriginalFilename, new Date(), - new byte[1 << 16]); - - long alreadyWritten = 0; - int length; - byte[] buffer = new byte[1 << 16]; - InputStream in = mData.getInputStream(); - while ((length = in.read(buffer)) > 0) { - pOut.write(buffer, 0, length); - - // update signature buffer if signature is requested - if (enableSignature) { - signatureGenerator.update(buffer, 0, length); - } - - alreadyWritten += length; - if (mData.getSize() > 0) { - long progress = 100 * alreadyWritten / mData.getSize(); - progressScaler.setProgress((int) progress, 100); - } - } - - literalGen.close(); - indent -= 1; - - } else if (enableSignature && mCleartextSignature && mEnableAsciiArmorOutput) { - /* cleartext signature: sign-only of ascii text */ - - updateProgress(R.string.progress_signing, 8, 100); - log.add(LogType.MSG_SE_SIGNING, indent); - - // write -----BEGIN PGP SIGNED MESSAGE----- - armorOut.beginClearText(mSignatureHashAlgorithm); - - InputStream in = mData.getInputStream(); - final BufferedReader reader = new BufferedReader(new InputStreamReader(in)); - - // update signature buffer with first line - processLine(reader.readLine(), armorOut, signatureGenerator); - - // TODO: progress: fake annealing? - while (true) { - String line = reader.readLine(); - - // end cleartext signature with newline, see http://tools.ietf.org/html/rfc4880#section-7 - if (line == null) { - armorOut.write(NEW_LINE); - break; - } - - armorOut.write(NEW_LINE); - - // update signature buffer with input line - signatureGenerator.update(NEW_LINE); - processLine(line, armorOut, signatureGenerator); - } - - armorOut.endClearText(); - - pOut = new BCPGOutputStream(armorOut); - } else if (enableSignature && mDetachedSignature) { - /* detached signature */ - - updateProgress(R.string.progress_signing, 8, 100); - log.add(LogType.MSG_SE_SIGNING, indent); - - InputStream in = mData.getInputStream(); - - // handle output stream separately for detached signatures - detachedByteOut = new ByteArrayOutputStream(); - OutputStream detachedOut = detachedByteOut; - if (mEnableAsciiArmorOutput) { - detachedArmorOut = new ArmoredOutputStream(detachedOut); - if (mVersionHeader != null) { - detachedArmorOut.setHeader("Version", mVersionHeader); - } - - detachedOut = detachedArmorOut; - } - detachedBcpgOut = new BCPGOutputStream(detachedOut); - - long alreadyWritten = 0; - int length; - byte[] buffer = new byte[1 << 16]; - while ((length = in.read(buffer)) > 0) { - // no output stream is written, no changed to original data! - - signatureGenerator.update(buffer, 0, length); - - alreadyWritten += length; - if (mData.getSize() > 0) { - long progress = 100 * alreadyWritten / mData.getSize(); - progressScaler.setProgress((int) progress, 100); - } - } - - pOut = null; - } else if (enableSignature && !mCleartextSignature && !mDetachedSignature) { - /* sign-only binary (files/data stream) */ - - updateProgress(R.string.progress_signing, 8, 100); - log.add(LogType.MSG_SE_SIGNING, indent); - - InputStream in = mData.getInputStream(); - - if (enableCompression) { - compressGen = new PGPCompressedDataGenerator(mCompressionId); - bcpgOut = new BCPGOutputStream(compressGen.open(out)); - } else { - bcpgOut = new BCPGOutputStream(out); - } - - signatureGenerator.generateOnePassVersion(false).encode(bcpgOut); - - PGPLiteralDataGenerator literalGen = new PGPLiteralDataGenerator(); - pOut = literalGen.open(bcpgOut, PGPLiteralData.BINARY, mOriginalFilename, new Date(), - new byte[1 << 16]); - - long alreadyWritten = 0; - int length; - byte[] buffer = new byte[1 << 16]; - while ((length = in.read(buffer)) > 0) { - pOut.write(buffer, 0, length); - - signatureGenerator.update(buffer, 0, length); - - alreadyWritten += length; - if (mData.getSize() > 0) { - long progress = 100 * alreadyWritten / mData.getSize(); - progressScaler.setProgress((int) progress, 100); - } - } - - literalGen.close(); - } else { - pOut = null; - // TODO: Is this log right? - log.add(LogType.MSG_SE_CLEARSIGN_ONLY, indent); - } - - if (enableSignature) { - updateProgress(R.string.progress_generating_signature, 95, 100); - try { - if (detachedBcpgOut != null) { - signatureGenerator.generate().encode(detachedBcpgOut); - } else { - signatureGenerator.generate().encode(pOut); - } - } catch (NfcSyncPGPContentSignerBuilder.NfcInteractionNeeded e) { - // this secret key diverts to a OpenPGP card, throw exception with hash that will be signed - log.add(LogType.MSG_SE_PENDING_NFC, indent); - SignEncryptResult result = - new SignEncryptResult(SignEncryptResult.RESULT_PENDING_NFC, log); - // Note that the checked key here is the master key, not the signing key - // (although these are always the same on Yubikeys) - result.setNfcData(mSignatureSubKeyId, e.hashToSign, e.hashAlgo, e.creationTimestamp, mSignaturePassphrase); - Log.d(Constants.TAG, "e.hashToSign" + Hex.toHexString(e.hashToSign)); - return result; - } - } - - // closing outputs - // NOTE: closing needs to be done in the correct order! - if (encryptionOut != null) { - if (compressGen != null) { - compressGen.close(); - } - - encryptionOut.close(); - } - // Note: Closing ArmoredOutputStream does not close the underlying stream - if (armorOut != null) { - armorOut.close(); - } - // Note: Closing ArmoredOutputStream does not close the underlying stream - if (detachedArmorOut != null) { - detachedArmorOut.close(); - } - // Also closes detachedBcpgOut - if (detachedByteOut != null) { - detachedByteOut.close(); - } - if (out != null) { - out.close(); - } - if (mOutStream != null) { - mOutStream.close(); - } - - } catch (SignatureException e) { - log.add(LogType.MSG_SE_ERROR_SIG, indent); - return new SignEncryptResult(SignEncryptResult.RESULT_ERROR, log); - } catch (PGPException e) { - log.add(LogType.MSG_SE_ERROR_PGP, indent); - return new SignEncryptResult(SignEncryptResult.RESULT_ERROR, log); - } catch (IOException e) { - log.add(LogType.MSG_SE_ERROR_IO, indent); - return new SignEncryptResult(SignEncryptResult.RESULT_ERROR, log); - } - - updateProgress(R.string.progress_done, 100, 100); - - log.add(LogType.MSG_SE_OK, indent); - SignEncryptResult result = new SignEncryptResult(SignEncryptResult.RESULT_OK, log); - if (detachedByteOut != null) { - try { - detachedByteOut.flush(); - detachedByteOut.close(); - } catch (IOException e) { - // silently catch - } - result.setDetachedSignature(detachedByteOut.toByteArray()); - } - return result; - } - - /** - * Remove whitespaces on line endings - */ - private static void processLine(final String pLine, final ArmoredOutputStream pArmoredOutput, - final PGPSignatureGenerator pSignatureGenerator) - throws IOException, SignatureException { - - if (pLine == null) { - return; - } - - final char[] chars = pLine.toCharArray(); - int len = chars.length; - - while (len > 0) { - if (!Character.isWhitespace(chars[len - 1])) { - break; - } - len--; - } - - final byte[] data = pLine.substring(0, len).getBytes("UTF-8"); - - if (pArmoredOutput != null) { - pArmoredOutput.write(data); - } - pSignatureGenerator.update(data); - } - -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptInput.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptInput.java new file mode 100644 index 000000000..9318be006 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptInput.java @@ -0,0 +1,176 @@ +package org.sufficientlysecure.keychain.pgp; + +import org.spongycastle.bcpg.CompressionAlgorithmTags; +import org.sufficientlysecure.keychain.Constants; + +import java.util.Date; + +public class PgpSignEncryptInput { + + protected String mVersionHeader = null; + protected boolean mEnableAsciiArmorOutput = false; + protected int mCompressionId = CompressionAlgorithmTags.UNCOMPRESSED; + protected long[] mEncryptionMasterKeyIds = null; + protected String mSymmetricPassphrase = null; + protected int mSymmetricEncryptionAlgorithm = 0; + protected long mSignatureMasterKeyId = Constants.key.none; + protected Long mSignatureSubKeyId = null; + protected int mSignatureHashAlgorithm = 0; + protected String mSignaturePassphrase = null; + protected long mAdditionalEncryptId = Constants.key.none; + protected byte[] mNfcSignedHash = null; + protected Date mNfcCreationTimestamp = null; + protected boolean mFailOnMissingEncryptionKeyIds = false; + protected String mCharset; + protected boolean mCleartextSignature; + protected boolean mDetachedSignature; + + public String getCharset() { + return mCharset; + } + + public void setCharset(String mCharset) { + this.mCharset = mCharset; + } + + public boolean ismFailOnMissingEncryptionKeyIds() { + return mFailOnMissingEncryptionKeyIds; + } + + public Date getNfcCreationTimestamp() { + return mNfcCreationTimestamp; + } + + public byte[] getNfcSignedHash() { + return mNfcSignedHash; + } + + public long getAdditionalEncryptId() { + return mAdditionalEncryptId; + } + + public PgpSignEncryptInput setAdditionalEncryptId(long additionalEncryptId) { + mAdditionalEncryptId = additionalEncryptId; + return this; + } + + public String getSignaturePassphrase() { + return mSignaturePassphrase; + } + + public PgpSignEncryptInput setSignaturePassphrase(String signaturePassphrase) { + mSignaturePassphrase = signaturePassphrase; + return this; + } + + public int getSignatureHashAlgorithm() { + return mSignatureHashAlgorithm; + } + + public PgpSignEncryptInput setSignatureHashAlgorithm(int signatureHashAlgorithm) { + mSignatureHashAlgorithm = signatureHashAlgorithm; + return this; + } + + public Long getSignatureSubKeyId() { + return mSignatureSubKeyId; + } + + public PgpSignEncryptInput setSignatureSubKeyId(long signatureSubKeyId) { + mSignatureSubKeyId = signatureSubKeyId; + return this; + } + + public long getSignatureMasterKeyId() { + return mSignatureMasterKeyId; + } + + public PgpSignEncryptInput setSignatureMasterKeyId(long signatureMasterKeyId) { + mSignatureMasterKeyId = signatureMasterKeyId; + return this; + } + + public int getSymmetricEncryptionAlgorithm() { + return mSymmetricEncryptionAlgorithm; + } + + public PgpSignEncryptInput setSymmetricEncryptionAlgorithm(int symmetricEncryptionAlgorithm) { + mSymmetricEncryptionAlgorithm = symmetricEncryptionAlgorithm; + return this; + } + + public String getSymmetricPassphrase() { + return mSymmetricPassphrase; + } + + public PgpSignEncryptInput setSymmetricPassphrase(String symmetricPassphrase) { + mSymmetricPassphrase = symmetricPassphrase; + return this; + } + + public long[] getEncryptionMasterKeyIds() { + return mEncryptionMasterKeyIds; + } + + public PgpSignEncryptInput setEncryptionMasterKeyIds(long[] encryptionMasterKeyIds) { + mEncryptionMasterKeyIds = encryptionMasterKeyIds; + return this; + } + + public int getCompressionId() { + return mCompressionId; + } + + public PgpSignEncryptInput setCompressionId(int compressionId) { + mCompressionId = compressionId; + return this; + } + + public boolean ismEnableAsciiArmorOutput() { + return mEnableAsciiArmorOutput; + } + + public String getVersionHeader() { + return mVersionHeader; + } + + public PgpSignEncryptInput setVersionHeader(String versionHeader) { + mVersionHeader = versionHeader; + return this; + } + + public PgpSignEncryptInput setEnableAsciiArmorOutput(boolean enableAsciiArmorOutput) { + mEnableAsciiArmorOutput = enableAsciiArmorOutput; + return this; + } + + public PgpSignEncryptInput setFailOnMissingEncryptionKeyIds(boolean failOnMissingEncryptionKeyIds) { + mFailOnMissingEncryptionKeyIds = failOnMissingEncryptionKeyIds; + return this; + } + + public PgpSignEncryptInput setNfcState(byte[] signedHash, Date creationTimestamp) { + mNfcSignedHash = signedHash; + mNfcCreationTimestamp = creationTimestamp; + return this; + } + + public PgpSignEncryptInput setCleartextSignature(boolean cleartextSignature) { + this.mCleartextSignature = cleartextSignature; + return this; + } + + public boolean isCleartextSignature() { + return mCleartextSignature; + } + + public PgpSignEncryptInput setDetachedSignature(boolean detachedSignature) { + this.mDetachedSignature = detachedSignature; + return this; + } + + public boolean isDetachedSignature() { + return mDetachedSignature; + } +} + diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java new file mode 100644 index 000000000..2fa01d241 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncryptOperation.java @@ -0,0 +1,578 @@ +/* + * Copyright (C) 2012-2014 Dominik Schürmann + * Copyright (C) 2010-2014 Thialfihar + * Copyright (C) 2014 Vincent Breitmoser + * + * 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 . + */ + +package org.sufficientlysecure.keychain.pgp; + +import android.content.Context; + +import org.spongycastle.bcpg.ArmoredOutputStream; +import org.spongycastle.bcpg.BCPGOutputStream; +import org.spongycastle.bcpg.CompressionAlgorithmTags; +import org.spongycastle.openpgp.PGPCompressedDataGenerator; +import org.spongycastle.openpgp.PGPEncryptedData; +import org.spongycastle.openpgp.PGPEncryptedDataGenerator; +import org.spongycastle.openpgp.PGPException; +import org.spongycastle.openpgp.PGPLiteralData; +import org.spongycastle.openpgp.PGPLiteralDataGenerator; +import org.spongycastle.openpgp.PGPSignatureGenerator; +import org.spongycastle.openpgp.operator.jcajce.JcePBEKeyEncryptionMethodGenerator; +import org.spongycastle.openpgp.operator.jcajce.JcePGPDataEncryptorBuilder; +import org.spongycastle.openpgp.operator.jcajce.NfcSyncPGPContentSignerBuilder; +import org.spongycastle.util.encoders.Hex; +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.operations.BaseOperation; +import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; +import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; +import org.sufficientlysecure.keychain.operations.results.PgpSignEncryptResult; +import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; +import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; +import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; +import org.sufficientlysecure.keychain.provider.ProviderHelper; +import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; +import org.sufficientlysecure.keychain.util.InputData; +import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.ProgressScaler; + +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.security.SignatureException; +import java.util.Arrays; +import java.util.Date; +import java.util.LinkedList; +import java.util.concurrent.atomic.AtomicBoolean; + +/** This class supports a single, low-level, sign/encrypt operation. + * + * The operation of this class takes an Input- and OutputStream plus a + * PgpSignEncryptInput, and signs and/or encrypts the stream as + * parametrized in the PgpSignEncryptInput object. It returns its status + * and a possible detached signature as a SignEncryptResult. + * + * For a high-level operation based on URIs, see SignEncryptOperation. + * + * @see org.sufficientlysecure.keychain.pgp.PgpSignEncryptInput + * @see org.sufficientlysecure.keychain.operations.results.PgpSignEncryptResult + * @see org.sufficientlysecure.keychain.operations.SignEncryptOperation + * + */ +public class PgpSignEncryptOperation extends BaseOperation { + + private static byte[] NEW_LINE; + + static { + try { + NEW_LINE = "\r\n".getBytes("UTF-8"); + } catch (UnsupportedEncodingException e) { + Log.e(Constants.TAG, "UnsupportedEncodingException", e); + } + } + + public PgpSignEncryptOperation(Context context, ProviderHelper providerHelper, Progressable progressable, AtomicBoolean cancelled) { + super(context, providerHelper, progressable, cancelled); + } + + public PgpSignEncryptOperation(Context context, ProviderHelper providerHelper, Progressable progressable) { + super(context, providerHelper, progressable); + } + + /** + * Signs and/or encrypts data based on parameters of class + */ + public PgpSignEncryptResult execute(PgpSignEncryptInput input, + InputData inputData, OutputStream outputStream) { + + int indent = 0; + OperationLog log = new OperationLog(); + + log.add(LogType.MSG_PSE, indent); + indent += 1; + + boolean enableSignature = input.getSignatureMasterKeyId() != Constants.key.none; + boolean enableEncryption = ((input.getEncryptionMasterKeyIds() != null && input.getEncryptionMasterKeyIds().length > 0) + || input.getSymmetricPassphrase() != null); + boolean enableCompression = (input.getCompressionId() != CompressionAlgorithmTags.UNCOMPRESSED); + + Log.d(Constants.TAG, "enableSignature:" + enableSignature + + "\nenableEncryption:" + enableEncryption + + "\nenableCompression:" + enableCompression + + "\nenableAsciiArmorOutput:" + input.ismEnableAsciiArmorOutput()); + + // add additional key id to encryption ids (mostly to do self-encryption) + if (enableEncryption && input.getAdditionalEncryptId() != Constants.key.none) { + input.setEncryptionMasterKeyIds(Arrays.copyOf(input.getEncryptionMasterKeyIds(), input.getEncryptionMasterKeyIds().length + 1)); + input.getEncryptionMasterKeyIds()[input.getEncryptionMasterKeyIds().length - 1] = input.getAdditionalEncryptId(); + } + + ArmoredOutputStream armorOut = null; + OutputStream out; + if (input.ismEnableAsciiArmorOutput()) { + armorOut = new ArmoredOutputStream(outputStream); + if (input.getVersionHeader() != null) { + armorOut.setHeader("Version", input.getVersionHeader()); + } + // if we have a charset, put it in the header + if (input.getCharset() != null) { + armorOut.setHeader("Charset", input.getCharset()); + } + out = armorOut; + } else { + out = outputStream; + } + + /* Get keys for signature generation for later usage */ + CanonicalizedSecretKey signingKey = null; + if (enableSignature) { + + try { + // fetch the indicated master key id (the one whose name we sign in) + CanonicalizedSecretKeyRing signingKeyRing = + mProviderHelper.getCanonicalizedSecretKeyRing(input.getSignatureMasterKeyId()); + + long signKeyId; + // use specified signing subkey, or find the one to use + if (input.getSignatureSubKeyId() == null) { + signKeyId = signingKeyRing.getSecretSignId(); + } else { + signKeyId = input.getSignatureSubKeyId(); + } + + // fetch the specific subkey to sign with, or just use the master key if none specified + signingKey = signingKeyRing.getSecretKey(signKeyId); + + } catch (ProviderHelper.NotFoundException | PgpGeneralException e) { + log.add(LogType.MSG_PSE_ERROR_SIGN_KEY, indent); + return new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_ERROR, log); + } + + // Make sure we are allowed to sign here! + if (!signingKey.canSign()) { + log.add(LogType.MSG_PSE_ERROR_KEY_SIGN, indent); + return new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_ERROR, log); + } + + // if no passphrase was explicitly set try to get it from the cache service + if (input.getSignaturePassphrase() == null) { + try { + // returns "" if key has no passphrase + input.setSignaturePassphrase(getCachedPassphrase(signingKey.getKeyId())); + // TODO +// log.add(LogType.MSG_DC_PASS_CACHED, indent + 1); + } catch (PassphraseCacheInterface.NoSecretKeyException e) { + // TODO +// log.add(LogType.MSG_DC_ERROR_NO_KEY, indent + 1); + return new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_ERROR, log); + } + + // if passphrase was not cached, return here indicating that a passphrase is missing! + if (input.getSignaturePassphrase() == null) { + log.add(LogType.MSG_PSE_PENDING_PASSPHRASE, indent + 1); + PgpSignEncryptResult result = new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_PENDING_PASSPHRASE, log); + result.setKeyIdPassphraseNeeded(signingKey.getKeyId()); + return result; + } + } + + updateProgress(R.string.progress_extracting_signature_key, 0, 100); + + try { + if (!signingKey.unlock(input.getSignaturePassphrase())) { + log.add(LogType.MSG_PSE_ERROR_BAD_PASSPHRASE, indent); + return new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_ERROR, log); + } + } catch (PgpGeneralException e) { + log.add(LogType.MSG_PSE_ERROR_UNLOCK, indent); + return new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_ERROR, log); + } + + // check if hash algo is supported + int requestedAlgorithm = input.getSignatureHashAlgorithm(); + LinkedList supported = signingKey.getSupportedHashAlgorithms(); + if (requestedAlgorithm == 0) { + // get most preferred + input.setSignatureHashAlgorithm(supported.getLast()); + } else if (!supported.contains(requestedAlgorithm)) { + log.add(LogType.MSG_PSE_ERROR_HASH_ALGO, indent); + return new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_ERROR, log); + } + } + updateProgress(R.string.progress_preparing_streams, 2, 100); + + /* Initialize PGPEncryptedDataGenerator for later usage */ + PGPEncryptedDataGenerator cPk = null; + if (enableEncryption) { + int algo = input.getSymmetricEncryptionAlgorithm(); + if (algo == 0) { + algo = PGPEncryptedData.AES_128; + } + // has Integrity packet enabled! + JcePGPDataEncryptorBuilder encryptorBuilder = + new JcePGPDataEncryptorBuilder(algo) + .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME) + .setWithIntegrityPacket(true); + + cPk = new PGPEncryptedDataGenerator(encryptorBuilder); + + if (input.getSymmetricPassphrase() != null) { + // Symmetric encryption + log.add(LogType.MSG_PSE_SYMMETRIC, indent); + + JcePBEKeyEncryptionMethodGenerator symmetricEncryptionGenerator = + new JcePBEKeyEncryptionMethodGenerator(input.getSymmetricPassphrase().toCharArray()); + cPk.addMethod(symmetricEncryptionGenerator); + } else { + log.add(LogType.MSG_PSE_ASYMMETRIC, indent); + + // Asymmetric encryption + for (long id : input.getEncryptionMasterKeyIds()) { + try { + CanonicalizedPublicKeyRing keyRing = mProviderHelper.getCanonicalizedPublicKeyRing( + KeyRings.buildUnifiedKeyRingUri(id)); + CanonicalizedPublicKey key = keyRing.getEncryptionSubKey(); + cPk.addMethod(key.getPubKeyEncryptionGenerator()); + log.add(LogType.MSG_PSE_KEY_OK, indent + 1, + KeyFormattingUtils.convertKeyIdToHex(id)); + } catch (PgpKeyNotFoundException e) { + log.add(LogType.MSG_PSE_KEY_WARN, indent + 1, + KeyFormattingUtils.convertKeyIdToHex(id)); + if (input.ismFailOnMissingEncryptionKeyIds()) { + return new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_ERROR, log); + } + } catch (ProviderHelper.NotFoundException e) { + log.add(LogType.MSG_PSE_KEY_UNKNOWN, indent + 1, + KeyFormattingUtils.convertKeyIdToHex(id)); + if (input.ismFailOnMissingEncryptionKeyIds()) { + return new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_ERROR, log); + } + } + } + } + } + + /* Initialize signature generator object for later usage */ + PGPSignatureGenerator signatureGenerator = null; + if (enableSignature) { + updateProgress(R.string.progress_preparing_signature, 4, 100); + + try { + boolean cleartext = input.isCleartextSignature() && input.ismEnableAsciiArmorOutput() && !enableEncryption; + signatureGenerator = signingKey.getSignatureGenerator( + input.getSignatureHashAlgorithm(), cleartext, input.getNfcSignedHash(), input.getNfcCreationTimestamp()); + } catch (PgpGeneralException e) { + log.add(LogType.MSG_PSE_ERROR_NFC, indent); + return new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_ERROR, log); + } + } + + ProgressScaler progressScaler = + new ProgressScaler(mProgressable, 8, 95, 100); + PGPCompressedDataGenerator compressGen = null; + OutputStream pOut; + OutputStream encryptionOut = null; + BCPGOutputStream bcpgOut; + + ByteArrayOutputStream detachedByteOut = null; + ArmoredOutputStream detachedArmorOut = null; + BCPGOutputStream detachedBcpgOut = null; + + try { + + if (enableEncryption) { + /* actual encryption */ + updateProgress(R.string.progress_encrypting, 8, 100); + log.add(enableSignature + ? LogType.MSG_PSE_SIGCRYPTING + : LogType.MSG_PSE_ENCRYPTING, + indent + ); + indent += 1; + + encryptionOut = cPk.open(out, new byte[1 << 16]); + + if (enableCompression) { + log.add(LogType.MSG_PSE_COMPRESSING, indent); + compressGen = new PGPCompressedDataGenerator(input.getCompressionId()); + bcpgOut = new BCPGOutputStream(compressGen.open(encryptionOut)); + } else { + bcpgOut = new BCPGOutputStream(encryptionOut); + } + + if (enableSignature) { + signatureGenerator.generateOnePassVersion(false).encode(bcpgOut); + } + + PGPLiteralDataGenerator literalGen = new PGPLiteralDataGenerator(); + char literalDataFormatTag; + if (input.isCleartextSignature()) { + literalDataFormatTag = PGPLiteralData.UTF8; + } else { + literalDataFormatTag = PGPLiteralData.BINARY; + } + pOut = literalGen.open(bcpgOut, literalDataFormatTag, + inputData.getOriginalFilename(), new Date(), new byte[1 << 16]); + + long alreadyWritten = 0; + int length; + byte[] buffer = new byte[1 << 16]; + InputStream in = inputData.getInputStream(); + while ((length = in.read(buffer)) > 0) { + pOut.write(buffer, 0, length); + + // update signature buffer if signature is requested + if (enableSignature) { + signatureGenerator.update(buffer, 0, length); + } + + alreadyWritten += length; + if (inputData.getSize() > 0) { + long progress = 100 * alreadyWritten / inputData.getSize(); + progressScaler.setProgress((int) progress, 100); + } + } + + literalGen.close(); + indent -= 1; + + } else if (enableSignature && input.isCleartextSignature() && input.ismEnableAsciiArmorOutput()) { + /* cleartext signature: sign-only of ascii text */ + + updateProgress(R.string.progress_signing, 8, 100); + log.add(LogType.MSG_PSE_SIGNING_CLEARTEXT, indent); + + // write -----BEGIN PGP SIGNED MESSAGE----- + armorOut.beginClearText(input.getSignatureHashAlgorithm()); + + InputStream in = inputData.getInputStream(); + final BufferedReader reader = new BufferedReader(new InputStreamReader(in)); + + // update signature buffer with first line + processLine(reader.readLine(), armorOut, signatureGenerator); + + // TODO: progress: fake annealing? + while (true) { + String line = reader.readLine(); + + // end cleartext signature with newline, see http://tools.ietf.org/html/rfc4880#section-7 + if (line == null) { + armorOut.write(NEW_LINE); + break; + } + + armorOut.write(NEW_LINE); + + // update signature buffer with input line + signatureGenerator.update(NEW_LINE); + processLine(line, armorOut, signatureGenerator); + } + + armorOut.endClearText(); + + pOut = new BCPGOutputStream(armorOut); + } else if (enableSignature && input.isDetachedSignature()) { + /* detached signature */ + + updateProgress(R.string.progress_signing, 8, 100); + log.add(LogType.MSG_PSE_SIGNING_DETACHED, indent); + + InputStream in = inputData.getInputStream(); + + // handle output stream separately for detached signatures + detachedByteOut = new ByteArrayOutputStream(); + OutputStream detachedOut = detachedByteOut; + if (input.ismEnableAsciiArmorOutput()) { + detachedArmorOut = new ArmoredOutputStream(detachedOut); + if (input.getVersionHeader() != null) { + detachedArmorOut.setHeader("Version", input.getVersionHeader()); + } + + detachedOut = detachedArmorOut; + } + detachedBcpgOut = new BCPGOutputStream(detachedOut); + + long alreadyWritten = 0; + int length; + byte[] buffer = new byte[1 << 16]; + while ((length = in.read(buffer)) > 0) { + // no output stream is written, no changed to original data! + + signatureGenerator.update(buffer, 0, length); + + alreadyWritten += length; + if (inputData.getSize() > 0) { + long progress = 100 * alreadyWritten / inputData.getSize(); + progressScaler.setProgress((int) progress, 100); + } + } + + pOut = null; + } else if (enableSignature && !input.isCleartextSignature() && !input.isDetachedSignature()) { + /* sign-only binary (files/data stream) */ + + updateProgress(R.string.progress_signing, 8, 100); + log.add(LogType.MSG_PSE_SIGNING, indent); + + InputStream in = inputData.getInputStream(); + + if (enableCompression) { + compressGen = new PGPCompressedDataGenerator(input.getCompressionId()); + bcpgOut = new BCPGOutputStream(compressGen.open(out)); + } else { + bcpgOut = new BCPGOutputStream(out); + } + + signatureGenerator.generateOnePassVersion(false).encode(bcpgOut); + + PGPLiteralDataGenerator literalGen = new PGPLiteralDataGenerator(); + pOut = literalGen.open(bcpgOut, PGPLiteralData.BINARY, + inputData.getOriginalFilename(), new Date(), + new byte[1 << 16]); + + long alreadyWritten = 0; + int length; + byte[] buffer = new byte[1 << 16]; + while ((length = in.read(buffer)) > 0) { + pOut.write(buffer, 0, length); + + signatureGenerator.update(buffer, 0, length); + + alreadyWritten += length; + if (inputData.getSize() > 0) { + long progress = 100 * alreadyWritten / inputData.getSize(); + progressScaler.setProgress((int) progress, 100); + } + } + + literalGen.close(); + } else { + pOut = null; + // TODO: Is this log right? + log.add(LogType.MSG_PSE_CLEARSIGN_ONLY, indent); + } + + if (enableSignature) { + updateProgress(R.string.progress_generating_signature, 95, 100); + try { + if (detachedBcpgOut != null) { + signatureGenerator.generate().encode(detachedBcpgOut); + } else { + signatureGenerator.generate().encode(pOut); + } + } catch (NfcSyncPGPContentSignerBuilder.NfcInteractionNeeded e) { + // this secret key diverts to a OpenPGP card, throw exception with hash that will be signed + log.add(LogType.MSG_PSE_PENDING_NFC, indent); + PgpSignEncryptResult result = + new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_PENDING_NFC, log); + // Note that the checked key here is the master key, not the signing key + // (although these are always the same on Yubikeys) + result.setNfcData(input.getSignatureSubKeyId(), e.hashToSign, e.hashAlgo, e.creationTimestamp, input.getSignaturePassphrase()); + Log.d(Constants.TAG, "e.hashToSign" + Hex.toHexString(e.hashToSign)); + return result; + } + } + + // closing outputs + // NOTE: closing needs to be done in the correct order! + if (encryptionOut != null) { + if (compressGen != null) { + compressGen.close(); + } + + encryptionOut.close(); + } + // Note: Closing ArmoredOutputStream does not close the underlying stream + if (armorOut != null) { + armorOut.close(); + } + // Note: Closing ArmoredOutputStream does not close the underlying stream + if (detachedArmorOut != null) { + detachedArmorOut.close(); + } + // Also closes detachedBcpgOut + if (detachedByteOut != null) { + detachedByteOut.close(); + } + if (out != null) { + out.close(); + } + if (outputStream != null) { + outputStream.close(); + } + + } catch (SignatureException e) { + log.add(LogType.MSG_PSE_ERROR_SIG, indent); + return new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_ERROR, log); + } catch (PGPException e) { + log.add(LogType.MSG_PSE_ERROR_PGP, indent); + return new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_ERROR, log); + } catch (IOException e) { + log.add(LogType.MSG_PSE_ERROR_IO, indent); + return new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_ERROR, log); + } + + updateProgress(R.string.progress_done, 100, 100); + + log.add(LogType.MSG_PSE_OK, indent); + PgpSignEncryptResult result = new PgpSignEncryptResult(PgpSignEncryptResult.RESULT_OK, log); + if (detachedByteOut != null) { + try { + detachedByteOut.flush(); + detachedByteOut.close(); + } catch (IOException e) { + // silently catch + } + result.setDetachedSignature(detachedByteOut.toByteArray()); + } + return result; + } + + /** + * Remove whitespaces on line endings + */ + private static void processLine(final String pLine, final ArmoredOutputStream pArmoredOutput, + final PGPSignatureGenerator pSignatureGenerator) + throws IOException, SignatureException { + + if (pLine == null) { + return; + } + + final char[] chars = pLine.toCharArray(); + int len = chars.length; + + while (len > 0) { + if (!Character.isWhitespace(chars[len - 1])) { + break; + } + len--; + } + + final byte[] data = pLine.substring(0, len).getBytes("UTF-8"); + + if (pArmoredOutput != null) { + pArmoredOutput.write(data); + } + pSignatureGenerator.update(data); + } + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/SignEncryptParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/SignEncryptParcel.java new file mode 100644 index 000000000..a4ed33397 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/SignEncryptParcel.java @@ -0,0 +1,135 @@ +package org.sufficientlysecure.keychain.pgp; + +import android.net.Uri; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.List; + +/** This parcel stores the input of one or more PgpSignEncrypt operations. + * All operations will use the same general paramters, differing only in + * input and output. Each input/output set depends on the paramters: + * + * - Each input uri is individually encrypted/signed + * - If a byte array is supplied, it is treated as an input before uris are processed + * - The number of output uris must match the number of input uris, plus one more + * if there is a byte array present. + * - Once the output uris are empty, there must be exactly one input (uri xor bytes) + * left, which will be returned in a byte array as part of the result parcel. + * + */ +public class SignEncryptParcel extends PgpSignEncryptInput implements Parcelable { + + public ArrayList mInputUris = new ArrayList<>(); + public ArrayList mOutputUris = new ArrayList<>(); + public byte[] mBytes; + + public SignEncryptParcel() { + super(); + } + + public SignEncryptParcel(Parcel src) { + + // we do all of those here, so the PgpSignEncryptInput class doesn't have to be parcelable + mVersionHeader = src.readString(); + mEnableAsciiArmorOutput = src.readInt() == 1; + mCompressionId = src.readInt(); + mEncryptionMasterKeyIds = src.createLongArray(); + mSymmetricPassphrase = src.readString(); + mSymmetricEncryptionAlgorithm = src.readInt(); + mSignatureMasterKeyId = src.readLong(); + mSignatureSubKeyId = src.readInt() == 1 ? src.readLong() : null; + mSignatureHashAlgorithm = src.readInt(); + mSignaturePassphrase = src.readString(); + mAdditionalEncryptId = src.readLong(); + mNfcSignedHash = src.createByteArray(); + mNfcCreationTimestamp = src.readInt() == 1 ? new Date(src.readLong()) : null; + mFailOnMissingEncryptionKeyIds = src.readInt() == 1; + mCharset = src.readString(); + mCleartextSignature = src.readInt() == 1; + mDetachedSignature = src.readInt() == 1; + + mInputUris = src.createTypedArrayList(Uri.CREATOR); + mOutputUris = src.createTypedArrayList(Uri.CREATOR); + mBytes = src.createByteArray(); + + } + + public byte[] getBytes() { + return mBytes; + } + + public void setBytes(byte[] bytes) { + mBytes = bytes; + } + + public List getInputUris() { + return Collections.unmodifiableList(mInputUris); + } + + public void addInputUris(Collection inputUris) { + mInputUris.addAll(inputUris); + } + + public List getOutputUris() { + return Collections.unmodifiableList(mOutputUris); + } + + public void addOutputUris(ArrayList outputUris) { + mOutputUris.addAll(outputUris); + } + + @Override + public int describeContents() { + return 0; + } + + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(mVersionHeader); + dest.writeInt(mEnableAsciiArmorOutput ? 1 : 0); + dest.writeInt(mCompressionId); + dest.writeLongArray(mEncryptionMasterKeyIds); + dest.writeString(mSymmetricPassphrase); + dest.writeInt(mSymmetricEncryptionAlgorithm); + dest.writeLong(mSignatureMasterKeyId); + if (mSignatureSubKeyId != null) { + dest.writeInt(1); + dest.writeLong(mSignatureSubKeyId); + } else { + dest.writeInt(0); + } + dest.writeInt(mSignatureHashAlgorithm); + dest.writeString(mSignaturePassphrase); + dest.writeLong(mAdditionalEncryptId); + dest.writeByteArray(mNfcSignedHash); + if (mNfcCreationTimestamp != null) { + dest.writeInt(1); + dest.writeLong(mNfcCreationTimestamp.getTime()); + } else { + dest.writeInt(0); + } + dest.writeInt(mFailOnMissingEncryptionKeyIds ? 1 : 0); + dest.writeString(mCharset); + dest.writeInt(mCleartextSignature ? 1 : 0); + dest.writeInt(mDetachedSignature ? 1 : 0); + + dest.writeTypedList(mInputUris); + dest.writeTypedList(mOutputUris); + dest.writeByteArray(mBytes); + } + + public static final Creator CREATOR = new Creator() { + public SignEncryptParcel createFromParcel(final Parcel source) { + return new SignEncryptParcel(source); + } + + public SignEncryptParcel[] newArray(final int size) { + return new SignEncryptParcel[size]; + } + }; + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java index af85bd878..681aff56d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java @@ -35,9 +35,9 @@ import org.spongycastle.openpgp.PGPUserAttributeSubpacketVector; import org.spongycastle.openpgp.PGPUtil; import org.spongycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator; import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; +import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.util.IterableIterator; import org.sufficientlysecure.keychain.util.Log; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedUserAttribute.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedUserAttribute.java index da6d8b287..8e23d36d9 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedUserAttribute.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedUserAttribute.java @@ -32,7 +32,6 @@ import java.io.IOException; import java.io.ObjectStreamException; import java.io.Serializable; import java.util.ArrayList; -import java.util.Arrays; public class WrappedUserAttribute implements Serializable { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java index d34cc74a3..b88cd6006 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainDatabase.java @@ -28,8 +28,8 @@ import android.provider.BaseColumns; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; -import org.sufficientlysecure.keychain.provider.KeychainContract.ApiAppsAllowedKeysColumns; import org.sufficientlysecure.keychain.provider.KeychainContract.ApiAppsAccountsColumns; +import org.sufficientlysecure.keychain.provider.KeychainContract.ApiAppsAllowedKeysColumns; import org.sufficientlysecure.keychain.provider.KeychainContract.ApiAppsColumns; import org.sufficientlysecure.keychain.provider.KeychainContract.CertsColumns; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingsColumns; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java index 2ffc8c2ca..2601c1f69 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/KeychainProvider.java @@ -31,8 +31,8 @@ import android.net.Uri; import android.text.TextUtils; import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.provider.KeychainContract.ApiAllowedKeys; import org.sufficientlysecure.keychain.provider.KeychainContract.ApiAccounts; +import org.sufficientlysecure.keychain.provider.KeychainContract.ApiAllowedKeys; import org.sufficientlysecure.keychain.provider.KeychainContract.ApiApps; import org.sufficientlysecure.keychain.provider.KeychainContract.Certs; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java index 2ba7a19dc..18efa2b80 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java @@ -30,13 +30,13 @@ import android.support.v4.util.LongSparseArray; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.operations.results.ImportKeyResult; -import org.sufficientlysecure.keychain.pgp.WrappedUserAttribute; -import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets; -import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; -import org.sufficientlysecure.keychain.util.ParcelableFileCache.IteratorWithSize; -import org.sufficientlysecure.keychain.util.Preferences; import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing; +import org.sufficientlysecure.keychain.operations.ImportExportOperation; +import org.sufficientlysecure.keychain.operations.results.ConsolidateResult; +import org.sufficientlysecure.keychain.operations.results.ImportKeyResult; +import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; +import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; +import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult; import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKey; import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing; import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey; @@ -44,11 +44,11 @@ import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType; import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKeyRing; import org.sufficientlysecure.keychain.pgp.KeyRing; import org.sufficientlysecure.keychain.pgp.PgpHelper; -import org.sufficientlysecure.keychain.operations.ImportExportOperation; import org.sufficientlysecure.keychain.pgp.Progressable; import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; import org.sufficientlysecure.keychain.pgp.UncachedPublicKey; import org.sufficientlysecure.keychain.pgp.WrappedSignature; +import org.sufficientlysecure.keychain.pgp.WrappedUserAttribute; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.provider.KeychainContract.ApiAllowedKeys; import org.sufficientlysecure.keychain.provider.KeychainContract.ApiApps; @@ -56,15 +56,15 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.Certs; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.KeychainContract.Keys; +import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets; import org.sufficientlysecure.keychain.remote.AccountSettings; import org.sufficientlysecure.keychain.remote.AppSettings; -import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; -import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; -import org.sufficientlysecure.keychain.operations.results.ConsolidateResult; -import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult; -import org.sufficientlysecure.keychain.util.ParcelableFileCache; +import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.util.IterableIterator; import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.ParcelableFileCache; +import org.sufficientlysecure.keychain.util.ParcelableFileCache.IteratorWithSize; +import org.sufficientlysecure.keychain.util.Preferences; import org.sufficientlysecure.keychain.util.ProgressFixedScaler; import org.sufficientlysecure.keychain.util.ProgressScaler; import org.sufficientlysecure.keychain.util.Utf8Util; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java index d4f1e248c..1a65b1bee 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java @@ -26,30 +26,28 @@ import android.os.ParcelFileDescriptor; import android.text.TextUtils; import org.openintents.openpgp.IOpenPgpService; -import org.openintents.openpgp.OpenPgpMetadata; import org.openintents.openpgp.OpenPgpError; +import org.openintents.openpgp.OpenPgpMetadata; import org.openintents.openpgp.OpenPgpSignatureResult; import org.openintents.openpgp.util.OpenPgpApi; import org.spongycastle.util.encoders.Hex; -import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; -import org.sufficientlysecure.keychain.ui.NfcActivity; import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify; -import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing; -import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables; import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult; +import org.sufficientlysecure.keychain.operations.results.OperationResult.LogEntryParcel; +import org.sufficientlysecure.keychain.operations.results.PgpSignEncryptResult; +import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify; import org.sufficientlysecure.keychain.pgp.PgpHelper; -import org.sufficientlysecure.keychain.pgp.PgpSignEncrypt; +import org.sufficientlysecure.keychain.pgp.PgpSignEncryptInput; +import org.sufficientlysecure.keychain.pgp.PgpSignEncryptOperation; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainContract.ApiAccounts; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; +import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.remote.ui.RemoteServiceActivity; -import org.sufficientlysecure.keychain.service.PassphraseCacheService; -import org.sufficientlysecure.keychain.operations.results.OperationResult.LogEntryParcel; -import org.sufficientlysecure.keychain.operations.results.SignEncryptResult; import org.sufficientlysecure.keychain.ui.ImportKeysActivity; +import org.sufficientlysecure.keychain.ui.NfcActivity; import org.sufficientlysecure.keychain.ui.PassphraseDialogActivity; import org.sufficientlysecure.keychain.ui.ViewKeyActivity; import org.sufficientlysecure.keychain.util.InputData; @@ -255,60 +253,26 @@ public class OpenPgpService extends RemoteService { long inputLength = is.available(); InputData inputData = new InputData(is, inputLength); - // Find the appropriate subkey to sign with - long sigSubKeyId; - try { - CachedPublicKeyRing signingRing = - new ProviderHelper(this).getCachedPublicKeyRing(accSettings.getKeyId()); - sigSubKeyId = signingRing.getSecretSignId(); - } catch (PgpKeyNotFoundException e) { - // secret key that is set for this account is deleted? - // show account config again! - return getCreateAccountIntent(data, getAccountName(data)); - } - - // get passphrase from cache, if key has "no" passphrase, this returns an empty String - String passphrase; - if (data.hasExtra(OpenPgpApi.EXTRA_PASSPHRASE)) { - passphrase = data.getStringExtra(OpenPgpApi.EXTRA_PASSPHRASE); - } else { - try { - passphrase = PassphraseCacheService.getCachedPassphrase(getContext(), - accSettings.getKeyId(), sigSubKeyId); - } catch (PassphraseCacheService.KeyNotFoundException e) { - // should happen earlier, but return again here if it happens - return getCreateAccountIntent(data, getAccountName(data)); - } - } - if (passphrase == null) { - // get PendingIntent for passphrase input, add it to given params and return to client - return getPassphraseIntent(data, sigSubKeyId); - } - // sign-only - PgpSignEncrypt.Builder builder = new PgpSignEncrypt.Builder( - this, new ProviderHelper(getContext()), null, - inputData, os - ); - builder.setEnableAsciiArmorOutput(asciiArmor) + PgpSignEncryptInput pseInput = new PgpSignEncryptInput() + .setEnableAsciiArmorOutput(asciiArmor) .setCleartextSignature(cleartextSign) .setDetachedSignature(!cleartextSign) .setVersionHeader(PgpHelper.getVersionForHeader(this)) .setSignatureHashAlgorithm(accSettings.getHashAlgorithm()) .setSignatureMasterKeyId(accSettings.getKeyId()) - .setSignatureSubKeyId(sigSubKeyId) - .setSignaturePassphrase(passphrase) .setNfcState(nfcSignedHash, nfcCreationDate); // execute PGP operation! - SignEncryptResult pgpResult = builder.build().execute(); + PgpSignEncryptOperation pse = new PgpSignEncryptOperation(this, new ProviderHelper(getContext()), null); + PgpSignEncryptResult pgpResult = pse.execute(pseInput, inputData, os); if (pgpResult.isPending()) { - if ((pgpResult.getResult() & SignEncryptResult.RESULT_PENDING_PASSPHRASE) == - SignEncryptResult.RESULT_PENDING_PASSPHRASE) { + if ((pgpResult.getResult() & PgpSignEncryptResult.RESULT_PENDING_PASSPHRASE) == + PgpSignEncryptResult.RESULT_PENDING_PASSPHRASE) { return getPassphraseIntent(data, pgpResult.getKeyIdPassphraseNeeded()); - } else if ((pgpResult.getResult() & SignEncryptResult.RESULT_PENDING_NFC) == - SignEncryptResult.RESULT_PENDING_NFC) { + } else if ((pgpResult.getResult() & PgpSignEncryptResult.RESULT_PENDING_NFC) == + PgpSignEncryptResult.RESULT_PENDING_NFC) { // return PendingIntent to execute NFC activity // pass through the signature creation timestamp to be used again on second execution // of PgpSignEncrypt when we have the signed hash! @@ -388,46 +352,19 @@ public class OpenPgpService extends RemoteService { os = new ParcelFileDescriptor.AutoCloseOutputStream(output); long inputLength = is.available(); - InputData inputData = new InputData(is, inputLength); + InputData inputData = new InputData(is, inputLength, originalFilename); - PgpSignEncrypt.Builder builder = new PgpSignEncrypt.Builder( - this, new ProviderHelper(getContext()), null, inputData, os - ); - builder.setEnableAsciiArmorOutput(asciiArmor) + PgpSignEncryptInput pseInput = new PgpSignEncryptInput(); + pseInput.setEnableAsciiArmorOutput(asciiArmor) .setVersionHeader(PgpHelper.getVersionForHeader(this)) .setCompressionId(accSettings.getCompression()) .setSymmetricEncryptionAlgorithm(accSettings.getEncryptionAlgorithm()) .setEncryptionMasterKeyIds(keyIds) .setFailOnMissingEncryptionKeyIds(true) - .setOriginalFilename(originalFilename) .setAdditionalEncryptId(accSettings.getKeyId()); // add acc key for encryption if (sign) { - // Find the appropriate subkey to sign with - long sigSubKeyId; - try { - CachedPublicKeyRing signingRing = - new ProviderHelper(this).getCachedPublicKeyRing(accSettings.getKeyId()); - sigSubKeyId = signingRing.getSecretSignId(); - } catch (PgpKeyNotFoundException e) { - // secret key that is set for this account is deleted? - // show account config again! - return getCreateAccountIntent(data, getAccountName(data)); - } - - String passphrase; - if (data.hasExtra(OpenPgpApi.EXTRA_PASSPHRASE)) { - passphrase = data.getStringExtra(OpenPgpApi.EXTRA_PASSPHRASE); - } else { - passphrase = PassphraseCacheService.getCachedPassphrase(getContext(), - accSettings.getKeyId(), sigSubKeyId); - } - if (passphrase == null) { - // get PendingIntent for passphrase input, add it to given params and return to client - return getPassphraseIntent(data, sigSubKeyId); - } - byte[] nfcSignedHash = data.getByteArrayExtra(OpenPgpApi.EXTRA_NFC_SIGNED_HASH); // carefully: only set if timestamp exists Date nfcCreationDate = null; @@ -437,22 +374,22 @@ public class OpenPgpService extends RemoteService { } // sign and encrypt - builder.setSignatureHashAlgorithm(accSettings.getHashAlgorithm()) + pseInput.setSignatureHashAlgorithm(accSettings.getHashAlgorithm()) .setSignatureMasterKeyId(accSettings.getKeyId()) - .setSignatureSubKeyId(sigSubKeyId) - .setSignaturePassphrase(passphrase) .setNfcState(nfcSignedHash, nfcCreationDate); } + PgpSignEncryptOperation op = new PgpSignEncryptOperation(this, new ProviderHelper(getContext()), null); + // execute PGP operation! - SignEncryptResult pgpResult = builder.build().execute(); + PgpSignEncryptResult pgpResult = op.execute(pseInput, inputData, os); if (pgpResult.isPending()) { - if ((pgpResult.getResult() & SignEncryptResult.RESULT_PENDING_PASSPHRASE) == - SignEncryptResult.RESULT_PENDING_PASSPHRASE) { + if ((pgpResult.getResult() & PgpSignEncryptResult.RESULT_PENDING_PASSPHRASE) == + PgpSignEncryptResult.RESULT_PENDING_PASSPHRASE) { return getPassphraseIntent(data, pgpResult.getKeyIdPassphraseNeeded()); - } else if ((pgpResult.getResult() & SignEncryptResult.RESULT_PENDING_NFC) == - SignEncryptResult.RESULT_PENDING_NFC) { + } else if ((pgpResult.getResult() & PgpSignEncryptResult.RESULT_PENDING_NFC) == + PgpSignEncryptResult.RESULT_PENDING_NFC) { // return PendingIntent to execute NFC activity // pass through the signature creation timestamp to be used again on second execution // of PgpSignEncrypt when we have the signed hash! diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsActivity.java index 02bf98b12..fbba400a0 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsActivity.java @@ -26,12 +26,12 @@ import android.view.View; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.ui.BaseActivity; -import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.remote.AccountSettings; import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; import org.sufficientlysecure.keychain.operations.results.SingletonResult; +import org.sufficientlysecure.keychain.provider.ProviderHelper; +import org.sufficientlysecure.keychain.remote.AccountSettings; +import org.sufficientlysecure.keychain.ui.BaseActivity; import org.sufficientlysecure.keychain.util.Log; public class AccountSettingsActivity extends BaseActivity { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsFragment.java index a3027f728..a5bc05ba8 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsFragment.java @@ -31,10 +31,10 @@ import android.widget.TextView; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.pgp.KeyRing; -import org.sufficientlysecure.keychain.remote.AccountSettings; import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult; +import org.sufficientlysecure.keychain.pgp.KeyRing; +import org.sufficientlysecure.keychain.remote.AccountSettings; import org.sufficientlysecure.keychain.ui.CreateKeyActivity; import org.sufficientlysecure.keychain.ui.adapter.KeyValueSpinnerAdapter; import org.sufficientlysecure.keychain.ui.widget.KeySpinner; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java index 8f822a338..3bb7578a4 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java @@ -28,10 +28,10 @@ import android.view.View; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.remote.AppSettings; -import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.ui.BaseActivity; import org.sufficientlysecure.keychain.util.Log; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ContactSyncAdapterService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ContactSyncAdapterService.java index 447f413ef..7688b9252 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ContactSyncAdapterService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ContactSyncAdapterService.java @@ -53,7 +53,7 @@ public class ContactSyncAdapterService extends Service { // new Handler.Callback() { // @Override // public boolean handleMessage(Message msg) { -// Bundle data = msg.getData(); +// Bundle data = msg.getInputData(); // switch (msg.arg1) { // case KeychainIntentServiceHandler.MESSAGE_OKAY: // Log.d(Constants.TAG, "Syncing... Done."); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java index 264b45035..72eec6955 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -27,40 +27,36 @@ import android.os.Messenger; import android.os.RemoteException; import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.keyimport.HkpKeyserver; +import org.sufficientlysecure.keychain.keyimport.Keyserver; +import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing; import org.sufficientlysecure.keychain.operations.CertifyOperation; import org.sufficientlysecure.keychain.operations.DeleteOperation; import org.sufficientlysecure.keychain.operations.EditKeyOperation; +import org.sufficientlysecure.keychain.operations.ImportExportOperation; import org.sufficientlysecure.keychain.operations.PromoteKeyOperation; +import org.sufficientlysecure.keychain.operations.SignEncryptOperation; +import org.sufficientlysecure.keychain.operations.results.CertifyResult; +import org.sufficientlysecure.keychain.operations.results.ConsolidateResult; +import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult; import org.sufficientlysecure.keychain.operations.results.DeleteResult; import org.sufficientlysecure.keychain.operations.results.EditKeyResult; import org.sufficientlysecure.keychain.operations.results.ExportResult; +import org.sufficientlysecure.keychain.operations.results.ImportKeyResult; +import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.operations.results.PromoteKeyResult; -import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; -import org.sufficientlysecure.keychain.operations.results.CertifyResult; -import org.sufficientlysecure.keychain.util.FileHelper; -import org.sufficientlysecure.keychain.util.ParcelableFileCache.IteratorWithSize; -import org.sufficientlysecure.keychain.util.Preferences; -import org.sufficientlysecure.keychain.keyimport.HkpKeyserver; -import org.sufficientlysecure.keychain.keyimport.Keyserver; -import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing; +import org.sufficientlysecure.keychain.operations.results.SignEncryptResult; import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing; import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify; -import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult; -import org.sufficientlysecure.keychain.pgp.PgpHelper; -import org.sufficientlysecure.keychain.operations.ImportExportOperation; -import org.sufficientlysecure.keychain.pgp.PgpSignEncrypt; import org.sufficientlysecure.keychain.pgp.Progressable; +import org.sufficientlysecure.keychain.pgp.SignEncryptParcel; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralMsgIdException; -import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing; import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.operations.results.OperationResult; -import org.sufficientlysecure.keychain.operations.results.ConsolidateResult; -import org.sufficientlysecure.keychain.operations.results.ImportKeyResult; -import org.sufficientlysecure.keychain.operations.results.SignEncryptResult; -import org.sufficientlysecure.keychain.util.ParcelableFileCache; +import org.sufficientlysecure.keychain.util.FileHelper; import org.sufficientlysecure.keychain.util.InputData; import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.ParcelableFileCache; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -68,8 +64,6 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; -import java.util.Date; -import java.util.Iterator; import java.util.concurrent.atomic.AtomicBoolean; /** @@ -115,24 +109,11 @@ public class KeychainIntentService extends IntentService implements Progressable // possible targets: public static final int IO_BYTES = 1; public static final int IO_URI = 2; - public static final int IO_URIS = 3; - - public static final String SELECTED_URI = "selected_uri"; // encrypt - public static final String ENCRYPT_SIGNATURE_MASTER_ID = "secret_key_id"; - public static final String ENCRYPT_SIGNATURE_KEY_PASSPHRASE = "secret_key_passphrase"; - public static final String ENCRYPT_SIGNATURE_NFC_TIMESTAMP = "signature_nfc_timestamp"; - public static final String ENCRYPT_SIGNATURE_NFC_HASH = "signature_nfc_hash"; - public static final String ENCRYPT_USE_ASCII_ARMOR = "use_ascii_armor"; - public static final String ENCRYPT_ENCRYPTION_KEYS_IDS = "encryption_keys_ids"; - public static final String ENCRYPT_COMPRESSION_ID = "compression_id"; - public static final String ENCRYPT_MESSAGE_BYTES = "message_bytes"; public static final String ENCRYPT_DECRYPT_INPUT_URI = "input_uri"; - public static final String ENCRYPT_INPUT_URIS = "input_uris"; public static final String ENCRYPT_DECRYPT_OUTPUT_URI = "output_uri"; - public static final String ENCRYPT_OUTPUT_URIS = "output_uris"; - public static final String ENCRYPT_SYMMETRIC_PASSPHRASE = "passphrase"; + public static final String SIGN_ENCRYPT_PARCEL = "sign_encrypt_parcel"; // decrypt/verify public static final String DECRYPT_CIPHERTEXT_BYTES = "ciphertext_bytes"; @@ -176,9 +157,6 @@ public class KeychainIntentService extends IntentService implements Progressable * possible data keys as result send over messenger */ - // encrypt - public static final String RESULT_BYTES = "encrypted_data"; - // decrypt/verify public static final String RESULT_DECRYPTED_BYTES = "decrypted_data"; @@ -427,83 +405,19 @@ public class KeychainIntentService extends IntentService implements Progressable } case ACTION_SIGN_ENCRYPT: - try { - /* Input */ - int source = data.get(SOURCE) != null ? data.getInt(SOURCE) : data.getInt(TARGET); - Bundle resultData = new Bundle(); - - long sigMasterKeyId = data.getLong(ENCRYPT_SIGNATURE_MASTER_ID); - String sigKeyPassphrase = data.getString(ENCRYPT_SIGNATURE_KEY_PASSPHRASE); - - byte[] nfcHash = data.getByteArray(ENCRYPT_SIGNATURE_NFC_HASH); - Date nfcTimestamp = (Date) data.getSerializable(ENCRYPT_SIGNATURE_NFC_TIMESTAMP); - - String symmetricPassphrase = data.getString(ENCRYPT_SYMMETRIC_PASSPHRASE); - - boolean useAsciiArmor = data.getBoolean(ENCRYPT_USE_ASCII_ARMOR); - long encryptionKeyIds[] = data.getLongArray(ENCRYPT_ENCRYPTION_KEYS_IDS); - int compressionId = data.getInt(ENCRYPT_COMPRESSION_ID); - int urisCount = data.containsKey(ENCRYPT_INPUT_URIS) ? data.getParcelableArrayList(ENCRYPT_INPUT_URIS).size() : 1; - for (int i = 0; i < urisCount; i++) { - data.putInt(SELECTED_URI, i); - InputData inputData = createEncryptInputData(data); - OutputStream outStream = createCryptOutputStream(data); - String originalFilename = getOriginalFilename(data); - - /* Operation */ - PgpSignEncrypt.Builder builder = new PgpSignEncrypt.Builder( - this, new ProviderHelper(this), this, inputData, outStream - ); - builder.setEnableAsciiArmorOutput(useAsciiArmor) - .setCleartextSignature(true) - .setVersionHeader(PgpHelper.getVersionForHeader(this)) - .setCompressionId(compressionId) - .setSymmetricEncryptionAlgorithm( - Preferences.getPreferences(this).getDefaultEncryptionAlgorithm()) - .setEncryptionMasterKeyIds(encryptionKeyIds) - .setSymmetricPassphrase(symmetricPassphrase) - .setOriginalFilename(originalFilename); - - try { - - // Find the appropriate subkey to sign with - CachedPublicKeyRing signingRing = - new ProviderHelper(this).getCachedPublicKeyRing(sigMasterKeyId); - long sigSubKeyId = signingRing.getSecretSignId(); - - // Set signature settings - builder.setSignatureMasterKeyId(sigMasterKeyId) - .setSignatureSubKeyId(sigSubKeyId) - .setSignaturePassphrase(sigKeyPassphrase) - .setSignatureHashAlgorithm( - Preferences.getPreferences(this).getDefaultHashAlgorithm()) - .setAdditionalEncryptId(sigMasterKeyId); - if (nfcHash != null && nfcTimestamp != null) { - builder.setNfcState(nfcHash, nfcTimestamp); - } - - } catch (PgpKeyNotFoundException e) { - // encrypt-only - // TODO Just silently drop the requested signature? Shouldn't we throw here? - } - - SignEncryptResult result = builder.build().execute(); - resultData.putParcelable(SignEncryptResult.EXTRA_RESULT, result); - - outStream.close(); - - /* Output */ - finalizeEncryptOutputStream(data, resultData, outStream); - } + // Input + SignEncryptParcel inputParcel = data.getParcelable(SIGN_ENCRYPT_PARCEL); - Log.logDebugBundle(resultData, "resultData"); + // Operation + SignEncryptOperation op = new SignEncryptOperation( + this, new ProviderHelper(this), this, mActionCanceled); + SignEncryptResult result = op.execute(inputParcel); - sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, resultData); - } catch (Exception e) { - sendErrorToHandler(e); - } + // Result + sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result); break; + case ACTION_UPLOAD_KEYRING: try { @@ -620,10 +534,6 @@ public class KeychainIntentService extends IntentService implements Progressable return createCryptInputData(data, DECRYPT_CIPHERTEXT_BYTES); } - private InputData createEncryptInputData(Bundle data) throws IOException, PgpGeneralException { - return createCryptInputData(data, ENCRYPT_MESSAGE_BYTES); - } - private InputData createCryptInputData(Bundle data, String bytesName) throws PgpGeneralException, IOException { int source = data.get(SOURCE) != null ? data.getInt(SOURCE) : data.getInt(TARGET); switch (source) { @@ -637,33 +547,6 @@ public class KeychainIntentService extends IntentService implements Progressable // InputStream return new InputData(getContentResolver().openInputStream(providerUri), FileHelper.getFileSize(this, providerUri, 0)); - case IO_URIS: - providerUri = data.getParcelableArrayList(ENCRYPT_INPUT_URIS).get(data.getInt(SELECTED_URI)); - - // InputStream - return new InputData(getContentResolver().openInputStream(providerUri), FileHelper.getFileSize(this, providerUri, 0)); - - default: - throw new PgpGeneralException("No target choosen!"); - } - } - - private String getOriginalFilename(Bundle data) throws PgpGeneralException, FileNotFoundException { - int target = data.getInt(TARGET); - switch (target) { - case IO_BYTES: - return ""; - - case IO_URI: - Uri providerUri = data.getParcelable(ENCRYPT_DECRYPT_INPUT_URI); - - return FileHelper.getFilename(this, providerUri); - - case IO_URIS: - providerUri = data.getParcelableArrayList(ENCRYPT_INPUT_URIS).get(data.getInt(SELECTED_URI)); - - return FileHelper.getFilename(this, providerUri); - default: throw new PgpGeneralException("No target choosen!"); } @@ -680,20 +563,11 @@ public class KeychainIntentService extends IntentService implements Progressable return getContentResolver().openOutputStream(providerUri); - case IO_URIS: - providerUri = data.getParcelableArrayList(ENCRYPT_OUTPUT_URIS).get(data.getInt(SELECTED_URI)); - - return getContentResolver().openOutputStream(providerUri); - default: throw new PgpGeneralException("No target choosen!"); } } - private void finalizeEncryptOutputStream(Bundle data, Bundle resultData, OutputStream outStream) { - finalizeCryptOutputStream(data, resultData, outStream, RESULT_BYTES); - } - private void finalizeDecryptOutputStream(Bundle data, Bundle resultData, OutputStream outStream) { finalizeCryptOutputStream(data, resultData, outStream, RESULT_DECRYPTED_BYTES); } @@ -706,7 +580,6 @@ public class KeychainIntentService extends IntentService implements Progressable resultData.putByteArray(bytesName, output); break; case IO_URI: - case IO_URIS: // nothing, output was written, just send okay and verification bundle break; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java index a6d5b02c9..6aae1269f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java @@ -27,8 +27,8 @@ import android.support.v4.app.FragmentManager; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment; -import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.ui.util.Notify; +import org.sufficientlysecure.keychain.util.Log; public class KeychainIntentServiceHandler extends Handler { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java index 142814d99..57881f8ee 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/PassphraseCacheService.java @@ -39,11 +39,11 @@ import android.support.v4.util.LongSparseArray; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.util.Preferences; import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType; import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.Preferences; import java.util.Date; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java index f5df5858c..e2d0c03c9 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java @@ -22,6 +22,7 @@ import android.os.Parcel; import android.os.Parcelable; import org.sufficientlysecure.keychain.pgp.WrappedUserAttribute; + import java.io.Serializable; import java.util.ArrayList; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ConsolidateDialogActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ConsolidateDialogActivity.java index 0d8905c5b..f0ef8b9ef 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ConsolidateDialogActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ConsolidateDialogActivity.java @@ -61,7 +61,7 @@ public class ConsolidateDialogActivity extends FragmentActivity { /* don't care about the results (for now?) // get returned data bundle - Bundle returnData = message.getData(); + Bundle returnData = message.getInputData(); if (returnData == null) { return; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java index 377a9d1f4..6e0115342 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CreateKeyFinalFragment.java @@ -35,16 +35,16 @@ import org.spongycastle.bcpg.sig.KeyFlags; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.operations.results.EditKeyResult; -import org.sufficientlysecure.keychain.service.SaveKeyringParcel.ChangeUnlockParcel; -import org.sufficientlysecure.keychain.util.Preferences; +import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.pgp.KeyRing; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; -import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.service.SaveKeyringParcel; import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm; +import org.sufficientlysecure.keychain.service.SaveKeyringParcel.ChangeUnlockParcel; import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.Preferences; public class CreateKeyFinalFragment extends Fragment { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesActivity.java index 7e91889b3..89dd4970b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesActivity.java @@ -88,7 +88,7 @@ public class DecryptFilesActivity extends BaseActivity { loadFragment(savedInstanceState, null, true); } else if (ACTION_DECRYPT_DATA.equals(action)) { Log.e(Constants.TAG, - "Include an Uri with setData() in your Intent!"); + "Include an Uri with setInputData() in your Intent!"); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesFragment.java index 691f1c240..5606523be 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFilesFragment.java @@ -35,13 +35,13 @@ import android.widget.TextView; import org.openintents.openpgp.util.OpenPgpApi; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.util.FileHelper; import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult; import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; import org.sufficientlysecure.keychain.ui.dialog.DeleteFileDialogFragment; -import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.ui.util.Notify; +import org.sufficientlysecure.keychain.util.FileHelper; +import org.sufficientlysecure.keychain.util.Log; import java.io.File; @@ -310,7 +310,7 @@ public class DecryptFilesFragment extends DecryptFragment { // A future open after decryption feature if () { Intent viewFile = new Intent(Intent.ACTION_VIEW); - viewFile.setData(mOutputUri); + viewFile.setInputData(mOutputUri); startActivity(viewFile); } */ diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java index 7f06d36e8..8723c7255 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptFragment.java @@ -27,9 +27,9 @@ import android.widget.TextView; import org.openintents.openpgp.OpenPgpSignatureResult; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult; import org.sufficientlysecure.keychain.pgp.KeyRing; import org.sufficientlysecure.keychain.provider.KeychainContract; -import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; public abstract class DecryptFragment extends Fragment { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextActivity.java index 2afc4b7b3..81a8a2ac4 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextActivity.java @@ -26,11 +26,11 @@ import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.api.OpenKeychainIntents; import org.sufficientlysecure.keychain.compatibility.ClipboardReflection; -import org.sufficientlysecure.keychain.pgp.PgpHelper; import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.operations.results.SingletonResult; -import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.pgp.PgpHelper; import org.sufficientlysecure.keychain.ui.util.Notify; +import org.sufficientlysecure.keychain.util.Log; import java.util.regex.Matcher; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextFragment.java index 78333a8d8..a15b23c06 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptTextFragment.java @@ -34,9 +34,9 @@ import org.openintents.openpgp.util.OpenPgpApi; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.compatibility.ClipboardReflection; +import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult; import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; -import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult; import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.ShareHelper; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java index 611078f95..0d7e6056e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptActivity.java @@ -8,9 +8,11 @@ import android.os.Messenger; import org.openintents.openpgp.util.OpenPgpApi; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.operations.results.PgpSignEncryptResult; +import org.sufficientlysecure.keychain.operations.results.SignEncryptResult; +import org.sufficientlysecure.keychain.pgp.SignEncryptParcel; import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; -import org.sufficientlysecure.keychain.operations.results.SignEncryptResult; import java.util.Date; @@ -82,7 +84,10 @@ public abstract class EncryptActivity extends BaseActivity { // Send all information needed to service to edit key in other thread Intent intent = new Intent(this, KeychainIntentService.class); intent.setAction(KeychainIntentService.ACTION_SIGN_ENCRYPT); - intent.putExtra(KeychainIntentService.EXTRA_DATA, createEncryptBundle()); + + Bundle data = new Bundle(); + data.putParcelable(KeychainIntentService.SIGN_ENCRYPT_PARCEL, createEncryptBundle()); + intent.putExtra(KeychainIntentService.EXTRA_DATA, data); // Message is received after encrypting is done in KeychainIntentService KeychainIntentServiceHandler serviceHandler = new KeychainIntentServiceHandler(this, @@ -92,28 +97,31 @@ public abstract class EncryptActivity extends BaseActivity { super.handleMessage(message); if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) { - SignEncryptResult pgpResult = + SignEncryptResult result = message.getData().getParcelable(SignEncryptResult.EXTRA_RESULT); - if (pgpResult.isPending()) { - if ((pgpResult.getResult() & SignEncryptResult.RESULT_PENDING_PASSPHRASE) == - SignEncryptResult.RESULT_PENDING_PASSPHRASE) { + PgpSignEncryptResult pgpResult = result.getPending(); + + if (pgpResult != null && pgpResult.isPending()) { + if ((pgpResult.getResult() & PgpSignEncryptResult.RESULT_PENDING_PASSPHRASE) == + PgpSignEncryptResult.RESULT_PENDING_PASSPHRASE) { startPassphraseDialog(pgpResult.getKeyIdPassphraseNeeded()); - } else if ((pgpResult.getResult() & SignEncryptResult.RESULT_PENDING_NFC) == - SignEncryptResult.RESULT_PENDING_NFC) { + } else if ((pgpResult.getResult() & PgpSignEncryptResult.RESULT_PENDING_NFC) == + PgpSignEncryptResult.RESULT_PENDING_NFC) { mNfcTimestamp = pgpResult.getNfcTimestamp(); - startNfcSign(pgpResult.getNfcKeyId(), pgpResult.getNfcPassphrase(), pgpResult.getNfcHash(), pgpResult.getNfcAlgo()); + startNfcSign(pgpResult.getNfcKeyId(), pgpResult.getNfcPassphrase(), + pgpResult.getNfcHash(), pgpResult.getNfcAlgo()); } else { throw new RuntimeException("Unhandled pending result!"); } return; } - if (pgpResult.success()) { - onEncryptSuccess(message, pgpResult); + if (result.success()) { + onEncryptSuccess(result); } else { - pgpResult.createNotify(EncryptActivity.this).show(); + result.createNotify(EncryptActivity.this).show(); } // no matter the result, reset parameters @@ -136,8 +144,8 @@ public abstract class EncryptActivity extends BaseActivity { protected abstract boolean inputIsValid(); - protected abstract void onEncryptSuccess(Message message, SignEncryptResult result); + protected abstract void onEncryptSuccess(SignEncryptResult result); - protected abstract Bundle createEncryptBundle(); + protected abstract SignEncryptParcel createEncryptBundle(); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java index 63708ae8e..1286617d3 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesActivity.java @@ -21,7 +21,6 @@ package org.sufficientlysecure.keychain.ui; import android.content.Intent; import android.net.Uri; import android.os.Bundle; -import android.os.Message; import android.support.v4.app.Fragment; import android.view.Menu; import android.view.MenuItem; @@ -29,14 +28,14 @@ import android.view.MenuItem; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.api.OpenKeychainIntents; -import org.sufficientlysecure.keychain.util.Preferences; -import org.sufficientlysecure.keychain.util.ShareHelper; -import org.sufficientlysecure.keychain.pgp.KeyRing; -import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.operations.results.SignEncryptResult; +import org.sufficientlysecure.keychain.pgp.KeyRing; +import org.sufficientlysecure.keychain.pgp.SignEncryptParcel; import org.sufficientlysecure.keychain.ui.dialog.DeleteFileDialogFragment; -import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.ui.util.Notify; +import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.Preferences; +import org.sufficientlysecure.keychain.util.ShareHelper; import java.util.ArrayList; import java.util.HashSet; @@ -170,7 +169,7 @@ public class EncryptFilesActivity extends EncryptActivity implements EncryptActi } @Override - public void onEncryptSuccess(Message message, SignEncryptResult pgpResult) { + public void onEncryptSuccess(SignEncryptResult result) { if (mDeleteAfterEncrypt) { for (Uri inputUri : mInputUris) { DeleteFileDialogFragment deleteFileDialog = DeleteFileDialogFragment.newInstance(inputUri); @@ -182,29 +181,25 @@ public class EncryptFilesActivity extends EncryptActivity implements EncryptActi if (mShareAfterEncrypt) { // Share encrypted message/file - startActivity(sendWithChooserExcludingEncrypt(message)); + startActivity(sendWithChooserExcludingEncrypt()); } else { // Save encrypted file - pgpResult.createNotify(EncryptFilesActivity.this).show(); + result.createNotify(EncryptFilesActivity.this).show(); } } @Override - protected Bundle createEncryptBundle() { + protected SignEncryptParcel createEncryptBundle() { // fill values for this action - Bundle data = new Bundle(); - - data.putInt(KeychainIntentService.SOURCE, KeychainIntentService.IO_URIS); - data.putParcelableArrayList(KeychainIntentService.ENCRYPT_INPUT_URIS, mInputUris); + SignEncryptParcel data = new SignEncryptParcel(); - data.putInt(KeychainIntentService.TARGET, KeychainIntentService.IO_URIS); - data.putParcelableArrayList(KeychainIntentService.ENCRYPT_OUTPUT_URIS, mOutputUris); + data.addInputUris(mInputUris); + data.addOutputUris(mOutputUris); - data.putInt(KeychainIntentService.ENCRYPT_COMPRESSION_ID, - Preferences.getPreferences(this).getDefaultFileCompression()); + data.setCompressionId(Preferences.getPreferences(this).getDefaultMessageCompression()); // Always use armor for messages - data.putBoolean(KeychainIntentService.ENCRYPT_USE_ASCII_ARMOR, mUseArmor); + data.setEnableAsciiArmorOutput(mUseArmor); if (isModeSymmetric()) { Log.d(Constants.TAG, "Symmetric encryption enabled!"); @@ -212,13 +207,12 @@ public class EncryptFilesActivity extends EncryptActivity implements EncryptActi if (passphrase.length() == 0) { passphrase = null; } - data.putString(KeychainIntentService.ENCRYPT_SYMMETRIC_PASSPHRASE, passphrase); + data.setSymmetricPassphrase(passphrase); } else { - data.putLong(KeychainIntentService.ENCRYPT_SIGNATURE_MASTER_ID, mSigningKeyId); - data.putLongArray(KeychainIntentService.ENCRYPT_ENCRYPTION_KEYS_IDS, mEncryptionKeyIds); - data.putString(KeychainIntentService.ENCRYPT_SIGNATURE_KEY_PASSPHRASE, mSigningKeyPassphrase); - data.putSerializable(KeychainIntentService.ENCRYPT_SIGNATURE_NFC_TIMESTAMP, mNfcTimestamp); - data.putByteArray(KeychainIntentService.ENCRYPT_SIGNATURE_NFC_HASH, mNfcHash); + data.setEncryptionMasterKeyIds(mEncryptionKeyIds); + data.setSignatureMasterKeyId(mSigningKeyId); + data.setSignaturePassphrase(mSigningKeyPassphrase); + data.setNfcState(mNfcHash, mNfcTimestamp); } return data; } @@ -226,8 +220,8 @@ public class EncryptFilesActivity extends EncryptActivity implements EncryptActi /** * Create Intent Chooser but exclude OK's EncryptActivity. */ - private Intent sendWithChooserExcludingEncrypt(Message message) { - Intent prototype = createSendIntent(message); + private Intent sendWithChooserExcludingEncrypt() { + Intent prototype = createSendIntent(); String title = getString(R.string.title_share_file); // we don't want to encrypt the encrypted, no inception ;) @@ -239,7 +233,7 @@ public class EncryptFilesActivity extends EncryptActivity implements EncryptActi return new ShareHelper(this).createChooserExcluding(prototype, title, blacklist); } - private Intent createSendIntent(Message message) { + private Intent createSendIntent() { Intent sendIntent; // file if (mOutputUris.size() == 1) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java index be305cc58..860bd8502 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptFilesFragment.java @@ -36,10 +36,10 @@ import android.widget.TextView; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.provider.TemporaryStorageProvider; import org.sufficientlysecure.keychain.ui.util.FormattingUtils; import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.util.FileHelper; -import org.sufficientlysecure.keychain.provider.TemporaryStorageProvider; import java.io.File; import java.util.HashMap; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java index b4c12996e..2dd861d07 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptTextActivity.java @@ -21,7 +21,6 @@ package org.sufficientlysecure.keychain.ui; import android.content.Intent; import android.net.Uri; import android.os.Bundle; -import android.os.Message; import android.support.v4.app.Fragment; import android.view.Menu; import android.view.MenuItem; @@ -30,13 +29,13 @@ import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.api.OpenKeychainIntents; import org.sufficientlysecure.keychain.compatibility.ClipboardReflection; -import org.sufficientlysecure.keychain.util.Preferences; -import org.sufficientlysecure.keychain.util.ShareHelper; -import org.sufficientlysecure.keychain.pgp.KeyRing; -import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.operations.results.SignEncryptResult; -import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.pgp.KeyRing; +import org.sufficientlysecure.keychain.pgp.SignEncryptParcel; import org.sufficientlysecure.keychain.ui.util.Notify; +import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.Preferences; +import org.sufficientlysecure.keychain.util.ShareHelper; import java.util.ArrayList; import java.util.HashSet; @@ -169,32 +168,31 @@ public class EncryptTextActivity extends EncryptActivity implements EncryptActiv } @Override - protected void onEncryptSuccess(Message message, SignEncryptResult pgpResult) { + protected void onEncryptSuccess(SignEncryptResult result) { if (mShareAfterEncrypt) { // Share encrypted message/file - startActivity(sendWithChooserExcludingEncrypt(message)); + startActivity(sendWithChooserExcludingEncrypt(result.getResultBytes())); } else { // Copy to clipboard - copyToClipboard(message); - pgpResult.createNotify(EncryptTextActivity.this).show(); + copyToClipboard(result.getResultBytes()); + result.createNotify(EncryptTextActivity.this).show(); // Notify.showNotify(EncryptTextActivity.this, // R.string.encrypt_sign_clipboard_successful, Notify.Style.INFO); } } @Override - protected Bundle createEncryptBundle() { + protected SignEncryptParcel createEncryptBundle() { // fill values for this action - Bundle data = new Bundle(); + SignEncryptParcel data = new SignEncryptParcel(); - data.putInt(KeychainIntentService.TARGET, KeychainIntentService.IO_BYTES); - data.putByteArray(KeychainIntentService.ENCRYPT_MESSAGE_BYTES, mMessage.getBytes()); + data.setBytes(mMessage.getBytes()); + data.setCleartextSignature(true); - data.putInt(KeychainIntentService.ENCRYPT_COMPRESSION_ID, - Preferences.getPreferences(this).getDefaultMessageCompression()); + data.setCompressionId(Preferences.getPreferences(this).getDefaultMessageCompression()); // Always use armor for messages - data.putBoolean(KeychainIntentService.ENCRYPT_USE_ASCII_ARMOR, true); + data.setEnableAsciiArmorOutput(true); if (isModeSymmetric()) { Log.d(Constants.TAG, "Symmetric encryption enabled!"); @@ -202,26 +200,25 @@ public class EncryptTextActivity extends EncryptActivity implements EncryptActiv if (passphrase.length() == 0) { passphrase = null; } - data.putString(KeychainIntentService.ENCRYPT_SYMMETRIC_PASSPHRASE, passphrase); + data.setSymmetricPassphrase(passphrase); } else { - data.putLong(KeychainIntentService.ENCRYPT_SIGNATURE_MASTER_ID, mSigningKeyId); - data.putLongArray(KeychainIntentService.ENCRYPT_ENCRYPTION_KEYS_IDS, mEncryptionKeyIds); - data.putString(KeychainIntentService.ENCRYPT_SIGNATURE_KEY_PASSPHRASE, mSigningKeyPassphrase); - data.putSerializable(KeychainIntentService.ENCRYPT_SIGNATURE_NFC_TIMESTAMP, mNfcTimestamp); - data.putByteArray(KeychainIntentService.ENCRYPT_SIGNATURE_NFC_HASH, mNfcHash); + data.setEncryptionMasterKeyIds(mEncryptionKeyIds); + data.setSignatureMasterKeyId(mSigningKeyId); + data.setSignaturePassphrase(mSigningKeyPassphrase); + data.setNfcState(mNfcHash, mNfcTimestamp); } return data; } - private void copyToClipboard(Message message) { - ClipboardReflection.copyToClipboard(this, new String(message.getData().getByteArray(KeychainIntentService.RESULT_BYTES))); + private void copyToClipboard(byte[] resultBytes) { + ClipboardReflection.copyToClipboard(this, new String(resultBytes)); } /** * Create Intent Chooser but exclude OK's EncryptActivity. */ - private Intent sendWithChooserExcludingEncrypt(Message message) { - Intent prototype = createSendIntent(message); + private Intent sendWithChooserExcludingEncrypt(byte[] resultBytes) { + Intent prototype = createSendIntent(resultBytes); String title = getString(R.string.title_share_message); // we don't want to encrypt the encrypted, no inception ;) @@ -233,11 +230,11 @@ public class EncryptTextActivity extends EncryptActivity implements EncryptActiv return new ShareHelper(this).createChooserExcluding(prototype, title, blacklist); } - private Intent createSendIntent(Message message) { + private Intent createSendIntent(byte[] resultBytes) { Intent sendIntent; sendIntent = new Intent(Intent.ACTION_SEND); sendIntent.setType("text/plain"); - sendIntent.putExtra(Intent.EXTRA_TEXT, new String(message.getData().getByteArray(KeychainIntentService.RESULT_BYTES))); + sendIntent.putExtra(Intent.EXTRA_TEXT, new String(resultBytes)); if (!isModeSymmetric() && mEncryptionUserIds != null) { Set users = new HashSet<>(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/FirstTimeActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/FirstTimeActivity.java index 4e51c62d2..393e15cfa 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/FirstTimeActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/FirstTimeActivity.java @@ -25,8 +25,8 @@ import android.view.Window; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.util.Preferences; import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.Preferences; public class FirstTimeActivity extends BaseActivity { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysCloudFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysCloudFragment.java index 1d12f49f9..be7653b52 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysCloudFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysCloudFragment.java @@ -36,8 +36,8 @@ import android.widget.TextView; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.util.ContactHelper; -import org.sufficientlysecure.keychain.util.Preferences; import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.Preferences; import java.util.List; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java index 8abb381f8..079ebb729 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java @@ -61,19 +61,19 @@ import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.operations.results.ConsolidateResult; import org.sufficientlysecure.keychain.operations.results.DeleteResult; import org.sufficientlysecure.keychain.operations.results.OperationResult; +import org.sufficientlysecure.keychain.pgp.KeyRing; import org.sufficientlysecure.keychain.provider.KeychainContract; +import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.KeychainDatabase; import org.sufficientlysecure.keychain.service.KeychainIntentService; -import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; -import org.sufficientlysecure.keychain.util.ExportHelper; -import org.sufficientlysecure.keychain.pgp.KeyRing; -import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment; -import org.sufficientlysecure.keychain.ui.widget.ListAwareSwipeRefreshLayout; import org.sufficientlysecure.keychain.ui.util.Highlighter; -import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.Notify; +import org.sufficientlysecure.keychain.ui.widget.ListAwareSwipeRefreshLayout; +import org.sufficientlysecure.keychain.util.ExportHelper; +import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Preferences; import java.io.IOException; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NavDrawerActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NavDrawerActivity.java index bc9c36a2e..035bed412 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NavDrawerActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NavDrawerActivity.java @@ -19,8 +19,6 @@ package org.sufficientlysecure.keychain.ui; import android.content.Intent; import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.remote.ui.AppsListFragment; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcIntentActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcIntentActivity.java index 3e8d688fa..0ccb206d1 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcIntentActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NfcIntentActivity.java @@ -21,8 +21,8 @@ import android.widget.Toast; import org.spongycastle.util.encoders.Hex; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.util.Iso7816TLV; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; +import org.sufficientlysecure.keychain.util.Iso7816TLV; import org.sufficientlysecure.keychain.util.Log; import java.io.IOException; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeViewActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeViewActivity.java index ef1d797be..204ea1d38 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeViewActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeViewActivity.java @@ -26,13 +26,13 @@ import android.widget.ImageView; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.ui.util.Notify.Style; import org.sufficientlysecure.keychain.ui.util.QrCodeUtils; +import org.sufficientlysecure.keychain.util.Log; public class QrCodeViewActivity extends BaseActivity { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java index ed86fea0a..e19793fd5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/UploadKeyActivity.java @@ -33,12 +33,12 @@ import android.widget.Toast; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.util.Preferences; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.Preferences; /** * Sends the selected public key to a keyserver diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java index 05d9dd58e..a80503591 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewCertActivity.java @@ -34,13 +34,13 @@ import android.widget.TextView; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; -import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.pgp.WrappedSignature; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; +import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.provider.KeychainContract.Certs; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.ProviderHelper; +import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.util.Log; import java.util.Date; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java index 205d19628..8e957a36f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java @@ -37,16 +37,16 @@ import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround; import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; -import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets; -import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; +import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.provider.ProviderHelper.NotFoundException; import org.sufficientlysecure.keychain.ui.adapter.UserIdsAdapter; import org.sufficientlysecure.keychain.ui.dialog.UserIdInfoDialogFragment; -import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.Notify; +import org.sufficientlysecure.keychain.util.Log; import java.util.Date; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListCloudLoader.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListCloudLoader.java index 235fdf1d5..4781864dd 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListCloudLoader.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListCloudLoader.java @@ -21,13 +21,13 @@ import android.content.Context; import android.support.v4.content.AsyncTaskLoader; import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.keyimport.CloudSearch; +import org.sufficientlysecure.keychain.keyimport.ImportKeysListEntry; import org.sufficientlysecure.keychain.keyimport.Keyserver; import org.sufficientlysecure.keychain.operations.results.GetKeyResult; import org.sufficientlysecure.keychain.operations.results.OperationResult; -import org.sufficientlysecure.keychain.util.Preferences; -import org.sufficientlysecure.keychain.keyimport.CloudSearch; -import org.sufficientlysecure.keychain.keyimport.ImportKeysListEntry; import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.Preferences; import java.util.ArrayList; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java index 144a16a48..5447c5f96 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysListLoader.java @@ -24,9 +24,9 @@ import android.support.v4.util.LongSparseArray; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.keyimport.ImportKeysListEntry; import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing; -import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; import org.sufficientlysecure.keychain.operations.results.GetKeyResult; import org.sufficientlysecure.keychain.operations.results.OperationResult; +import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; import org.sufficientlysecure.keychain.pgp.UncachedKeyRing.IteratorWithIOThrow; import org.sufficientlysecure.keychain.util.InputData; import org.sufficientlysecure.keychain.util.Log; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/MultiUserIdsAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/MultiUserIdsAdapter.java index 47ad5e664..015775669 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/MultiUserIdsAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/MultiUserIdsAdapter.java @@ -21,13 +21,13 @@ import android.content.Context; import android.database.Cursor; import android.os.Parcel; import android.support.v4.util.LongSparseArray; +import android.support.v4.widget.CursorAdapter; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.CheckBox; import android.widget.CompoundButton; -import android.support.v4.widget.CursorAdapter; import android.widget.TextView; import org.sufficientlysecure.keychain.R; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SelectKeyCursorAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SelectKeyCursorAdapter.java index 60c130969..e90b57c1c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SelectKeyCursorAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SelectKeyCursorAdapter.java @@ -30,9 +30,9 @@ import android.widget.TextView; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.pgp.KeyRing; -import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.ui.util.Highlighter; +import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; /** diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java index 5ba09be7e..c286218ed 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java @@ -35,11 +35,11 @@ import android.widget.ImageView; import android.widget.TextView; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.service.SaveKeyringParcel.SubkeyChange; import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey.SecretKeyType; -import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.provider.KeychainContract.Keys; import org.sufficientlysecure.keychain.service.SaveKeyringParcel; +import org.sufficientlysecure.keychain.service.SaveKeyringParcel.SubkeyChange; +import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import java.util.Calendar; import java.util.Date; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAddedAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAddedAdapter.java index 9f5d5341e..abc1d8816 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAddedAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAddedAdapter.java @@ -31,8 +31,8 @@ import android.widget.TextView; import org.spongycastle.bcpg.sig.KeyFlags; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.service.SaveKeyringParcel; +import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import java.util.Calendar; import java.util.Date; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java index 52c21e253..9f3096b23 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java @@ -31,9 +31,9 @@ import android.widget.ImageView; import android.widget.TextView; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets; import org.sufficientlysecure.keychain.pgp.KeyRing; import org.sufficientlysecure.keychain.provider.KeychainContract.Certs; +import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets; import org.sufficientlysecure.keychain.service.SaveKeyringParcel; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddUserIdDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddUserIdDialogFragment.java index a4ecc7c27..094c4d8a9 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddUserIdDialogFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AddUserIdDialogFragment.java @@ -45,8 +45,8 @@ import android.widget.TextView.OnEditorActionListener; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.util.ContactHelper; import org.sufficientlysecure.keychain.pgp.KeyRing; +import org.sufficientlysecure.keychain.util.ContactHelper; import org.sufficientlysecure.keychain.util.Log; import java.util.regex.Matcher; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/FileDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/FileDialogFragment.java index 1cc800b2b..7ac85781f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/FileDialogFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/FileDialogFragment.java @@ -37,9 +37,9 @@ import android.widget.TextView; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.util.FileHelper; import org.sufficientlysecure.keychain.util.Log; -import org.sufficientlysecure.keychain.ui.util.Notify; import java.io.File; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EncryptKeyCompletionView.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EncryptKeyCompletionView.java index 5f6f13181..f05f5f96b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EncryptKeyCompletionView.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/EncryptKeyCompletionView.java @@ -41,13 +41,13 @@ import com.tokenautocomplete.TokenCompleteTextView; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; -import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; -import org.sufficientlysecure.keychain.util.ContactHelper; import org.sufficientlysecure.keychain.pgp.KeyRing; +import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.provider.CachedPublicKeyRing; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables; +import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; +import org.sufficientlysecure.keychain.util.ContactHelper; import org.sufficientlysecure.keychain.util.Log; import java.util.ArrayList; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeySpinner.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeySpinner.java index 7ec6ffe95..17bfbef57 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeySpinner.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeySpinner.java @@ -37,8 +37,8 @@ import android.widget.TextView; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.pgp.KeyRing; -import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.provider.KeychainContract; +import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.util.Log; public abstract class KeySpinner extends Spinner implements LoaderManager.LoaderCallbacks { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ContactHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ContactHelper.java index 11b29f521..60bc846b2 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ContactHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/ContactHelper.java @@ -35,9 +35,9 @@ import android.util.Patterns; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.pgp.KeyRing; +import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; -import org.sufficientlysecure.keychain.provider.KeychainContract; import java.io.InputStream; import java.util.ArrayList; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/InputData.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/InputData.java index f89ffd139..1f73dcb28 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/InputData.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/InputData.java @@ -25,16 +25,28 @@ import java.io.InputStream; public class InputData { private PositionAwareInputStream mInputStream; private long mSize; + String mOriginalFilename; + + public InputData(InputStream inputStream, long size, String originalFilename) { + mInputStream = new PositionAwareInputStream(inputStream); + mSize = size; + mOriginalFilename = originalFilename; + } public InputData(InputStream inputStream, long size) { mInputStream = new PositionAwareInputStream(inputStream); mSize = size; + mOriginalFilename = ""; } public InputStream getInputStream() { return mInputStream; } + public String getOriginalFilename () { + return mOriginalFilename; + } + public long getSize() { return mSize; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/TlsHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/TlsHelper.java index 7e318281d..4ff14e3bb 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/TlsHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/TlsHelper.java @@ -20,7 +20,6 @@ package org.sufficientlysecure.keychain.util; import android.content.res.AssetManager; import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.util.Log; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; -- cgit v1.2.3 From 95e534e1f5c8494d745b6fec016b21b754fa108e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Mon, 2 Feb 2015 17:19:27 +0100 Subject: UI experiments for app settings --- .../keychain/remote/ui/AppSettingsActivity.java | 31 ++++++++++++++-------- .../keychain/ui/BaseActivity.java | 8 ++++++ 2 files changed, 28 insertions(+), 11 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java index 8f822a338..38e971f2b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java @@ -17,6 +17,7 @@ package org.sufficientlysecure.keychain.remote.ui; +import android.app.Activity; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; @@ -59,9 +60,10 @@ public class AppSettingsActivity extends BaseActivity { new View.OnClickListener() { @Override public void onClick(View v) { - finish(); + cancel(); } }); + setTitle(null); mSettingsFragment = (AppSettingsHeaderFragment) getSupportFragmentManager().findFragmentById( R.id.api_app_settings_fragment); @@ -80,6 +82,13 @@ public class AppSettingsActivity extends BaseActivity { private void save() { mAllowedKeysFragment.saveAllowedKeys(); + setResult(Activity.RESULT_OK); + finish(); + } + + private void cancel() { + setResult(Activity.RESULT_CANCELED); + finish(); } @Override @@ -127,16 +136,16 @@ public class AppSettingsActivity extends BaseActivity { mAppSettings = new ProviderHelper(this).getApiAppSettings(appUri); mSettingsFragment.setAppSettings(mAppSettings); - String appName; - PackageManager pm = getPackageManager(); - try { - ApplicationInfo ai = pm.getApplicationInfo(mAppSettings.getPackageName(), 0); - appName = (String) pm.getApplicationLabel(ai); - } catch (PackageManager.NameNotFoundException e) { - // fallback - appName = mAppSettings.getPackageName(); - } - setTitle(appName); +// String appName; +// PackageManager pm = getPackageManager(); +// try { +// ApplicationInfo ai = pm.getApplicationInfo(mAppSettings.getPackageName(), 0); +// appName = (String) pm.getApplicationLabel(ai); +// } catch (PackageManager.NameNotFoundException e) { +// // fallback +// appName = mAppSettings.getPackageName(); +// } +// setTitle(appName); Uri accountsUri = appUri.buildUpon().appendPath(KeychainContract.PATH_ACCOUNTS).build(); Log.d(Constants.TAG, "accountsUri: " + accountsUri); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BaseActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BaseActivity.java index 7423e6828..7037b5536 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BaseActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BaseActivity.java @@ -26,6 +26,7 @@ import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.LinearLayout; import android.widget.TextView; import org.sufficientlysecure.keychain.R; @@ -126,5 +127,12 @@ public abstract class BaseActivity extends ActionBarActivity { ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); } +// public void add() { +// LayoutInflater inflater = LayoutInflater.from(mToolbar.getContext()); +// View view = inflater.inflate(R.layout.api_app_settings_fragment, null); +// Toolbar.LayoutParams layoutParams = new Toolbar.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); +//// layoutParams.gravity = Gravity.BOTTOM; +// mToolbar.addView(view, layoutParams); +// } } -- cgit v1.2.3 From e2a8819385dab5c925cbc25f728a6491fea185e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Tue, 3 Feb 2015 14:28:54 +0100 Subject: Floating Action Button added in app settings --- .../keychain/remote/ui/AppSettingsActivity.java | 99 +++++++++++++++------- 1 file changed, 68 insertions(+), 31 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java index 8abe40016..fa72f4de3 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java @@ -21,12 +21,18 @@ import android.app.Activity; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; +import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; +import com.getbase.floatingactionbutton.FloatingActionButton; + +import org.spongycastle.util.encoders.Hex; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.operations.results.OperationResult; @@ -36,13 +42,22 @@ import org.sufficientlysecure.keychain.remote.AppSettings; import org.sufficientlysecure.keychain.ui.BaseActivity; import org.sufficientlysecure.keychain.util.Log; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + public class AppSettingsActivity extends BaseActivity { private Uri mAppUri; - private AppSettingsHeaderFragment mSettingsFragment; private AccountsListFragment mAccountsListFragment; private AppSettingsAllowedKeysListFragment mAllowedKeysFragment; + private TextView mAppNameView; + private ImageView mAppIconView; + private TextView mPackageName; + private TextView mPackageSignature; + + private FloatingActionButton mStartFab; + // model AppSettings mAppSettings; @@ -50,23 +65,26 @@ public class AppSettingsActivity extends BaseActivity { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - setFullScreenDialogDoneClose(R.string.api_settings_save, - new View.OnClickListener() { - @Override - public void onClick(View v) { - save(); - } - }, - new View.OnClickListener() { - @Override - public void onClick(View v) { - cancel(); - } - }); - setTitle(null); + mAppNameView = (TextView) findViewById(R.id.api_app_settings_app_name); + mAppIconView = (ImageView) findViewById(R.id.api_app_settings_app_icon); + mPackageName = (TextView) findViewById(R.id.api_app_settings_package_name); + mPackageSignature = (TextView) findViewById(R.id.api_app_settings_package_signature); + mStartFab = (FloatingActionButton) findViewById(R.id.fab); - mSettingsFragment = (AppSettingsHeaderFragment) getSupportFragmentManager().findFragmentById( - R.id.api_app_settings_fragment); + mStartFab.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + startApp(); + } + }); + + setFullScreenDialogClose(new View.OnClickListener() { + @Override + public void onClick(View v) { + cancel(); + } + }); + setTitle(null); Intent intent = getIntent(); mAppUri = intent.getData(); @@ -109,8 +127,8 @@ public class AppSettingsActivity extends BaseActivity { case R.id.menu_api_settings_revoke: revokeAccess(); return true; - case R.id.menu_api_settings_start: - startApp(); + case R.id.menu_api_save: + save(); return true; } return super.onOptionsItemSelected(item); @@ -134,18 +152,37 @@ public class AppSettingsActivity extends BaseActivity { private void loadData(Bundle savedInstanceState, Uri appUri) { mAppSettings = new ProviderHelper(this).getApiAppSettings(appUri); - mSettingsFragment.setAppSettings(mAppSettings); - -// String appName; -// PackageManager pm = getPackageManager(); -// try { -// ApplicationInfo ai = pm.getApplicationInfo(mAppSettings.getPackageName(), 0); -// appName = (String) pm.getApplicationLabel(ai); -// } catch (PackageManager.NameNotFoundException e) { -// // fallback -// appName = mAppSettings.getPackageName(); -// } -// setTitle(appName); + + // get application name and icon from package manager + String appName; + Drawable appIcon = null; + PackageManager pm = getApplicationContext().getPackageManager(); + try { + ApplicationInfo ai = pm.getApplicationInfo(mAppSettings.getPackageName(), 0); + + appName = (String) pm.getApplicationLabel(ai); + appIcon = pm.getApplicationIcon(ai); + } catch (PackageManager.NameNotFoundException e) { + // fallback + appName = mAppSettings.getPackageName(); + } + mAppNameView.setText(appName); + mAppIconView.setImageDrawable(appIcon); + + // advanced info: package name + mPackageName.setText(mAppSettings.getPackageName()); + + // advanced info: package signature SHA-256 + try { + MessageDigest md = MessageDigest.getInstance("SHA-256"); + md.update(mAppSettings.getPackageSignature()); + byte[] digest = md.digest(); + String signature = new String(Hex.encode(digest)); + + mPackageSignature.setText(signature); + } catch (NoSuchAlgorithmException e) { + Log.e(Constants.TAG, "Should not happen!", e); + } Uri accountsUri = appUri.buildUpon().appendPath(KeychainContract.PATH_ACCOUNTS).build(); Log.d(Constants.TAG, "accountsUri: " + accountsUri); -- cgit v1.2.3 From 7914aa5c08d25306be0def7873fe850514e89cb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Tue, 3 Feb 2015 16:05:18 +0100 Subject: Toolbar fixes, Toolbar under status bar on Lollipop --- .../keychain/remote/ui/AppSettingsActivity.java | 26 ++++++++++++++++------ .../keychain/ui/BaseActivity.java | 9 -------- 2 files changed, 19 insertions(+), 16 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java index fa72f4de3..c6b8b186c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java @@ -21,6 +21,7 @@ import android.app.Activity; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; +import android.database.Cursor; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Bundle; @@ -48,7 +49,6 @@ import java.security.NoSuchAlgorithmException; public class AppSettingsActivity extends BaseActivity { private Uri mAppUri; - private AccountsListFragment mAccountsListFragment; private AppSettingsAllowedKeysListFragment mAllowedKeysFragment; private TextView mAppNameView; @@ -58,6 +58,11 @@ public class AppSettingsActivity extends BaseActivity { private FloatingActionButton mStartFab; + // deprecated API + private AccountsListFragment mAccountsListFragment; + private TextView mAccountsLabel; + + // model AppSettings mAppSettings; @@ -65,6 +70,7 @@ public class AppSettingsActivity extends BaseActivity { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + mAccountsLabel = (TextView) findViewById(R.id.api_accounts_label); mAppNameView = (TextView) findViewById(R.id.api_app_settings_app_name); mAppIconView = (ImageView) findViewById(R.id.api_app_settings_app_icon); mPackageName = (TextView) findViewById(R.id.api_app_settings_package_name); @@ -199,15 +205,21 @@ public class AppSettingsActivity extends BaseActivity { return; } - // Create an instance of the fragment - mAccountsListFragment = AccountsListFragment.newInstance(accountsUri); - mAllowedKeysFragment = AppSettingsAllowedKeysListFragment.newInstance(allowedKeysUri); + // show accounts only if available (deprecated API) + Cursor cursor = getContentResolver().query(accountsUri, null, null, null, null); + if (cursor.moveToFirst()) { + mAccountsLabel.setVisibility(View.VISIBLE); + mAccountsListFragment = AccountsListFragment.newInstance(accountsUri); + // Create an instance of the fragments + getSupportFragmentManager().beginTransaction() + .replace(R.id.api_accounts_list_fragment, mAccountsListFragment) + .commitAllowingStateLoss(); + } + // Create an instance of the fragments + mAllowedKeysFragment = AppSettingsAllowedKeysListFragment.newInstance(allowedKeysUri); // Add the fragment to the 'fragment_container' FrameLayout // NOTE: We use commitAllowingStateLoss() to prevent weird crashes! - getSupportFragmentManager().beginTransaction() - .replace(R.id.api_accounts_list_fragment, mAccountsListFragment) - .commitAllowingStateLoss(); getSupportFragmentManager().beginTransaction() .replace(R.id.api_allowed_keys_list_fragment, mAllowedKeysFragment) .commitAllowingStateLoss(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BaseActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BaseActivity.java index 7037b5536..03bb2f733 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BaseActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BaseActivity.java @@ -26,7 +26,6 @@ import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.LinearLayout; import android.widget.TextView; import org.sufficientlysecure.keychain.R; @@ -127,12 +126,4 @@ public abstract class BaseActivity extends ActionBarActivity { ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); } -// public void add() { -// LayoutInflater inflater = LayoutInflater.from(mToolbar.getContext()); -// View view = inflater.inflate(R.layout.api_app_settings_fragment, null); -// Toolbar.LayoutParams layoutParams = new Toolbar.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); -//// layoutParams.gravity = Gravity.BOTTOM; -// mToolbar.addView(view, layoutParams); -// } - } -- cgit v1.2.3 From 9e011860c480d274d9a99bf32947eaea9229dcd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Tue, 3 Feb 2015 18:10:13 +0100 Subject: More toolbar fixes --- .../sufficientlysecure/keychain/remote/ui/AccountSettingsActivity.java | 1 + 1 file changed, 1 insertion(+) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsActivity.java index fbba400a0..4d6df24d2 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AccountSettingsActivity.java @@ -57,6 +57,7 @@ public class AccountSettingsActivity extends BaseActivity { finish(); } }); + setTitle(null); mAccountSettingsFragment = (AccountSettingsFragment) getSupportFragmentManager().findFragmentById( R.id.api_account_settings_fragment); -- cgit v1.2.3 From d6d679997b7bb7d6b10b58c8b1ce0a416ccf9b05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Tue, 3 Feb 2015 18:39:07 +0100 Subject: Move encrypt decrypt operations in own starter activity --- .../keychain/ui/DecryptOverviewFragment.java | 130 ------------------ .../ui/EncryptDecryptOverviewFragment.java | 150 +++++++++++++++++++++ .../keychain/ui/NavDrawerActivity.java | 5 +- 3 files changed, 151 insertions(+), 134 deletions(-) delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptOverviewFragment.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptDecryptOverviewFragment.java (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptOverviewFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptOverviewFragment.java deleted file mode 100644 index 8407a8ca7..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/DecryptOverviewFragment.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (C) 2014-2015 Dominik Schürmann - * Copyright (C) 2014 Vincent Breitmoser - * - * 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 . - */ - -package org.sufficientlysecure.keychain.ui; - -import android.content.Intent; -import android.os.AsyncTask; -import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.v4.app.Fragment; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; - -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.compatibility.ClipboardReflection; -import org.sufficientlysecure.keychain.operations.results.OperationResult; -import org.sufficientlysecure.keychain.pgp.PgpHelper; -import org.sufficientlysecure.keychain.ui.util.SubtleAttentionSeeker; - -import java.util.regex.Matcher; - -public class DecryptOverviewFragment extends Fragment { - - View mActionFile; - View mActionFromClipboard; - View mClipboardIcon; - - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - - } - - @Override - public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.decrypt_overview_fragment, container, false); - - mActionFile = view.findViewById(R.id.decrypt_files); - mActionFromClipboard = view.findViewById(R.id.decrypt_from_clipboard); - mClipboardIcon = view.findViewById(R.id.clipboard_icon); - - mActionFile.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - Intent filesDecrypt = new Intent(getActivity(), DecryptFilesActivity.class); - filesDecrypt.setAction(DecryptFilesActivity.ACTION_DECRYPT_DATA_OPEN); - startActivity(filesDecrypt); - } - }); - - mActionFromClipboard.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - Intent clipboardDecrypt = new Intent(getActivity(), DecryptTextActivity.class); - clipboardDecrypt.setAction(DecryptTextActivity.ACTION_DECRYPT_FROM_CLIPBOARD); - startActivityForResult(clipboardDecrypt, 0); - } - }); - - return view; - } - - @Override - public void onResume() { - super.onResume(); - - // get text from clipboard - final CharSequence clipboardText = - ClipboardReflection.getClipboardText(getActivity()); - - // if it's null, nothing to do here /o/ - if (clipboardText == null) { - return; - } - - new AsyncTask() { - @Override - protected Boolean doInBackground(String... clipboardText) { - - // see if it looks like a pgp thing - Matcher matcher = PgpHelper.PGP_MESSAGE.matcher(clipboardText[0]); - boolean animate = matcher.matches(); - - // see if it looks like another pgp thing - if (!animate) { - matcher = PgpHelper.PGP_CLEARTEXT_SIGNATURE.matcher(clipboardText[0]); - animate = matcher.matches(); - } - return animate; - } - - @Override - protected void onPostExecute(Boolean animate) { - super.onPostExecute(animate); - - // if so, animate the clipboard icon just a bit~ - if (animate) { - SubtleAttentionSeeker.tada(mClipboardIcon, 1.5f).start(); - } - } - }.execute(clipboardText.toString()); - } - - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - // if a result has been returned, display a notify - if (data != null && data.hasExtra(OperationResult.EXTRA_RESULT)) { - OperationResult result = data.getParcelableExtra(OperationResult.EXTRA_RESULT); - result.createNotify(getActivity()).show(); - } else { - super.onActivityResult(requestCode, resultCode, data); - } - } -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptDecryptOverviewFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptDecryptOverviewFragment.java new file mode 100644 index 000000000..a498d0763 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/EncryptDecryptOverviewFragment.java @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2014-2015 Dominik Schürmann + * Copyright (C) 2014 Vincent Breitmoser + * + * 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 . + */ + +package org.sufficientlysecure.keychain.ui; + +import android.content.Intent; +import android.os.AsyncTask; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.compatibility.ClipboardReflection; +import org.sufficientlysecure.keychain.operations.results.OperationResult; +import org.sufficientlysecure.keychain.pgp.PgpHelper; +import org.sufficientlysecure.keychain.ui.util.SubtleAttentionSeeker; + +import java.util.regex.Matcher; + +public class EncryptDecryptOverviewFragment extends Fragment { + + View mEncryptFile; + View mEncryptText; + View mDecryptFile; + View mDecryptFromClipboard; + View mClipboardIcon; + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + } + + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.encrypt_decrypt_overview_fragment, container, false); + + mEncryptFile = view.findViewById(R.id.encrypt_files); + mEncryptText = view.findViewById(R.id.encrypt_text); + mDecryptFile = view.findViewById(R.id.decrypt_files); + mDecryptFromClipboard = view.findViewById(R.id.decrypt_from_clipboard); + mClipboardIcon = view.findViewById(R.id.clipboard_icon); + + mEncryptFile.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent encrypt = new Intent(getActivity(), EncryptFilesActivity.class); + startActivity(encrypt); + } + }); + + mEncryptText.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent encrypt = new Intent(getActivity(), EncryptTextActivity.class); + startActivity(encrypt); + } + }); + + mDecryptFile.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent filesDecrypt = new Intent(getActivity(), DecryptFilesActivity.class); + filesDecrypt.setAction(DecryptFilesActivity.ACTION_DECRYPT_DATA_OPEN); + startActivity(filesDecrypt); + } + }); + + mDecryptFromClipboard.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent clipboardDecrypt = new Intent(getActivity(), DecryptTextActivity.class); + clipboardDecrypt.setAction(DecryptTextActivity.ACTION_DECRYPT_FROM_CLIPBOARD); + startActivityForResult(clipboardDecrypt, 0); + } + }); + + return view; + } + + @Override + public void onResume() { + super.onResume(); + + // get text from clipboard + final CharSequence clipboardText = + ClipboardReflection.getClipboardText(getActivity()); + + // if it's null, nothing to do here /o/ + if (clipboardText == null) { + return; + } + + new AsyncTask() { + @Override + protected Boolean doInBackground(String... clipboardText) { + + // see if it looks like a pgp thing + Matcher matcher = PgpHelper.PGP_MESSAGE.matcher(clipboardText[0]); + boolean animate = matcher.matches(); + + // see if it looks like another pgp thing + if (!animate) { + matcher = PgpHelper.PGP_CLEARTEXT_SIGNATURE.matcher(clipboardText[0]); + animate = matcher.matches(); + } + return animate; + } + + @Override + protected void onPostExecute(Boolean animate) { + super.onPostExecute(animate); + + // if so, animate the clipboard icon just a bit~ + if (animate) { + SubtleAttentionSeeker.tada(mClipboardIcon, 1.5f).start(); + } + } + }.execute(clipboardText.toString()); + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + // if a result has been returned, display a notify + if (data != null && data.hasExtra(OperationResult.EXTRA_RESULT)) { + OperationResult result = data.getParcelableExtra(OperationResult.EXTRA_RESULT); + result.createNotify(getActivity()).show(); + } else { + super.onActivityResult(requestCode, resultCode, data); + } + } +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NavDrawerActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NavDrawerActivity.java index 035bed412..d82e1c246 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NavDrawerActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NavDrawerActivity.java @@ -40,10 +40,7 @@ public abstract class NavDrawerActivity extends MaterialNavigationDrawer { // create sections addSection(newSection(getString(R.string.title_keys), R.drawable.ic_vpn_key_black_24dp, new KeyListFragment())); - - addSection(newSection(getString(R.string.title_encrypt_text), R.drawable.ic_lock_outline_black_24dp, new Intent(this, EncryptTextActivity.class))); - addSection(newSection(getString(R.string.title_encrypt_files), R.drawable.ic_lock_outline_black_24dp, new Intent(this, EncryptFilesActivity.class))); - addSection(newSection(getString(R.string.title_decrypt), R.drawable.ic_lock_open_black_24dp, new DecryptOverviewFragment())); + addSection(newSection(getString(R.string.nav_encrypt_decrypt), R.drawable.ic_lock_black_24dp, new EncryptDecryptOverviewFragment())); addSection(newSection(getString(R.string.title_api_registered_apps), R.drawable.ic_apps_black_24dp, new AppsListFragment())); // create bottom section -- cgit v1.2.3 From 3efaac2175d5b971e83bf4322d221bcde80157dc Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Tue, 17 Feb 2015 18:08:45 +0100 Subject: determine correct filesize during decryption from LiteralData packet --- .../keychain/operations/results/OperationResult.java | 1 + .../sufficientlysecure/keychain/pgp/PgpDecryptVerify.java | 12 +++++------- 2 files changed, 6 insertions(+), 7 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java index 078eb7354..ec26d4bbe 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java @@ -555,6 +555,7 @@ public abstract class OperationResult implements Parcelable { MSG_DC_CLEAR_META_FILE (LogLevel.DEBUG, R.string.msg_dc_clear_meta_file), MSG_DC_CLEAR_META_MIME (LogLevel.DEBUG, R.string.msg_dc_clear_meta_mime), MSG_DC_CLEAR_META_SIZE (LogLevel.DEBUG, R.string.msg_dc_clear_meta_size), + MSG_DC_CLEAR_META_SIZE_UNKNOWN (LogLevel.DEBUG, R.string.msg_dc_clear_meta_size_unknown), MSG_DC_CLEAR_META_TIME (LogLevel.DEBUG, R.string.msg_dc_clear_meta_time), MSG_DC_CLEAR (LogLevel.DEBUG, R.string.msg_dc_clear), MSG_DC_CLEAR_SIGNATURE_BAD (LogLevel.WARN, R.string.msg_dc_clear_signature_bad), diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java index ad9b1900e..e7ab05261 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java @@ -540,12 +540,8 @@ public class PgpDecryptVerify extends BaseOperation { PGPLiteralData literalData = (PGPLiteralData) dataChunk; - // TODO: how to get the real original size? // this is the encrypted size so if we enable compression this value is wrong! - long originalSize = mData.getSize() - mData.getStreamPosition(); - if (originalSize < 0) { - originalSize = 0; - } + Long originalSize = literalData.getDataLengthIfAvailable(); String originalFilename = literalData.getFileName(); String mimeType = null; @@ -573,7 +569,7 @@ public class PgpDecryptVerify extends BaseOperation { originalFilename, mimeType, literalData.getModificationTime().getTime(), - originalSize); + originalSize == null ? 0 : originalSize); if (!originalFilename.equals("")) { log.add(LogType.MSG_DC_CLEAR_META_FILE, indent + 1, originalFilename); @@ -582,9 +578,11 @@ public class PgpDecryptVerify extends BaseOperation { mimeType); log.add(LogType.MSG_DC_CLEAR_META_TIME, indent + 1, new Date(literalData.getModificationTime().getTime()).toString()); - if (originalSize != 0) { + if (originalSize != null) { log.add(LogType.MSG_DC_CLEAR_META_SIZE, indent + 1, Long.toString(originalSize)); + } else { + log.add(LogType.MSG_DC_CLEAR_META_SIZE_UNKNOWN, indent + 1); } // return here if we want to decrypt the metadata only -- cgit v1.2.3 From bb30cb540123577e87c313f71b460482be3e287c Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Tue, 17 Feb 2015 18:43:43 +0100 Subject: fix comments and some warnings in PgpDecryptVerify --- .../sufficientlysecure/keychain/pgp/PgpDecryptVerify.java | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java index e7ab05261..2ee923e42 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpDecryptVerify.java @@ -160,9 +160,6 @@ public class PgpDecryptVerify extends BaseOperation { /** * If detachedSignature != null, it will be used exclusively to verify the signature - * - * @param detachedSignature - * @return */ public Builder setDetachedSignature(byte[] detachedSignature) { mDetachedSignature = detachedSignature; @@ -540,7 +537,7 @@ public class PgpDecryptVerify extends BaseOperation { PGPLiteralData literalData = (PGPLiteralData) dataChunk; - // this is the encrypted size so if we enable compression this value is wrong! + // reported size may be null if partial packets are involved (highly unlikely though) Long originalSize = literalData.getDataLengthIfAvailable(); String originalFilename = literalData.getFileName(); @@ -571,7 +568,7 @@ public class PgpDecryptVerify extends BaseOperation { literalData.getModificationTime().getTime(), originalSize == null ? 0 : originalSize); - if (!originalFilename.equals("")) { + if (!"".equals(originalFilename)) { log.add(LogType.MSG_DC_CLEAR_META_FILE, indent + 1, originalFilename); } log.add(LogType.MSG_DC_CLEAR_META_MIME, indent + 1, @@ -631,9 +628,8 @@ public class PgpDecryptVerify extends BaseOperation { progress = 100; } progressScaler.setProgress((int) progress, 100); - } else { - // TODO: slow annealing to fake a progress? } + // TODO: slow annealing to fake a progress? } if (signature != null) { @@ -849,9 +845,8 @@ public class PgpDecryptVerify extends BaseOperation { progress = 100; } progressScaler.setProgress((int) progress, 100); - } else { - // TODO: slow annealing to fake a progress? } + // TODO: slow annealing to fake a progress? } updateProgress(R.string.progress_verifying_signature, 90, 100); -- cgit v1.2.3 From 9d7e05c06ea485725389768c83eade445f5ecbb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Fri, 20 Feb 2015 11:04:07 +0100 Subject: Screenshot for GSoC --- .../main/java/org/sufficientlysecure/keychain/ui/NavDrawerActivity.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NavDrawerActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NavDrawerActivity.java index d82e1c246..1bb8a9fb4 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NavDrawerActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NavDrawerActivity.java @@ -39,7 +39,7 @@ public abstract class NavDrawerActivity extends MaterialNavigationDrawer { setDrawerHeaderImage(R.drawable.drawer_header); // create sections - addSection(newSection(getString(R.string.title_keys), R.drawable.ic_vpn_key_black_24dp, new KeyListFragment())); + addSection(newSection(getString(R.string.app_name), R.drawable.ic_vpn_key_black_24dp, new KeyListFragment())); addSection(newSection(getString(R.string.nav_encrypt_decrypt), R.drawable.ic_lock_black_24dp, new EncryptDecryptOverviewFragment())); addSection(newSection(getString(R.string.title_api_registered_apps), R.drawable.ic_apps_black_24dp, new AppsListFragment())); -- cgit v1.2.3 From 32acd946982747a37b29a5e23ac313a49df31823 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Sat, 21 Feb 2015 20:46:37 +0100 Subject: Floating action button icons and methods for key list --- .../keychain/ui/KeyListFragment.java | 56 ++++++++++++++++------ 1 file changed, 41 insertions(+), 15 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java index 079ebb729..0f4b0278b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java @@ -56,6 +56,8 @@ import android.widget.ImageView; import android.widget.ListView; import android.widget.TextView; +import com.getbase.floatingactionbutton.FloatingActionButton; + import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.operations.results.ConsolidateResult; @@ -105,6 +107,10 @@ public class KeyListFragment extends LoaderFragment private String mQuery; private SearchView mSearchView; + private FloatingActionButton mFabQrCode; + private FloatingActionButton mFabCloud; + private FloatingActionButton mFabFile; + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -123,6 +129,29 @@ public class KeyListFragment extends LoaderFragment mStickyList = (StickyListHeadersListView) view.findViewById(R.id.key_list_list); mStickyList.setOnItemClickListener(this); + mFabQrCode = (FloatingActionButton) view.findViewById(R.id.fab_add_qr_code); + mFabCloud = (FloatingActionButton) view.findViewById(R.id.fab_add_cloud); + mFabFile = (FloatingActionButton) view.findViewById(R.id.fab_add_file); + + mFabQrCode.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + scanQrCode(); + } + }); + mFabCloud.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + searchCloud(); + } + }); + mFabFile.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + importFile(); + } + }); + mSwipeRefreshLayout = (ListAwareSwipeRefreshLayout) view.findViewById(R.id.key_list_swipe_container); mSwipeRefreshLayout.setOnRefreshListener(new NoScrollableSwipeRefreshLayout.OnRefreshListener() { @Override @@ -496,26 +525,11 @@ public class KeyListFragment extends LoaderFragment @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { - case R.id.menu_key_list_add: - Intent scanQrCode = new Intent(getActivity(), QrCodeScanActivity.class); - scanQrCode.setAction(QrCodeScanActivity.ACTION_SCAN_WITH_RESULT); - startActivityForResult(scanQrCode, 0); - return true; - - case R.id.menu_key_list_search_cloud: - searchCloud(); - return true; case R.id.menu_key_list_create: createKey(); return true; - case R.id.menu_key_list_import_existing_key: - Intent intentImportExisting = new Intent(getActivity(), ImportKeysActivity.class); - intentImportExisting.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_FILE_AND_RETURN); - startActivityForResult(intentImportExisting, 0); - return true; - case R.id.menu_key_list_export: mExportHelper.showExportKeysDialog(null, Constants.Path.APP_DIR_FILE, true); return true; @@ -587,6 +601,18 @@ public class KeyListFragment extends LoaderFragment startActivity(importIntent); } + private void scanQrCode() { + Intent scanQrCode = new Intent(getActivity(), QrCodeScanActivity.class); + scanQrCode.setAction(QrCodeScanActivity.ACTION_SCAN_WITH_RESULT); + startActivityForResult(scanQrCode, 0); + } + + private void importFile() { + Intent intentImportExisting = new Intent(getActivity(), ImportKeysActivity.class); + intentImportExisting.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_FILE_AND_RETURN); + startActivityForResult(intentImportExisting, 0); + } + private void createKey() { Intent intent = new Intent(getActivity(), CreateKeyActivity.class); startActivityForResult(intent, 0); -- cgit v1.2.3 From 6008b65bbd1c96947ad49ccd6dff8bcc69ea43ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Sat, 21 Feb 2015 21:04:26 +0100 Subject: show app name instead of keys in main list --- .../main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java | 3 +++ .../java/org/sufficientlysecure/keychain/ui/NavDrawerActivity.java | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java index 0f4b0278b..55efd9bb0 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java @@ -227,6 +227,9 @@ public class KeyListFragment extends LoaderFragment public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); + // show app name instead of "keys" from nav drawer + getActivity().setTitle(R.string.app_name); + mStickyList.setOnItemClickListener(this); mStickyList.setAreHeadersSticky(true); mStickyList.setDrawingListUnderStickyHeader(false); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NavDrawerActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NavDrawerActivity.java index 1bb8a9fb4..1bd1f0085 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NavDrawerActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NavDrawerActivity.java @@ -24,6 +24,8 @@ import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.remote.ui.AppsListFragment; import it.neokree.materialnavigationdrawer.MaterialNavigationDrawer; +import it.neokree.materialnavigationdrawer.elements.MaterialSection; +import it.neokree.materialnavigationdrawer.elements.listeners.MaterialSectionListener; public abstract class NavDrawerActivity extends MaterialNavigationDrawer { @@ -39,7 +41,7 @@ public abstract class NavDrawerActivity extends MaterialNavigationDrawer { setDrawerHeaderImage(R.drawable.drawer_header); // create sections - addSection(newSection(getString(R.string.app_name), R.drawable.ic_vpn_key_black_24dp, new KeyListFragment())); + addSection(newSection(getString(R.string.nav_keys), R.drawable.ic_vpn_key_black_24dp, new KeyListFragment())); addSection(newSection(getString(R.string.nav_encrypt_decrypt), R.drawable.ic_lock_black_24dp, new EncryptDecryptOverviewFragment())); addSection(newSection(getString(R.string.title_api_registered_apps), R.drawable.ic_apps_black_24dp, new AppsListFragment())); -- cgit v1.2.3 From 04740121a5a964718664436a4a7548c2a2f6ec39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Sun, 22 Feb 2015 21:22:25 +0100 Subject: Go to keyserver settings directly --- .../sufficientlysecure/keychain/ui/ImportKeysCloudFragment.java | 9 ++++----- .../org/sufficientlysecure/keychain/ui/SettingsActivity.java | 1 - 2 files changed, 4 insertions(+), 6 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysCloudFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysCloudFragment.java index be7653b52..91ca93c36 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysCloudFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysCloudFragment.java @@ -21,6 +21,7 @@ import android.app.Activity; import android.content.Context; import android.content.Intent; import android.os.Bundle; +import android.preference.PreferenceActivity; import android.support.v4.app.Fragment; import android.view.KeyEvent; import android.view.LayoutInflater; @@ -110,11 +111,9 @@ public class ImportKeysCloudFragment extends Fragment { mConfigButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { - Intent i = new Intent(mImportActivity, SettingsActivity.class); - // GRR, for some reason I can’t set the Action or I get an incomprehensible - // exception about “modern two-pane layouts” - // i.setAction(PreferencesActivity.ACTION_PREFS_CLOUD); - startActivity(i); + Intent intent = new Intent(mImportActivity, SettingsActivity.class); + intent.putExtra(PreferenceActivity.EXTRA_SHOW_FRAGMENT, SettingsActivity.CloudSearchPrefsFragment.class.getName()); + startActivity(intent); } }); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java index e2fc44689..53986a392 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/SettingsActivity.java @@ -183,7 +183,6 @@ public class SettingsActivity extends PreferenceActivity { } } - /* Called only on Honeycomb and later */ @Override public void onBuildHeaders(List

target) { super.onBuildHeaders(target); -- cgit v1.2.3 From e46fa777abebaa70847d625b704cf1bef77458f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Sun, 22 Feb 2015 21:28:57 +0100 Subject: Use right colors in snackbars and logs --- .../keychain/ui/LogDisplayFragment.java | 20 ++++++++++---------- .../sufficientlysecure/keychain/ui/util/Notify.java | 18 ++++++++++-------- 2 files changed, 20 insertions(+), 18 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayFragment.java index 2baebc83d..b655a7e55 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/LogDisplayFragment.java @@ -153,11 +153,11 @@ public class LogDisplayFragment extends ListFragment implements OnItemClickListe switch (subEntry.mType.mLevel) { case DEBUG: ih.mSecondImg.setBackgroundColor(Color.GRAY); break; case INFO: ih.mSecondImg.setBackgroundColor(Color.BLACK); break; - case WARN: ih.mSecondImg.setBackgroundColor(Color.YELLOW); break; - case ERROR: ih.mSecondImg.setBackgroundColor(Color.RED); break; - case START: ih.mSecondImg.setBackgroundColor(getResources().getColor(R.color.emphasis)); break; - case OK: ih.mSecondImg.setBackgroundColor(Color.GREEN); break; - case CANCELLED: ih.mSecondImg.setBackgroundColor(Color.RED); break; + case WARN: ih.mSecondImg.setBackgroundColor(getResources().getColor(R.color.android_orange_light)); break; + case ERROR: ih.mSecondImg.setBackgroundColor(getResources().getColor(R.color.android_red_light)); break; + case START: ih.mSecondImg.setBackgroundColor(Color.BLACK); break; + case OK: ih.mSecondImg.setBackgroundColor(getResources().getColor(R.color.android_green_light)); break; + case CANCELLED: ih.mSecondImg.setBackgroundColor(getResources().getColor(R.color.android_red_light)); break; } } else { ih.mSecond.setVisibility(View.GONE); @@ -184,11 +184,11 @@ public class LogDisplayFragment extends ListFragment implements OnItemClickListe switch (entry.mType.mLevel) { case DEBUG: ih.mImg.setBackgroundColor(Color.GRAY); break; case INFO: ih.mImg.setBackgroundColor(Color.BLACK); break; - case WARN: ih.mImg.setBackgroundColor(Color.YELLOW); break; - case ERROR: ih.mImg.setBackgroundColor(Color.RED); break; - case START: ih.mImg.setBackgroundColor(getResources().getColor(R.color.emphasis)); break; - case OK: ih.mImg.setBackgroundColor(Color.GREEN); break; - case CANCELLED: ih.mImg.setBackgroundColor(Color.RED); break; + case WARN: ih.mImg.setBackgroundColor(getResources().getColor(R.color.android_orange_light)); break; + case ERROR: ih.mImg.setBackgroundColor(getResources().getColor(R.color.android_red_light)); break; + case START: ih.mImg.setBackgroundColor(Color.BLACK); break; + case OK: ih.mImg.setBackgroundColor(getResources().getColor(R.color.android_green_light)); break; + case CANCELLED: ih.mImg.setBackgroundColor(getResources().getColor(R.color.android_red_light)); break; } return convertView; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/Notify.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/Notify.java index 66d6bf9e3..6f8c477c0 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/Notify.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/Notify.java @@ -26,6 +26,8 @@ import com.nispok.snackbar.Snackbar.SnackbarDuration; import com.nispok.snackbar.SnackbarManager; import com.nispok.snackbar.listeners.ActionClickListener; +import org.sufficientlysecure.keychain.R; + /** * Notify wrapper which allows a more easy use of different notification libraries */ @@ -52,10 +54,10 @@ public class Notify { case OK: break; case WARN: - bar.textColor(Color.YELLOW); + bar.textColor(activity.getResources().getColor(R.color.android_orange_light)); break; case ERROR: - bar.textColor(Color.RED); + bar.textColor(activity.getResources().getColor(R.color.android_red_light)); break; } @@ -74,13 +76,13 @@ public class Notify { switch (style) { case OK: - bar.actionColor(Color.GREEN); + bar.actionColor(activity.getResources().getColor(R.color.android_green_light)); break; case WARN: - bar.textColor(Color.YELLOW); + bar.textColor(activity.getResources().getColor(R.color.android_orange_light)); break; case ERROR: - bar.textColor(Color.RED); + bar.textColor(activity.getResources().getColor(R.color.android_red_light)); break; } @@ -116,13 +118,13 @@ public class Notify { switch (style) { case OK: - bar.actionColor(Color.GREEN); + bar.actionColor(activity.getResources().getColor(R.color.android_green_light)); break; case WARN: - bar.textColor(Color.YELLOW); + bar.textColor(activity.getResources().getColor(R.color.android_orange_light)); break; case ERROR: - bar.textColor(Color.RED); + bar.textColor(activity.getResources().getColor(R.color.android_red_light)); break; } -- cgit v1.2.3 From e20c6add4398ffc0137fc637bb9897c2cd09cb18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Sun, 22 Feb 2015 23:52:29 +0100 Subject: Fix multi select and more colors --- .../java/org/sufficientlysecure/keychain/KeychainApplication.java | 2 +- .../main/java/org/sufficientlysecure/keychain/ui/MainActivity.java | 2 -- .../java/org/sufficientlysecure/keychain/ui/NavDrawerActivity.java | 2 -- .../keychain/ui/dialog/CustomAlertDialogBuilder.java | 4 ++-- 4 files changed, 3 insertions(+), 7 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java index 957ce4b23..01f6735ea 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/KeychainApplication.java @@ -86,7 +86,7 @@ public class KeychainApplication extends Application { } brandGlowEffect(getApplicationContext(), - getApplicationContext().getResources().getColor(R.color.emphasis)); + getApplicationContext().getResources().getColor(R.color.primary)); setupAccountAsNeeded(this); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java index f3bf337c9..2f29f9360 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java @@ -31,8 +31,6 @@ public class MainActivity extends NavDrawerActivity { public void init(Bundle savedInstanceState) { super.init(savedInstanceState); - setTitle(R.string.nav_keys); - // if this is the first time show first time activity Preferences prefs = Preferences.getPreferences(this); if (prefs.isFirstTime()) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NavDrawerActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NavDrawerActivity.java index 1bd1f0085..fb23c7d3a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NavDrawerActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NavDrawerActivity.java @@ -24,8 +24,6 @@ import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.remote.ui.AppsListFragment; import it.neokree.materialnavigationdrawer.MaterialNavigationDrawer; -import it.neokree.materialnavigationdrawer.elements.MaterialSection; -import it.neokree.materialnavigationdrawer.elements.listeners.MaterialSectionListener; public abstract class NavDrawerActivity extends MaterialNavigationDrawer { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/CustomAlertDialogBuilder.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/CustomAlertDialogBuilder.java index aa27e8391..d405b1dda 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/CustomAlertDialogBuilder.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/CustomAlertDialogBuilder.java @@ -26,13 +26,13 @@ public class CustomAlertDialogBuilder extends AlertDialog.Builder { int dividerId = dialog.getContext().getResources().getIdentifier("android:id/titleDivider", null, null); View divider = dialog.findViewById(dividerId); if (divider != null) { - divider.setBackgroundColor(dialog.getContext().getResources().getColor(R.color.emphasis)); + divider.setBackgroundColor(dialog.getContext().getResources().getColor(R.color.header_text)); } int textViewId = dialog.getContext().getResources().getIdentifier("android:id/alertTitle", null, null); TextView tv = (TextView) dialog.findViewById(textViewId); if (tv != null) { - tv.setTextColor(dialog.getContext().getResources().getColor(R.color.emphasis)); + tv.setTextColor(dialog.getContext().getResources().getColor(R.color.header_text)); } return dialog; -- cgit v1.2.3 From d984f50cb77db4fe8d1eae17c669673a3380bb92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Sun, 22 Feb 2015 23:55:23 +0100 Subject: Disable default yubikey PIN by default --- .../src/main/java/org/sufficientlysecure/keychain/util/Preferences.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Preferences.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Preferences.java index 8d4af58d7..a36af5c87 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Preferences.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/Preferences.java @@ -172,7 +172,7 @@ public class Preferences { } public boolean useDefaultYubikeyPin() { - return mSharedPreferences.getBoolean(Pref.USE_DEFAULT_YUBIKEY_PIN, true); + return mSharedPreferences.getBoolean(Pref.USE_DEFAULT_YUBIKEY_PIN, false); } public void setUseDefaultYubikeyPin(boolean useDefaultYubikeyPin) { -- cgit v1.2.3 From 6b57afc350996484256d85b862c284788b9f3f70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Mon, 23 Feb 2015 00:17:27 +0100 Subject: Removed submodule android-lockpattern --- .../android/lockpattern/LockPatternFragment.java | 55 -- .../lockpattern/LockPatternFragmentOld.java | 926 --------------------- 2 files changed, 981 deletions(-) delete mode 100644 OpenKeychain/src/main/java/com/haibison/android/lockpattern/LockPatternFragment.java delete mode 100644 OpenKeychain/src/main/java/com/haibison/android/lockpattern/LockPatternFragmentOld.java (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/com/haibison/android/lockpattern/LockPatternFragment.java b/OpenKeychain/src/main/java/com/haibison/android/lockpattern/LockPatternFragment.java deleted file mode 100644 index 318a7c2e5..000000000 --- a/OpenKeychain/src/main/java/com/haibison/android/lockpattern/LockPatternFragment.java +++ /dev/null @@ -1,55 +0,0 @@ - - -package com.haibison.android.lockpattern; - -import android.app.Activity; -import android.os.Bundle; -import android.support.v4.app.Fragment; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; - -import com.haibison.android.lockpattern.widget.LockPatternUtils; -import com.haibison.android.lockpattern.widget.LockPatternView; - - -public class LockPatternFragment extends Fragment { - public static final String NUMBER_OF_MEASUREMENTS = "number_of_measurements"; - public static final String PATTERN_STRING = "pattern_string"; - - private String mPatternString; - private LockPatternView.OnPatternListener mEvents; - - public static LockPatternFragment newInstance(String pattern) { - LockPatternFragment fragment = new LockPatternFragment(); - Bundle args = new Bundle(); - args.putString(PATTERN_STRING, pattern); - fragment.setArguments(args); - return fragment; - } - - public LockPatternFragment() { - } - - @Override - public void onAttach(Activity activity) { - super.onAttach(activity); - - mEvents = (LockPatternView.OnPatternListener) activity; - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - // Get the number of measurements from the bundle, or load the default: - mPatternString = getArguments().getString(PATTERN_STRING); - - View rootView = inflater.inflate(R.layout.alp_42447968_lock_pattern_activity, container, false); - - final LockPatternView lpv = (LockPatternView) rootView.findViewById(R.id.alp_42447968_view_lock_pattern); - lpv.setPattern(LockPatternView.DisplayMode.Correct, LockPatternUtils.stringToPattern(mPatternString)); - - lpv.setOnPatternListener(mEvents); - - return rootView; - } -} diff --git a/OpenKeychain/src/main/java/com/haibison/android/lockpattern/LockPatternFragmentOld.java b/OpenKeychain/src/main/java/com/haibison/android/lockpattern/LockPatternFragmentOld.java deleted file mode 100644 index 439cf3562..000000000 --- a/OpenKeychain/src/main/java/com/haibison/android/lockpattern/LockPatternFragmentOld.java +++ /dev/null @@ -1,926 +0,0 @@ -/* - * Copyright 2012 Hai Bison - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use getActivity() file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.haibison.android.lockpattern; - -import android.app.Activity; -import android.app.PendingIntent; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.content.pm.PackageManager.NameNotFoundException; -import android.content.res.Configuration; -import android.os.Bundle; -import android.os.ResultReceiver; -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentActivity; -import android.text.TextUtils; -import android.text.format.DateUtils; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.view.ViewGroup.LayoutParams; -import android.widget.Button; -import android.widget.TextView; -import android.widget.Toast; - -import com.haibison.android.lockpattern.util.IEncrypter; -import com.haibison.android.lockpattern.util.InvalidEncrypterException; -import com.haibison.android.lockpattern.util.LoadingDialog; -import com.haibison.android.lockpattern.util.Settings; -import com.haibison.android.lockpattern.util.UI; -import com.haibison.android.lockpattern.widget.LockPatternUtils; -import com.haibison.android.lockpattern.widget.LockPatternView; -import com.haibison.android.lockpattern.widget.LockPatternView.Cell; -import com.haibison.android.lockpattern.widget.LockPatternView.DisplayMode; - -import org.sufficientlysecure.keychain.ui.PassphraseWizardActivity; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import static com.haibison.android.lockpattern.util.Settings.Display.METADATA_CAPTCHA_WIRED_DOTS; -import static com.haibison.android.lockpattern.util.Settings.Display.METADATA_MAX_RETRIES; -import static com.haibison.android.lockpattern.util.Settings.Display.METADATA_MIN_WIRED_DOTS; -import static com.haibison.android.lockpattern.util.Settings.Display.METADATA_STEALTH_MODE; -import static com.haibison.android.lockpattern.util.Settings.Security.METADATA_AUTO_SAVE_PATTERN; -import static com.haibison.android.lockpattern.util.Settings.Security.METADATA_ENCRYPTER_CLASS; - -/** - * Main activity for getActivity() library. - *

- * You can deliver result to {@link android.app.PendingIntent}'s and/ or - * {@link android.os.ResultReceiver} too. See {@link #EXTRA_PENDING_INTENT_OK}, - * {@link #EXTRA_PENDING_INTENT_CANCELLED} and {@link #EXTRA_RESULT_RECEIVER} - * for more details. - *

- * - *

NOTES

- *
    - *
  • - * You must use one of built-in actions when calling getActivity() activity. They start - * with {@code ACTION_*}. Otherwise the library might behave strangely (we don't - * cover those cases).
  • - *
  • You must use one of the themes that getActivity() library supports. They start - * with {@code R.style.Alp_42447968_Theme_*}. The reason is the themes contain - * resources that the library needs.
  • - *
  • With {@link #ACTION_COMPARE_PATTERN}, there are 4 possible result - * codes: {@link android.app.Activity#RESULT_OK}, {@link android.app.Activity#RESULT_CANCELED}, - * {@link #RESULT_FAILED} and {@link #RESULT_FORGOT_PATTERN}.
  • - *
  • With {@link #ACTION_VERIFY_CAPTCHA}, there are 3 possible result - * codes: {@link android.app.Activity#RESULT_OK}, {@link android.app.Activity#RESULT_CANCELED}, - * and {@link #RESULT_FAILED}.
  • - *
- * - * @author Hai Bison - * @since v1.0 - */ -public class LockPatternFragmentOld extends Fragment { - - private static final String CLASSNAME = LockPatternFragmentOld.class.getName(); - - public static final String ACTION_CREATE_PATTERN = "create"; - - /** - * Use getSelectedMethod() to compare pattern. You provide the pattern to be - * compared with {@link #EXTRA_PATTERN}. - *

- * If you enabled feature auto-save pattern before (with - * {@link com.haibison.android.lockpattern.util.Settings.Security#setAutoSavePattern(android.content.Context, boolean)} ), - * then you don't need {@link #EXTRA_PATTERN} at getActivity() time. - *

- * You can use {@link #EXTRA_PENDING_INTENT_FORGOT_PATTERN} to help your - * users in case they forgot the patterns. - *

- * If the user passes, {@link android.app.Activity#RESULT_OK} returns. If not, - * {@link #RESULT_FAILED} returns. - *

- * If the user cancels the task, {@link android.app.Activity#RESULT_CANCELED} returns. - *

- * In any case, there will have extra {@link #EXTRA_RETRY_COUNT} available - * in the intent result. - * - * @see #EXTRA_PATTERN - * @see #EXTRA_PENDING_INTENT_OK - * @see #EXTRA_PENDING_INTENT_CANCELLED - * @see #RESULT_FAILED - * @see #EXTRA_RETRY_COUNT - * @since v2.4 beta - */ - public static final String ACTION_COMPARE_PATTERN = "authenticate";//CLASSNAME + ".compare_pattern"; - - /** - * Use getActivity() action to let the activity generate a random pattern and ask the - * user to re-draw it to verify. - *

- * The default length of the auto-generated pattern is {@code 4}. You can - * change it with - * {@link com.haibison.android.lockpattern.util.Settings.Display#setCaptchaWiredDots(android.content.Context, int)}. - * - * @since v2.7 beta - */ - public static final String ACTION_VERIFY_CAPTCHA = CLASSNAME + ".verify_captcha"; - - /** - * If you use {@link #ACTION_COMPARE_PATTERN} and the user fails to "login" - * after a number of tries, getActivity() activity will finish with getActivity() result code. - * - * @see #ACTION_COMPARE_PATTERN - * @see #EXTRA_RETRY_COUNT - */ - public final int RESULT_FAILED = Activity.RESULT_FIRST_USER + 1; - - /** - * If you use {@link #ACTION_COMPARE_PATTERN} and the user forgot his/ her - * pattern and decided to ask for your help with recovering the pattern ( - * {@link #EXTRA_PENDING_INTENT_FORGOT_PATTERN}), getActivity() activity will finish - * with getActivity() result code. - * - * @see #ACTION_COMPARE_PATTERN - * @see #EXTRA_RETRY_COUNT - * @see #EXTRA_PENDING_INTENT_FORGOT_PATTERN - * @since v2.8 beta - */ - public static final int RESULT_FORGOT_PATTERN = Activity.RESULT_FIRST_USER + 2; - - /** - * For actions {@link #ACTION_COMPARE_PATTERN} and - * {@link #ACTION_VERIFY_CAPTCHA}, getActivity() key holds the number of tries that - * the user attempted to verify the input pattern. - */ - public static final String EXTRA_RETRY_COUNT = CLASSNAME + ".retry_count"; - - /** - * Sets value of getActivity() key to a theme in {@code R.style.Alp_42447968_Theme_*} - * . Default is the one you set in your {@code AndroidManifest.xml}. Note - * that theme {@link R.style#Alp_42447968_Theme_Light_DarkActionBar} is - * available in API 4+, but it only works in API 14+. - * - * @since v1.5.3 beta - */ - public static final String EXTRA_THEME = CLASSNAME + ".theme"; - - /** - * Key to hold the pattern. It must be a {@code char[]} array. - *

- *

    - *
  • If you use encrypter, it should be an encrypted array.
  • - *
  • If you don't use encrypter, it should be the SHA-1 value of the - * actual pattern. You can generate the value by - * {@link com.haibison.android.lockpattern.widget.LockPatternUtils#patternToSha1(java.util.List)}.
  • - *
- * - * @since v2 beta - */ - public static final String EXTRA_PATTERN = CLASSNAME + ".pattern"; - - /** - * You can provide an {@link android.os.ResultReceiver} with getActivity() key. The activity - * will notify your receiver the same result code and intent data as you - * will receive them in {@link #onActivityResult(int, int, android.content.Intent)}. - * - * @since v2.4 beta - */ - public static final String EXTRA_RESULT_RECEIVER = CLASSNAME - + ".result_receiver"; - - /** - * Put a {@link android.app.PendingIntent} into getActivity() key. It will be sent before - * {@link android.app.Activity#RESULT_OK} will be returning. If you were calling getActivity() - * activity with {@link #ACTION_CREATE_PATTERN}, key {@link #EXTRA_PATTERN} - * will be attached to the original intent which the pending intent holds. - * - *

Notes

- *
    - *
  • If you're going to use an activity, you don't need - * {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK} for the intent, since the library - * will call it inside {@link LockPatternFragmentOld} .
  • - *
- */ - public static final String EXTRA_PENDING_INTENT_OK = CLASSNAME - + ".pending_intent_ok"; - - /** - * Put a {@link android.app.PendingIntent} into getActivity() key. It will be sent before - * {@link android.app.Activity#RESULT_CANCELED} will be returning. - * - *

Notes

- *
    - *
  • If you're going to use an activity, you don't need - * {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK} for the intent, since the library - * will call it inside {@link LockPatternFragmentOld} .
  • - *
- */ - public static final String EXTRA_PENDING_INTENT_CANCELLED = CLASSNAME - + ".pending_intent_cancelled"; - - /** - * You put a {@link android.app.PendingIntent} into getActivity() extra. The library will show a - * button "Forgot pattern?" and call your intent later when the user - * taps it. - *

- *

Notes

- *
    - *
  • If you use an activity, you don't need - * {@link android.content.Intent#FLAG_ACTIVITY_NEW_TASK} for the intent, since the library - * will call it inside {@link LockPatternFragmentOld} .
  • - *
  • {@link LockPatternFragmentOld} will finish with - * {@link #RESULT_FORGOT_PATTERN} after making a call to start - * your pending intent.
  • - *
  • It is your responsibility to make sure the Intent is good. The - * library doesn't cover any errors when calling your intent.
  • - *
- * - * @see #ACTION_COMPARE_PATTERN - * @since v2.8 beta - */ - public static final String EXTRA_PENDING_INTENT_FORGOT_PATTERN = CLASSNAME - + ".pending_intent_forgot_pattern"; - - /** - * Helper enum for button OK commands. (Because we use only one "OK" button - * for different commands). - * - * @author Hai Bison - */ - private static enum ButtonOkCommand { - CONTINUE,DONE - }// ButtonOkCommand - - /** - * Delay time to reload the lock pattern view after a wrong pattern. - */ - private static final long DELAY_TIME_TO_RELOAD_LOCK_PATTERN_VIEW = DateUtils.SECOND_IN_MILLIS; - - /* - * FIELDS - */ - private int mMaxRetries, mMinWiredDots, mRetryCount = 0, mCaptchaWiredDots; - private boolean mAutoSave, mStealthMode; - private IEncrypter mEncrypter; - private ButtonOkCommand mBtnOkCmd; - private Intent mIntentResult; - - /* - * CONTROLS - */ - private TextView mTextInfo; - private LockPatternView mLockPatternView; - private Button mBtnConfirm; - - /* - * FRAGMENTS - */ - private FragmentActivity fa; - - /** - * Called when the activity is first created. - */ - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - - fa = getActivity(); - - /* - * EXTRA_THEME - */ - if (fa.getIntent().hasExtra(EXTRA_THEME)) - fa.setTheme(fa.getIntent().getIntExtra(EXTRA_THEME, - R.style.Alp_42447968_Theme_Dark)); - View view = inflater.inflate(R.layout.alp_42447968_lock_pattern_activity, container, false); - loadSettings(); - - mIntentResult = new Intent(); - fa.setResult(Activity.RESULT_CANCELED, mIntentResult); - initContentView(view); - return view; - } - - @Override - public void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - } - - /** - * Loads settings, either from manifest or {@link com.haibison.android.lockpattern.util.Settings}. - */ - private void loadSettings() { - Bundle metaData = null; - try { - metaData = fa.getPackageManager().getActivityInfo(fa.getComponentName(), - PackageManager.GET_META_DATA).metaData; - } catch (NameNotFoundException e) { - /* - * Never catch getActivity(). - */ - e.printStackTrace(); - } - - if (metaData != null && metaData.containsKey(METADATA_MIN_WIRED_DOTS)) - mMinWiredDots = Settings.Display.validateMinWiredDots(getActivity(), - metaData.getInt(METADATA_MIN_WIRED_DOTS)); - else - mMinWiredDots = Settings.Display.getMinWiredDots(getActivity()); - - if (metaData != null && metaData.containsKey(METADATA_MAX_RETRIES)) - mMaxRetries = Settings.Display.validateMaxRetries(getActivity(), - metaData.getInt(METADATA_MAX_RETRIES)); - else - mMaxRetries = Settings.Display.getMaxRetries(getActivity()); - - if (metaData != null - && metaData.containsKey(METADATA_AUTO_SAVE_PATTERN)) - mAutoSave = metaData.getBoolean(METADATA_AUTO_SAVE_PATTERN); - else - mAutoSave = Settings.Security.isAutoSavePattern(getActivity()); - - if (metaData != null - && metaData.containsKey(METADATA_CAPTCHA_WIRED_DOTS)) - mCaptchaWiredDots = Settings.Display.validateCaptchaWiredDots(getActivity(), - metaData.getInt(METADATA_CAPTCHA_WIRED_DOTS)); - else - mCaptchaWiredDots = Settings.Display.getCaptchaWiredDots(getActivity()); - - if (metaData != null && metaData.containsKey(METADATA_STEALTH_MODE)) - mStealthMode = metaData.getBoolean(METADATA_STEALTH_MODE); - else - mStealthMode = Settings.Display.isStealthMode(getActivity()); - - /* - * Encrypter. - */ - char[] encrypterClass; - if (metaData != null && metaData.containsKey(METADATA_ENCRYPTER_CLASS)) - encrypterClass = metaData.getString(METADATA_ENCRYPTER_CLASS) - .toCharArray(); - else - encrypterClass = Settings.Security.getEncrypterClass(getActivity()); - - if (encrypterClass != null) { - try { - mEncrypter = (IEncrypter) Class.forName( - new String(encrypterClass), false, fa.getClassLoader()) - .newInstance(); - } catch (Throwable t) { - throw new InvalidEncrypterException(); - } - } - } - - /** - * Initializes UI... - */ - private void initContentView(View view) { - - /* - * Save all controls' state to restore later. - */ - CharSequence infoText = mTextInfo != null ? mTextInfo.getText() : null; - Boolean btnOkEnabled = mBtnConfirm != null ? mBtnConfirm.isEnabled() - : null; - DisplayMode lastDisplayMode = mLockPatternView != null ? mLockPatternView - .getDisplayMode() : null; - List lastPattern = mLockPatternView != null ? mLockPatternView - .getPattern() : null; - - UI.adjustDialogSizeForLargeScreens(fa.getWindow()); - - View mFooter; - Button mBtnCancel; - - mTextInfo = (TextView) view.findViewById(R.id.alp_42447968_textview_info); - mLockPatternView = (LockPatternView) view.findViewById(R.id.alp_42447968_view_lock_pattern); - - mFooter = view.findViewById(R.id.alp_42447968_viewgroup_footer); - mBtnCancel = (Button) view.findViewById(R.id.alp_42447968_button_cancel); - mBtnConfirm = (Button) view.findViewById(R.id.alp_42447968_button_confirm); - - /* - * LOCK PATTERN VIEW - */ - - switch (getResources().getConfiguration().screenLayout - & Configuration.SCREENLAYOUT_SIZE_MASK) { - case Configuration.SCREENLAYOUT_SIZE_LARGE: - case Configuration.SCREENLAYOUT_SIZE_XLARGE: { - final int size = getResources().getDimensionPixelSize( - R.dimen.alp_42447968_lockpatternview_size); - LayoutParams lp = mLockPatternView.getLayoutParams(); - lp.width = size; - lp.height = size; - mLockPatternView.setLayoutParams(lp); - - break; - } - } - - /* - * Haptic feedback. - */ - boolean hapticFeedbackEnabled = false; - try { - hapticFeedbackEnabled = android.provider.Settings.System - .getInt(fa.getContentResolver(), - android.provider.Settings.System.HAPTIC_FEEDBACK_ENABLED, - 0) != 0; - } catch (Throwable t) { - /* - * Ignore it. - */ - } - mLockPatternView.setTactileFeedbackEnabled(hapticFeedbackEnabled); - - mLockPatternView.setInStealthMode(mStealthMode - && !ACTION_VERIFY_CAPTCHA.equals(fa.getIntent().getAction())); - mLockPatternView.setOnPatternListener(mLockPatternViewListener); - if (lastPattern != null && lastDisplayMode != null - && !ACTION_VERIFY_CAPTCHA.equals(fa.getIntent().getAction())) - mLockPatternView.setPattern(lastDisplayMode, lastPattern); - /* - * COMMAND BUTTONS - */ - - if (ACTION_CREATE_PATTERN.equals(getSelectedMethod())) { - mBtnCancel.setOnClickListener(mBtnCancelOnClickListener); - mBtnConfirm.setOnClickListener(mBtnConfirmOnClickListener); - - mBtnCancel.setVisibility(View.VISIBLE); - mFooter.setVisibility(View.VISIBLE); - mTextInfo.setVisibility(View.VISIBLE); - if (infoText != null) - mTextInfo.setText(infoText); - else - mTextInfo //TODO nfc text glaube ich hier oder so - .setText(R.string.alp_42447968_msg_draw_an_unlock_pattern); - - /* - * BUTTON OK - */ - if (mBtnOkCmd == null) - mBtnOkCmd = ButtonOkCommand.CONTINUE; - switch (mBtnOkCmd) { - case CONTINUE: - mBtnConfirm.setText(R.string.alp_42447968_cmd_continue); - break; - case DONE: - mBtnConfirm.setText(R.string.alp_42447968_cmd_confirm); - break; - default: - break; - } - if (btnOkEnabled != null) - mBtnConfirm.setEnabled(btnOkEnabled); - } - else if (ACTION_COMPARE_PATTERN.equals(getSelectedMethod())) { - if (TextUtils.isEmpty(infoText)) - mTextInfo - .setText(R.string.alp_42447968_msg_draw_pattern_to_unlock); - else - mTextInfo.setText(infoText); - if (fa.getIntent().hasExtra(EXTRA_PENDING_INTENT_FORGOT_PATTERN)) { - mBtnConfirm.setOnClickListener(mBtnConfirmOnClickListener); - mBtnConfirm.setText(R.string.alp_42447968_cmd_forgot_pattern); - mBtnConfirm.setEnabled(true); - mFooter.setVisibility(View.VISIBLE); - } - } - else if (ACTION_VERIFY_CAPTCHA.equals(fa.getIntent().getAction())) { - mTextInfo - .setText(R.string.alp_42447968_msg_redraw_pattern_to_confirm); - - /* - * NOTE: EXTRA_PATTERN should hold a char[] array. In getActivity() case we - * use it as a temporary variable to hold a list of Cell. - */ - - final ArrayList pattern; - if (fa.getIntent().hasExtra(EXTRA_PATTERN)) - pattern = fa.getIntent() - .getParcelableArrayListExtra(EXTRA_PATTERN); - else - fa.getIntent().putParcelableArrayListExtra( - EXTRA_PATTERN, - pattern = LockPatternUtils - .genCaptchaPattern(mCaptchaWiredDots)); - - mLockPatternView.setPattern(DisplayMode.Animate, pattern); - } - } - - /** - * Compares {@code pattern} to the given pattern ( - * {@link #ACTION_COMPARE_PATTERN}) or to the generated "CAPTCHA" pattern ( - * {@link #ACTION_VERIFY_CAPTCHA}). Then finishes the activity if they - * match. - * - * @param pattern - * the pattern to be compared. - */ - private void doComparePattern(final List pattern) { - if (pattern == null) - return; - - /* - * Use a LoadingDialog because decrypting pattern might take time... - */ - new LoadingDialog(getActivity(), false) { - - @Override - protected Boolean doInBackground(Void... params) { - if (ACTION_COMPARE_PATTERN.equals(getSelectedMethod())) { - char[] currentPattern = PassphraseWizardActivity.pattern; - if (currentPattern == null) - currentPattern = Settings.Security - .getPattern(getActivity()); - if (currentPattern != null) { - if (mEncrypter != null) { - return pattern.equals(mEncrypter.decrypt( - getActivity(), currentPattern)); - } else - return Arrays.equals(currentPattern, - LockPatternUtils.patternToSha1(pattern) - .toCharArray()); - } - } - else if (ACTION_VERIFY_CAPTCHA.equals(fa.getIntent().getAction())) { - return pattern.equals(fa.getIntent() - .getParcelableArrayListExtra(EXTRA_PATTERN)); - } - return false; - } - - @Override - protected void onPostExecute(Boolean result) { - super.onPostExecute(result); - if (result) { - Toast.makeText(getActivity(), "unlocked", Toast.LENGTH_SHORT).show(); - finishWithResultOk(null); - }else { - mRetryCount++; - mIntentResult.putExtra(EXTRA_RETRY_COUNT, mRetryCount); - - if (mRetryCount >= mMaxRetries) - finishWithNegativeResult(RESULT_FAILED); - else { - mLockPatternView.setDisplayMode(DisplayMode.Wrong); - mTextInfo.setText(R.string.alp_42447968_msg_try_again); - mLockPatternView.postDelayed(mLockPatternViewReloader, - DELAY_TIME_TO_RELOAD_LOCK_PATTERN_VIEW); - } - } - } - - }.execute(); - } - - /** - * Checks and creates the pattern. - * - * @param pattern - * the current pattern of lock pattern view. - */ - private void doCheckAndCreatePattern(final List pattern) { - if (pattern.size() < mMinWiredDots) { - mLockPatternView.setDisplayMode(DisplayMode.Wrong); - mTextInfo.setText(getResources().getQuantityString( - R.plurals.alp_42447968_pmsg_connect_x_dots, mMinWiredDots, - mMinWiredDots)); - mLockPatternView.postDelayed(mLockPatternViewReloader, - DELAY_TIME_TO_RELOAD_LOCK_PATTERN_VIEW); - return; - } - - if (fa.getIntent().hasExtra(EXTRA_PATTERN)) { - /* - * Use a LoadingDialog because decrypting pattern might take time... - */ - new LoadingDialog(getActivity(), false) { - - @Override - protected Boolean doInBackground(Void... params) { - if (mEncrypter != null) - return pattern.equals(mEncrypter.decrypt( - getActivity(), fa.getIntent() - .getCharArrayExtra(EXTRA_PATTERN))); - else - return Arrays.equals( - fa.getIntent().getCharArrayExtra(EXTRA_PATTERN), - LockPatternUtils.patternToSha1(pattern) - .toCharArray()); - } - - @Override - protected void onPostExecute(Boolean result) { - super.onPostExecute(result); - - if (result) { - mTextInfo - .setText(R.string.alp_42447968_msg_your_new_unlock_pattern); - mBtnConfirm.setEnabled(true); - PassphraseWizardActivity.pattern = fa.getIntent() - .getCharArrayExtra(EXTRA_PATTERN); - } else { - mTextInfo - .setText(R.string.alp_42447968_msg_redraw_pattern_to_confirm); - mBtnConfirm.setEnabled(false); - mLockPatternView.setDisplayMode(DisplayMode.Wrong); - mLockPatternView.postDelayed(mLockPatternViewReloader, - DELAY_TIME_TO_RELOAD_LOCK_PATTERN_VIEW); - } - } - }.execute(); - } else { - /* - * Use a LoadingDialog because encrypting pattern might take time... - */ - new LoadingDialog(getActivity(), false) { - - @Override - protected char[] doInBackground(Void... params) { - return mEncrypter != null ? mEncrypter.encrypt( - getActivity(), pattern) - : LockPatternUtils.patternToSha1(pattern) - .toCharArray(); - } - - @Override - protected void onPostExecute(char[] result) { - super.onPostExecute(result); - - fa.getIntent().putExtra(EXTRA_PATTERN, result); - mTextInfo - .setText(R.string.alp_42447968_msg_pattern_recorded); - mBtnConfirm.setEnabled(true); - } - - }.execute(); - } - } - - /** - * Finishes activity with {@link android.app.Activity#RESULT_OK}. - * - * @param pattern - * the pattern, if getActivity() is in mode creating pattern. In any - * cases, it can be set to {@code null}. - */ - private void finishWithResultOk(char[] pattern) { - if (ACTION_CREATE_PATTERN.equals(getSelectedMethod())) - mIntentResult.putExtra(EXTRA_PATTERN, pattern); - else { - /* - * If the user was "logging in", minimum try count can not be zero. - */ - mIntentResult.putExtra(EXTRA_RETRY_COUNT, mRetryCount + 1); - } - - fa.setResult(fa.RESULT_OK, mIntentResult); - - /* - * ResultReceiver - */ - ResultReceiver receiver = fa.getIntent().getParcelableExtra( - EXTRA_RESULT_RECEIVER); - if (receiver != null) { - Bundle bundle = new Bundle(); - if (ACTION_CREATE_PATTERN.equals(getSelectedMethod())) - bundle.putCharArray(EXTRA_PATTERN, pattern); - else { - /* - * If the user was "logging in", minimum try count can not be - * zero. - */ - bundle.putInt(EXTRA_RETRY_COUNT, mRetryCount + 1); - } - receiver.send(fa.RESULT_OK, bundle); - } - - /* - * PendingIntent - */ - PendingIntent pi = fa.getIntent().getParcelableExtra( - EXTRA_PENDING_INTENT_OK); - if (pi != null) { - try { - pi.send(getActivity(), fa.RESULT_OK, mIntentResult); - } catch (Throwable t) { - t.printStackTrace(); - } - } - - fa.finish(); - } - - /** - * Finishes the activity with negative result ( - * {@link android.app.Activity#RESULT_CANCELED}, {@link #RESULT_FAILED} or - * {@link #RESULT_FORGOT_PATTERN}). - */ - private void finishWithNegativeResult(int resultCode) { - if (ACTION_COMPARE_PATTERN.equals(getSelectedMethod())) - mIntentResult.putExtra(EXTRA_RETRY_COUNT, mRetryCount); - - fa.setResult(resultCode, mIntentResult); - - /* - * ResultReceiver - */ - ResultReceiver receiver = fa.getIntent().getParcelableExtra( - EXTRA_RESULT_RECEIVER); - if (receiver != null) { - Bundle resultBundle = null; - if (ACTION_COMPARE_PATTERN.equals(getSelectedMethod())) { - resultBundle = new Bundle(); - resultBundle.putInt(EXTRA_RETRY_COUNT, mRetryCount); - } - receiver.send(resultCode, resultBundle); - } - - /* - * PendingIntent - */ - PendingIntent pi = fa.getIntent().getParcelableExtra( - EXTRA_PENDING_INTENT_CANCELLED); - if (pi != null) { - try { - pi.send(getActivity(), resultCode, mIntentResult); - } catch (Throwable t) { - t.printStackTrace(); - } - } - - fa.finish(); - } - - /* - * LISTENERS - */ - - private final LockPatternView.OnPatternListener mLockPatternViewListener = new LockPatternView.OnPatternListener() { - - @Override - public void onPatternStart() { - mLockPatternView.removeCallbacks(mLockPatternViewReloader); - mLockPatternView.setDisplayMode(DisplayMode.Correct); - - if (ACTION_CREATE_PATTERN.equals(getSelectedMethod())) { - mTextInfo - .setText(R.string.alp_42447968_msg_release_finger_when_done); - mBtnConfirm.setEnabled(false); - if (mBtnOkCmd == ButtonOkCommand.CONTINUE) - fa.getIntent().removeExtra(EXTRA_PATTERN); - } - else if (ACTION_COMPARE_PATTERN.equals(getSelectedMethod())) { - mTextInfo - .setText(R.string.alp_42447968_msg_draw_pattern_to_unlock); - } - else if (ACTION_VERIFY_CAPTCHA.equals(getSelectedMethod())) { - mTextInfo - .setText(R.string.alp_42447968_msg_redraw_pattern_to_confirm); - } - } - - @Override - public void onPatternDetected(List pattern) { - if (ACTION_CREATE_PATTERN.equals(getSelectedMethod())) { - doCheckAndCreatePattern(pattern); - } - else if (ACTION_COMPARE_PATTERN.equals(getSelectedMethod())) { - doComparePattern(pattern); - } - else if (ACTION_VERIFY_CAPTCHA.equals(getSelectedMethod())) { - if (!DisplayMode.Animate.equals(mLockPatternView - .getDisplayMode())) - doComparePattern(pattern); - } - } - - @Override - public void onPatternCleared() { - mLockPatternView.removeCallbacks(mLockPatternViewReloader); - - if (ACTION_CREATE_PATTERN.equals(getSelectedMethod())) { - mLockPatternView.setDisplayMode(DisplayMode.Correct); - mBtnConfirm.setEnabled(false); - if (mBtnOkCmd == ButtonOkCommand.CONTINUE) { - fa.getIntent().removeExtra(EXTRA_PATTERN); - mTextInfo - .setText(R.string.alp_42447968_msg_draw_an_unlock_pattern); - } else - mTextInfo - .setText(R.string.alp_42447968_msg_redraw_pattern_to_confirm); - } - else if (ACTION_COMPARE_PATTERN.equals(getSelectedMethod())) { - mLockPatternView.setDisplayMode(DisplayMode.Correct); - mTextInfo - .setText(R.string.alp_42447968_msg_draw_pattern_to_unlock); - } - else if (ACTION_VERIFY_CAPTCHA.equals(fa.getIntent().getAction())) { - mTextInfo - .setText(R.string.alp_42447968_msg_redraw_pattern_to_confirm); - List pattern = fa.getIntent().getParcelableArrayListExtra( - EXTRA_PATTERN); - mLockPatternView.setPattern(DisplayMode.Animate, pattern); - } - } - - @Override - public void onPatternCellAdded(List pattern) { - } - }; - - private final View.OnClickListener mBtnCancelOnClickListener = new View.OnClickListener() { - - @Override - public void onClick(View v) { - finishWithNegativeResult(fa.RESULT_CANCELED); - } - }; - - private final View.OnClickListener mBtnConfirmOnClickListener = new View.OnClickListener() { - - @Override - public void onClick(View v) { - if (ACTION_CREATE_PATTERN.equals(getSelectedMethod())) { - if (mBtnOkCmd == ButtonOkCommand.CONTINUE) { - mBtnOkCmd = ButtonOkCommand.DONE; - mLockPatternView.clearPattern(); - mTextInfo - .setText(R.string.alp_42447968_msg_redraw_pattern_to_confirm); - mBtnConfirm.setText(R.string.alp_42447968_cmd_confirm); - mBtnConfirm.setEnabled(false); - } else { - final char[] pattern = fa.getIntent().getCharArrayExtra( - EXTRA_PATTERN); - if (mAutoSave) - Settings.Security.setPattern(getActivity(), - pattern); - finishWithResultOk(pattern); - } - } - else if (ACTION_COMPARE_PATTERN.equals(getSelectedMethod())) { - /* - * We don't need to verify the extra. First, getActivity() button is only - * visible if there is getActivity() extra in the intent. Second, it is - * the responsibility of the caller to make sure the extra is - * good. - */ - PendingIntent pi; - try { - pi = fa.getIntent().getParcelableExtra( - EXTRA_PENDING_INTENT_FORGOT_PATTERN); - pi.send(); - } catch (Throwable t) { - t.printStackTrace(); - } - finishWithNegativeResult(RESULT_FORGOT_PATTERN); - } - } - }; - - /** - * getActivity() reloads the {@link #mLockPatternView} after a wrong pattern. - */ - private final Runnable mLockPatternViewReloader = new Runnable() { - - @Override - public void run() { - mLockPatternView.clearPattern(); - mLockPatternViewListener.onPatternCleared(); - } - }; - - /** - * Fragment constructor allowing to add a bundle with all necessary information to the fragment - * @param method contains information about which method to choose (set - * @return LockPatternFragment with bundle - */ - public static LockPatternFragmentOld newInstance(String method){ - LockPatternFragmentOld fragment = new LockPatternFragmentOld(); - Bundle args = new Bundle(); - args.putString("ACTION", method); - fragment.setArguments(args); - return fragment; - } - - /** - * Getter for the method string saved in fragment arguments - * @return String telling which method was selected - */ - public String getSelectedMethod () { - return getArguments().getString("ACTION"); - } -} -- cgit v1.2.3 From 7bddd5be1d76360f1112e780091ee6636591caae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Mon, 23 Feb 2015 00:28:26 +0100 Subject: Remove old pattern lib, add new pattern lib --- .../keychain/ui/PassphraseDialogActivity.java | 24 ++++++------ .../keychain/ui/PassphraseWizardActivity.java | 45 ++++++---------------- 2 files changed, 22 insertions(+), 47 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java index fd9324992..d5ca08936 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseDialogActivity.java @@ -41,8 +41,6 @@ import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; -import com.haibison.android.lockpattern.LockPatternActivity; - import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround; @@ -108,20 +106,20 @@ public class PassphraseDialogActivity extends FragmentActivity { case RESULT_CANCELED: // The user cancelled the task break; - case LockPatternActivity.RESULT_FAILED: - // The user failed to enter the pattern - break; - case LockPatternActivity.RESULT_FORGOT_PATTERN: - // The user forgot the pattern and invoked your recovery Activity. - break; +// case LockPatternActivity.RESULT_FAILED: +// // The user failed to enter the pattern +// break; +// case LockPatternActivity.RESULT_FORGOT_PATTERN: +// // The user forgot the pattern and invoked your recovery Activity. +// break; } /* * In any case, there's always a key EXTRA_RETRY_COUNT, which holds * the number of tries that the user did. */ - int retryCount = data.getIntExtra( - LockPatternActivity.EXTRA_RETRY_COUNT, 0); +// int retryCount = data.getIntExtra( +// LockPatternActivity.EXTRA_RETRY_COUNT, 0); break; } @@ -253,9 +251,9 @@ public class PassphraseDialogActivity extends FragmentActivity { if (keyType == CanonicalizedSecretKey.SecretKeyType.PATTERN) { // start pattern dialog and show progress circle here... - Intent patternActivity = new Intent(getActivity(), LockPatternActivity.class); - patternActivity.putExtra(LockPatternActivity.EXTRA_PATTERN, "123"); - startActivityForResult(patternActivity, REQUEST_CODE_ENTER_PATTERN); +// Intent patternActivity = new Intent(getActivity(), LockPatternActivity.class); +// patternActivity.putExtra(LockPatternActivity.EXTRA_PATTERN, "123"); +// startActivityForResult(patternActivity, REQUEST_CODE_ENTER_PATTERN); mInput.setVisibility(View.GONE); mProgress.setVisibility(View.VISIBLE); } else { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseWizardActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseWizardActivity.java index 872e888a8..2e838535d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseWizardActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/PassphraseWizardActivity.java @@ -43,10 +43,6 @@ import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; -import com.haibison.android.lockpattern.LockPatternFragment; -import com.haibison.android.lockpattern.LockPatternFragmentOld; -import com.haibison.android.lockpattern.widget.LockPatternView; - import org.sufficientlysecure.keychain.R; import java.io.IOException; @@ -56,7 +52,8 @@ import java.util.Arrays; import java.util.List; @TargetApi(Build.VERSION_CODES.HONEYCOMB) -public class PassphraseWizardActivity extends FragmentActivity implements LockPatternView.OnPatternListener { +public class PassphraseWizardActivity extends FragmentActivity { +//public class PassphraseWizardActivity extends FragmentActivity implements LockPatternView.OnPatternListener { //create or authenticate public String selectedAction; //for lockpattern @@ -117,10 +114,10 @@ public class PassphraseWizardActivity extends FragmentActivity implements LockPa getActionBar().setTitle(R.string.draw_lockpattern); } // LockPatternFragmentOld lpf = LockPatternFragmentOld.newInstance(selectedAction); - LockPatternFragment lpf = LockPatternFragment.newInstance("asd"); +// LockPatternFragment lpf = LockPatternFragment.newInstance("asd"); - FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); - transaction.replace(R.id.fragmentContainer, lpf).addToBackStack(null).commit(); +// FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); +// transaction.replace(R.id.fragmentContainer, lpf).addToBackStack(null).commit(); } public void cancel(View view) { @@ -205,9 +202,9 @@ public class PassphraseWizardActivity extends FragmentActivity implements LockPa writeNFC = false; //just write once Toast.makeText(this, R.string.nfc_write_succesful, Toast.LENGTH_SHORT).show(); //advance to lockpattern - LockPatternFragmentOld lpf = LockPatternFragmentOld.newInstance(selectedAction); - FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); - transaction.replace(R.id.fragmentContainer, lpf).addToBackStack(null).commit(); +// LockPatternFragmentOld lpf = LockPatternFragmentOld.newInstance(selectedAction); +// FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); +// transaction.replace(R.id.fragmentContainer, lpf).addToBackStack(null).commit(); } } catch (IOException | FormatException e) { e.printStackTrace(); @@ -224,9 +221,9 @@ public class PassphraseWizardActivity extends FragmentActivity implements LockPa //passwort matches, go to next view Toast.makeText(this, R.string.passphrases_match + "!", Toast.LENGTH_SHORT).show(); - LockPatternFragmentOld lpf = LockPatternFragmentOld.newInstance(selectedAction); - FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); - transaction.replace(R.id.fragmentContainer, lpf).addToBackStack(null).commit(); +// LockPatternFragmentOld lpf = LockPatternFragmentOld.newInstance(selectedAction); +// FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); +// transaction.replace(R.id.fragmentContainer, lpf).addToBackStack(null).commit(); readNFC = false; //just once } else { //passwort doesnt match @@ -352,26 +349,6 @@ public class PassphraseWizardActivity extends FragmentActivity implements LockPa adapter.disableForegroundDispatch(this); } - @Override - public void onPatternStart() { - - } - - @Override - public void onPatternCleared() { - - } - - @Override - public void onPatternCellAdded(List pattern) { - - } - - @Override - public void onPatternDetected(List pattern) { - - } - public static class SelectMethods extends Fragment { // private OnFragmentInteractionListener mListener; -- cgit v1.2.3 From 4c7622e257288f75ec02b4182f2665970987f556 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Mon, 23 Feb 2015 00:30:02 +0100 Subject: Remove unused FixedDrawerLayout --- .../support/v4/widget/FixedDrawerLayout.java | 49 ---------------------- 1 file changed, 49 deletions(-) delete mode 100644 OpenKeychain/src/main/java/android/support/v4/widget/FixedDrawerLayout.java (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/android/support/v4/widget/FixedDrawerLayout.java b/OpenKeychain/src/main/java/android/support/v4/widget/FixedDrawerLayout.java deleted file mode 100644 index 6924e0b06..000000000 --- a/OpenKeychain/src/main/java/android/support/v4/widget/FixedDrawerLayout.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2014 Dominik Schürmann - * - * 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 - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.support.v4.widget; - -import android.content.Context; -import android.util.AttributeSet; -import android.view.Gravity; -import android.view.View; - -/** - * Fix for NullPointerException at android.support.v4.widget.DrawerLayout.isContentView(DrawerLayout.java:840) - *

- * http://stackoverflow.com/a/18107942 - */ -public class FixedDrawerLayout extends DrawerLayout { - public FixedDrawerLayout(Context context) { - super(context); - } - - public FixedDrawerLayout(Context context, AttributeSet attrs) { - super(context, attrs); - } - - public FixedDrawerLayout(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - } - - @Override - boolean isContentView(View child) { - if (child == null) { - return false; - } - return ((LayoutParams) child.getLayoutParams()).gravity == Gravity.NO_GRAVITY; - } -} -- cgit v1.2.3 From dd3af50956ec80502f9f14e91cffbd271cc232fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Mon, 23 Feb 2015 10:36:39 +0100 Subject: Uncluttering App Settings: Move advanced info in dialog --- .../keychain/remote/ui/AppSettingsActivity.java | 48 +++++++++------ .../dialog/AdvancedAppSettingsDialogFragment.java | 72 ++++++++++++++++++++++ 2 files changed, 102 insertions(+), 18 deletions(-) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AdvancedAppSettingsDialogFragment.java (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java index c6b8b186c..407480c98 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppSettingsActivity.java @@ -40,7 +40,10 @@ import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.remote.AppSettings; +import org.sufficientlysecure.keychain.service.SaveKeyringParcel; import org.sufficientlysecure.keychain.ui.BaseActivity; +import org.sufficientlysecure.keychain.ui.dialog.AddSubkeyDialogFragment; +import org.sufficientlysecure.keychain.ui.dialog.AdvancedAppSettingsDialogFragment; import org.sufficientlysecure.keychain.util.Log; import java.security.MessageDigest; @@ -130,16 +133,40 @@ public class AppSettingsActivity extends BaseActivity { @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { - case R.id.menu_api_settings_revoke: + case R.id.menu_api_save: { + save(); + return true; + } + case R.id.menu_api_settings_revoke: { revokeAccess(); return true; - case R.id.menu_api_save: - save(); + } + case R.id.menu_api_settings_advanced: { + showAdvancedInfo(); return true; + } } return super.onOptionsItemSelected(item); } + private void showAdvancedInfo() { + String signature = null; + // advanced info: package signature SHA-256 + try { + MessageDigest md = MessageDigest.getInstance("SHA-256"); + md.update(mAppSettings.getPackageSignature()); + byte[] digest = md.digest(); + signature = new String(Hex.encode(digest)); + } catch (NoSuchAlgorithmException e) { + Log.e(Constants.TAG, "Should not happen!", e); + } + + AdvancedAppSettingsDialogFragment dialogFragment = + AdvancedAppSettingsDialogFragment.newInstance(mAppSettings.getPackageName(), signature); + + dialogFragment.show(getSupportFragmentManager(), "advancedDialog"); + } + private void startApp() { Intent i; PackageManager manager = getPackageManager(); @@ -175,21 +202,6 @@ public class AppSettingsActivity extends BaseActivity { mAppNameView.setText(appName); mAppIconView.setImageDrawable(appIcon); - // advanced info: package name - mPackageName.setText(mAppSettings.getPackageName()); - - // advanced info: package signature SHA-256 - try { - MessageDigest md = MessageDigest.getInstance("SHA-256"); - md.update(mAppSettings.getPackageSignature()); - byte[] digest = md.digest(); - String signature = new String(Hex.encode(digest)); - - mPackageSignature.setText(signature); - } catch (NoSuchAlgorithmException e) { - Log.e(Constants.TAG, "Should not happen!", e); - } - Uri accountsUri = appUri.buildUpon().appendPath(KeychainContract.PATH_ACCOUNTS).build(); Log.d(Constants.TAG, "accountsUri: " + accountsUri); Uri allowedKeysUri = appUri.buildUpon().appendPath(KeychainContract.PATH_ALLOWED_KEYS).build(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AdvancedAppSettingsDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AdvancedAppSettingsDialogFragment.java new file mode 100644 index 000000000..d2fa37cf7 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/AdvancedAppSettingsDialogFragment.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2015 Dominik Schürmann + * + * 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 . + */ + +package org.sufficientlysecure.keychain.ui.dialog; + +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 AdvancedAppSettingsDialogFragment extends DialogFragment { + private static final String ARG_PACKAGE_NAME = "package_name"; + private static final String ARG_SIGNATURE = "signature"; + + /** + * Creates new instance of this fragment + */ + public static AdvancedAppSettingsDialogFragment newInstance(String packageName, String digest) { + AdvancedAppSettingsDialogFragment frag = new AdvancedAppSettingsDialogFragment(); + Bundle args = new Bundle(); + args.putString(ARG_PACKAGE_NAME, packageName); + args.putString(ARG_SIGNATURE, digest); + + frag.setArguments(args); + return frag; + } + + /** + * Creates dialog + */ + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + final FragmentActivity activity = getActivity(); + + CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(activity); + + alert.setTitle(R.string.api_settings_advanced); + alert.setCancelable(true); + + alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + dismiss(); + } + }); + + String packageName = getArguments().getString(ARG_PACKAGE_NAME); + String signature = getArguments().getString(ARG_SIGNATURE); + + alert.setMessage(getString(R.string.api_settings_package_name) + ": " + packageName + "\n\n" + + getString(R.string.api_settings_package_signature) + ": " + signature); + + return alert.show(); + } +} -- cgit v1.2.3 From 2064d81aef27492e5f9f13a14375fc505bf105ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Mon, 23 Feb 2015 21:52:04 +0100 Subject: Refactor AppsListFragment --- .../keychain/remote/ui/AppsListFragment.java | 278 +++++++++++---------- 1 file changed, 142 insertions(+), 136 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppsListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppsListFragment.java index 976ce20d6..506b2da7f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppsListFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppsListFragment.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013-2014 Dominik Schürmann + * Copyright (C) 2013-2015 Dominik Schürmann * * 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 @@ -50,8 +50,7 @@ import org.sufficientlysecure.keychain.util.Log; public class AppsListFragment extends ListFragment implements LoaderManager.LoaderCallbacks { - // This is the Adapter being used to display the list's data. - RegisteredAppsAdapter mAdapter; + AppsAdapter mAdapter; @Override public void onActivityCreated(Bundle savedInstanceState) { @@ -66,7 +65,7 @@ public class AppsListFragment extends ListFragment implements if (installed) { if (registered) { - // edit app settings + // Edit app settings Intent intent = new Intent(getActivity(), AppSettingsActivity.class); intent.setData(KeychainContract.ApiApps.buildByPackageNameUri(selectedPackageName)); startActivity(intent); @@ -75,9 +74,10 @@ public class AppsListFragment extends ListFragment implements PackageManager manager = getActivity().getPackageManager(); try { i = manager.getLaunchIntentForPackage(selectedPackageName); - if (i == null) + if (i == null) { throw new PackageManager.NameNotFoundException(); - // start like the Android launcher would do + } + // Start like the Android launcher would do i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); i.addCategory(Intent.CATEGORY_LAUNCHER); startActivity(i); @@ -91,30 +91,32 @@ public class AppsListFragment extends ListFragment implements Uri.parse("market://details?id=" + selectedPackageName))); } catch (ActivityNotFoundException anfe) { startActivity(new Intent(Intent.ACTION_VIEW, - Uri.parse("http://play.google.com/store/apps/details?id=" + selectedPackageName))); + Uri.parse("https://play.google.com/store/apps/details?id=" + selectedPackageName))); } } } }); - // Give some text to display if there is no data. In a real - // application this would come from a resource. - setEmptyText(getString(R.string.api_no_apps)); + // NOTE: No setEmptyText(), we always have the default entries // We have a menu item to show in action bar. setHasOptionsMenu(true); // Create an empty adapter we will use to display the loaded data. - mAdapter = new RegisteredAppsAdapter(getActivity(), null, 0); + mAdapter = new AppsAdapter(getActivity(), null, 0); setListAdapter(mAdapter); - // Loader is started in onResume! + // NOTE: Loader is started in onResume! } @Override public void onResume() { super.onResume(); - // after coming back from Google Play -> reload + + // Start out with a progress indicator. + setListShown(false); + + // After coming back from Google Play -> reload getLoaderManager().restartLoader(0, null, this); } @@ -123,7 +125,6 @@ public class AppsListFragment extends ListFragment implements private static final String TEMP_COLUMN_REGISTERED = "REGISTERED"; private static final String TEMP_COLUMN_ICON_RES_ID = "ICON_RES_ID"; - // These are the Contacts rows that we will retrieve. static final String[] PROJECTION = new String[]{ ApiApps._ID, // 0 ApiApps.PACKAGE_NAME, // 1 @@ -149,106 +150,17 @@ public class AppsListFragment extends ListFragment implements // 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, + return new AppsLoader(getActivity(), baseUri, PROJECTION, null, null, ApiApps.PACKAGE_NAME + " COLLATE LOCALIZED ASC"); } public void onLoadFinished(Loader loader, Cursor data) { - MatrixCursor availableAppsCursor = new MatrixCursor(new String[]{ - ApiApps._ID, - ApiApps.PACKAGE_NAME, - TEMP_COLUMN_NAME, - TEMP_COLUMN_INSTALLED, - TEMP_COLUMN_REGISTERED, - TEMP_COLUMN_ICON_RES_ID - }); - // NOTE: SORT ascending by package name, this is REQUIRED for CursorJoiner! - // Drawables taken from projects res/drawables-xxhdpi/ic_launcher.png - availableAppsCursor.addRow(new Object[]{1, "com.fsck.k9", "K-9 Mail", 0, 0, R.drawable.apps_k9}); - availableAppsCursor.addRow(new Object[]{1, "com.zeapo.pwdstore", "Password Store", 0, 0, R.drawable.apps_password_store}); - availableAppsCursor.addRow(new Object[]{1, "eu.siacs.conversations", "Conversations (Instant Messaging)", 0, 0, R.drawable.apps_conversations}); - - MatrixCursor mergedCursor = new MatrixCursor(new String[]{ - ApiApps._ID, - ApiApps.PACKAGE_NAME, - TEMP_COLUMN_NAME, - TEMP_COLUMN_INSTALLED, - TEMP_COLUMN_REGISTERED, - TEMP_COLUMN_ICON_RES_ID - }); - - CursorJoiner joiner = new CursorJoiner( - availableAppsCursor, - new String[]{ApiApps.PACKAGE_NAME}, - data, - new String[]{ApiApps.PACKAGE_NAME}); - for (CursorJoiner.Result joinerResult : joiner) { - switch (joinerResult) { - case LEFT: { - // handle case where a row in availableAppsCursor is unique - String packageName = availableAppsCursor.getString(INDEX_PACKAGE_NAME); - - mergedCursor.addRow(new Object[]{ - 1, // no need for unique _ID - packageName, - availableAppsCursor.getString(INDEX_NAME), - isInstalled(packageName), - 0, - availableAppsCursor.getInt(INDEX_ICON_RES_ID) - }); - break; - } - case RIGHT: { - // handle case where a row in data is unique - String packageName = data.getString(INDEX_PACKAGE_NAME); - - mergedCursor.addRow(new Object[]{ - 1, // no need for unique _ID - packageName, - null, - isInstalled(packageName), - 1, // registered! - R.drawable.ic_launcher // icon is retrieved later - }); - break; - } - case BOTH: { - // handle case where a row with the same key is in both cursors - String packageName = data.getString(INDEX_PACKAGE_NAME); - - String name; - if (isInstalled(packageName) == 1) { - name = data.getString(INDEX_NAME); - } else { - // if not installed take name from available apps list - name = availableAppsCursor.getString(INDEX_NAME); - } - - mergedCursor.addRow(new Object[]{ - 1, // no need for unique _ID - packageName, - name, - isInstalled(packageName), - 1, // registered! - R.drawable.ic_launcher // icon is retrieved later - }); - break; - } - } - } - // Swap the new cursor in. (The framework will take care of closing the // old cursor once we return.) - mAdapter.swapCursor(mergedCursor); - } + mAdapter.swapCursor(data); - private int isInstalled(String packageName) { - try { - getActivity().getPackageManager().getApplicationInfo(packageName, 0); - return 1; - } catch (final PackageManager.NameNotFoundException e) { - return 0; - } + // The list should now be shown. + setListShown(true); } public void onLoaderReset(Loader loader) { @@ -258,12 +170,127 @@ public class AppsListFragment extends ListFragment implements mAdapter.swapCursor(null); } - private class RegisteredAppsAdapter extends CursorAdapter { + /** + * Besides the queried cursor with all registered apps, this loader also returns non-installed + * proposed apps using a MatrixCursor. + */ + private static class AppsLoader extends CursorLoader { + + public AppsLoader(Context context) { + super(context); + } + + public AppsLoader(Context context, Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { + super(context, uri, projection, selection, selectionArgs, sortOrder); + } + + @Override + public Cursor loadInBackground() { + // Load registered apps from content provider + Cursor data = super.loadInBackground(); + + MatrixCursor availableAppsCursor = new MatrixCursor(new String[]{ + ApiApps._ID, + ApiApps.PACKAGE_NAME, + TEMP_COLUMN_NAME, + TEMP_COLUMN_INSTALLED, + TEMP_COLUMN_REGISTERED, + TEMP_COLUMN_ICON_RES_ID + }); + // NOTE: SORT ascending by package name, this is REQUIRED for CursorJoiner! + // Drawables taken from projects res/drawables-xxhdpi/ic_launcher.png + availableAppsCursor.addRow(new Object[]{1, "com.fsck.k9", "K-9 Mail", 0, 0, R.drawable.apps_k9}); + availableAppsCursor.addRow(new Object[]{1, "com.zeapo.pwdstore", "Password Store", 0, 0, R.drawable.apps_password_store}); + availableAppsCursor.addRow(new Object[]{1, "eu.siacs.conversations", "Conversations (Instant Messaging)", 0, 0, R.drawable.apps_conversations}); + + MatrixCursor mergedCursor = new MatrixCursor(new String[]{ + ApiApps._ID, + ApiApps.PACKAGE_NAME, + TEMP_COLUMN_NAME, + TEMP_COLUMN_INSTALLED, + TEMP_COLUMN_REGISTERED, + TEMP_COLUMN_ICON_RES_ID + }); + + CursorJoiner joiner = new CursorJoiner( + availableAppsCursor, + new String[]{ApiApps.PACKAGE_NAME}, + data, + new String[]{ApiApps.PACKAGE_NAME}); + for (CursorJoiner.Result joinerResult : joiner) { + switch (joinerResult) { + case LEFT: { + // handle case where a row in availableAppsCursor is unique + String packageName = availableAppsCursor.getString(INDEX_PACKAGE_NAME); + + mergedCursor.addRow(new Object[]{ + 1, // no need for unique _ID + packageName, + availableAppsCursor.getString(INDEX_NAME), + isInstalled(packageName), + 0, + availableAppsCursor.getInt(INDEX_ICON_RES_ID) + }); + break; + } + case RIGHT: { + // handle case where a row in data is unique + String packageName = data.getString(INDEX_PACKAGE_NAME); + + mergedCursor.addRow(new Object[]{ + 1, // no need for unique _ID + packageName, + null, + isInstalled(packageName), + 1, // registered! + R.drawable.ic_launcher // icon is retrieved later + }); + break; + } + case BOTH: { + // handle case where a row with the same key is in both cursors + String packageName = data.getString(INDEX_PACKAGE_NAME); + + String name; + if (isInstalled(packageName) == 1) { + name = data.getString(INDEX_NAME); + } else { + // if not installed take name from available apps list + name = availableAppsCursor.getString(INDEX_NAME); + } + + mergedCursor.addRow(new Object[]{ + 1, // no need for unique _ID + packageName, + name, + isInstalled(packageName), + 1, // registered! + R.drawable.ic_launcher // icon is retrieved later + }); + break; + } + } + } + + return mergedCursor; + } + + private int isInstalled(String packageName) { + try { + getContext().getPackageManager().getApplicationInfo(packageName, 0); + return 1; + } catch (final PackageManager.NameNotFoundException e) { + return 0; + } + } + } + + private class AppsAdapter extends CursorAdapter { private LayoutInflater mInflater; private PackageManager mPM; - public RegisteredAppsAdapter(Context context, Cursor c, int flags) { + public AppsAdapter(Context context, Cursor c, int flags) { super(context, c, flags); mInflater = LayoutInflater.from(context); @@ -273,44 +300,23 @@ public class AppsListFragment extends ListFragment implements /** * Similar to CursorAdapter.getItemId(). * Required to build Uris for api apps, which are not based on row ids - * - * @param position - * @return */ public String getItemPackageName(int position) { - if (mDataValid && mCursor != null) { - if (mCursor.moveToPosition(position)) { - return mCursor.getString(INDEX_PACKAGE_NAME); - } else { - return null; - } + if (mDataValid && mCursor != null && mCursor.moveToPosition(position)) { + return mCursor.getString(INDEX_PACKAGE_NAME); } else { return null; } } public boolean getItemIsInstalled(int position) { - if (mDataValid && mCursor != null) { - if (mCursor.moveToPosition(position)) { - return (mCursor.getInt(INDEX_INSTALLED) == 1); - } else { - return false; - } - } else { - return false; - } + return mDataValid && mCursor != null + && mCursor.moveToPosition(position) && (mCursor.getInt(INDEX_INSTALLED) == 1); } public boolean getItemIsRegistered(int position) { - if (mDataValid && mCursor != null) { - if (mCursor.moveToPosition(position)) { - return (mCursor.getInt(INDEX_REGISTERED) == 1); - } else { - return false; - } - } else { - return false; - } + return mDataValid && mCursor != null + && mCursor.moveToPosition(position) && (mCursor.getInt(INDEX_REGISTERED) == 1); } @Override -- cgit v1.2.3 From 29628e54ec70c0867fea99172745f6c678b66ec7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Mon, 23 Feb 2015 21:55:44 +0100 Subject: Refactor AppsListFragment --- .../keychain/remote/ui/AppsListFragment.java | 82 +++++++++++----------- 1 file changed, 41 insertions(+), 41 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppsListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppsListFragment.java index 506b2da7f..2deb33a67 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppsListFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/ui/AppsListFragment.java @@ -48,7 +48,7 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.ApiApps; import org.sufficientlysecure.keychain.util.Log; public class AppsListFragment extends ListFragment implements - LoaderManager.LoaderCallbacks { + LoaderManager.LoaderCallbacks, OnItemClickListener { AppsAdapter mAdapter; @@ -56,46 +56,7 @@ public class AppsListFragment extends ListFragment implements public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); - getListView().setOnItemClickListener(new OnItemClickListener() { - @Override - public void onItemClick(AdapterView adapterView, View view, int position, long id) { - String selectedPackageName = mAdapter.getItemPackageName(position); - boolean installed = mAdapter.getItemIsInstalled(position); - boolean registered = mAdapter.getItemIsRegistered(position); - - if (installed) { - if (registered) { - // Edit app settings - Intent intent = new Intent(getActivity(), AppSettingsActivity.class); - intent.setData(KeychainContract.ApiApps.buildByPackageNameUri(selectedPackageName)); - startActivity(intent); - } else { - Intent i; - PackageManager manager = getActivity().getPackageManager(); - try { - i = manager.getLaunchIntentForPackage(selectedPackageName); - if (i == null) { - throw new PackageManager.NameNotFoundException(); - } - // Start like the Android launcher would do - i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); - i.addCategory(Intent.CATEGORY_LAUNCHER); - startActivity(i); - } catch (PackageManager.NameNotFoundException e) { - Log.e(Constants.TAG, "startApp", e); - } - } - } else { - try { - startActivity(new Intent(Intent.ACTION_VIEW, - Uri.parse("market://details?id=" + selectedPackageName))); - } catch (ActivityNotFoundException anfe) { - startActivity(new Intent(Intent.ACTION_VIEW, - Uri.parse("https://play.google.com/store/apps/details?id=" + selectedPackageName))); - } - } - } - }); + getListView().setOnItemClickListener(this); // NOTE: No setEmptyText(), we always have the default entries @@ -120,6 +81,45 @@ public class AppsListFragment extends ListFragment implements getLoaderManager().restartLoader(0, null, this); } + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + String selectedPackageName = mAdapter.getItemPackageName(position); + boolean installed = mAdapter.getItemIsInstalled(position); + boolean registered = mAdapter.getItemIsRegistered(position); + + if (installed) { + if (registered) { + // Edit app settings + Intent intent = new Intent(getActivity(), AppSettingsActivity.class); + intent.setData(KeychainContract.ApiApps.buildByPackageNameUri(selectedPackageName)); + startActivity(intent); + } else { + Intent i; + PackageManager manager = getActivity().getPackageManager(); + try { + i = manager.getLaunchIntentForPackage(selectedPackageName); + if (i == null) { + throw new PackageManager.NameNotFoundException(); + } + // Start like the Android launcher would do + i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); + i.addCategory(Intent.CATEGORY_LAUNCHER); + startActivity(i); + } catch (PackageManager.NameNotFoundException e) { + Log.e(Constants.TAG, "startApp", e); + } + } + } else { + try { + startActivity(new Intent(Intent.ACTION_VIEW, + Uri.parse("market://details?id=" + selectedPackageName))); + } catch (ActivityNotFoundException anfe) { + startActivity(new Intent(Intent.ACTION_VIEW, + Uri.parse("https://play.google.com/store/apps/details?id=" + selectedPackageName))); + } + } + } + private static final String TEMP_COLUMN_NAME = "NAME"; private static final String TEMP_COLUMN_INSTALLED = "INSTALLED"; private static final String TEMP_COLUMN_REGISTERED = "REGISTERED"; -- cgit v1.2.3 From 52bcfd71adc1935ad81be7c0a9b2aae02000357c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Mon, 23 Feb 2015 23:03:45 +0100 Subject: New advanced key view --- .../keychain/ui/BaseActivity.java | 2 + .../keychain/ui/ViewKeyActivity.java | 10 +- .../keychain/ui/ViewKeyAdvActivity.java | 240 +++++++++++++ .../keychain/ui/ViewKeyAdvCertsFragment.java | 342 ++++++++++++++++++ .../keychain/ui/ViewKeyAdvKeysFragment.java | 125 +++++++ .../keychain/ui/ViewKeyAdvMainFragment.java | 350 +++++++++++++++++++ .../keychain/ui/ViewKeyAdvShareFragment.java | 387 +++++++++++++++++++++ .../keychain/ui/ViewKeyAdvancedActivity.java | 91 ----- .../keychain/ui/ViewKeyAdvancedFragment.java | 378 -------------------- .../keychain/ui/ViewKeyMainFragment.java | 350 ------------------- .../keychain/ui/ViewKeyShareFragment.java | 387 --------------------- 11 files changed, 1451 insertions(+), 1211 deletions(-) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvActivity.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvCertsFragment.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvKeysFragment.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvMainFragment.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvancedActivity.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvancedFragment.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyShareFragment.java (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BaseActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BaseActivity.java index 03bb2f733..e6c2542a2 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BaseActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/BaseActivity.java @@ -35,6 +35,7 @@ import org.sufficientlysecure.keychain.R; */ public abstract class BaseActivity extends ActionBarActivity { protected Toolbar mToolbar; + protected View mStatusBar; @Override protected void onCreate(Bundle savedInstanceState) { @@ -51,6 +52,7 @@ public abstract class BaseActivity extends ActionBarActivity { setSupportActionBar(mToolbar); getSupportActionBar().setDisplayHomeAsUpEnabled(true); } + mStatusBar = findViewById(R.id.status_bar); } protected void setActionBarIcon(int iconRes) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java index 575df01b7..f45a29a96 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java @@ -162,13 +162,13 @@ public class ViewKeyActivity extends BaseActivity implements mViewPager.setAdapter(mTabsAdapter); Bundle mainBundle = new Bundle(); - mainBundle.putParcelable(ViewKeyMainFragment.ARG_DATA_URI, dataUri); - mTabsAdapter.addTab(ViewKeyMainFragment.class, + mainBundle.putParcelable(ViewKeyAdvMainFragment.ARG_DATA_URI, dataUri); + mTabsAdapter.addTab(ViewKeyAdvMainFragment.class, mainBundle, getString(R.string.key_view_tab_main)); Bundle shareBundle = new Bundle(); - shareBundle.putParcelable(ViewKeyMainFragment.ARG_DATA_URI, dataUri); - mTabsAdapter.addTab(ViewKeyShareFragment.class, + shareBundle.putParcelable(ViewKeyAdvMainFragment.ARG_DATA_URI, dataUri); + mTabsAdapter.addTab(ViewKeyAdvShareFragment.class, shareBundle, getString(R.string.key_view_tab_share)); // update layout after operations @@ -202,7 +202,7 @@ public class ViewKeyActivity extends BaseActivity implements return true; } case R.id.menu_key_view_advanced: { - Intent advancedIntent = new Intent(this, ViewKeyAdvancedActivity.class); + Intent advancedIntent = new Intent(this, ViewKeyAdvActivity.class); advancedIntent.setData(mDataUri); startActivity(advancedIntent); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvActivity.java new file mode 100644 index 000000000..6a43845d6 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvActivity.java @@ -0,0 +1,240 @@ +/* + * Copyright (C) 2015 Dominik Schürmann + * + * 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 . + */ + +package org.sufficientlysecure.keychain.ui; + +import android.content.Intent; +import android.database.Cursor; +import android.net.Uri; +import android.os.Bundle; +import android.provider.ContactsContract; +import android.support.v4.app.LoaderManager; +import android.support.v4.content.CursorLoader; +import android.support.v4.content.Loader; +import android.support.v4.view.ViewPager; +import android.view.View; +import android.widget.Toast; + +import com.astuetz.PagerSlidingTabStrip; + +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.pgp.KeyRing; +import org.sufficientlysecure.keychain.provider.KeychainContract; +import org.sufficientlysecure.keychain.provider.ProviderHelper; +import org.sufficientlysecure.keychain.ui.adapter.PagerTabStripAdapter; +import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; +import org.sufficientlysecure.keychain.util.ContactHelper; +import org.sufficientlysecure.keychain.util.ExportHelper; +import org.sufficientlysecure.keychain.util.Log; + +import java.util.Date; + +public class ViewKeyAdvActivity extends BaseActivity implements + LoaderManager.LoaderCallbacks { + + ExportHelper mExportHelper; + ProviderHelper mProviderHelper; + + protected Uri mDataUri; + + public static final String EXTRA_SELECTED_TAB = "selected_tab"; + public static final int TAB_MAIN = 0; + public static final int TAB_SHARE = 1; + + // view + private ViewPager mViewPager; + private PagerSlidingTabStrip mSlidingTabLayout; + private PagerTabStripAdapter mTabsAdapter; + + private static final int LOADER_ID_UNIFIED = 0; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setFullScreenDialogClose(new View.OnClickListener() { + @Override + public void onClick(View v) { + finish(); + } + }); + + mExportHelper = new ExportHelper(this); + mProviderHelper = new ProviderHelper(this); + + mViewPager = (ViewPager) findViewById(R.id.view_key_pager); + mSlidingTabLayout = (PagerSlidingTabStrip) findViewById(R.id.view_key_sliding_tab_layout); + + int switchToTab = TAB_MAIN; + Intent intent = getIntent(); + if (intent.getExtras() != null && intent.getExtras().containsKey(EXTRA_SELECTED_TAB)) { + switchToTab = intent.getExtras().getInt(EXTRA_SELECTED_TAB); + } + + mDataUri = getIntent().getData(); + if (mDataUri == null) { + Log.e(Constants.TAG, "Data missing. Should be uri of key!"); + finish(); + return; + } + if (mDataUri.getHost().equals(ContactsContract.AUTHORITY)) { + mDataUri = ContactHelper.dataUriFromContactUri(this, mDataUri); + if (mDataUri == null) { + Log.e(Constants.TAG, "Contact Data missing. Should be uri of key!"); + Toast.makeText(this, R.string.error_contacts_key_id_missing, Toast.LENGTH_LONG).show(); + finish(); + return; + } + } + + Log.i(Constants.TAG, "mDataUri: " + mDataUri.toString()); + + // Prepare the loaders. Either re-connect with an existing ones, + // or start new ones. + getSupportLoaderManager().initLoader(LOADER_ID_UNIFIED, null, this); + + initTabs(mDataUri); + + // switch to tab selected by extra + mViewPager.setCurrentItem(switchToTab); + } + + @Override + protected void initLayout() { + setContentView(R.layout.view_key_adv_activity); + } + + private void initTabs(Uri dataUri) { + mTabsAdapter = new PagerTabStripAdapter(this); + mViewPager.setAdapter(mTabsAdapter); + + Bundle mainBundle = new Bundle(); + mainBundle.putParcelable(ViewKeyAdvMainFragment.ARG_DATA_URI, dataUri); + mTabsAdapter.addTab(ViewKeyAdvMainFragment.class, + mainBundle, getString(R.string.key_view_tab_main)); + + Bundle shareBundle = new Bundle(); + shareBundle.putParcelable(ViewKeyAdvMainFragment.ARG_DATA_URI, dataUri); + mTabsAdapter.addTab(ViewKeyAdvShareFragment.class, + shareBundle, getString(R.string.key_view_tab_share)); + + Bundle keysBundle = new Bundle(); + keysBundle.putParcelable(ViewKeyAdvKeysFragment.ARG_DATA_URI, dataUri); + mTabsAdapter.addTab(ViewKeyAdvKeysFragment.class, + keysBundle, getString(R.string.key_view_tab_keys)); + + Bundle certsBundle = new Bundle(); + certsBundle.putParcelable(ViewKeyAdvCertsFragment.ARG_DATA_URI, dataUri); + mTabsAdapter.addTab(ViewKeyAdvCertsFragment.class, + certsBundle, getString(R.string.key_view_tab_certs)); + + // update layout after operations + mSlidingTabLayout.setViewPager(mViewPager); + } + + // These are the rows that we will retrieve. + static final String[] PROJECTION = new String[]{ + KeychainContract.KeyRings._ID, + KeychainContract.KeyRings.MASTER_KEY_ID, + KeychainContract.KeyRings.USER_ID, + KeychainContract.KeyRings.IS_REVOKED, + KeychainContract.KeyRings.EXPIRY, + KeychainContract.KeyRings.VERIFIED, + KeychainContract.KeyRings.HAS_ANY_SECRET + }; + + static final int INDEX_MASTER_KEY_ID = 1; + static final int INDEX_USER_ID = 2; + static final int INDEX_IS_REVOKED = 3; + static final int INDEX_EXPIRY = 4; + static final int INDEX_VERIFIED = 5; + static final int INDEX_HAS_ANY_SECRET = 6; + + @Override + public Loader onCreateLoader(int id, Bundle args) { + switch (id) { + case LOADER_ID_UNIFIED: { + Uri baseUri = KeychainContract.KeyRings.buildUnifiedKeyRingUri(mDataUri); + return new CursorLoader(this, baseUri, PROJECTION, null, null, null); + } + + default: + return null; + } + } + + @Override + public void onLoadFinished(Loader loader, Cursor data) { + /* TODO better error handling? May cause problems when a key is deleted, + * because the notification triggers faster than the activity closes. + */ + // Avoid NullPointerExceptions... + if (data.getCount() == 0) { + return; + } + // Swap the new cursor in. (The framework will take care of closing the + // old cursor once we return.) + switch (loader.getId()) { + case LOADER_ID_UNIFIED: { + if (data.moveToFirst()) { + // get name, email, and comment from USER_ID + String[] mainUserId = KeyRing.splitUserId(data.getString(INDEX_USER_ID)); + if (mainUserId[0] != null) { + setTitle(mainUserId[0]); + } else { + setTitle(R.string.user_id_no_name); + } + + // get key id from MASTER_KEY_ID + long masterKeyId = data.getLong(INDEX_MASTER_KEY_ID); + getSupportActionBar().setSubtitle(KeyFormattingUtils.beautifyKeyIdWithPrefix(this, masterKeyId)); + + boolean isSecret = data.getInt(INDEX_HAS_ANY_SECRET) != 0; + boolean isRevoked = data.getInt(INDEX_IS_REVOKED) > 0; + boolean isExpired = !data.isNull(INDEX_EXPIRY) + && new Date(data.getLong(INDEX_EXPIRY) * 1000).before(new Date()); + boolean isVerified = data.getInt(INDEX_VERIFIED) > 0; + + // Note: order is important + int color; + if (isRevoked || isExpired) { + color = getResources().getColor(R.color.android_red_light); + } else if (isSecret) { + color = getResources().getColor(R.color.primary); + } else { + if (isVerified) { + color = getResources().getColor(R.color.primary); + } else { + color = getResources().getColor(R.color.android_orange_light); + } + } + mToolbar.setBackgroundColor(color); + mStatusBar.setBackgroundColor(color); + mSlidingTabLayout.setBackgroundColor(color); + + break; + } + } + } + } + + @Override + public void onLoaderReset(Loader loader) { + + } +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvCertsFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvCertsFragment.java new file mode 100644 index 000000000..83daa541d --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvCertsFragment.java @@ -0,0 +1,342 @@ +/* + * Copyright (C) 2014-2015 Dominik Schürmann + * + * 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 . + */ + +package org.sufficientlysecure.keychain.ui; + +import android.content.Context; +import android.content.Intent; +import android.database.Cursor; +import android.net.Uri; +import android.os.Bundle; +import android.support.v4.app.LoaderManager; +import android.support.v4.content.CursorLoader; +import android.support.v4.content.Loader; +import android.support.v4.widget.CursorAdapter; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.TextView; + +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.pgp.KeyRing; +import org.sufficientlysecure.keychain.pgp.WrappedSignature; +import org.sufficientlysecure.keychain.provider.KeychainContract; +import org.sufficientlysecure.keychain.provider.KeychainDatabase; +import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; +import org.sufficientlysecure.keychain.util.Log; + +import se.emilsjolander.stickylistheaders.StickyListHeadersAdapter; +import se.emilsjolander.stickylistheaders.StickyListHeadersListView; + + +public class ViewKeyAdvCertsFragment extends LoaderFragment implements + LoaderManager.LoaderCallbacks, AdapterView.OnItemClickListener { + + public static final String ARG_DATA_URI = "data_uri"; + + private StickyListHeadersListView mStickyList; + private CertListAdapter mCertsAdapter; + + private Uri mDataUriCerts; + + // These are the rows that we will retrieve. + static final String[] CERTS_PROJECTION = new String[]{ + KeychainContract.Certs._ID, + KeychainContract.Certs.MASTER_KEY_ID, + KeychainContract.Certs.VERIFIED, + KeychainContract.Certs.TYPE, + KeychainContract.Certs.RANK, + KeychainContract.Certs.KEY_ID_CERTIFIER, + KeychainContract.Certs.USER_ID, + KeychainContract.Certs.SIGNER_UID + }; + + // sort by our user id, + static final String CERTS_SORT_ORDER = + KeychainDatabase.Tables.CERTS + "." + KeychainContract.Certs.RANK + " ASC, " + + KeychainContract.Certs.VERIFIED + " DESC, " + + KeychainDatabase.Tables.CERTS + "." + KeychainContract.Certs.TYPE + " DESC, " + + KeychainContract.Certs.SIGNER_UID + " ASC"; + + /** + * Creates new instance of this fragment + */ + public static ViewKeyAdvCertsFragment newInstance(Uri dataUri) { + ViewKeyAdvCertsFragment frag = new ViewKeyAdvCertsFragment(); + + Bundle args = new Bundle(); + args.putParcelable(ARG_DATA_URI, dataUri); + + frag.setArguments(args); + return frag; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup superContainer, Bundle savedInstanceState) { + View root = super.onCreateView(inflater, superContainer, savedInstanceState); + View view = inflater.inflate(R.layout.view_key_adv_certs_fragment, getContainer()); + + mStickyList = (StickyListHeadersListView) view.findViewById(R.id.certs_list); + + return root; + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + Uri dataUri = getArguments().getParcelable(ARG_DATA_URI); + if (dataUri == null) { + Log.e(Constants.TAG, "Data missing. Should be Uri of key!"); + getActivity().finish(); + return; + } + + loadData(dataUri); + } + + private void loadData(Uri dataUri) { + mDataUriCerts = KeychainContract.Certs.buildCertsUri(dataUri); + + mStickyList.setAreHeadersSticky(true); + mStickyList.setDrawingListUnderStickyHeader(false); + mStickyList.setOnItemClickListener(this); + + mStickyList.setEmptyView(getActivity().findViewById(R.id.empty)); + + // Create an empty adapter we will use to display the loaded data. + mCertsAdapter = new CertListAdapter(getActivity(), null); + mStickyList.setAdapter(mCertsAdapter); + + // Prepare the loaders. Either re-connect with an existing ones, + // or start new ones. + getLoaderManager().initLoader(0, null, this); + } + + public Loader onCreateLoader(int id, Bundle args) { + setContentShown(false); + + + // Now create and return a CursorLoader that will take care of + // creating a Cursor for the data being displayed. + return new CursorLoader(getActivity(), mDataUriCerts, + CERTS_PROJECTION, null, null, CERTS_SORT_ORDER); + + } + + public void onLoadFinished(Loader loader, Cursor data) { + // Avoid NullPointerExceptions, if we get an empty result set. + if (data.getCount() == 0) { + return; + } + + // Swap the new cursor in. (The framework will take care of closing the + // old cursor once we return.) + mCertsAdapter.swapCursor(data); + mStickyList.setAdapter(mCertsAdapter); + + // TODO: maybe show not before both are loaded! + setContentShown(true); + } + + /** + * This is called when the last Cursor provided to onLoadFinished() above is about to be closed. + * We need to make sure we are no longer using it. + */ + public void onLoaderReset(Loader loader) { + mCertsAdapter.swapCursor(null); + } + + /** + * On click on item, start key view activity + */ + @Override + public void onItemClick(AdapterView adapterView, View view, int position, long id) { + if (view.getTag(R.id.tag_mki) != null) { + long masterKeyId = (Long) view.getTag(R.id.tag_mki); + long rank = (Long) view.getTag(R.id.tag_rank); + long certifierId = (Long) view.getTag(R.id.tag_certifierId); + + Intent viewIntent = new Intent(getActivity(), ViewCertActivity.class); + viewIntent.setData(KeychainContract.Certs.buildCertsSpecificUri( + masterKeyId, rank, certifierId)); + startActivity(viewIntent); + } + } + + + /** + * Implements StickyListHeadersAdapter from library + */ + private class CertListAdapter extends CursorAdapter implements StickyListHeadersAdapter { + private LayoutInflater mInflater; + private int mIndexMasterKeyId, mIndexUserId, mIndexRank; + private int mIndexSignerKeyId, mIndexSignerUserId; + private int mIndexVerified, mIndexType; + + public CertListAdapter(Context context, Cursor c) { + super(context, c, 0); + + mInflater = LayoutInflater.from(context); + initIndex(c); + } + + @Override + public Cursor swapCursor(Cursor newCursor) { + initIndex(newCursor); + + return super.swapCursor(newCursor); + } + + /** + * Get column indexes for performance reasons just once in constructor and swapCursor. For a + * performance comparison see http://stackoverflow.com/a/17999582 + * + * @param cursor + */ + private void initIndex(Cursor cursor) { + if (cursor != null) { + mIndexMasterKeyId = cursor.getColumnIndexOrThrow(KeychainContract.Certs.MASTER_KEY_ID); + mIndexUserId = cursor.getColumnIndexOrThrow(KeychainContract.Certs.USER_ID); + mIndexRank = cursor.getColumnIndexOrThrow(KeychainContract.Certs.RANK); + mIndexType = cursor.getColumnIndexOrThrow(KeychainContract.Certs.TYPE); + mIndexVerified = cursor.getColumnIndexOrThrow(KeychainContract.Certs.VERIFIED); + mIndexSignerKeyId = cursor.getColumnIndexOrThrow(KeychainContract.Certs.KEY_ID_CERTIFIER); + mIndexSignerUserId = cursor.getColumnIndexOrThrow(KeychainContract.Certs.SIGNER_UID); + } + } + + /** + * Bind cursor data to the item list view + *

+ * NOTE: CursorAdapter already implements the ViewHolder pattern in its getView() method. + * Thus no ViewHolder is required here. + */ + @Override + public void bindView(View view, Context context, Cursor cursor) { + + // set name and stuff, common to both key types + TextView wSignerKeyId = (TextView) view.findViewById(R.id.signerKeyId); + TextView wSignerName = (TextView) view.findViewById(R.id.signerName); + TextView wSignStatus = (TextView) view.findViewById(R.id.signStatus); + + String signerKeyId = KeyFormattingUtils.beautifyKeyIdWithPrefix(getActivity(), cursor.getLong(mIndexSignerKeyId)); + String[] userId = KeyRing.splitUserId(cursor.getString(mIndexSignerUserId)); + if (userId[0] != null) { + wSignerName.setText(userId[0]); + } else { + wSignerName.setText(R.string.user_id_no_name); + } + wSignerKeyId.setText(signerKeyId); + + switch (cursor.getInt(mIndexType)) { + case WrappedSignature.DEFAULT_CERTIFICATION: // 0x10 + wSignStatus.setText(R.string.cert_default); + break; + case WrappedSignature.NO_CERTIFICATION: // 0x11 + wSignStatus.setText(R.string.cert_none); + break; + case WrappedSignature.CASUAL_CERTIFICATION: // 0x12 + wSignStatus.setText(R.string.cert_casual); + break; + case WrappedSignature.POSITIVE_CERTIFICATION: // 0x13 + wSignStatus.setText(R.string.cert_positive); + break; + case WrappedSignature.CERTIFICATION_REVOCATION: // 0x30 + wSignStatus.setText(R.string.cert_revoke); + break; + } + + + view.setTag(R.id.tag_mki, cursor.getLong(mIndexMasterKeyId)); + view.setTag(R.id.tag_rank, cursor.getLong(mIndexRank)); + view.setTag(R.id.tag_certifierId, cursor.getLong(mIndexSignerKeyId)); + } + + @Override + public View newView(Context context, Cursor cursor, ViewGroup parent) { + return mInflater.inflate(R.layout.view_key_certs_item, parent, false); + } + + /** + * Creates a new header view and binds the section headers to it. It uses the ViewHolder + * pattern. Most functionality is similar to getView() from Android's CursorAdapter. + *

+ * NOTE: The variables mDataValid and mCursor are available due to the super class + * CursorAdapter. + */ + @Override + public View getHeaderView(int position, View convertView, ViewGroup parent) { + HeaderViewHolder holder; + if (convertView == null) { + holder = new HeaderViewHolder(); + convertView = mInflater.inflate(R.layout.view_key_certs_header, parent, false); + holder.text = (TextView) convertView.findViewById(R.id.stickylist_header_text); + holder.count = (TextView) convertView.findViewById(R.id.certs_num); + convertView.setTag(holder); + } else { + holder = (HeaderViewHolder) convertView.getTag(); + } + + if (!mDataValid) { + // no data available at this point + Log.d(Constants.TAG, "getHeaderView: No data available at this point!"); + return convertView; + } + + if (!mCursor.moveToPosition(position)) { + throw new IllegalStateException("couldn't move cursor to position " + position); + } + + // set header text as first char in user id + String userId = mCursor.getString(mIndexUserId); + holder.text.setText(userId); + holder.count.setVisibility(View.GONE); + return convertView; + } + + /** + * Header IDs should be static, position=1 should always return the same Id that is. + */ + @Override + public long getHeaderId(int position) { + if (!mDataValid) { + // no data available at this point + Log.d(Constants.TAG, "getHeaderView: No data available at this point!"); + return -1; + } + + if (!mCursor.moveToPosition(position)) { + throw new IllegalStateException("couldn't move cursor to position " + position); + } + + // otherwise, return the first character of the name as ID + return mCursor.getInt(mIndexRank); + + // sort by the first four characters (should be enough I guess?) + // return ByteBuffer.wrap(userId.getBytes()).asLongBuffer().get(0); + } + + class HeaderViewHolder { + TextView text; + TextView count; + } + + } +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvKeysFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvKeysFragment.java new file mode 100644 index 000000000..548e249b6 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvKeysFragment.java @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2014-2015 Dominik Schürmann + * + * 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 . + */ + +package org.sufficientlysecure.keychain.ui; + +import android.database.Cursor; +import android.net.Uri; +import android.os.Bundle; +import android.support.v4.app.LoaderManager; +import android.support.v4.content.CursorLoader; +import android.support.v4.content.Loader; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ListView; + +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.provider.KeychainContract; +import org.sufficientlysecure.keychain.ui.adapter.SubkeysAdapter; +import org.sufficientlysecure.keychain.util.Log; + +public class ViewKeyAdvKeysFragment extends LoaderFragment implements + LoaderManager.LoaderCallbacks { + + public static final String ARG_DATA_URI = "data_uri"; + + private ListView mSubkeysList; + private SubkeysAdapter mSubkeysAdapter; + + private Uri mDataUriSubkeys; + + /** + * Creates new instance of this fragment + */ + public static ViewKeyAdvKeysFragment newInstance(Uri dataUri) { + ViewKeyAdvKeysFragment frag = new ViewKeyAdvKeysFragment(); + + Bundle args = new Bundle(); + args.putParcelable(ARG_DATA_URI, dataUri); + + frag.setArguments(args); + return frag; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup superContainer, Bundle savedInstanceState) { + View root = super.onCreateView(inflater, superContainer, savedInstanceState); + View view = inflater.inflate(R.layout.view_key_adv_subkeys_fragment, getContainer()); + + mSubkeysList = (ListView) view.findViewById(R.id.keys); + + return root; + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + Uri dataUri = getArguments().getParcelable(ARG_DATA_URI); + if (dataUri == null) { + Log.e(Constants.TAG, "Data missing. Should be Uri of key!"); + getActivity().finish(); + return; + } + + loadData(dataUri); + } + + private void loadData(Uri dataUri) { + mDataUriSubkeys = KeychainContract.Keys.buildKeysUri(dataUri); + + // Create an empty adapter we will use to display the loaded data. + mSubkeysAdapter = new SubkeysAdapter(getActivity(), null, 0); + mSubkeysList.setAdapter(mSubkeysAdapter); + + // Prepare the loaders. Either re-connect with an existing ones, + // or start new ones. + getLoaderManager().initLoader(0, null, this); + } + + public Loader onCreateLoader(int id, Bundle args) { + setContentShown(false); + + return new CursorLoader(getActivity(), mDataUriSubkeys, + SubkeysAdapter.SUBKEYS_PROJECTION, null, null, null); + } + + public void onLoadFinished(Loader loader, Cursor data) { + // Avoid NullPointerExceptions, if we get an empty result set. + if (data.getCount() == 0) { + return; + } + + // Swap the new cursor in. (The framework will take care of closing the + // old cursor once we return.) + mSubkeysAdapter.swapCursor(data); + + // TODO: maybe show not before both are loaded! + setContentShown(true); + } + + /** + * This is called when the last Cursor provided to onLoadFinished() above is about to be closed. + * We need to make sure we are no longer using it. + */ + public void onLoaderReset(Loader loader) { + mSubkeysAdapter.swapCursor(null); + } + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvMainFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvMainFragment.java new file mode 100644 index 000000000..8bab5e3bf --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvMainFragment.java @@ -0,0 +1,350 @@ +/* + * Copyright (C) 2014 Dominik Schürmann + * Copyright (C) 2014 Vincent Breitmoser + * + * 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 . + */ + +package org.sufficientlysecure.keychain.ui; + +import android.content.Intent; +import android.database.Cursor; +import android.graphics.PorterDuff; +import android.net.Uri; +import android.os.Bundle; +import android.support.v4.app.LoaderManager; +import android.support.v4.content.CursorLoader; +import android.support.v4.content.Loader; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.ImageView; +import android.widget.ListView; + +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround; +import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; +import org.sufficientlysecure.keychain.provider.KeychainContract; +import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; +import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets; +import org.sufficientlysecure.keychain.provider.ProviderHelper; +import org.sufficientlysecure.keychain.provider.ProviderHelper.NotFoundException; +import org.sufficientlysecure.keychain.ui.adapter.UserIdsAdapter; +import org.sufficientlysecure.keychain.ui.dialog.UserIdInfoDialogFragment; +import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; +import org.sufficientlysecure.keychain.ui.util.Notify; +import org.sufficientlysecure.keychain.util.Log; + +import java.util.Date; + +public class ViewKeyAdvMainFragment extends LoaderFragment implements + LoaderManager.LoaderCallbacks { + + public static final String ARG_DATA_URI = "uri"; + + private View mActionEdit; + private View mActionEditDivider; + private View mActionEncryptFiles; + private View mActionEncryptText; + private View mActionEncryptTextText; + private View mActionCertify; + private View mActionCertifyText; + private ImageView mActionCertifyImage; + private View mActionUpdate; + + private ListView mUserIds; + + private static final int LOADER_ID_UNIFIED = 0; + private static final int LOADER_ID_USER_IDS = 1; + + // conservative attitude + private boolean mHasEncrypt = true; + + private UserIdsAdapter mUserIdsAdapter; + + private Uri mDataUri; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup superContainer, Bundle savedInstanceState) { + View root = super.onCreateView(inflater, superContainer, savedInstanceState); + View view = inflater.inflate(R.layout.view_key_main_fragment, getContainer()); + + mUserIds = (ListView) view.findViewById(R.id.view_key_user_ids); + mActionEdit = view.findViewById(R.id.view_key_action_edit); + mActionEditDivider = view.findViewById(R.id.view_key_action_edit_divider); + mActionEncryptText = view.findViewById(R.id.view_key_action_encrypt_text); + mActionEncryptTextText = view.findViewById(R.id.view_key_action_encrypt_text_text); + mActionEncryptFiles = view.findViewById(R.id.view_key_action_encrypt_files); + mActionCertify = view.findViewById(R.id.view_key_action_certify); + mActionCertifyText = view.findViewById(R.id.view_key_action_certify_text); + mActionCertifyImage = (ImageView) view.findViewById(R.id.view_key_action_certify_image); + // make certify image gray, like action icons + mActionCertifyImage.setColorFilter(getResources().getColor(R.color.tertiary_text_light), + PorterDuff.Mode.SRC_IN); + mActionUpdate = view.findViewById(R.id.view_key_action_update); + + mUserIds.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + showUserIdInfo(position); + } + }); + + return root; + } + + private void showUserIdInfo(final int position) { + final boolean isRevoked = mUserIdsAdapter.getIsRevoked(position); + final int isVerified = mUserIdsAdapter.getIsVerified(position); + + DialogFragmentWorkaround.INTERFACE.runnableRunDelayed(new Runnable() { + public void run() { + UserIdInfoDialogFragment dialogFragment = + UserIdInfoDialogFragment.newInstance(isRevoked, isVerified); + + dialogFragment.show(getActivity().getSupportFragmentManager(), "userIdInfoDialog"); + } + }); + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + Uri dataUri = getArguments().getParcelable(ARG_DATA_URI); + if (dataUri == null) { + Log.e(Constants.TAG, "Data missing. Should be Uri of key!"); + getActivity().finish(); + return; + } + + loadData(dataUri); + } + + private void loadData(Uri dataUri) { + mDataUri = dataUri; + + Log.i(Constants.TAG, "mDataUri: " + mDataUri.toString()); + + mActionEncryptFiles.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + encrypt(mDataUri, false); + } + }); + mActionEncryptText.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + encrypt(mDataUri, true); + } + }); + mActionCertify.setOnClickListener(new View.OnClickListener() { + public void onClick(View view) { + certify(mDataUri); + } + }); + mActionEdit.setOnClickListener(new View.OnClickListener() { + public void onClick(View view) { + editKey(mDataUri); + } + }); + mActionUpdate.setOnClickListener(new View.OnClickListener() { + public void onClick(View view) { + try { + updateFromKeyserver(mDataUri, new ProviderHelper(getActivity())); + } catch (NotFoundException e) { + Notify.showNotify(getActivity(), R.string.error_key_not_found, Notify.Style.ERROR); + } + } + }); + + mUserIdsAdapter = new UserIdsAdapter(getActivity(), null, 0); + mUserIds.setAdapter(mUserIdsAdapter); + + // Prepare the loaders. Either re-connect with an existing ones, + // or start new ones. + getLoaderManager().initLoader(LOADER_ID_UNIFIED, null, this); + getLoaderManager().initLoader(LOADER_ID_USER_IDS, null, this); + } + + static final String[] UNIFIED_PROJECTION = new String[]{ + KeyRings._ID, KeyRings.MASTER_KEY_ID, + KeyRings.HAS_ANY_SECRET, KeyRings.IS_REVOKED, KeyRings.EXPIRY, KeyRings.HAS_ENCRYPT + }; + static final int INDEX_UNIFIED_MASTER_KEY_ID = 1; + static final int INDEX_UNIFIED_HAS_ANY_SECRET = 2; + static final int INDEX_UNIFIED_IS_REVOKED = 3; + static final int INDEX_UNIFIED_EXPIRY = 4; + static final int INDEX_UNIFIED_HAS_ENCRYPT = 5; + + public Loader onCreateLoader(int id, Bundle args) { + setContentShown(false); + + switch (id) { + case LOADER_ID_UNIFIED: { + Uri baseUri = KeyRings.buildUnifiedKeyRingUri(mDataUri); + return new CursorLoader(getActivity(), baseUri, UNIFIED_PROJECTION, null, null, null); + } + case LOADER_ID_USER_IDS: { + Uri baseUri = UserPackets.buildUserIdsUri(mDataUri); + return new CursorLoader(getActivity(), baseUri, + UserIdsAdapter.USER_IDS_PROJECTION, null, null, null); + } + + default: + return null; + } + } + + public void onLoadFinished(Loader loader, Cursor data) { + /* TODO better error handling? May cause problems when a key is deleted, + * because the notification triggers faster than the activity closes. + */ + // Avoid NullPointerExceptions... + if (data.getCount() == 0) { + return; + } + // Swap the new cursor in. (The framework will take care of closing the + // old cursor once we return.) + switch (loader.getId()) { + case LOADER_ID_UNIFIED: { + if (data.moveToFirst()) { + if (data.getInt(INDEX_UNIFIED_HAS_ANY_SECRET) != 0) { + // edit button + mActionEdit.setVisibility(View.VISIBLE); + mActionEditDivider.setVisibility(View.VISIBLE); + } else { + // edit button + mActionEdit.setVisibility(View.GONE); + mActionEditDivider.setVisibility(View.GONE); + } + + // If this key is revoked, it cannot be used for anything! + if (data.getInt(INDEX_UNIFIED_IS_REVOKED) != 0) { + mActionEdit.setEnabled(false); + mActionCertify.setEnabled(false); + mActionCertifyText.setEnabled(false); + mActionEncryptText.setEnabled(false); + mActionEncryptTextText.setEnabled(false); + mActionEncryptFiles.setEnabled(false); + } else { + mActionEdit.setEnabled(true); + + Date expiryDate = new Date(data.getLong(INDEX_UNIFIED_EXPIRY) * 1000); + if (!data.isNull(INDEX_UNIFIED_EXPIRY) && expiryDate.before(new Date())) { + mActionCertify.setEnabled(false); + mActionCertifyText.setEnabled(false); + mActionEncryptText.setEnabled(false); + mActionEncryptTextText.setEnabled(false); + mActionEncryptFiles.setEnabled(false); + } else { + mActionCertify.setEnabled(true); + mActionCertifyText.setEnabled(true); + mActionEncryptText.setEnabled(true); + mActionEncryptTextText.setEnabled(true); + mActionEncryptFiles.setEnabled(true); + } + } + + mHasEncrypt = data.getInt(INDEX_UNIFIED_HAS_ENCRYPT) != 0; + + break; + } + } + + case LOADER_ID_USER_IDS: + mUserIdsAdapter.swapCursor(data); + break; + + } + setContentShown(true); + } + + /** + * This is called when the last Cursor provided to onLoadFinished() above is about to be closed. + * We need to make sure we are no longer using it. + */ + public void onLoaderReset(Loader loader) { + switch (loader.getId()) { + case LOADER_ID_USER_IDS: + mUserIdsAdapter.swapCursor(null); + break; + } + } + + private void encrypt(Uri dataUri, boolean text) { + // If there is no encryption key, don't bother. + if (!mHasEncrypt) { + Notify.showNotify(getActivity(), R.string.error_no_encrypt_subkey, Notify.Style.ERROR); + return; + } + try { + long keyId = new ProviderHelper(getActivity()) + .getCachedPublicKeyRing(dataUri) + .extractOrGetMasterKeyId(); + long[] encryptionKeyIds = new long[]{keyId}; + Intent intent; + if (text) { + intent = new Intent(getActivity(), EncryptTextActivity.class); + intent.setAction(EncryptTextActivity.ACTION_ENCRYPT_TEXT); + intent.putExtra(EncryptTextActivity.EXTRA_ENCRYPTION_KEY_IDS, encryptionKeyIds); + } else { + intent = new Intent(getActivity(), EncryptFilesActivity.class); + intent.setAction(EncryptFilesActivity.ACTION_ENCRYPT_DATA); + intent.putExtra(EncryptFilesActivity.EXTRA_ENCRYPTION_KEY_IDS, encryptionKeyIds); + } + // used instead of startActivity set actionbar based on callingPackage + startActivityForResult(intent, 0); + } catch (PgpKeyNotFoundException e) { + Log.e(Constants.TAG, "key not found!", e); + } + } + + private void updateFromKeyserver(Uri dataUri, ProviderHelper providerHelper) + throws ProviderHelper.NotFoundException { + byte[] blob = (byte[]) providerHelper.getGenericData( + KeychainContract.KeyRings.buildUnifiedKeyRingUri(dataUri), + KeychainContract.Keys.FINGERPRINT, ProviderHelper.FIELD_TYPE_BLOB); + String fingerprint = KeyFormattingUtils.convertFingerprintToHex(blob); + + Intent queryIntent = new Intent(getActivity(), ImportKeysActivity.class); + queryIntent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_RESULT); + queryIntent.putExtra(ImportKeysActivity.EXTRA_FINGERPRINT, fingerprint); + + startActivityForResult(queryIntent, 0); + } + + private void certify(Uri dataUri) { + long keyId = 0; + try { + keyId = new ProviderHelper(getActivity()) + .getCachedPublicKeyRing(dataUri) + .extractOrGetMasterKeyId(); + } catch (PgpKeyNotFoundException e) { + Log.e(Constants.TAG, "key not found!", e); + } + Intent certifyIntent = new Intent(getActivity(), CertifyKeyActivity.class); + certifyIntent.putExtra(CertifyKeyActivity.EXTRA_KEY_IDS, new long[]{keyId}); + startActivityForResult(certifyIntent, 0); + } + + private void editKey(Uri dataUri) { + Intent editIntent = new Intent(getActivity(), EditKeyActivity.class); + editIntent.setData(KeychainContract.KeyRingData.buildSecretKeyRingUri(dataUri)); + startActivityForResult(editIntent, 0); + } + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java new file mode 100644 index 000000000..6208cff4e --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java @@ -0,0 +1,387 @@ +/* + * Copyright (C) 2014 Dominik Schürmann + * + * 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 . + */ + +package org.sufficientlysecure.keychain.ui; + +import android.annotation.TargetApi; +import android.content.Intent; +import android.database.Cursor; +import android.graphics.Bitmap; +import android.graphics.PorterDuff; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Build; +import android.os.Bundle; +import android.provider.Settings; +import android.support.v4.app.LoaderManager; +import android.support.v4.content.CursorLoader; +import android.support.v4.content.Loader; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.AlphaAnimation; +import android.widget.ImageButton; +import android.widget.ImageView; +import android.widget.TextView; + +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.compatibility.ClipboardReflection; +import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; +import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; +import org.sufficientlysecure.keychain.provider.KeychainContract; +import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; +import org.sufficientlysecure.keychain.provider.KeychainContract.Keys; +import org.sufficientlysecure.keychain.provider.ProviderHelper; +import org.sufficientlysecure.keychain.ui.dialog.ShareNfcDialogFragment; +import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; +import org.sufficientlysecure.keychain.ui.util.Notify; +import org.sufficientlysecure.keychain.ui.util.QrCodeUtils; +import org.sufficientlysecure.keychain.util.Log; + +import java.io.IOException; + + +public class ViewKeyAdvShareFragment extends LoaderFragment implements + LoaderManager.LoaderCallbacks { + + public static final String ARG_DATA_URI = "uri"; + + private TextView mFingerprint; + private ImageView mFingerprintQrCode; + private View mFingerprintShareButton; + private View mFingerprintClipboardButton; + private View mKeyShareButton; + private View mKeyClipboardButton; + private ImageButton mKeySafeSlingerButton; + private View mNfcHelpButton; + private View mNfcPrefsButton; + private View mKeyUploadButton; + + ProviderHelper mProviderHelper; + + private static final int LOADER_ID_UNIFIED = 0; + + private Uri mDataUri; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup superContainer, Bundle savedInstanceState) { + View root = super.onCreateView(inflater, superContainer, savedInstanceState); + View view = inflater.inflate(R.layout.view_key_adv_share_fragment, getContainer()); + + mProviderHelper = new ProviderHelper(ViewKeyAdvShareFragment.this.getActivity()); + + mFingerprint = (TextView) view.findViewById(R.id.view_key_fingerprint); + mFingerprintQrCode = (ImageView) view.findViewById(R.id.view_key_fingerprint_qr_code_image); + mFingerprintShareButton = view.findViewById(R.id.view_key_action_fingerprint_share); + mFingerprintClipboardButton = view.findViewById(R.id.view_key_action_fingerprint_clipboard); + mKeyShareButton = view.findViewById(R.id.view_key_action_key_share); + mKeyClipboardButton = view.findViewById(R.id.view_key_action_key_clipboard); + mKeySafeSlingerButton = (ImageButton) view.findViewById(R.id.view_key_action_key_safeslinger); + mNfcHelpButton = view.findViewById(R.id.view_key_action_nfc_help); + mNfcPrefsButton = view.findViewById(R.id.view_key_action_nfc_prefs); + mKeyUploadButton = view.findViewById(R.id.view_key_action_upload); + + mKeySafeSlingerButton.setColorFilter(getResources().getColor(R.color.tertiary_text_light), + PorterDuff.Mode.SRC_IN); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { + mNfcPrefsButton.setVisibility(View.VISIBLE); + } else { + mNfcPrefsButton.setVisibility(View.GONE); + } + + mFingerprintQrCode.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + showQrCodeDialog(); + } + }); + + mFingerprintShareButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + share(mDataUri, mProviderHelper, true, false); + } + }); + mFingerprintClipboardButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + share(mDataUri, mProviderHelper, true, true); + } + }); + mKeyShareButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + share(mDataUri, mProviderHelper, false, false); + } + }); + mKeyClipboardButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + share(mDataUri, mProviderHelper, false, true); + } + }); + mKeySafeSlingerButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + startSafeSlinger(mDataUri); + } + }); + mNfcHelpButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + showNfcHelpDialog(); + } + }); + mNfcPrefsButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + showNfcPrefs(); + } + }); + mKeyUploadButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + uploadToKeyserver(); + } + }); + + return root; + } + + private void startSafeSlinger(Uri dataUri) { + long keyId = 0; + try { + keyId = new ProviderHelper(getActivity()) + .getCachedPublicKeyRing(dataUri) + .extractOrGetMasterKeyId(); + } catch (PgpKeyNotFoundException e) { + Log.e(Constants.TAG, "key not found!", e); + } + Intent safeSlingerIntent = new Intent(getActivity(), SafeSlingerActivity.class); + safeSlingerIntent.putExtra(SafeSlingerActivity.EXTRA_MASTER_KEY_ID, keyId); + startActivityForResult(safeSlingerIntent, 0); + } + + private void share(Uri dataUri, ProviderHelper providerHelper, boolean fingerprintOnly, + boolean toClipboard) { + try { + String content; + if (fingerprintOnly) { + byte[] data = (byte[]) providerHelper.getGenericData( + KeyRings.buildUnifiedKeyRingUri(dataUri), + Keys.FINGERPRINT, ProviderHelper.FIELD_TYPE_BLOB); + String fingerprint = KeyFormattingUtils.convertFingerprintToHex(data); + if (!toClipboard) { + content = Constants.FINGERPRINT_SCHEME + ":" + fingerprint; + } else { + content = fingerprint; + } + } else { + Uri uri = KeychainContract.KeyRingData.buildPublicKeyRingUri(dataUri); + // get public keyring as ascii armored string + content = providerHelper.getKeyRingAsArmoredString(uri); + } + + if (toClipboard) { + ClipboardReflection.copyToClipboard(getActivity(), content); + String message; + if (fingerprintOnly) { + message = getResources().getString(R.string.fingerprint_copied_to_clipboard); + } else { + message = getResources().getString(R.string.key_copied_to_clipboard); + } + Notify.showNotify(getActivity(), message, Notify.Style.OK); + } else { + // Android will fail with android.os.TransactionTooLargeException if key is too big + // see http://www.lonestarprod.com/?p=34 + if (content.length() >= 86389) { + Notify.showNotify(getActivity(), R.string.key_too_big_for_sharing, + Notify.Style.ERROR); + return; + } + + // let user choose application + Intent sendIntent = new Intent(Intent.ACTION_SEND); + sendIntent.putExtra(Intent.EXTRA_TEXT, content); + sendIntent.setType("text/plain"); + String title; + if (fingerprintOnly) { + title = getResources().getString(R.string.title_share_fingerprint_with); + } else { + title = getResources().getString(R.string.title_share_key); + } + startActivity(Intent.createChooser(sendIntent, title)); + } + } catch (PgpGeneralException | IOException e) { + Log.e(Constants.TAG, "error processing key!", e); + Notify.showNotify(getActivity(), R.string.error_key_processing, Notify.Style.ERROR); + } catch (ProviderHelper.NotFoundException e) { + Log.e(Constants.TAG, "key not found!", e); + Notify.showNotify(getActivity(), R.string.error_key_not_found, Notify.Style.ERROR); + } + } + + private void showQrCodeDialog() { + Intent qrCodeIntent = new Intent(getActivity(), QrCodeViewActivity.class); + qrCodeIntent.setData(mDataUri); + startActivity(qrCodeIntent); + } + + private void showNfcHelpDialog() { + ShareNfcDialogFragment dialog = ShareNfcDialogFragment.newInstance(); + dialog.show(getActivity().getSupportFragmentManager(), "shareNfcDialog"); + } + + @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) + private void showNfcPrefs() { + Intent intentSettings = new Intent( + Settings.ACTION_NFCSHARING_SETTINGS); + startActivity(intentSettings); + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + Uri dataUri = getArguments().getParcelable(ARG_DATA_URI); + if (dataUri == null) { + Log.e(Constants.TAG, "Data missing. Should be Uri of key!"); + getActivity().finish(); + return; + } + + loadData(dataUri); + } + + private void loadData(Uri dataUri) { + mDataUri = dataUri; + + Log.i(Constants.TAG, "mDataUri: " + mDataUri.toString()); + + // Prepare the loaders. Either re-connect with an existing ones, + // or start new ones. + getLoaderManager().initLoader(LOADER_ID_UNIFIED, null, this); + } + + static final String[] UNIFIED_PROJECTION = new String[]{ + KeyRings._ID, KeyRings.MASTER_KEY_ID, KeyRings.HAS_ANY_SECRET, + KeyRings.USER_ID, KeyRings.FINGERPRINT, + KeyRings.ALGORITHM, KeyRings.KEY_SIZE, KeyRings.CREATION, KeyRings.EXPIRY, + + }; + static final int INDEX_UNIFIED_MASTER_KEY_ID = 1; + static final int INDEX_UNIFIED_HAS_ANY_SECRET = 2; + static final int INDEX_UNIFIED_USER_ID = 3; + static final int INDEX_UNIFIED_FINGERPRINT = 4; + static final int INDEX_UNIFIED_ALGORITHM = 5; + static final int INDEX_UNIFIED_KEY_SIZE = 6; + static final int INDEX_UNIFIED_CREATION = 7; + static final int INDEX_UNIFIED_EXPIRY = 8; + + public Loader onCreateLoader(int id, Bundle args) { + setContentShown(false); + switch (id) { + case LOADER_ID_UNIFIED: { + Uri baseUri = KeyRings.buildUnifiedKeyRingUri(mDataUri); + return new CursorLoader(getActivity(), baseUri, UNIFIED_PROJECTION, null, null, null); + } + + default: + return null; + } + } + + public void onLoadFinished(Loader loader, Cursor data) { + /* TODO better error handling? May cause problems when a key is deleted, + * because the notification triggers faster than the activity closes. + */ + // Avoid NullPointerExceptions... + if (data.getCount() == 0) { + return; + } + // Swap the new cursor in. (The framework will take care of closing the + // old cursor once we return.) + switch (loader.getId()) { + case LOADER_ID_UNIFIED: { + if (data.moveToFirst()) { + + byte[] fingerprintBlob = data.getBlob(INDEX_UNIFIED_FINGERPRINT); + String fingerprint = KeyFormattingUtils.convertFingerprintToHex(fingerprintBlob); + mFingerprint.setText(KeyFormattingUtils.colorizeFingerprint(fingerprint)); + + loadQrCode(fingerprint); + + break; + } + } + + } + setContentShown(true); + } + + /** + * This is called when the last Cursor provided to onLoadFinished() above is about to be closed. + * We need to make sure we are no longer using it. + */ + public void onLoaderReset(Loader loader) { + } + + /** + * Load QR Code asynchronously and with a fade in animation + * + * @param fingerprint + */ + private void loadQrCode(final String fingerprint) { + AsyncTask loadTask = + new AsyncTask() { + protected Bitmap doInBackground(Void... unused) { + String qrCodeContent = Constants.FINGERPRINT_SCHEME + ":" + fingerprint; + // render with minimal size + return QrCodeUtils.getQRCodeBitmap(qrCodeContent, 0); + } + + protected void onPostExecute(Bitmap qrCode) { + // only change view, if fragment is attached to activity + if (ViewKeyAdvShareFragment.this.isAdded()) { + + // scale the image up to our actual size. we do this in code rather + // than let the ImageView do this because we don't require filtering. + Bitmap scaled = Bitmap.createScaledBitmap(qrCode, + mFingerprintQrCode.getHeight(), mFingerprintQrCode.getHeight(), + false); + mFingerprintQrCode.setImageBitmap(scaled); + + // simple fade-in animation + AlphaAnimation anim = new AlphaAnimation(0.0f, 1.0f); + anim.setDuration(200); + mFingerprintQrCode.startAnimation(anim); + } + } + }; + + loadTask.execute(); + } + + private void uploadToKeyserver() { + Intent uploadIntent = new Intent(getActivity(), UploadKeyActivity.class); + uploadIntent.setData(mDataUri); + startActivityForResult(uploadIntent, 0); + } + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvancedActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvancedActivity.java deleted file mode 100644 index 471f55c47..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvancedActivity.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (C) 2013-2014 Dominik Schürmann - * Copyright (C) 2013 Bahtiar 'kalkin' Gadimov - * - * 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 . - */ - -package org.sufficientlysecure.keychain.ui; - -import android.net.Uri; -import android.os.Bundle; -import android.view.View; - -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.util.ExportHelper; -import org.sufficientlysecure.keychain.util.Log; - -public class ViewKeyAdvancedActivity extends BaseActivity { - - ExportHelper mExportHelper; - ProviderHelper mProviderHelper; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - mExportHelper = new ExportHelper(this); - mProviderHelper = new ProviderHelper(this); - - // Inflate a "Done" custom action bar - setFullScreenDialogClose( - new View.OnClickListener() { - @Override - public void onClick(View v) { - // "Done" - finish(); - } - } - ); - - Uri dataUri = getIntent().getData(); - if (dataUri == null) { - Log.e(Constants.TAG, "Data missing. Should be uri of key!"); - finish(); - return; - } - - Log.i(Constants.TAG, "mDataUri: " + dataUri.toString()); - - startFragment(savedInstanceState, dataUri); - } - - @Override - protected void initLayout() { - setContentView(R.layout.view_key_advanced_activity); - } - - private void startFragment(Bundle savedInstanceState, Uri dataUri) { - // However, if we're being restored from a previous state, - // then we don't need to do anything and should return or else - // we could end up with overlapping fragments. - if (savedInstanceState != null) { - return; - } - - // Create an instance of the fragment - ViewKeyAdvancedFragment frag = ViewKeyAdvancedFragment.newInstance(dataUri); - - // Add the fragment to the 'fragment_container' FrameLayout - // NOTE: We use commitAllowingStateLoss() to prevent weird crashes! - getSupportFragmentManager().beginTransaction() - .replace(R.id.view_key_advanced_fragment, frag) - .commitAllowingStateLoss(); - // do it immediately! - getSupportFragmentManager().executePendingTransactions(); - } - -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvancedFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvancedFragment.java deleted file mode 100644 index 61bd126ce..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvancedFragment.java +++ /dev/null @@ -1,378 +0,0 @@ -/* - * Copyright (C) 2014 Dominik Schürmann - * - * 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 . - */ - -package org.sufficientlysecure.keychain.ui; - -import android.content.Context; -import android.content.Intent; -import android.database.Cursor; -import android.net.Uri; -import android.os.Bundle; -import android.support.v4.app.LoaderManager; -import android.support.v4.content.CursorLoader; -import android.support.v4.content.Loader; -import android.support.v4.widget.CursorAdapter; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.AdapterView; -import android.widget.ListView; -import android.widget.TextView; - -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.pgp.KeyRing; -import org.sufficientlysecure.keychain.pgp.WrappedSignature; -import org.sufficientlysecure.keychain.provider.KeychainContract; -import org.sufficientlysecure.keychain.provider.KeychainDatabase; -import org.sufficientlysecure.keychain.ui.adapter.SubkeysAdapter; -import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; -import org.sufficientlysecure.keychain.util.Log; - -import se.emilsjolander.stickylistheaders.StickyListHeadersAdapter; -import se.emilsjolander.stickylistheaders.StickyListHeadersListView; - - -public class ViewKeyAdvancedFragment extends LoaderFragment implements - LoaderManager.LoaderCallbacks, AdapterView.OnItemClickListener { - - public static final String ARG_DATA_URI = "data_uri"; - - private ListView mSubkeysList; - private SubkeysAdapter mSubkeysAdapter; - - private StickyListHeadersListView mStickyList; - private CertListAdapter mCertsAdapter; - - private Uri mDataUriSubkeys; - private Uri mDataUriCerts; - - private static final int LOADER_SUBKEYS = 1; - private static final int LOADER_CERTS = 2; - - // These are the rows that we will retrieve. - static final String[] CERTS_PROJECTION = new String[]{ - KeychainContract.Certs._ID, - KeychainContract.Certs.MASTER_KEY_ID, - KeychainContract.Certs.VERIFIED, - KeychainContract.Certs.TYPE, - KeychainContract.Certs.RANK, - KeychainContract.Certs.KEY_ID_CERTIFIER, - KeychainContract.Certs.USER_ID, - KeychainContract.Certs.SIGNER_UID - }; - - // sort by our user id, - static final String CERTS_SORT_ORDER = - KeychainDatabase.Tables.CERTS + "." + KeychainContract.Certs.RANK + " ASC, " - + KeychainContract.Certs.VERIFIED + " DESC, " - + KeychainDatabase.Tables.CERTS + "." + KeychainContract.Certs.TYPE + " DESC, " - + KeychainContract.Certs.SIGNER_UID + " ASC"; - - /** - * Creates new instance of this fragment - */ - public static ViewKeyAdvancedFragment newInstance(Uri dataUri) { - ViewKeyAdvancedFragment frag = new ViewKeyAdvancedFragment(); - - Bundle args = new Bundle(); - args.putParcelable(ARG_DATA_URI, dataUri); - - frag.setArguments(args); - return frag; - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup superContainer, Bundle savedInstanceState) { - View root = super.onCreateView(inflater, superContainer, savedInstanceState); - View view = inflater.inflate(R.layout.view_key_advanced_fragment, getContainer()); - - mSubkeysList = (ListView) view.findViewById(R.id.keys); - mStickyList = (StickyListHeadersListView) view.findViewById(R.id.certs_list); - - return root; - } - - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - - Uri dataUri = getArguments().getParcelable(ARG_DATA_URI); - if (dataUri == null) { - Log.e(Constants.TAG, "Data missing. Should be Uri of key!"); - getActivity().finish(); - return; - } - - loadData(dataUri); - } - - private void loadData(Uri dataUri) { - mDataUriSubkeys = KeychainContract.Keys.buildKeysUri(dataUri); - mDataUriCerts = KeychainContract.Certs.buildCertsUri(dataUri); - - mStickyList.setAreHeadersSticky(true); - mStickyList.setDrawingListUnderStickyHeader(false); - mStickyList.setOnItemClickListener(this); - - mStickyList.setEmptyView(getActivity().findViewById(R.id.empty)); - - // Create an empty adapter we will use to display the loaded data. - mSubkeysAdapter = new SubkeysAdapter(getActivity(), null, 0); - mSubkeysList.setAdapter(mSubkeysAdapter); - - mCertsAdapter = new CertListAdapter(getActivity(), null); - mStickyList.setAdapter(mCertsAdapter); - - // Prepare the loaders. Either re-connect with an existing ones, - // or start new ones. - getLoaderManager().initLoader(LOADER_SUBKEYS, null, this); - getLoaderManager().initLoader(LOADER_CERTS, null, this); - } - - public Loader onCreateLoader(int id, Bundle args) { - setContentShown(false); - switch (id) { - case LOADER_SUBKEYS: - return new CursorLoader(getActivity(), mDataUriSubkeys, - SubkeysAdapter.SUBKEYS_PROJECTION, null, null, null); - - case LOADER_CERTS: - // Now create and return a CursorLoader that will take care of - // creating a Cursor for the data being displayed. - return new CursorLoader(getActivity(), mDataUriCerts, - CERTS_PROJECTION, null, null, CERTS_SORT_ORDER); - - default: - return null; - } - } - - public void onLoadFinished(Loader loader, Cursor data) { - // Avoid NullPointerExceptions, if we get an empty result set. - if (data.getCount() == 0) { - return; - } - - // Swap the new cursor in. (The framework will take care of closing the - // old cursor once we return.) - switch (loader.getId()) { - case LOADER_SUBKEYS: - mSubkeysAdapter.swapCursor(data); - break; - case LOADER_CERTS: - mCertsAdapter.swapCursor(data); - mStickyList.setAdapter(mCertsAdapter); - break; - } - - // TODO: maybe show not before both are loaded! - setContentShown(true); - } - - /** - * This is called when the last Cursor provided to onLoadFinished() above is about to be closed. - * We need to make sure we are no longer using it. - */ - public void onLoaderReset(Loader loader) { - switch (loader.getId()) { - case LOADER_SUBKEYS: - mSubkeysAdapter.swapCursor(null); - break; - case LOADER_CERTS: - mCertsAdapter.swapCursor(null); - break; - } - } - - /** - * On click on item, start key view activity - */ - @Override - public void onItemClick(AdapterView adapterView, View view, int position, long id) { - if (view.getTag(R.id.tag_mki) != null) { - long masterKeyId = (Long) view.getTag(R.id.tag_mki); - long rank = (Long) view.getTag(R.id.tag_rank); - long certifierId = (Long) view.getTag(R.id.tag_certifierId); - - Intent viewIntent = new Intent(getActivity(), ViewCertActivity.class); - viewIntent.setData(KeychainContract.Certs.buildCertsSpecificUri( - masterKeyId, rank, certifierId)); - startActivity(viewIntent); - } - } - - - /** - * Implements StickyListHeadersAdapter from library - */ - private class CertListAdapter extends CursorAdapter implements StickyListHeadersAdapter { - private LayoutInflater mInflater; - private int mIndexMasterKeyId, mIndexUserId, mIndexRank; - private int mIndexSignerKeyId, mIndexSignerUserId; - private int mIndexVerified, mIndexType; - - public CertListAdapter(Context context, Cursor c) { - super(context, c, 0); - - mInflater = LayoutInflater.from(context); - initIndex(c); - } - - @Override - public Cursor swapCursor(Cursor newCursor) { - initIndex(newCursor); - - return super.swapCursor(newCursor); - } - - /** - * Get column indexes for performance reasons just once in constructor and swapCursor. For a - * performance comparison see http://stackoverflow.com/a/17999582 - * - * @param cursor - */ - private void initIndex(Cursor cursor) { - if (cursor != null) { - mIndexMasterKeyId = cursor.getColumnIndexOrThrow(KeychainContract.Certs.MASTER_KEY_ID); - mIndexUserId = cursor.getColumnIndexOrThrow(KeychainContract.Certs.USER_ID); - mIndexRank = cursor.getColumnIndexOrThrow(KeychainContract.Certs.RANK); - mIndexType = cursor.getColumnIndexOrThrow(KeychainContract.Certs.TYPE); - mIndexVerified = cursor.getColumnIndexOrThrow(KeychainContract.Certs.VERIFIED); - mIndexSignerKeyId = cursor.getColumnIndexOrThrow(KeychainContract.Certs.KEY_ID_CERTIFIER); - mIndexSignerUserId = cursor.getColumnIndexOrThrow(KeychainContract.Certs.SIGNER_UID); - } - } - - /** - * Bind cursor data to the item list view - *

- * NOTE: CursorAdapter already implements the ViewHolder pattern in its getView() method. - * Thus no ViewHolder is required here. - */ - @Override - public void bindView(View view, Context context, Cursor cursor) { - - // set name and stuff, common to both key types - TextView wSignerKeyId = (TextView) view.findViewById(R.id.signerKeyId); - TextView wSignerName = (TextView) view.findViewById(R.id.signerName); - TextView wSignStatus = (TextView) view.findViewById(R.id.signStatus); - - String signerKeyId = KeyFormattingUtils.beautifyKeyIdWithPrefix(getActivity(), cursor.getLong(mIndexSignerKeyId)); - String[] userId = KeyRing.splitUserId(cursor.getString(mIndexSignerUserId)); - if (userId[0] != null) { - wSignerName.setText(userId[0]); - } else { - wSignerName.setText(R.string.user_id_no_name); - } - wSignerKeyId.setText(signerKeyId); - - switch (cursor.getInt(mIndexType)) { - case WrappedSignature.DEFAULT_CERTIFICATION: // 0x10 - wSignStatus.setText(R.string.cert_default); - break; - case WrappedSignature.NO_CERTIFICATION: // 0x11 - wSignStatus.setText(R.string.cert_none); - break; - case WrappedSignature.CASUAL_CERTIFICATION: // 0x12 - wSignStatus.setText(R.string.cert_casual); - break; - case WrappedSignature.POSITIVE_CERTIFICATION: // 0x13 - wSignStatus.setText(R.string.cert_positive); - break; - case WrappedSignature.CERTIFICATION_REVOCATION: // 0x30 - wSignStatus.setText(R.string.cert_revoke); - break; - } - - - view.setTag(R.id.tag_mki, cursor.getLong(mIndexMasterKeyId)); - view.setTag(R.id.tag_rank, cursor.getLong(mIndexRank)); - view.setTag(R.id.tag_certifierId, cursor.getLong(mIndexSignerKeyId)); - } - - @Override - public View newView(Context context, Cursor cursor, ViewGroup parent) { - return mInflater.inflate(R.layout.view_key_certs_item, parent, false); - } - - /** - * Creates a new header view and binds the section headers to it. It uses the ViewHolder - * pattern. Most functionality is similar to getView() from Android's CursorAdapter. - *

- * NOTE: The variables mDataValid and mCursor are available due to the super class - * CursorAdapter. - */ - @Override - public View getHeaderView(int position, View convertView, ViewGroup parent) { - HeaderViewHolder holder; - if (convertView == null) { - holder = new HeaderViewHolder(); - convertView = mInflater.inflate(R.layout.view_key_certs_header, parent, false); - holder.text = (TextView) convertView.findViewById(R.id.stickylist_header_text); - holder.count = (TextView) convertView.findViewById(R.id.certs_num); - convertView.setTag(holder); - } else { - holder = (HeaderViewHolder) convertView.getTag(); - } - - if (!mDataValid) { - // no data available at this point - Log.d(Constants.TAG, "getHeaderView: No data available at this point!"); - return convertView; - } - - if (!mCursor.moveToPosition(position)) { - throw new IllegalStateException("couldn't move cursor to position " + position); - } - - // set header text as first char in user id - String userId = mCursor.getString(mIndexUserId); - holder.text.setText(userId); - holder.count.setVisibility(View.GONE); - return convertView; - } - - /** - * Header IDs should be static, position=1 should always return the same Id that is. - */ - @Override - public long getHeaderId(int position) { - if (!mDataValid) { - // no data available at this point - Log.d(Constants.TAG, "getHeaderView: No data available at this point!"); - return -1; - } - - if (!mCursor.moveToPosition(position)) { - throw new IllegalStateException("couldn't move cursor to position " + position); - } - - // otherwise, return the first character of the name as ID - return mCursor.getInt(mIndexRank); - - // sort by the first four characters (should be enough I guess?) - // return ByteBuffer.wrap(userId.getBytes()).asLongBuffer().get(0); - } - - class HeaderViewHolder { - TextView text; - TextView count; - } - - } -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java deleted file mode 100644 index 8e957a36f..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyMainFragment.java +++ /dev/null @@ -1,350 +0,0 @@ -/* - * Copyright (C) 2014 Dominik Schürmann - * Copyright (C) 2014 Vincent Breitmoser - * - * 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 . - */ - -package org.sufficientlysecure.keychain.ui; - -import android.content.Intent; -import android.database.Cursor; -import android.graphics.PorterDuff; -import android.net.Uri; -import android.os.Bundle; -import android.support.v4.app.LoaderManager; -import android.support.v4.content.CursorLoader; -import android.support.v4.content.Loader; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.AdapterView; -import android.widget.ImageView; -import android.widget.ListView; - -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround; -import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; -import org.sufficientlysecure.keychain.provider.KeychainContract; -import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; -import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets; -import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.provider.ProviderHelper.NotFoundException; -import org.sufficientlysecure.keychain.ui.adapter.UserIdsAdapter; -import org.sufficientlysecure.keychain.ui.dialog.UserIdInfoDialogFragment; -import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; -import org.sufficientlysecure.keychain.ui.util.Notify; -import org.sufficientlysecure.keychain.util.Log; - -import java.util.Date; - -public class ViewKeyMainFragment extends LoaderFragment implements - LoaderManager.LoaderCallbacks { - - public static final String ARG_DATA_URI = "uri"; - - private View mActionEdit; - private View mActionEditDivider; - private View mActionEncryptFiles; - private View mActionEncryptText; - private View mActionEncryptTextText; - private View mActionCertify; - private View mActionCertifyText; - private ImageView mActionCertifyImage; - private View mActionUpdate; - - private ListView mUserIds; - - private static final int LOADER_ID_UNIFIED = 0; - private static final int LOADER_ID_USER_IDS = 1; - - // conservative attitude - private boolean mHasEncrypt = true; - - private UserIdsAdapter mUserIdsAdapter; - - private Uri mDataUri; - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup superContainer, Bundle savedInstanceState) { - View root = super.onCreateView(inflater, superContainer, savedInstanceState); - View view = inflater.inflate(R.layout.view_key_main_fragment, getContainer()); - - mUserIds = (ListView) view.findViewById(R.id.view_key_user_ids); - mActionEdit = view.findViewById(R.id.view_key_action_edit); - mActionEditDivider = view.findViewById(R.id.view_key_action_edit_divider); - mActionEncryptText = view.findViewById(R.id.view_key_action_encrypt_text); - mActionEncryptTextText = view.findViewById(R.id.view_key_action_encrypt_text_text); - mActionEncryptFiles = view.findViewById(R.id.view_key_action_encrypt_files); - mActionCertify = view.findViewById(R.id.view_key_action_certify); - mActionCertifyText = view.findViewById(R.id.view_key_action_certify_text); - mActionCertifyImage = (ImageView) view.findViewById(R.id.view_key_action_certify_image); - // make certify image gray, like action icons - mActionCertifyImage.setColorFilter(getResources().getColor(R.color.tertiary_text_light), - PorterDuff.Mode.SRC_IN); - mActionUpdate = view.findViewById(R.id.view_key_action_update); - - mUserIds.setOnItemClickListener(new AdapterView.OnItemClickListener() { - @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { - showUserIdInfo(position); - } - }); - - return root; - } - - private void showUserIdInfo(final int position) { - final boolean isRevoked = mUserIdsAdapter.getIsRevoked(position); - final int isVerified = mUserIdsAdapter.getIsVerified(position); - - DialogFragmentWorkaround.INTERFACE.runnableRunDelayed(new Runnable() { - public void run() { - UserIdInfoDialogFragment dialogFragment = - UserIdInfoDialogFragment.newInstance(isRevoked, isVerified); - - dialogFragment.show(getActivity().getSupportFragmentManager(), "userIdInfoDialog"); - } - }); - } - - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - - Uri dataUri = getArguments().getParcelable(ARG_DATA_URI); - if (dataUri == null) { - Log.e(Constants.TAG, "Data missing. Should be Uri of key!"); - getActivity().finish(); - return; - } - - loadData(dataUri); - } - - private void loadData(Uri dataUri) { - mDataUri = dataUri; - - Log.i(Constants.TAG, "mDataUri: " + mDataUri.toString()); - - mActionEncryptFiles.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - encrypt(mDataUri, false); - } - }); - mActionEncryptText.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - encrypt(mDataUri, true); - } - }); - mActionCertify.setOnClickListener(new View.OnClickListener() { - public void onClick(View view) { - certify(mDataUri); - } - }); - mActionEdit.setOnClickListener(new View.OnClickListener() { - public void onClick(View view) { - editKey(mDataUri); - } - }); - mActionUpdate.setOnClickListener(new View.OnClickListener() { - public void onClick(View view) { - try { - updateFromKeyserver(mDataUri, new ProviderHelper(getActivity())); - } catch (NotFoundException e) { - Notify.showNotify(getActivity(), R.string.error_key_not_found, Notify.Style.ERROR); - } - } - }); - - mUserIdsAdapter = new UserIdsAdapter(getActivity(), null, 0); - mUserIds.setAdapter(mUserIdsAdapter); - - // Prepare the loaders. Either re-connect with an existing ones, - // or start new ones. - getLoaderManager().initLoader(LOADER_ID_UNIFIED, null, this); - getLoaderManager().initLoader(LOADER_ID_USER_IDS, null, this); - } - - static final String[] UNIFIED_PROJECTION = new String[]{ - KeyRings._ID, KeyRings.MASTER_KEY_ID, - KeyRings.HAS_ANY_SECRET, KeyRings.IS_REVOKED, KeyRings.EXPIRY, KeyRings.HAS_ENCRYPT - }; - static final int INDEX_UNIFIED_MASTER_KEY_ID = 1; - static final int INDEX_UNIFIED_HAS_ANY_SECRET = 2; - static final int INDEX_UNIFIED_IS_REVOKED = 3; - static final int INDEX_UNIFIED_EXPIRY = 4; - static final int INDEX_UNIFIED_HAS_ENCRYPT = 5; - - public Loader onCreateLoader(int id, Bundle args) { - setContentShown(false); - - switch (id) { - case LOADER_ID_UNIFIED: { - Uri baseUri = KeyRings.buildUnifiedKeyRingUri(mDataUri); - return new CursorLoader(getActivity(), baseUri, UNIFIED_PROJECTION, null, null, null); - } - case LOADER_ID_USER_IDS: { - Uri baseUri = UserPackets.buildUserIdsUri(mDataUri); - return new CursorLoader(getActivity(), baseUri, - UserIdsAdapter.USER_IDS_PROJECTION, null, null, null); - } - - default: - return null; - } - } - - public void onLoadFinished(Loader loader, Cursor data) { - /* TODO better error handling? May cause problems when a key is deleted, - * because the notification triggers faster than the activity closes. - */ - // Avoid NullPointerExceptions... - if (data.getCount() == 0) { - return; - } - // Swap the new cursor in. (The framework will take care of closing the - // old cursor once we return.) - switch (loader.getId()) { - case LOADER_ID_UNIFIED: { - if (data.moveToFirst()) { - if (data.getInt(INDEX_UNIFIED_HAS_ANY_SECRET) != 0) { - // edit button - mActionEdit.setVisibility(View.VISIBLE); - mActionEditDivider.setVisibility(View.VISIBLE); - } else { - // edit button - mActionEdit.setVisibility(View.GONE); - mActionEditDivider.setVisibility(View.GONE); - } - - // If this key is revoked, it cannot be used for anything! - if (data.getInt(INDEX_UNIFIED_IS_REVOKED) != 0) { - mActionEdit.setEnabled(false); - mActionCertify.setEnabled(false); - mActionCertifyText.setEnabled(false); - mActionEncryptText.setEnabled(false); - mActionEncryptTextText.setEnabled(false); - mActionEncryptFiles.setEnabled(false); - } else { - mActionEdit.setEnabled(true); - - Date expiryDate = new Date(data.getLong(INDEX_UNIFIED_EXPIRY) * 1000); - if (!data.isNull(INDEX_UNIFIED_EXPIRY) && expiryDate.before(new Date())) { - mActionCertify.setEnabled(false); - mActionCertifyText.setEnabled(false); - mActionEncryptText.setEnabled(false); - mActionEncryptTextText.setEnabled(false); - mActionEncryptFiles.setEnabled(false); - } else { - mActionCertify.setEnabled(true); - mActionCertifyText.setEnabled(true); - mActionEncryptText.setEnabled(true); - mActionEncryptTextText.setEnabled(true); - mActionEncryptFiles.setEnabled(true); - } - } - - mHasEncrypt = data.getInt(INDEX_UNIFIED_HAS_ENCRYPT) != 0; - - break; - } - } - - case LOADER_ID_USER_IDS: - mUserIdsAdapter.swapCursor(data); - break; - - } - setContentShown(true); - } - - /** - * This is called when the last Cursor provided to onLoadFinished() above is about to be closed. - * We need to make sure we are no longer using it. - */ - public void onLoaderReset(Loader loader) { - switch (loader.getId()) { - case LOADER_ID_USER_IDS: - mUserIdsAdapter.swapCursor(null); - break; - } - } - - private void encrypt(Uri dataUri, boolean text) { - // If there is no encryption key, don't bother. - if (!mHasEncrypt) { - Notify.showNotify(getActivity(), R.string.error_no_encrypt_subkey, Notify.Style.ERROR); - return; - } - try { - long keyId = new ProviderHelper(getActivity()) - .getCachedPublicKeyRing(dataUri) - .extractOrGetMasterKeyId(); - long[] encryptionKeyIds = new long[]{keyId}; - Intent intent; - if (text) { - intent = new Intent(getActivity(), EncryptTextActivity.class); - intent.setAction(EncryptTextActivity.ACTION_ENCRYPT_TEXT); - intent.putExtra(EncryptTextActivity.EXTRA_ENCRYPTION_KEY_IDS, encryptionKeyIds); - } else { - intent = new Intent(getActivity(), EncryptFilesActivity.class); - intent.setAction(EncryptFilesActivity.ACTION_ENCRYPT_DATA); - intent.putExtra(EncryptFilesActivity.EXTRA_ENCRYPTION_KEY_IDS, encryptionKeyIds); - } - // used instead of startActivity set actionbar based on callingPackage - startActivityForResult(intent, 0); - } catch (PgpKeyNotFoundException e) { - Log.e(Constants.TAG, "key not found!", e); - } - } - - private void updateFromKeyserver(Uri dataUri, ProviderHelper providerHelper) - throws ProviderHelper.NotFoundException { - byte[] blob = (byte[]) providerHelper.getGenericData( - KeychainContract.KeyRings.buildUnifiedKeyRingUri(dataUri), - KeychainContract.Keys.FINGERPRINT, ProviderHelper.FIELD_TYPE_BLOB); - String fingerprint = KeyFormattingUtils.convertFingerprintToHex(blob); - - Intent queryIntent = new Intent(getActivity(), ImportKeysActivity.class); - queryIntent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_RESULT); - queryIntent.putExtra(ImportKeysActivity.EXTRA_FINGERPRINT, fingerprint); - - startActivityForResult(queryIntent, 0); - } - - private void certify(Uri dataUri) { - long keyId = 0; - try { - keyId = new ProviderHelper(getActivity()) - .getCachedPublicKeyRing(dataUri) - .extractOrGetMasterKeyId(); - } catch (PgpKeyNotFoundException e) { - Log.e(Constants.TAG, "key not found!", e); - } - Intent certifyIntent = new Intent(getActivity(), CertifyKeyActivity.class); - certifyIntent.putExtra(CertifyKeyActivity.EXTRA_KEY_IDS, new long[]{keyId}); - startActivityForResult(certifyIntent, 0); - } - - private void editKey(Uri dataUri) { - Intent editIntent = new Intent(getActivity(), EditKeyActivity.class); - editIntent.setData(KeychainContract.KeyRingData.buildSecretKeyRingUri(dataUri)); - startActivityForResult(editIntent, 0); - } - -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyShareFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyShareFragment.java deleted file mode 100644 index 7c47cbd0d..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyShareFragment.java +++ /dev/null @@ -1,387 +0,0 @@ -/* - * Copyright (C) 2014 Dominik Schürmann - * - * 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 . - */ - -package org.sufficientlysecure.keychain.ui; - -import android.annotation.TargetApi; -import android.content.Intent; -import android.database.Cursor; -import android.graphics.Bitmap; -import android.graphics.PorterDuff; -import android.net.Uri; -import android.os.AsyncTask; -import android.os.Build; -import android.os.Bundle; -import android.provider.Settings; -import android.support.v4.app.LoaderManager; -import android.support.v4.content.CursorLoader; -import android.support.v4.content.Loader; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.view.animation.AlphaAnimation; -import android.widget.ImageButton; -import android.widget.ImageView; -import android.widget.TextView; - -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.compatibility.ClipboardReflection; -import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; -import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; -import org.sufficientlysecure.keychain.provider.KeychainContract; -import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; -import org.sufficientlysecure.keychain.provider.KeychainContract.Keys; -import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.ui.dialog.ShareNfcDialogFragment; -import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; -import org.sufficientlysecure.keychain.ui.util.Notify; -import org.sufficientlysecure.keychain.ui.util.QrCodeUtils; -import org.sufficientlysecure.keychain.util.Log; - -import java.io.IOException; - - -public class ViewKeyShareFragment extends LoaderFragment implements - LoaderManager.LoaderCallbacks { - - public static final String ARG_DATA_URI = "uri"; - - private TextView mFingerprint; - private ImageView mFingerprintQrCode; - private View mFingerprintShareButton; - private View mFingerprintClipboardButton; - private View mKeyShareButton; - private View mKeyClipboardButton; - private ImageButton mKeySafeSlingerButton; - private View mNfcHelpButton; - private View mNfcPrefsButton; - private View mKeyUploadButton; - - ProviderHelper mProviderHelper; - - private static final int LOADER_ID_UNIFIED = 0; - - private Uri mDataUri; - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup superContainer, Bundle savedInstanceState) { - View root = super.onCreateView(inflater, superContainer, savedInstanceState); - View view = inflater.inflate(R.layout.view_key_share_fragment, getContainer()); - - mProviderHelper = new ProviderHelper(ViewKeyShareFragment.this.getActivity()); - - mFingerprint = (TextView) view.findViewById(R.id.view_key_fingerprint); - mFingerprintQrCode = (ImageView) view.findViewById(R.id.view_key_fingerprint_qr_code_image); - mFingerprintShareButton = view.findViewById(R.id.view_key_action_fingerprint_share); - mFingerprintClipboardButton = view.findViewById(R.id.view_key_action_fingerprint_clipboard); - mKeyShareButton = view.findViewById(R.id.view_key_action_key_share); - mKeyClipboardButton = view.findViewById(R.id.view_key_action_key_clipboard); - mKeySafeSlingerButton = (ImageButton) view.findViewById(R.id.view_key_action_key_safeslinger); - mNfcHelpButton = view.findViewById(R.id.view_key_action_nfc_help); - mNfcPrefsButton = view.findViewById(R.id.view_key_action_nfc_prefs); - mKeyUploadButton = view.findViewById(R.id.view_key_action_upload); - - mKeySafeSlingerButton.setColorFilter(getResources().getColor(R.color.tertiary_text_light), - PorterDuff.Mode.SRC_IN); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { - mNfcPrefsButton.setVisibility(View.VISIBLE); - } else { - mNfcPrefsButton.setVisibility(View.GONE); - } - - mFingerprintQrCode.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - showQrCodeDialog(); - } - }); - - mFingerprintShareButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - share(mDataUri, mProviderHelper, true, false); - } - }); - mFingerprintClipboardButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - share(mDataUri, mProviderHelper, true, true); - } - }); - mKeyShareButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - share(mDataUri, mProviderHelper, false, false); - } - }); - mKeyClipboardButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - share(mDataUri, mProviderHelper, false, true); - } - }); - mKeySafeSlingerButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - startSafeSlinger(mDataUri); - } - }); - mNfcHelpButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - showNfcHelpDialog(); - } - }); - mNfcPrefsButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - showNfcPrefs(); - } - }); - mKeyUploadButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - uploadToKeyserver(); - } - }); - - return root; - } - - private void startSafeSlinger(Uri dataUri) { - long keyId = 0; - try { - keyId = new ProviderHelper(getActivity()) - .getCachedPublicKeyRing(dataUri) - .extractOrGetMasterKeyId(); - } catch (PgpKeyNotFoundException e) { - Log.e(Constants.TAG, "key not found!", e); - } - Intent safeSlingerIntent = new Intent(getActivity(), SafeSlingerActivity.class); - safeSlingerIntent.putExtra(SafeSlingerActivity.EXTRA_MASTER_KEY_ID, keyId); - startActivityForResult(safeSlingerIntent, 0); - } - - private void share(Uri dataUri, ProviderHelper providerHelper, boolean fingerprintOnly, - boolean toClipboard) { - try { - String content; - if (fingerprintOnly) { - byte[] data = (byte[]) providerHelper.getGenericData( - KeyRings.buildUnifiedKeyRingUri(dataUri), - Keys.FINGERPRINT, ProviderHelper.FIELD_TYPE_BLOB); - String fingerprint = KeyFormattingUtils.convertFingerprintToHex(data); - if (!toClipboard) { - content = Constants.FINGERPRINT_SCHEME + ":" + fingerprint; - } else { - content = fingerprint; - } - } else { - Uri uri = KeychainContract.KeyRingData.buildPublicKeyRingUri(dataUri); - // get public keyring as ascii armored string - content = providerHelper.getKeyRingAsArmoredString(uri); - } - - if (toClipboard) { - ClipboardReflection.copyToClipboard(getActivity(), content); - String message; - if (fingerprintOnly) { - message = getResources().getString(R.string.fingerprint_copied_to_clipboard); - } else { - message = getResources().getString(R.string.key_copied_to_clipboard); - } - Notify.showNotify(getActivity(), message, Notify.Style.OK); - } else { - // Android will fail with android.os.TransactionTooLargeException if key is too big - // see http://www.lonestarprod.com/?p=34 - if (content.length() >= 86389) { - Notify.showNotify(getActivity(), R.string.key_too_big_for_sharing, - Notify.Style.ERROR); - return; - } - - // let user choose application - Intent sendIntent = new Intent(Intent.ACTION_SEND); - sendIntent.putExtra(Intent.EXTRA_TEXT, content); - sendIntent.setType("text/plain"); - String title; - if (fingerprintOnly) { - title = getResources().getString(R.string.title_share_fingerprint_with); - } else { - title = getResources().getString(R.string.title_share_key); - } - startActivity(Intent.createChooser(sendIntent, title)); - } - } catch (PgpGeneralException | IOException e) { - Log.e(Constants.TAG, "error processing key!", e); - Notify.showNotify(getActivity(), R.string.error_key_processing, Notify.Style.ERROR); - } catch (ProviderHelper.NotFoundException e) { - Log.e(Constants.TAG, "key not found!", e); - Notify.showNotify(getActivity(), R.string.error_key_not_found, Notify.Style.ERROR); - } - } - - private void showQrCodeDialog() { - Intent qrCodeIntent = new Intent(getActivity(), QrCodeViewActivity.class); - qrCodeIntent.setData(mDataUri); - startActivity(qrCodeIntent); - } - - private void showNfcHelpDialog() { - ShareNfcDialogFragment dialog = ShareNfcDialogFragment.newInstance(); - dialog.show(getActivity().getSupportFragmentManager(), "shareNfcDialog"); - } - - @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) - private void showNfcPrefs() { - Intent intentSettings = new Intent( - Settings.ACTION_NFCSHARING_SETTINGS); - startActivity(intentSettings); - } - - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - - Uri dataUri = getArguments().getParcelable(ARG_DATA_URI); - if (dataUri == null) { - Log.e(Constants.TAG, "Data missing. Should be Uri of key!"); - getActivity().finish(); - return; - } - - loadData(dataUri); - } - - private void loadData(Uri dataUri) { - mDataUri = dataUri; - - Log.i(Constants.TAG, "mDataUri: " + mDataUri.toString()); - - // Prepare the loaders. Either re-connect with an existing ones, - // or start new ones. - getLoaderManager().initLoader(LOADER_ID_UNIFIED, null, this); - } - - static final String[] UNIFIED_PROJECTION = new String[]{ - KeyRings._ID, KeyRings.MASTER_KEY_ID, KeyRings.HAS_ANY_SECRET, - KeyRings.USER_ID, KeyRings.FINGERPRINT, - KeyRings.ALGORITHM, KeyRings.KEY_SIZE, KeyRings.CREATION, KeyRings.EXPIRY, - - }; - static final int INDEX_UNIFIED_MASTER_KEY_ID = 1; - static final int INDEX_UNIFIED_HAS_ANY_SECRET = 2; - static final int INDEX_UNIFIED_USER_ID = 3; - static final int INDEX_UNIFIED_FINGERPRINT = 4; - static final int INDEX_UNIFIED_ALGORITHM = 5; - static final int INDEX_UNIFIED_KEY_SIZE = 6; - static final int INDEX_UNIFIED_CREATION = 7; - static final int INDEX_UNIFIED_EXPIRY = 8; - - public Loader onCreateLoader(int id, Bundle args) { - setContentShown(false); - switch (id) { - case LOADER_ID_UNIFIED: { - Uri baseUri = KeyRings.buildUnifiedKeyRingUri(mDataUri); - return new CursorLoader(getActivity(), baseUri, UNIFIED_PROJECTION, null, null, null); - } - - default: - return null; - } - } - - public void onLoadFinished(Loader loader, Cursor data) { - /* TODO better error handling? May cause problems when a key is deleted, - * because the notification triggers faster than the activity closes. - */ - // Avoid NullPointerExceptions... - if (data.getCount() == 0) { - return; - } - // Swap the new cursor in. (The framework will take care of closing the - // old cursor once we return.) - switch (loader.getId()) { - case LOADER_ID_UNIFIED: { - if (data.moveToFirst()) { - - byte[] fingerprintBlob = data.getBlob(INDEX_UNIFIED_FINGERPRINT); - String fingerprint = KeyFormattingUtils.convertFingerprintToHex(fingerprintBlob); - mFingerprint.setText(KeyFormattingUtils.colorizeFingerprint(fingerprint)); - - loadQrCode(fingerprint); - - break; - } - } - - } - setContentShown(true); - } - - /** - * This is called when the last Cursor provided to onLoadFinished() above is about to be closed. - * We need to make sure we are no longer using it. - */ - public void onLoaderReset(Loader loader) { - } - - /** - * Load QR Code asynchronously and with a fade in animation - * - * @param fingerprint - */ - private void loadQrCode(final String fingerprint) { - AsyncTask loadTask = - new AsyncTask() { - protected Bitmap doInBackground(Void... unused) { - String qrCodeContent = Constants.FINGERPRINT_SCHEME + ":" + fingerprint; - // render with minimal size - return QrCodeUtils.getQRCodeBitmap(qrCodeContent, 0); - } - - protected void onPostExecute(Bitmap qrCode) { - // only change view, if fragment is attached to activity - if (ViewKeyShareFragment.this.isAdded()) { - - // scale the image up to our actual size. we do this in code rather - // than let the ImageView do this because we don't require filtering. - Bitmap scaled = Bitmap.createScaledBitmap(qrCode, - mFingerprintQrCode.getHeight(), mFingerprintQrCode.getHeight(), - false); - mFingerprintQrCode.setImageBitmap(scaled); - - // simple fade-in animation - AlphaAnimation anim = new AlphaAnimation(0.0f, 1.0f); - anim.setDuration(200); - mFingerprintQrCode.startAnimation(anim); - } - } - }; - - loadTask.execute(); - } - - private void uploadToKeyserver() { - Intent uploadIntent = new Intent(getActivity(), UploadKeyActivity.class); - uploadIntent.setData(mDataUri); - startActivityForResult(uploadIntent, 0); - } - -} -- cgit v1.2.3 From 17a6003eddff3fd52b4b2ac5ee553e3f70315d5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Tue, 24 Feb 2015 11:25:19 +0100 Subject: Remove tabs in view key --- .../keychain/ui/ViewKeyActivity.java | 50 +- .../keychain/ui/ViewKeyAdvActivity.java | 4 +- .../keychain/ui/ViewKeyAdvCertsFragment.java | 4 +- .../keychain/ui/ViewKeyAdvKeysFragment.java | 125 ----- .../keychain/ui/ViewKeyAdvMainFragment.java | 2 +- .../keychain/ui/ViewKeyAdvSubkeysFragment.java | 125 +++++ .../keychain/ui/ViewKeyFragment.java | 615 +++++++++++++++++++++ .../keychain/ui/adapter/SubkeysAdapter.java | 2 +- .../keychain/ui/adapter/SubkeysAddedAdapter.java | 2 +- .../keychain/ui/adapter/UserIdsAdapter.java | 2 +- .../keychain/ui/adapter/UserIdsAddedAdapter.java | 2 +- 11 files changed, 766 insertions(+), 167 deletions(-) delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvKeysFragment.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvSubkeysFragment.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyFragment.java (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java index f45a29a96..18a63f5ad 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java @@ -72,15 +72,6 @@ public class ViewKeyActivity extends BaseActivity implements protected Uri mDataUri; - public static final String EXTRA_SELECTED_TAB = "selected_tab"; - public static final int TAB_MAIN = 0; - public static final int TAB_SHARE = 1; - - // view - private ViewPager mViewPager; - private PagerSlidingTabStrip mSlidingTabLayout; - private PagerTabStripAdapter mTabsAdapter; - private LinearLayout mStatusLayout; private TextView mStatusText; private ImageView mStatusImage; @@ -113,14 +104,8 @@ public class ViewKeyActivity extends BaseActivity implements mStatusImage = (ImageView) findViewById(R.id.view_key_status_image); mStatusDivider = findViewById(R.id.view_key_status_divider); - mViewPager = (ViewPager) findViewById(R.id.view_key_pager); - mSlidingTabLayout = (PagerSlidingTabStrip) findViewById(R.id.view_key_sliding_tab_layout); - int switchToTab = TAB_MAIN; Intent intent = getIntent(); - if (intent.getExtras() != null && intent.getExtras().containsKey(EXTRA_SELECTED_TAB)) { - switchToTab = intent.getExtras().getInt(EXTRA_SELECTED_TAB); - } mDataUri = getIntent().getData(); if (mDataUri == null) { @@ -146,10 +131,7 @@ public class ViewKeyActivity extends BaseActivity implements initNfc(mDataUri); - initTabs(mDataUri); - - // switch to tab selected by extra - mViewPager.setCurrentItem(switchToTab); + startFragment(savedInstanceState, mDataUri); } @Override @@ -157,22 +139,24 @@ public class ViewKeyActivity extends BaseActivity implements setContentView(R.layout.view_key_activity); } - private void initTabs(Uri dataUri) { - mTabsAdapter = new PagerTabStripAdapter(this); - mViewPager.setAdapter(mTabsAdapter); - - Bundle mainBundle = new Bundle(); - mainBundle.putParcelable(ViewKeyAdvMainFragment.ARG_DATA_URI, dataUri); - mTabsAdapter.addTab(ViewKeyAdvMainFragment.class, - mainBundle, getString(R.string.key_view_tab_main)); + private void startFragment(Bundle savedInstanceState, Uri dataUri) { + // However, if we're being restored from a previous state, + // then we don't need to do anything and should return or else + // we could end up with overlapping fragments. + if (savedInstanceState != null) { + return; + } - Bundle shareBundle = new Bundle(); - shareBundle.putParcelable(ViewKeyAdvMainFragment.ARG_DATA_URI, dataUri); - mTabsAdapter.addTab(ViewKeyAdvShareFragment.class, - shareBundle, getString(R.string.key_view_tab_share)); + // Create an instance of the fragment + ViewKeyFragment frag = ViewKeyFragment.newInstance(dataUri); - // update layout after operations - mSlidingTabLayout.setViewPager(mViewPager); + // Add the fragment to the 'fragment_container' FrameLayout + // NOTE: We use commitAllowingStateLoss() to prevent weird crashes! + getSupportFragmentManager().beginTransaction() + .replace(R.id.view_key_fragment, frag) + .commitAllowingStateLoss(); + // do it immediately! + getSupportFragmentManager().executePendingTransactions(); } @Override diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvActivity.java index 6a43845d6..840dea471 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvActivity.java @@ -134,8 +134,8 @@ public class ViewKeyAdvActivity extends BaseActivity implements shareBundle, getString(R.string.key_view_tab_share)); Bundle keysBundle = new Bundle(); - keysBundle.putParcelable(ViewKeyAdvKeysFragment.ARG_DATA_URI, dataUri); - mTabsAdapter.addTab(ViewKeyAdvKeysFragment.class, + keysBundle.putParcelable(ViewKeyAdvSubkeysFragment.ARG_DATA_URI, dataUri); + mTabsAdapter.addTab(ViewKeyAdvSubkeysFragment.class, keysBundle, getString(R.string.key_view_tab_keys)); Bundle certsBundle = new Bundle(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvCertsFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvCertsFragment.java index 83daa541d..90d7a400f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvCertsFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvCertsFragment.java @@ -271,7 +271,7 @@ public class ViewKeyAdvCertsFragment extends LoaderFragment implements @Override public View newView(Context context, Cursor cursor, ViewGroup parent) { - return mInflater.inflate(R.layout.view_key_certs_item, parent, false); + return mInflater.inflate(R.layout.view_key_adv_certs_item, parent, false); } /** @@ -286,7 +286,7 @@ public class ViewKeyAdvCertsFragment extends LoaderFragment implements HeaderViewHolder holder; if (convertView == null) { holder = new HeaderViewHolder(); - convertView = mInflater.inflate(R.layout.view_key_certs_header, parent, false); + convertView = mInflater.inflate(R.layout.view_key_adv_certs_header, parent, false); holder.text = (TextView) convertView.findViewById(R.id.stickylist_header_text); holder.count = (TextView) convertView.findViewById(R.id.certs_num); convertView.setTag(holder); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvKeysFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvKeysFragment.java deleted file mode 100644 index 548e249b6..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvKeysFragment.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (C) 2014-2015 Dominik Schürmann - * - * 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 . - */ - -package org.sufficientlysecure.keychain.ui; - -import android.database.Cursor; -import android.net.Uri; -import android.os.Bundle; -import android.support.v4.app.LoaderManager; -import android.support.v4.content.CursorLoader; -import android.support.v4.content.Loader; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ListView; - -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.provider.KeychainContract; -import org.sufficientlysecure.keychain.ui.adapter.SubkeysAdapter; -import org.sufficientlysecure.keychain.util.Log; - -public class ViewKeyAdvKeysFragment extends LoaderFragment implements - LoaderManager.LoaderCallbacks { - - public static final String ARG_DATA_URI = "data_uri"; - - private ListView mSubkeysList; - private SubkeysAdapter mSubkeysAdapter; - - private Uri mDataUriSubkeys; - - /** - * Creates new instance of this fragment - */ - public static ViewKeyAdvKeysFragment newInstance(Uri dataUri) { - ViewKeyAdvKeysFragment frag = new ViewKeyAdvKeysFragment(); - - Bundle args = new Bundle(); - args.putParcelable(ARG_DATA_URI, dataUri); - - frag.setArguments(args); - return frag; - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup superContainer, Bundle savedInstanceState) { - View root = super.onCreateView(inflater, superContainer, savedInstanceState); - View view = inflater.inflate(R.layout.view_key_adv_subkeys_fragment, getContainer()); - - mSubkeysList = (ListView) view.findViewById(R.id.keys); - - return root; - } - - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - - Uri dataUri = getArguments().getParcelable(ARG_DATA_URI); - if (dataUri == null) { - Log.e(Constants.TAG, "Data missing. Should be Uri of key!"); - getActivity().finish(); - return; - } - - loadData(dataUri); - } - - private void loadData(Uri dataUri) { - mDataUriSubkeys = KeychainContract.Keys.buildKeysUri(dataUri); - - // Create an empty adapter we will use to display the loaded data. - mSubkeysAdapter = new SubkeysAdapter(getActivity(), null, 0); - mSubkeysList.setAdapter(mSubkeysAdapter); - - // Prepare the loaders. Either re-connect with an existing ones, - // or start new ones. - getLoaderManager().initLoader(0, null, this); - } - - public Loader onCreateLoader(int id, Bundle args) { - setContentShown(false); - - return new CursorLoader(getActivity(), mDataUriSubkeys, - SubkeysAdapter.SUBKEYS_PROJECTION, null, null, null); - } - - public void onLoadFinished(Loader loader, Cursor data) { - // Avoid NullPointerExceptions, if we get an empty result set. - if (data.getCount() == 0) { - return; - } - - // Swap the new cursor in. (The framework will take care of closing the - // old cursor once we return.) - mSubkeysAdapter.swapCursor(data); - - // TODO: maybe show not before both are loaded! - setContentShown(true); - } - - /** - * This is called when the last Cursor provided to onLoadFinished() above is about to be closed. - * We need to make sure we are no longer using it. - */ - public void onLoaderReset(Loader loader) { - mSubkeysAdapter.swapCursor(null); - } - -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvMainFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvMainFragment.java index 8bab5e3bf..abed59aa9 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvMainFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvMainFragment.java @@ -80,7 +80,7 @@ public class ViewKeyAdvMainFragment extends LoaderFragment implements @Override public View onCreateView(LayoutInflater inflater, ViewGroup superContainer, Bundle savedInstanceState) { View root = super.onCreateView(inflater, superContainer, savedInstanceState); - View view = inflater.inflate(R.layout.view_key_main_fragment, getContainer()); + View view = inflater.inflate(R.layout.view_key_adv_main_fragment, getContainer()); mUserIds = (ListView) view.findViewById(R.id.view_key_user_ids); mActionEdit = view.findViewById(R.id.view_key_action_edit); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvSubkeysFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvSubkeysFragment.java new file mode 100644 index 000000000..bd00c6780 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvSubkeysFragment.java @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2014-2015 Dominik Schürmann + * + * 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 . + */ + +package org.sufficientlysecure.keychain.ui; + +import android.database.Cursor; +import android.net.Uri; +import android.os.Bundle; +import android.support.v4.app.LoaderManager; +import android.support.v4.content.CursorLoader; +import android.support.v4.content.Loader; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ListView; + +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.provider.KeychainContract; +import org.sufficientlysecure.keychain.ui.adapter.SubkeysAdapter; +import org.sufficientlysecure.keychain.util.Log; + +public class ViewKeyAdvSubkeysFragment extends LoaderFragment implements + LoaderManager.LoaderCallbacks { + + public static final String ARG_DATA_URI = "data_uri"; + + private ListView mSubkeysList; + private SubkeysAdapter mSubkeysAdapter; + + private Uri mDataUriSubkeys; + + /** + * Creates new instance of this fragment + */ + public static ViewKeyAdvSubkeysFragment newInstance(Uri dataUri) { + ViewKeyAdvSubkeysFragment frag = new ViewKeyAdvSubkeysFragment(); + + Bundle args = new Bundle(); + args.putParcelable(ARG_DATA_URI, dataUri); + + frag.setArguments(args); + return frag; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup superContainer, Bundle savedInstanceState) { + View root = super.onCreateView(inflater, superContainer, savedInstanceState); + View view = inflater.inflate(R.layout.view_key_adv_subkeys_fragment, getContainer()); + + mSubkeysList = (ListView) view.findViewById(R.id.keys); + + return root; + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + Uri dataUri = getArguments().getParcelable(ARG_DATA_URI); + if (dataUri == null) { + Log.e(Constants.TAG, "Data missing. Should be Uri of key!"); + getActivity().finish(); + return; + } + + loadData(dataUri); + } + + private void loadData(Uri dataUri) { + mDataUriSubkeys = KeychainContract.Keys.buildKeysUri(dataUri); + + // Create an empty adapter we will use to display the loaded data. + mSubkeysAdapter = new SubkeysAdapter(getActivity(), null, 0); + mSubkeysList.setAdapter(mSubkeysAdapter); + + // Prepare the loaders. Either re-connect with an existing ones, + // or start new ones. + getLoaderManager().initLoader(0, null, this); + } + + public Loader onCreateLoader(int id, Bundle args) { + setContentShown(false); + + return new CursorLoader(getActivity(), mDataUriSubkeys, + SubkeysAdapter.SUBKEYS_PROJECTION, null, null, null); + } + + public void onLoadFinished(Loader loader, Cursor data) { + // Avoid NullPointerExceptions, if we get an empty result set. + if (data.getCount() == 0) { + return; + } + + // Swap the new cursor in. (The framework will take care of closing the + // old cursor once we return.) + mSubkeysAdapter.swapCursor(data); + + // TODO: maybe show not before both are loaded! + setContentShown(true); + } + + /** + * This is called when the last Cursor provided to onLoadFinished() above is about to be closed. + * We need to make sure we are no longer using it. + */ + public void onLoaderReset(Loader loader) { + mSubkeysAdapter.swapCursor(null); + } + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyFragment.java new file mode 100644 index 000000000..9ae656b2d --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyFragment.java @@ -0,0 +1,615 @@ +/* + * Copyright (C) 2014 Dominik Schürmann + * Copyright (C) 2014 Vincent Breitmoser + * + * 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 . + */ + +package org.sufficientlysecure.keychain.ui; + +import android.annotation.TargetApi; +import android.content.Intent; +import android.database.Cursor; +import android.graphics.Bitmap; +import android.graphics.PorterDuff; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Build; +import android.os.Bundle; +import android.provider.Settings; +import android.support.v4.app.LoaderManager; +import android.support.v4.content.CursorLoader; +import android.support.v4.content.Loader; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.AlphaAnimation; +import android.widget.AdapterView; +import android.widget.ImageButton; +import android.widget.ImageView; +import android.widget.ListView; +import android.widget.TextView; + +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.compatibility.ClipboardReflection; +import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround; +import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; +import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; +import org.sufficientlysecure.keychain.provider.KeychainContract; +import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; +import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets; +import org.sufficientlysecure.keychain.provider.ProviderHelper; +import org.sufficientlysecure.keychain.provider.ProviderHelper.NotFoundException; +import org.sufficientlysecure.keychain.ui.adapter.UserIdsAdapter; +import org.sufficientlysecure.keychain.ui.dialog.ShareNfcDialogFragment; +import org.sufficientlysecure.keychain.ui.dialog.UserIdInfoDialogFragment; +import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; +import org.sufficientlysecure.keychain.ui.util.Notify; +import org.sufficientlysecure.keychain.ui.util.QrCodeUtils; +import org.sufficientlysecure.keychain.util.Log; + +import java.io.IOException; +import java.util.Date; + +public class ViewKeyFragment extends LoaderFragment implements + LoaderManager.LoaderCallbacks { + + public static final String ARG_DATA_URI = "uri"; + + private View mActionEdit; + private View mActionEditDivider; + private View mActionEncryptFiles; + private View mActionEncryptText; + private View mActionEncryptTextText; + private View mActionCertify; + private View mActionCertifyText; + private ImageView mActionCertifyImage; + private View mActionUpdate; + + private TextView mFingerprint; + private ImageView mFingerprintQrCode; + private View mFingerprintShareButton; + private View mFingerprintClipboardButton; + private View mKeyShareButton; + private View mKeyClipboardButton; + private ImageButton mKeySafeSlingerButton; + private View mNfcHelpButton; + private View mNfcPrefsButton; + private View mKeyUploadButton; + private ListView mUserIds; + + private static final int LOADER_ID_UNIFIED = 0; + private static final int LOADER_ID_USER_IDS = 1; + + // conservative attitude + private boolean mHasEncrypt = true; + + private UserIdsAdapter mUserIdsAdapter; + + private Uri mDataUri; + + ProviderHelper mProviderHelper; + + /** + * Creates new instance of this fragment + */ + public static ViewKeyFragment newInstance(Uri dataUri) { + ViewKeyFragment frag = new ViewKeyFragment(); + Bundle args = new Bundle(); + args.putParcelable(ARG_DATA_URI, dataUri); + + frag.setArguments(args); + + return frag; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup superContainer, Bundle savedInstanceState) { + View root = super.onCreateView(inflater, superContainer, savedInstanceState); + View view = inflater.inflate(R.layout.view_key_fragment, getContainer()); + + mProviderHelper = new ProviderHelper(getActivity()); + + mUserIds = (ListView) view.findViewById(R.id.view_key_user_ids); + mActionEdit = view.findViewById(R.id.view_key_action_edit); + mActionEditDivider = view.findViewById(R.id.view_key_action_edit_divider); + mActionEncryptText = view.findViewById(R.id.view_key_action_encrypt_text); + mActionEncryptTextText = view.findViewById(R.id.view_key_action_encrypt_text_text); + mActionEncryptFiles = view.findViewById(R.id.view_key_action_encrypt_files); + mActionCertify = view.findViewById(R.id.view_key_action_certify); + mActionCertifyText = view.findViewById(R.id.view_key_action_certify_text); + mActionCertifyImage = (ImageView) view.findViewById(R.id.view_key_action_certify_image); + // make certify image gray, like action icons + mActionCertifyImage.setColorFilter(getResources().getColor(R.color.tertiary_text_light), + PorterDuff.Mode.SRC_IN); + mActionUpdate = view.findViewById(R.id.view_key_action_update); + + mUserIds.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + showUserIdInfo(position); + } + }); + + mFingerprint = (TextView) view.findViewById(R.id.view_key_fingerprint); + mFingerprintQrCode = (ImageView) view.findViewById(R.id.view_key_fingerprint_qr_code_image); + mFingerprintShareButton = view.findViewById(R.id.view_key_action_fingerprint_share); + mFingerprintClipboardButton = view.findViewById(R.id.view_key_action_fingerprint_clipboard); + mKeyShareButton = view.findViewById(R.id.view_key_action_key_share); + mKeyClipboardButton = view.findViewById(R.id.view_key_action_key_clipboard); + mKeySafeSlingerButton = (ImageButton) view.findViewById(R.id.view_key_action_key_safeslinger); + mNfcHelpButton = view.findViewById(R.id.view_key_action_nfc_help); + mNfcPrefsButton = view.findViewById(R.id.view_key_action_nfc_prefs); + mKeyUploadButton = view.findViewById(R.id.view_key_action_upload); + + mKeySafeSlingerButton.setColorFilter(getResources().getColor(R.color.tertiary_text_light), + PorterDuff.Mode.SRC_IN); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { + mNfcPrefsButton.setVisibility(View.VISIBLE); + } else { + mNfcPrefsButton.setVisibility(View.GONE); + } + + mFingerprintQrCode.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + showQrCodeDialog(); + } + }); + + mFingerprintShareButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + share(mDataUri, mProviderHelper, true, false); + } + }); + mFingerprintClipboardButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + share(mDataUri, mProviderHelper, true, true); + } + }); + mKeyShareButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + share(mDataUri, mProviderHelper, false, false); + } + }); + mKeyClipboardButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + share(mDataUri, mProviderHelper, false, true); + } + }); + mKeySafeSlingerButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + startSafeSlinger(mDataUri); + } + }); + mNfcHelpButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + showNfcHelpDialog(); + } + }); + mNfcPrefsButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + showNfcPrefs(); + } + }); + mKeyUploadButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + uploadToKeyserver(); + } + }); + + + return root; + } + + private void startSafeSlinger(Uri dataUri) { + long keyId = 0; + try { + keyId = new ProviderHelper(getActivity()) + .getCachedPublicKeyRing(dataUri) + .extractOrGetMasterKeyId(); + } catch (PgpKeyNotFoundException e) { + Log.e(Constants.TAG, "key not found!", e); + } + Intent safeSlingerIntent = new Intent(getActivity(), SafeSlingerActivity.class); + safeSlingerIntent.putExtra(SafeSlingerActivity.EXTRA_MASTER_KEY_ID, keyId); + startActivityForResult(safeSlingerIntent, 0); + } + + private void share(Uri dataUri, ProviderHelper providerHelper, boolean fingerprintOnly, + boolean toClipboard) { + try { + String content; + if (fingerprintOnly) { + byte[] data = (byte[]) providerHelper.getGenericData( + KeyRings.buildUnifiedKeyRingUri(dataUri), + KeychainContract.Keys.FINGERPRINT, ProviderHelper.FIELD_TYPE_BLOB); + String fingerprint = KeyFormattingUtils.convertFingerprintToHex(data); + if (!toClipboard) { + content = Constants.FINGERPRINT_SCHEME + ":" + fingerprint; + } else { + content = fingerprint; + } + } else { + Uri uri = KeychainContract.KeyRingData.buildPublicKeyRingUri(dataUri); + // get public keyring as ascii armored string + content = providerHelper.getKeyRingAsArmoredString(uri); + } + + if (toClipboard) { + ClipboardReflection.copyToClipboard(getActivity(), content); + String message; + if (fingerprintOnly) { + message = getResources().getString(R.string.fingerprint_copied_to_clipboard); + } else { + message = getResources().getString(R.string.key_copied_to_clipboard); + } + Notify.showNotify(getActivity(), message, Notify.Style.OK); + } else { + // Android will fail with android.os.TransactionTooLargeException if key is too big + // see http://www.lonestarprod.com/?p=34 + if (content.length() >= 86389) { + Notify.showNotify(getActivity(), R.string.key_too_big_for_sharing, + Notify.Style.ERROR); + return; + } + + // let user choose application + Intent sendIntent = new Intent(Intent.ACTION_SEND); + sendIntent.putExtra(Intent.EXTRA_TEXT, content); + sendIntent.setType("text/plain"); + String title; + if (fingerprintOnly) { + title = getResources().getString(R.string.title_share_fingerprint_with); + } else { + title = getResources().getString(R.string.title_share_key); + } + startActivity(Intent.createChooser(sendIntent, title)); + } + } catch (PgpGeneralException | IOException e) { + Log.e(Constants.TAG, "error processing key!", e); + Notify.showNotify(getActivity(), R.string.error_key_processing, Notify.Style.ERROR); + } catch (ProviderHelper.NotFoundException e) { + Log.e(Constants.TAG, "key not found!", e); + Notify.showNotify(getActivity(), R.string.error_key_not_found, Notify.Style.ERROR); + } + } + + private void showQrCodeDialog() { + Intent qrCodeIntent = new Intent(getActivity(), QrCodeViewActivity.class); + qrCodeIntent.setData(mDataUri); + startActivity(qrCodeIntent); + } + + private void showNfcHelpDialog() { + ShareNfcDialogFragment dialog = ShareNfcDialogFragment.newInstance(); + dialog.show(getActivity().getSupportFragmentManager(), "shareNfcDialog"); + } + + @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) + private void showNfcPrefs() { + Intent intentSettings = new Intent( + Settings.ACTION_NFCSHARING_SETTINGS); + startActivity(intentSettings); + } + + private void showUserIdInfo(final int position) { + final boolean isRevoked = mUserIdsAdapter.getIsRevoked(position); + final int isVerified = mUserIdsAdapter.getIsVerified(position); + + DialogFragmentWorkaround.INTERFACE.runnableRunDelayed(new Runnable() { + public void run() { + UserIdInfoDialogFragment dialogFragment = + UserIdInfoDialogFragment.newInstance(isRevoked, isVerified); + + dialogFragment.show(getActivity().getSupportFragmentManager(), "userIdInfoDialog"); + } + }); + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + Uri dataUri = getArguments().getParcelable(ARG_DATA_URI); + if (dataUri == null) { + Log.e(Constants.TAG, "Data missing. Should be Uri of key!"); + getActivity().finish(); + return; + } + + loadData(dataUri); + } + + private void loadData(Uri dataUri) { + mDataUri = dataUri; + + Log.i(Constants.TAG, "mDataUri: " + mDataUri.toString()); + + mActionEncryptFiles.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + encrypt(mDataUri, false); + } + }); + mActionEncryptText.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + encrypt(mDataUri, true); + } + }); + mActionCertify.setOnClickListener(new View.OnClickListener() { + public void onClick(View view) { + certify(mDataUri); + } + }); + mActionEdit.setOnClickListener(new View.OnClickListener() { + public void onClick(View view) { + editKey(mDataUri); + } + }); + mActionUpdate.setOnClickListener(new View.OnClickListener() { + public void onClick(View view) { + try { + updateFromKeyserver(mDataUri, new ProviderHelper(getActivity())); + } catch (NotFoundException e) { + Notify.showNotify(getActivity(), R.string.error_key_not_found, Notify.Style.ERROR); + } + } + }); + + mUserIdsAdapter = new UserIdsAdapter(getActivity(), null, 0); + mUserIds.setAdapter(mUserIdsAdapter); + + // Prepare the loaders. Either re-connect with an existing ones, + // or start new ones. + getLoaderManager().initLoader(LOADER_ID_UNIFIED, null, this); + getLoaderManager().initLoader(LOADER_ID_USER_IDS, null, this); + } + + static final String[] UNIFIED_PROJECTION = new String[]{ + KeyRings._ID, KeyRings.MASTER_KEY_ID, KeyRings.HAS_ANY_SECRET, + KeyRings.USER_ID, KeyRings.FINGERPRINT, + KeyRings.ALGORITHM, KeyRings.KEY_SIZE, KeyRings.CREATION, KeyRings.EXPIRY, + KeyRings.IS_REVOKED, KeyRings.HAS_ENCRYPT, + + }; + static final int INDEX_UNIFIED_MASTER_KEY_ID = 1; + static final int INDEX_UNIFIED_HAS_ANY_SECRET = 2; + static final int INDEX_UNIFIED_USER_ID = 3; + static final int INDEX_UNIFIED_FINGERPRINT = 4; + static final int INDEX_UNIFIED_ALGORITHM = 5; + static final int INDEX_UNIFIED_KEY_SIZE = 6; + static final int INDEX_UNIFIED_CREATION = 7; + static final int INDEX_UNIFIED_EXPIRY = 8; + static final int INDEX_UNIFIED_IS_REVOKED = 9; + static final int INDEX_UNIFIED_HAS_ENCRYPT = 10; + + public Loader onCreateLoader(int id, Bundle args) { + setContentShown(false); + + switch (id) { + case LOADER_ID_UNIFIED: { + Uri baseUri = KeyRings.buildUnifiedKeyRingUri(mDataUri); + return new CursorLoader(getActivity(), baseUri, UNIFIED_PROJECTION, null, null, null); + } + case LOADER_ID_USER_IDS: { + Uri baseUri = UserPackets.buildUserIdsUri(mDataUri); + return new CursorLoader(getActivity(), baseUri, + UserIdsAdapter.USER_IDS_PROJECTION, null, null, null); + } + + default: + return null; + } + } + + public void onLoadFinished(Loader loader, Cursor data) { + /* TODO better error handling? May cause problems when a key is deleted, + * because the notification triggers faster than the activity closes. + */ + // Avoid NullPointerExceptions... + if (data.getCount() == 0) { + return; + } + // Swap the new cursor in. (The framework will take care of closing the + // old cursor once we return.) + switch (loader.getId()) { + case LOADER_ID_UNIFIED: { + if (data.moveToFirst()) { + byte[] fingerprintBlob = data.getBlob(INDEX_UNIFIED_FINGERPRINT); + String fingerprint = KeyFormattingUtils.convertFingerprintToHex(fingerprintBlob); + mFingerprint.setText(KeyFormattingUtils.colorizeFingerprint(fingerprint)); + + loadQrCode(fingerprint); + + if (data.getInt(INDEX_UNIFIED_HAS_ANY_SECRET) != 0) { + // edit button + mActionEdit.setVisibility(View.VISIBLE); + mActionEditDivider.setVisibility(View.VISIBLE); + } else { + // edit button + mActionEdit.setVisibility(View.GONE); + mActionEditDivider.setVisibility(View.GONE); + } + + // If this key is revoked, it cannot be used for anything! + if (data.getInt(INDEX_UNIFIED_IS_REVOKED) != 0) { + mActionEdit.setEnabled(false); + mActionCertify.setEnabled(false); + mActionCertifyText.setEnabled(false); + mActionEncryptText.setEnabled(false); + mActionEncryptTextText.setEnabled(false); + mActionEncryptFiles.setEnabled(false); + } else { + mActionEdit.setEnabled(true); + + Date expiryDate = new Date(data.getLong(INDEX_UNIFIED_EXPIRY) * 1000); + if (!data.isNull(INDEX_UNIFIED_EXPIRY) && expiryDate.before(new Date())) { + mActionCertify.setEnabled(false); + mActionCertifyText.setEnabled(false); + mActionEncryptText.setEnabled(false); + mActionEncryptTextText.setEnabled(false); + mActionEncryptFiles.setEnabled(false); + } else { + mActionCertify.setEnabled(true); + mActionCertifyText.setEnabled(true); + mActionEncryptText.setEnabled(true); + mActionEncryptTextText.setEnabled(true); + mActionEncryptFiles.setEnabled(true); + } + } + + mHasEncrypt = data.getInt(INDEX_UNIFIED_HAS_ENCRYPT) != 0; + + break; + } + } + + case LOADER_ID_USER_IDS: + mUserIdsAdapter.swapCursor(data); + break; + + } + setContentShown(true); + } + + /** + * This is called when the last Cursor provided to onLoadFinished() above is about to be closed. + * We need to make sure we are no longer using it. + */ + public void onLoaderReset(Loader loader) { + switch (loader.getId()) { + case LOADER_ID_USER_IDS: + mUserIdsAdapter.swapCursor(null); + break; + } + } + + + /** + * Load QR Code asynchronously and with a fade in animation + * + * @param fingerprint + */ + private void loadQrCode(final String fingerprint) { + AsyncTask loadTask = + new AsyncTask() { + protected Bitmap doInBackground(Void... unused) { + String qrCodeContent = Constants.FINGERPRINT_SCHEME + ":" + fingerprint; + // render with minimal size + return QrCodeUtils.getQRCodeBitmap(qrCodeContent, 0); + } + + protected void onPostExecute(Bitmap qrCode) { + // only change view, if fragment is attached to activity + if (ViewKeyFragment.this.isAdded()) { + + // scale the image up to our actual size. we do this in code rather + // than let the ImageView do this because we don't require filtering. + Bitmap scaled = Bitmap.createScaledBitmap(qrCode, + mFingerprintQrCode.getHeight(), mFingerprintQrCode.getHeight(), + false); + mFingerprintQrCode.setImageBitmap(scaled); + + // simple fade-in animation + AlphaAnimation anim = new AlphaAnimation(0.0f, 1.0f); + anim.setDuration(200); + mFingerprintQrCode.startAnimation(anim); + } + } + }; + + loadTask.execute(); + } + + private void uploadToKeyserver() { + Intent uploadIntent = new Intent(getActivity(), UploadKeyActivity.class); + uploadIntent.setData(mDataUri); + startActivityForResult(uploadIntent, 0); + } + + private void encrypt(Uri dataUri, boolean text) { + // If there is no encryption key, don't bother. + if (!mHasEncrypt) { + Notify.showNotify(getActivity(), R.string.error_no_encrypt_subkey, Notify.Style.ERROR); + return; + } + try { + long keyId = new ProviderHelper(getActivity()) + .getCachedPublicKeyRing(dataUri) + .extractOrGetMasterKeyId(); + long[] encryptionKeyIds = new long[]{keyId}; + Intent intent; + if (text) { + intent = new Intent(getActivity(), EncryptTextActivity.class); + intent.setAction(EncryptTextActivity.ACTION_ENCRYPT_TEXT); + intent.putExtra(EncryptTextActivity.EXTRA_ENCRYPTION_KEY_IDS, encryptionKeyIds); + } else { + intent = new Intent(getActivity(), EncryptFilesActivity.class); + intent.setAction(EncryptFilesActivity.ACTION_ENCRYPT_DATA); + intent.putExtra(EncryptFilesActivity.EXTRA_ENCRYPTION_KEY_IDS, encryptionKeyIds); + } + // used instead of startActivity set actionbar based on callingPackage + startActivityForResult(intent, 0); + } catch (PgpKeyNotFoundException e) { + Log.e(Constants.TAG, "key not found!", e); + } + } + + private void updateFromKeyserver(Uri dataUri, ProviderHelper providerHelper) + throws NotFoundException { + byte[] blob = (byte[]) providerHelper.getGenericData( + KeyRings.buildUnifiedKeyRingUri(dataUri), + KeychainContract.Keys.FINGERPRINT, ProviderHelper.FIELD_TYPE_BLOB); + String fingerprint = KeyFormattingUtils.convertFingerprintToHex(blob); + + Intent queryIntent = new Intent(getActivity(), ImportKeysActivity.class); + queryIntent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_RESULT); + queryIntent.putExtra(ImportKeysActivity.EXTRA_FINGERPRINT, fingerprint); + + startActivityForResult(queryIntent, 0); + } + + private void certify(Uri dataUri) { + long keyId = 0; + try { + keyId = new ProviderHelper(getActivity()) + .getCachedPublicKeyRing(dataUri) + .extractOrGetMasterKeyId(); + } catch (PgpKeyNotFoundException e) { + Log.e(Constants.TAG, "key not found!", e); + } + Intent certifyIntent = new Intent(getActivity(), CertifyKeyActivity.class); + certifyIntent.putExtra(CertifyKeyActivity.EXTRA_KEY_IDS, new long[]{keyId}); + startActivityForResult(certifyIntent, 0); + } + + private void editKey(Uri dataUri) { + Intent editIntent = new Intent(getActivity(), EditKeyActivity.class); + editIntent.setData(KeychainContract.KeyRingData.buildSecretKeyRingUri(dataUri)); + startActivityForResult(editIntent, 0); + } + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java index c286218ed..a3bd4d470 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java @@ -301,7 +301,7 @@ public class SubkeysAdapter extends CursorAdapter { @Override public View newView(Context context, Cursor cursor, ViewGroup parent) { - View view = mInflater.inflate(R.layout.view_key_subkey_item, null); + View view = mInflater.inflate(R.layout.view_key_adv_subkey_item, null); if (mDefaultTextColor == null) { TextView keyId = (TextView) view.findViewById(R.id.subkey_item_key_id); mDefaultTextColor = keyId.getTextColors(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAddedAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAddedAdapter.java index abc1d8816..d2359a387 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAddedAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAddedAdapter.java @@ -68,7 +68,7 @@ public class SubkeysAddedAdapter extends ArrayAdapter { public View getView(final int position, View convertView, ViewGroup parent) { if (convertView == null) { // Not recycled, inflate a new view - convertView = mInflater.inflate(R.layout.view_key_user_id_item, null); + convertView = mInflater.inflate(R.layout.view_key_adv_user_id_item, null); final ViewHolder holder = new ViewHolder(); holder.vAddress = (TextView) convertView.findViewById(R.id.user_id_item_address); holder.vName = (TextView) convertView.findViewById(R.id.user_id_item_name); -- cgit v1.2.3 From 56d38dd68b7248dff54d56affce0af14e8e2e161 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Wed, 25 Feb 2015 02:35:09 +0100 Subject: First work on new key view toolbar --- .../keychain/ui/KeyListFragment.java | 4 +- .../keychain/ui/ViewKeyActivity.java | 151 +++++++++++++++------ .../keychain/ui/adapter/ImportKeysAdapter.java | 4 +- .../ui/adapter/SelectKeyCursorAdapter.java | 4 +- .../keychain/ui/adapter/UserIdsAdapter.java | 8 +- .../keychain/ui/util/KeyFormattingUtils.java | 48 ++++--- .../keychain/ui/widget/AspectRatioImageView.java | 138 +++++++++++++++++++ .../keychain/ui/widget/CertifyKeySpinner.java | 7 +- .../keychain/ui/widget/SignKeySpinner.java | 7 +- 9 files changed, 299 insertions(+), 72 deletions(-) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/AspectRatioImageView.java (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java index 55efd9bb0..f60ddcef6 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java @@ -778,13 +778,13 @@ public class KeyListFragment extends LoaderFragment // Note: order is important! if (isRevoked) { - KeyFormattingUtils.setStatusImage(getActivity(), h.mStatus, null, KeyFormattingUtils.STATE_REVOKED, true); + KeyFormattingUtils.setStatusImage(getActivity(), h.mStatus, null, KeyFormattingUtils.STATE_REVOKED, R.color.bg_gray); h.mStatus.setVisibility(View.VISIBLE); h.mSlinger.setVisibility(View.GONE); h.mMainUserId.setTextColor(context.getResources().getColor(R.color.bg_gray)); h.mMainUserIdRest.setTextColor(context.getResources().getColor(R.color.bg_gray)); } else if (isExpired) { - KeyFormattingUtils.setStatusImage(getActivity(), h.mStatus, null, KeyFormattingUtils.STATE_EXPIRED, true); + KeyFormattingUtils.setStatusImage(getActivity(), h.mStatus, null, KeyFormattingUtils.STATE_EXPIRED, R.color.bg_gray); h.mStatus.setVisibility(View.VISIBLE); h.mSlinger.setVisibility(View.GONE); h.mMainUserId.setTextColor(context.getResources().getColor(R.color.bg_gray)); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java index 18a63f5ad..8ef5d01aa 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java @@ -21,6 +21,7 @@ package org.sufficientlysecure.keychain.ui; import android.annotation.TargetApi; import android.content.Intent; import android.database.Cursor; +import android.graphics.Bitmap; import android.net.Uri; import android.nfc.NdefMessage; import android.nfc.NdefRecord; @@ -35,17 +36,20 @@ import android.provider.ContactsContract; import android.support.v4.app.LoaderManager; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; -import android.support.v4.view.ViewPager; import android.support.v7.app.ActionBar; +import android.support.v7.widget.Toolbar; +import android.view.Gravity; import android.view.Menu; import android.view.MenuItem; import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageButton; import android.widget.ImageView; -import android.widget.LinearLayout; +import android.widget.RelativeLayout; import android.widget.TextView; import android.widget.Toast; -import com.astuetz.PagerSlidingTabStrip; +import com.getbase.floatingactionbutton.FloatingActionButton; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; @@ -54,9 +58,9 @@ import org.sufficientlysecure.keychain.pgp.KeyRing; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; -import org.sufficientlysecure.keychain.ui.adapter.PagerTabStripAdapter; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.Notify; +import org.sufficientlysecure.keychain.ui.widget.AspectRatioImageView; import org.sufficientlysecure.keychain.util.ContactHelper; import org.sufficientlysecure.keychain.util.ExportHelper; import org.sufficientlysecure.keychain.util.Log; @@ -72,10 +76,16 @@ public class ViewKeyActivity extends BaseActivity implements protected Uri mDataUri; - private LinearLayout mStatusLayout; + private TextView mName; private TextView mStatusText; private ImageView mStatusImage; - private View mStatusDivider; + private RelativeLayout mBigToolbar; + + private ImageButton mActionEncryptFile; + private ImageButton mActionEncryptText; + private ImageButton mActionVerify; + private FloatingActionButton mFab; + private AspectRatioImageView mPhoto; // NFC private NfcAdapter mNfcAdapter; @@ -93,19 +103,18 @@ public class ViewKeyActivity extends BaseActivity implements mExportHelper = new ExportHelper(this); mProviderHelper = new ProviderHelper(this); - // let the actionbar look like Android's contact app - ActionBar actionBar = getSupportActionBar(); - actionBar.setDisplayHomeAsUpEnabled(true); - actionBar.setIcon(android.R.color.transparent); - actionBar.setHomeButtonEnabled(true); + setTitle(null); - mStatusLayout = (LinearLayout) findViewById(R.id.view_key_status_layout); - mStatusText = (TextView) findViewById(R.id.view_key_status_text); + mName = (TextView) findViewById(R.id.view_key_name); + mStatusText = (TextView) findViewById(R.id.view_key_status); mStatusImage = (ImageView) findViewById(R.id.view_key_status_image); - mStatusDivider = findViewById(R.id.view_key_status_divider); - + mBigToolbar = (RelativeLayout) findViewById(R.id.toolbar_big); - Intent intent = getIntent(); + mActionEncryptFile = (ImageButton) findViewById(R.id.view_key_action_encrypt_files); + mActionEncryptText = (ImageButton) findViewById(R.id.view_key_action_encrypt_text); + mActionVerify = (ImageButton) findViewById(R.id.view_key_action_verify); + mFab = (FloatingActionButton) findViewById(R.id.fab); + mPhoto = (AspectRatioImageView) findViewById(R.id.view_key_photo); mDataUri = getIntent().getData(); if (mDataUri == null) { @@ -329,25 +338,32 @@ public class ViewKeyActivity extends BaseActivity implements } }; - static final String[] UNIFIED_PROJECTION = new String[]{ + // These are the rows that we will retrieve. + static final String[] PROJECTION = new String[]{ KeychainContract.KeyRings._ID, KeychainContract.KeyRings.MASTER_KEY_ID, KeychainContract.KeyRings.USER_ID, KeychainContract.KeyRings.IS_REVOKED, KeychainContract.KeyRings.EXPIRY, - + KeychainContract.KeyRings.VERIFIED, + KeychainContract.KeyRings.HAS_ANY_SECRET, + KeychainContract.KeyRings.FINGERPRINT }; - static final int INDEX_UNIFIED_MASTER_KEY_ID = 1; - static final int INDEX_UNIFIED_USER_ID = 2; - static final int INDEX_UNIFIED_IS_REVOKED = 3; - static final int INDEX_UNIFIED_EXPIRY = 4; + + static final int INDEX_MASTER_KEY_ID = 1; + static final int INDEX_USER_ID = 2; + static final int INDEX_IS_REVOKED = 3; + static final int INDEX_EXPIRY = 4; + static final int INDEX_VERIFIED = 5; + static final int INDEX_HAS_ANY_SECRET = 6; + static final int INDEX_FINGERPRINT = 7; @Override public Loader onCreateLoader(int id, Bundle args) { switch (id) { case LOADER_ID_UNIFIED: { Uri baseUri = KeychainContract.KeyRings.buildUnifiedKeyRingUri(mDataUri); - return new CursorLoader(this, baseUri, UNIFIED_PROJECTION, null, null, null); + return new CursorLoader(this, baseUri, PROJECTION, null, null, null); } default: @@ -370,36 +386,91 @@ public class ViewKeyActivity extends BaseActivity implements case LOADER_ID_UNIFIED: { if (data.moveToFirst()) { // get name, email, and comment from USER_ID - String[] mainUserId = KeyRing.splitUserId(data.getString(INDEX_UNIFIED_USER_ID)); + String[] mainUserId = KeyRing.splitUserId(data.getString(INDEX_USER_ID)); if (mainUserId[0] != null) { - setTitle(mainUserId[0]); + mName.setText(mainUserId[0]); } else { - setTitle(R.string.user_id_no_name); + mName.setText(R.string.user_id_no_name); } - // get key id from MASTER_KEY_ID - long masterKeyId = data.getLong(INDEX_UNIFIED_MASTER_KEY_ID); - getSupportActionBar().setSubtitle(KeyFormattingUtils.beautifyKeyIdWithPrefix(this, masterKeyId)); + String fingerprint = KeyFormattingUtils.convertFingerprintToHex(data.getBlob(INDEX_FINGERPRINT)); - boolean isRevoked = data.getInt(INDEX_UNIFIED_IS_REVOKED) > 0; - boolean isExpired = !data.isNull(INDEX_UNIFIED_EXPIRY) - && new Date(data.getLong(INDEX_UNIFIED_EXPIRY) * 1000).before(new Date()); + boolean isSecret = data.getInt(INDEX_HAS_ANY_SECRET) != 0; + boolean isRevoked = data.getInt(INDEX_IS_REVOKED) > 0; + boolean isExpired = !data.isNull(INDEX_EXPIRY) + && new Date(data.getLong(INDEX_EXPIRY) * 1000).before(new Date()); + boolean isVerified = data.getInt(INDEX_VERIFIED) > 0; // Note: order is important + int color; if (isRevoked) { mStatusText.setText(R.string.view_key_revoked); - KeyFormattingUtils.setStatusImage(this, mStatusImage, mStatusText, KeyFormattingUtils.STATE_REVOKED); - mStatusDivider.setVisibility(View.VISIBLE); - mStatusLayout.setVisibility(View.VISIBLE); + mStatusImage.setVisibility(View.VISIBLE); + KeyFormattingUtils.setStatusImage(this, mStatusImage, mStatusText, KeyFormattingUtils.STATE_REVOKED, R.color.icons); + color = getResources().getColor(R.color.android_red_light); + + mActionEncryptFile.setVisibility(View.INVISIBLE); + mActionEncryptText.setVisibility(View.INVISIBLE); + mActionVerify.setVisibility(View.INVISIBLE); + mFab.setVisibility(View.INVISIBLE); } else if (isExpired) { mStatusText.setText(R.string.view_key_expired); - KeyFormattingUtils.setStatusImage(this, mStatusImage, mStatusText, KeyFormattingUtils.STATE_EXPIRED); - mStatusDivider.setVisibility(View.VISIBLE); - mStatusLayout.setVisibility(View.VISIBLE); + mStatusImage.setVisibility(View.VISIBLE); + KeyFormattingUtils.setStatusImage(this, mStatusImage, mStatusText, KeyFormattingUtils.STATE_EXPIRED, R.color.icons); + color = getResources().getColor(R.color.android_red_light); + + mActionEncryptFile.setVisibility(View.INVISIBLE); + mActionEncryptText.setVisibility(View.INVISIBLE); + mActionVerify.setVisibility(View.INVISIBLE); + mFab.setVisibility(View.INVISIBLE); + } else if (isSecret) { + mStatusText.setText(R.string.view_key_my_key); + mStatusImage.setVisibility(View.INVISIBLE); + color = getResources().getColor(R.color.primary); + + mActionEncryptFile.setVisibility(View.VISIBLE); + mActionEncryptText.setVisibility(View.VISIBLE); + mActionVerify.setVisibility(View.INVISIBLE); + mFab.setVisibility(View.INVISIBLE); // TODO } else { - mStatusDivider.setVisibility(View.GONE); - mStatusLayout.setVisibility(View.GONE); + mActionEncryptFile.setVisibility(View.VISIBLE); + mActionEncryptText.setVisibility(View.VISIBLE); + + if (isVerified) { + mStatusText.setText(R.string.view_key_verified); + mStatusImage.setVisibility(View.VISIBLE); + KeyFormattingUtils.setStatusImage(this, mStatusImage, mStatusText, KeyFormattingUtils.STATE_VERIFIED, R.color.icons); + color = getResources().getColor(R.color.primary); + + AsyncTask photoTask = + new AsyncTask() { + protected Bitmap doInBackground(String... fingerprint) { + return ContactHelper.photoFromFingerprint(getContentResolver(), fingerprint[0]); + } + + protected void onPostExecute(Bitmap photo) { + mPhoto.setImageBitmap(photo); + mPhoto.setVisibility(View.VISIBLE); + } + }; + + photoTask.execute(fingerprint); + + mActionVerify.setVisibility(View.INVISIBLE); + mFab.setVisibility(View.INVISIBLE); + } else { + mStatusText.setText(R.string.view_key_unverified); + mStatusImage.setVisibility(View.VISIBLE); + KeyFormattingUtils.setStatusImage(this, mStatusImage, mStatusText, KeyFormattingUtils.STATE_UNVERIFIED, R.color.icons); + color = getResources().getColor(R.color.android_orange_light); + + mActionVerify.setVisibility(View.VISIBLE); + mFab.setVisibility(View.VISIBLE); + } } + mToolbar.setBackgroundColor(color); + mStatusBar.setBackgroundColor(color); + mBigToolbar.setBackgroundColor(color); break; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java index 8e82dd7d0..598793233 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/ImportKeysAdapter.java @@ -175,9 +175,9 @@ public class ImportKeysAdapter extends ArrayAdapter { } if (entry.isRevoked()) { - KeyFormattingUtils.setStatusImage(getContext(), holder.status, null, KeyFormattingUtils.STATE_REVOKED, true); + KeyFormattingUtils.setStatusImage(getContext(), holder.status, null, KeyFormattingUtils.STATE_REVOKED, R.color.bg_gray); } else if (entry.isExpired()) { - KeyFormattingUtils.setStatusImage(getContext(), holder.status, null, KeyFormattingUtils.STATE_EXPIRED, true); + KeyFormattingUtils.setStatusImage(getContext(), holder.status, null, KeyFormattingUtils.STATE_EXPIRED, R.color.bg_gray); } if (entry.isRevoked() || entry.isExpired()) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SelectKeyCursorAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SelectKeyCursorAdapter.java index e90b57c1c..a836b35df 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SelectKeyCursorAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SelectKeyCursorAdapter.java @@ -133,11 +133,11 @@ abstract public class SelectKeyCursorAdapter extends CursorAdapter { boolean enabled; if (cursor.getInt(mIndexIsRevoked) != 0) { h.statusIcon.setVisibility(View.VISIBLE); - KeyFormattingUtils.setStatusImage(mContext, h.statusIcon, null, KeyFormattingUtils.STATE_REVOKED, true); + KeyFormattingUtils.setStatusImage(mContext, h.statusIcon, null, KeyFormattingUtils.STATE_REVOKED, R.color.bg_gray); enabled = false; } else if (cursor.getInt(mIndexIsExpiry) != 0) { h.statusIcon.setVisibility(View.VISIBLE); - KeyFormattingUtils.setStatusImage(mContext, h.statusIcon, null, KeyFormattingUtils.STATE_EXPIRED, true); + KeyFormattingUtils.setStatusImage(mContext, h.statusIcon, null, KeyFormattingUtils.STATE_EXPIRED, R.color.bg_gray); enabled = false; } else { h.statusIcon.setVisibility(View.GONE); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java index 6281bb8b3..8e86efebe 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java @@ -162,7 +162,7 @@ public class UserIdsAdapter extends CursorAdapter implements AdapterView.OnItemC if (isRevoked) { // set revocation icon (can this even be primary?) - KeyFormattingUtils.setStatusImage(mContext, vVerified, null, KeyFormattingUtils.STATE_REVOKED, true); + KeyFormattingUtils.setStatusImage(mContext, vVerified, null, KeyFormattingUtils.STATE_REVOKED, R.color.bg_gray); // disable revoked user ids vName.setEnabled(false); @@ -184,13 +184,13 @@ public class UserIdsAdapter extends CursorAdapter implements AdapterView.OnItemC int isVerified = cursor.getInt(INDEX_VERIFIED); switch (isVerified) { case Certs.VERIFIED_SECRET: - KeyFormattingUtils.setStatusImage(mContext, vVerified, null, KeyFormattingUtils.STATE_VERIFIED, false); + KeyFormattingUtils.setStatusImage(mContext, vVerified, null, KeyFormattingUtils.STATE_VERIFIED, KeyFormattingUtils.DEFAULT_COLOR); break; case Certs.VERIFIED_SELF: - KeyFormattingUtils.setStatusImage(mContext, vVerified, null, KeyFormattingUtils.STATE_UNVERIFIED, false); + KeyFormattingUtils.setStatusImage(mContext, vVerified, null, KeyFormattingUtils.STATE_UNVERIFIED, KeyFormattingUtils.DEFAULT_COLOR); break; default: - KeyFormattingUtils.setStatusImage(mContext, vVerified, null, KeyFormattingUtils.STATE_INVALID, false); + KeyFormattingUtils.setStatusImage(mContext, vVerified, null, KeyFormattingUtils.STATE_INVALID, KeyFormattingUtils.DEFAULT_COLOR); break; } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/KeyFormattingUtils.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/KeyFormattingUtils.java index bff7d6b27..1c3dec629 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/KeyFormattingUtils.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/KeyFormattingUtils.java @@ -377,6 +377,8 @@ public class KeyFormattingUtils { ((int) digest[2] + 256) % 256}; } + public static final int DEFAULT_COLOR = -1; + public static final int STATE_REVOKED = 1; public static final int STATE_EXPIRED = 2; public static final int STATE_VERIFIED = 3; @@ -393,20 +395,22 @@ public class KeyFormattingUtils { } public static void setStatusImage(Context context, ImageView statusIcon, TextView statusText, int state) { - setStatusImage(context, statusIcon, statusText, state, false); + setStatusImage(context, statusIcon, statusText, state, KeyFormattingUtils.DEFAULT_COLOR); } /** * Sets status image based on constant */ public static void setStatusImage(Context context, ImageView statusIcon, TextView statusText, - int state, boolean unobtrusive) { + int state, int color) { switch (state) { /** GREEN: everything is good **/ case STATE_VERIFIED: { statusIcon.setImageDrawable( context.getResources().getDrawable(R.drawable.status_signature_verified_cutout)); - int color = R.color.android_green_light; + if (color == KeyFormattingUtils.DEFAULT_COLOR) { + color = R.color.android_green_light; + } statusIcon.setColorFilter(context.getResources().getColor(color), PorterDuff.Mode.SRC_IN); if (statusText != null) { @@ -417,7 +421,9 @@ public class KeyFormattingUtils { case STATE_ENCRYPTED: { statusIcon.setImageDrawable( context.getResources().getDrawable(R.drawable.status_lock_closed)); - int color = R.color.android_green_light; + if (color == KeyFormattingUtils.DEFAULT_COLOR) { + color = R.color.android_green_light; + } statusIcon.setColorFilter(context.getResources().getColor(color), PorterDuff.Mode.SRC_IN); if (statusText != null) { @@ -429,7 +435,9 @@ public class KeyFormattingUtils { case STATE_UNVERIFIED: { statusIcon.setImageDrawable( context.getResources().getDrawable(R.drawable.status_signature_unverified_cutout)); - int color = R.color.android_orange_light; + if (color == KeyFormattingUtils.DEFAULT_COLOR) { + color = R.color.android_orange_light; + } statusIcon.setColorFilter(context.getResources().getColor(color), PorterDuff.Mode.SRC_IN); if (statusText != null) { @@ -440,7 +448,9 @@ public class KeyFormattingUtils { case STATE_UNKNOWN_KEY: { statusIcon.setImageDrawable( context.getResources().getDrawable(R.drawable.status_signature_unknown_cutout)); - int color = R.color.android_orange_light; + if (color == KeyFormattingUtils.DEFAULT_COLOR) { + color = R.color.android_orange_light; + } statusIcon.setColorFilter(context.getResources().getColor(color), PorterDuff.Mode.SRC_IN); if (statusText != null) { @@ -452,9 +462,8 @@ public class KeyFormattingUtils { case STATE_REVOKED: { statusIcon.setImageDrawable( context.getResources().getDrawable(R.drawable.status_signature_revoked_cutout)); - int color = R.color.android_red_light; - if (unobtrusive) { - color = R.color.bg_gray; + if (color == KeyFormattingUtils.DEFAULT_COLOR) { + color = R.color.android_red_light; } statusIcon.setColorFilter(context.getResources().getColor(color), PorterDuff.Mode.SRC_IN); @@ -466,9 +475,8 @@ public class KeyFormattingUtils { case STATE_EXPIRED: { statusIcon.setImageDrawable( context.getResources().getDrawable(R.drawable.status_signature_expired_cutout)); - int color = R.color.android_red_light; - if (unobtrusive) { - color = R.color.bg_gray; + if (color == KeyFormattingUtils.DEFAULT_COLOR) { + color = R.color.android_red_light; } statusIcon.setColorFilter(context.getResources().getColor(color), PorterDuff.Mode.SRC_IN); @@ -480,7 +488,9 @@ public class KeyFormattingUtils { case STATE_NOT_ENCRYPTED: { statusIcon.setImageDrawable( context.getResources().getDrawable(R.drawable.status_lock_open)); - int color = R.color.android_red_light; + if (color == KeyFormattingUtils.DEFAULT_COLOR) { + color = R.color.android_red_light; + } statusIcon.setColorFilter(context.getResources().getColor(color), PorterDuff.Mode.SRC_IN); if (statusText != null) { @@ -491,7 +501,9 @@ public class KeyFormattingUtils { case STATE_NOT_SIGNED: { statusIcon.setImageDrawable( context.getResources().getDrawable(R.drawable.status_signature_unknown_cutout)); - int color = R.color.android_red_light; + if (color == KeyFormattingUtils.DEFAULT_COLOR) { + color = R.color.android_red_light; + } statusIcon.setColorFilter(context.getResources().getColor(color), PorterDuff.Mode.SRC_IN); if (statusText != null) { @@ -502,7 +514,9 @@ public class KeyFormattingUtils { case STATE_INVALID: { statusIcon.setImageDrawable( context.getResources().getDrawable(R.drawable.status_signature_invalid_cutout)); - int color = R.color.android_red_light; + if (color == KeyFormattingUtils.DEFAULT_COLOR) { + color = R.color.android_red_light; + } statusIcon.setColorFilter(context.getResources().getColor(color), PorterDuff.Mode.SRC_IN); if (statusText != null) { @@ -514,7 +528,9 @@ public class KeyFormattingUtils { case STATE_UNAVAILABLE: { statusIcon.setImageDrawable( context.getResources().getDrawable(R.drawable.status_signature_invalid_cutout)); - int color = R.color.bg_gray; + if (color == KeyFormattingUtils.DEFAULT_COLOR) { + color = R.color.bg_gray; + } statusIcon.setColorFilter(context.getResources().getColor(color), PorterDuff.Mode.SRC_IN); if (statusText != null) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/AspectRatioImageView.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/AspectRatioImageView.java new file mode 100644 index 000000000..0df5ba5e8 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/AspectRatioImageView.java @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2015 Dominik Schürmann + * + * 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 . + */ + +package org.sufficientlysecure.keychain.ui.widget; + +import android.content.Context; +import android.content.res.TypedArray; +import android.util.AttributeSet; +import android.widget.ImageView; + +import org.sufficientlysecure.keychain.R; + +/** + * Maintains an aspect ratio based on either width or height. Disabled by default. + * + * from https://gist.github.com/JakeWharton/2856179 + */ +public class AspectRatioImageView extends ImageView { + // NOTE: These must be kept in sync with the AspectRatioImageView attributes in attrs.xml. + public static final int MEASUREMENT_WIDTH = 0; + public static final int MEASUREMENT_HEIGHT = 1; + + private static final float DEFAULT_ASPECT_RATIO = 1f; + private static final boolean DEFAULT_ASPECT_RATIO_ENABLED = false; + private static final int DEFAULT_DOMINANT_MEASUREMENT = MEASUREMENT_WIDTH; + + private float aspectRatio; + private boolean aspectRatioEnabled; + private int dominantMeasurement; + + public AspectRatioImageView(Context context) { + this(context, null); + } + + public AspectRatioImageView(Context context, AttributeSet attrs) { + super(context, attrs); + + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AspectRatioImageView); + aspectRatio = a.getFloat(R.styleable.AspectRatioImageView_aspectRatio, DEFAULT_ASPECT_RATIO); + aspectRatioEnabled = a.getBoolean(R.styleable.AspectRatioImageView_aspectRatioEnabled, + DEFAULT_ASPECT_RATIO_ENABLED); + dominantMeasurement = a.getInt(R.styleable.AspectRatioImageView_dominantMeasurement, + DEFAULT_DOMINANT_MEASUREMENT); + a.recycle(); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + if (!aspectRatioEnabled) return; + + int newWidth; + int newHeight; + switch (dominantMeasurement) { + case MEASUREMENT_WIDTH: + newWidth = getMeasuredWidth(); + newHeight = (int) (newWidth * aspectRatio); + break; + + case MEASUREMENT_HEIGHT: + newHeight = getMeasuredHeight(); + newWidth = (int) (newHeight * aspectRatio); + break; + + default: + throw new IllegalStateException("Unknown measurement with ID " + dominantMeasurement); + } + + setMeasuredDimension(newWidth, newHeight); + } + + /** + * Get the aspect ratio for this image view. + */ + public float getAspectRatio() { + return aspectRatio; + } + + /** + * Set the aspect ratio for this image view. This will update the view instantly. + */ + public void setAspectRatio(float aspectRatio) { + this.aspectRatio = aspectRatio; + if (aspectRatioEnabled) { + requestLayout(); + } + } + + /** + * Get whether or not forcing the aspect ratio is enabled. + */ + public boolean getAspectRatioEnabled() { + return aspectRatioEnabled; + } + + /** + * set whether or not forcing the aspect ratio is enabled. This will re-layout the view. + */ + public void setAspectRatioEnabled(boolean aspectRatioEnabled) { + this.aspectRatioEnabled = aspectRatioEnabled; + requestLayout(); + } + + /** + * Get the dominant measurement for the aspect ratio. + */ + public int getDominantMeasurement() { + return dominantMeasurement; + } + + /** + * Set the dominant measurement for the aspect ratio. + * + * @see #MEASUREMENT_WIDTH + * @see #MEASUREMENT_HEIGHT + */ + public void setDominantMeasurement(int dominantMeasurement) { + if (dominantMeasurement != MEASUREMENT_HEIGHT && dominantMeasurement != MEASUREMENT_WIDTH) { + throw new IllegalArgumentException("Invalid measurement type."); + } + this.dominantMeasurement = dominantMeasurement; + requestLayout(); + } +} \ No newline at end of file diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/CertifyKeySpinner.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/CertifyKeySpinner.java index 904cde47e..25033658d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/CertifyKeySpinner.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/CertifyKeySpinner.java @@ -27,6 +27,7 @@ import android.util.AttributeSet; import android.widget.ImageView; import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainDatabase; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; @@ -101,16 +102,16 @@ public class CertifyKeySpinner extends KeySpinner { @Override boolean setStatus(Context context, Cursor cursor, ImageView statusView) { if (cursor.getInt(mIndexIsRevoked) != 0) { - KeyFormattingUtils.setStatusImage(getContext(), statusView, null, KeyFormattingUtils.STATE_REVOKED, true); + KeyFormattingUtils.setStatusImage(getContext(), statusView, null, KeyFormattingUtils.STATE_REVOKED, R.color.bg_gray); return false; } if (cursor.getInt(mIndexIsExpired) != 0) { - KeyFormattingUtils.setStatusImage(getContext(), statusView, null, KeyFormattingUtils.STATE_EXPIRED, true); + KeyFormattingUtils.setStatusImage(getContext(), statusView, null, KeyFormattingUtils.STATE_EXPIRED, R.color.bg_gray); return false; } // don't invalidate the "None" entry, which is also null! if (cursor.getPosition() != 0 && cursor.isNull(mIndexHasCertify)) { - KeyFormattingUtils.setStatusImage(getContext(), statusView, null, KeyFormattingUtils.STATE_UNAVAILABLE, true); + KeyFormattingUtils.setStatusImage(getContext(), statusView, null, KeyFormattingUtils.STATE_UNAVAILABLE, R.color.bg_gray); return false; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SignKeySpinner.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SignKeySpinner.java index 9c8e4aedb..fe91e306e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SignKeySpinner.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/SignKeySpinner.java @@ -26,6 +26,7 @@ import android.support.v4.content.Loader; import android.util.AttributeSet; import android.widget.ImageView; +import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; @@ -83,15 +84,15 @@ public class SignKeySpinner extends KeySpinner { @Override boolean setStatus(Context context, Cursor cursor, ImageView statusView) { if (cursor.getInt(mIndexIsRevoked) != 0) { - KeyFormattingUtils.setStatusImage(getContext(), statusView, null, KeyFormattingUtils.STATE_REVOKED, true); + KeyFormattingUtils.setStatusImage(getContext(), statusView, null, KeyFormattingUtils.STATE_REVOKED, R.color.bg_gray); return false; } if (cursor.getInt(mIndexIsExpired) != 0) { - KeyFormattingUtils.setStatusImage(getContext(), statusView, null, KeyFormattingUtils.STATE_EXPIRED, true); + KeyFormattingUtils.setStatusImage(getContext(), statusView, null, KeyFormattingUtils.STATE_EXPIRED, R.color.bg_gray); return false; } if (cursor.getInt(mIndexHasSign) == 0) { - KeyFormattingUtils.setStatusImage(getContext(), statusView, null, KeyFormattingUtils.STATE_UNAVAILABLE, true); + KeyFormattingUtils.setStatusImage(getContext(), statusView, null, KeyFormattingUtils.STATE_UNAVAILABLE, R.color.bg_gray); return false; } -- cgit v1.2.3 From 430ba2f7778e70c6c8a8c46e51de46543e074f34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Wed, 25 Feb 2015 11:29:46 +0100 Subject: Bigger status icon in key view --- .../keychain/ui/ViewKeyActivity.java | 10 ++-- .../keychain/ui/adapter/SubkeysAdapter.java | 4 +- .../keychain/ui/util/KeyFormattingUtils.java | 57 ++++++++++++++++------ 3 files changed, 49 insertions(+), 22 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java index 8ef5d01aa..ac1988d08 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java @@ -406,7 +406,7 @@ public class ViewKeyActivity extends BaseActivity implements if (isRevoked) { mStatusText.setText(R.string.view_key_revoked); mStatusImage.setVisibility(View.VISIBLE); - KeyFormattingUtils.setStatusImage(this, mStatusImage, mStatusText, KeyFormattingUtils.STATE_REVOKED, R.color.icons); + KeyFormattingUtils.setStatusImage(this, mStatusImage, mStatusText, KeyFormattingUtils.STATE_REVOKED, R.color.icons, true); color = getResources().getColor(R.color.android_red_light); mActionEncryptFile.setVisibility(View.INVISIBLE); @@ -416,7 +416,7 @@ public class ViewKeyActivity extends BaseActivity implements } else if (isExpired) { mStatusText.setText(R.string.view_key_expired); mStatusImage.setVisibility(View.VISIBLE); - KeyFormattingUtils.setStatusImage(this, mStatusImage, mStatusText, KeyFormattingUtils.STATE_EXPIRED, R.color.icons); + KeyFormattingUtils.setStatusImage(this, mStatusImage, mStatusText, KeyFormattingUtils.STATE_EXPIRED, R.color.icons, true); color = getResources().getColor(R.color.android_red_light); mActionEncryptFile.setVisibility(View.INVISIBLE); @@ -439,7 +439,7 @@ public class ViewKeyActivity extends BaseActivity implements if (isVerified) { mStatusText.setText(R.string.view_key_verified); mStatusImage.setVisibility(View.VISIBLE); - KeyFormattingUtils.setStatusImage(this, mStatusImage, mStatusText, KeyFormattingUtils.STATE_VERIFIED, R.color.icons); + KeyFormattingUtils.setStatusImage(this, mStatusImage, mStatusText, KeyFormattingUtils.STATE_VERIFIED, R.color.icons, true); color = getResources().getColor(R.color.primary); AsyncTask photoTask = @@ -461,7 +461,7 @@ public class ViewKeyActivity extends BaseActivity implements } else { mStatusText.setText(R.string.view_key_unverified); mStatusImage.setVisibility(View.VISIBLE); - KeyFormattingUtils.setStatusImage(this, mStatusImage, mStatusText, KeyFormattingUtils.STATE_UNVERIFIED, R.color.icons); + KeyFormattingUtils.setStatusImage(this, mStatusImage, mStatusText, KeyFormattingUtils.STATE_UNVERIFIED, R.color.icons, true); color = getResources().getColor(R.color.android_orange_light); mActionVerify.setVisibility(View.VISIBLE); @@ -472,6 +472,8 @@ public class ViewKeyActivity extends BaseActivity implements mStatusBar.setBackgroundColor(color); mBigToolbar.setBackgroundColor(color); + mStatusImage.setAlpha(80); + break; } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java index a3bd4d470..ff5fbb49a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/SubkeysAdapter.java @@ -272,12 +272,12 @@ public class SubkeysAdapter extends CursorAdapter { PorterDuff.Mode.SRC_IN); if (isRevoked) { - vStatus.setImageResource(R.drawable.status_signature_revoked_cutout); + vStatus.setImageResource(R.drawable.status_signature_revoked_cutout_24px); vStatus.setColorFilter( mContext.getResources().getColor(R.color.bg_gray), PorterDuff.Mode.SRC_IN); } else if (isExpired) { - vStatus.setImageResource(R.drawable.status_signature_expired_cutout); + vStatus.setImageResource(R.drawable.status_signature_expired_cutout_24px); vStatus.setColorFilter( mContext.getResources().getColor(R.color.bg_gray), PorterDuff.Mode.SRC_IN); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/KeyFormattingUtils.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/KeyFormattingUtils.java index 1c3dec629..38ed88b9c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/KeyFormattingUtils.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/KeyFormattingUtils.java @@ -395,19 +395,29 @@ public class KeyFormattingUtils { } public static void setStatusImage(Context context, ImageView statusIcon, TextView statusText, int state) { - setStatusImage(context, statusIcon, statusText, state, KeyFormattingUtils.DEFAULT_COLOR); + setStatusImage(context, statusIcon, statusText, state, KeyFormattingUtils.DEFAULT_COLOR, false); + } + + public static void setStatusImage(Context context, ImageView statusIcon, TextView statusText, + int state, int color) { + setStatusImage(context, statusIcon, statusText, state, color, false); } /** * Sets status image based on constant */ public static void setStatusImage(Context context, ImageView statusIcon, TextView statusText, - int state, int color) { + int state, int color, boolean big) { switch (state) { /** GREEN: everything is good **/ case STATE_VERIFIED: { - statusIcon.setImageDrawable( - context.getResources().getDrawable(R.drawable.status_signature_verified_cutout)); + if (big) { + statusIcon.setImageDrawable( + context.getResources().getDrawable(R.drawable.status_signature_verified_cutout_96px)); + } else { + statusIcon.setImageDrawable( + context.getResources().getDrawable(R.drawable.status_signature_verified_cutout_24px)); + } if (color == KeyFormattingUtils.DEFAULT_COLOR) { color = R.color.android_green_light; } @@ -420,7 +430,7 @@ public class KeyFormattingUtils { } case STATE_ENCRYPTED: { statusIcon.setImageDrawable( - context.getResources().getDrawable(R.drawable.status_lock_closed)); + context.getResources().getDrawable(R.drawable.status_lock_closed_24px)); if (color == KeyFormattingUtils.DEFAULT_COLOR) { color = R.color.android_green_light; } @@ -433,8 +443,13 @@ public class KeyFormattingUtils { } /** ORANGE: mostly bad... **/ case STATE_UNVERIFIED: { - statusIcon.setImageDrawable( - context.getResources().getDrawable(R.drawable.status_signature_unverified_cutout)); + if (big) { + statusIcon.setImageDrawable( + context.getResources().getDrawable(R.drawable.status_signature_unverified_cutout_96px)); + } else { + statusIcon.setImageDrawable( + context.getResources().getDrawable(R.drawable.status_signature_unverified_cutout_24px)); + } if (color == KeyFormattingUtils.DEFAULT_COLOR) { color = R.color.android_orange_light; } @@ -447,7 +462,7 @@ public class KeyFormattingUtils { } case STATE_UNKNOWN_KEY: { statusIcon.setImageDrawable( - context.getResources().getDrawable(R.drawable.status_signature_unknown_cutout)); + context.getResources().getDrawable(R.drawable.status_signature_unknown_cutout_24px)); if (color == KeyFormattingUtils.DEFAULT_COLOR) { color = R.color.android_orange_light; } @@ -460,8 +475,13 @@ public class KeyFormattingUtils { } /** RED: really bad... **/ case STATE_REVOKED: { - statusIcon.setImageDrawable( - context.getResources().getDrawable(R.drawable.status_signature_revoked_cutout)); + if (big) { + statusIcon.setImageDrawable( + context.getResources().getDrawable(R.drawable.status_signature_revoked_cutout_96px)); + } else { + statusIcon.setImageDrawable( + context.getResources().getDrawable(R.drawable.status_signature_revoked_cutout_24px)); + } if (color == KeyFormattingUtils.DEFAULT_COLOR) { color = R.color.android_red_light; } @@ -473,8 +493,13 @@ public class KeyFormattingUtils { break; } case STATE_EXPIRED: { - statusIcon.setImageDrawable( - context.getResources().getDrawable(R.drawable.status_signature_expired_cutout)); + if (big) { + statusIcon.setImageDrawable( + context.getResources().getDrawable(R.drawable.status_signature_expired_cutout_96px)); + } else { + statusIcon.setImageDrawable( + context.getResources().getDrawable(R.drawable.status_signature_expired_cutout_24px)); + } if (color == KeyFormattingUtils.DEFAULT_COLOR) { color = R.color.android_red_light; } @@ -487,7 +512,7 @@ public class KeyFormattingUtils { } case STATE_NOT_ENCRYPTED: { statusIcon.setImageDrawable( - context.getResources().getDrawable(R.drawable.status_lock_open)); + context.getResources().getDrawable(R.drawable.status_lock_open_24px)); if (color == KeyFormattingUtils.DEFAULT_COLOR) { color = R.color.android_red_light; } @@ -500,7 +525,7 @@ public class KeyFormattingUtils { } case STATE_NOT_SIGNED: { statusIcon.setImageDrawable( - context.getResources().getDrawable(R.drawable.status_signature_unknown_cutout)); + context.getResources().getDrawable(R.drawable.status_signature_unknown_cutout_24px)); if (color == KeyFormattingUtils.DEFAULT_COLOR) { color = R.color.android_red_light; } @@ -513,7 +538,7 @@ public class KeyFormattingUtils { } case STATE_INVALID: { statusIcon.setImageDrawable( - context.getResources().getDrawable(R.drawable.status_signature_invalid_cutout)); + context.getResources().getDrawable(R.drawable.status_signature_invalid_cutout_24px)); if (color == KeyFormattingUtils.DEFAULT_COLOR) { color = R.color.android_red_light; } @@ -527,7 +552,7 @@ public class KeyFormattingUtils { /** special **/ case STATE_UNAVAILABLE: { statusIcon.setImageDrawable( - context.getResources().getDrawable(R.drawable.status_signature_invalid_cutout)); + context.getResources().getDrawable(R.drawable.status_signature_invalid_cutout_24px)); if (color == KeyFormattingUtils.DEFAULT_COLOR) { color = R.color.bg_gray; } -- cgit v1.2.3 From fa92ceeae3ba89d11cce1282e7c2f824969acf80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Wed, 25 Feb 2015 13:49:21 +0100 Subject: Toolbar: qr code in header, cleanup of fragment --- .../keychain/ui/ViewKeyActivity.java | 254 ++++++++++-- .../keychain/ui/ViewKeyFragment.java | 456 +-------------------- 2 files changed, 226 insertions(+), 484 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java index ac1988d08..5454e4f3e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java @@ -36,13 +36,10 @@ import android.provider.ContactsContract; import android.support.v4.app.LoaderManager; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; -import android.support.v7.app.ActionBar; -import android.support.v7.widget.Toolbar; -import android.view.Gravity; import android.view.Menu; import android.view.MenuItem; import android.view.View; -import android.view.ViewGroup; +import android.view.animation.AlphaAnimation; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.RelativeLayout; @@ -55,11 +52,13 @@ import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.pgp.KeyRing; +import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.Notify; +import org.sufficientlysecure.keychain.ui.util.QrCodeUtils; import org.sufficientlysecure.keychain.ui.widget.AspectRatioImageView; import org.sufficientlysecure.keychain.util.ContactHelper; import org.sufficientlysecure.keychain.util.ExportHelper; @@ -84,8 +83,10 @@ public class ViewKeyActivity extends BaseActivity implements private ImageButton mActionEncryptFile; private ImageButton mActionEncryptText; private ImageButton mActionVerify; + private ImageButton mActionEdit; private FloatingActionButton mFab; private AspectRatioImageView mPhoto; + private ImageButton mQrCode; // NFC private NfcAdapter mNfcAdapter; @@ -96,6 +97,9 @@ public class ViewKeyActivity extends BaseActivity implements private static final int LOADER_ID_UNIFIED = 0; + private boolean mIsSecret; + private boolean mHasEncrypt; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -113,8 +117,10 @@ public class ViewKeyActivity extends BaseActivity implements mActionEncryptFile = (ImageButton) findViewById(R.id.view_key_action_encrypt_files); mActionEncryptText = (ImageButton) findViewById(R.id.view_key_action_encrypt_text); mActionVerify = (ImageButton) findViewById(R.id.view_key_action_verify); + mActionEdit = (ImageButton) findViewById(R.id.view_key_action_edit); mFab = (FloatingActionButton) findViewById(R.id.fab); mPhoto = (AspectRatioImageView) findViewById(R.id.view_key_photo); + mQrCode = (ImageButton) findViewById(R.id.view_key_qr_code); mDataUri = getIntent().getData(); if (mDataUri == null) { @@ -134,6 +140,48 @@ public class ViewKeyActivity extends BaseActivity implements Log.i(Constants.TAG, "mDataUri: " + mDataUri.toString()); + mActionEncryptFile.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + encrypt(mDataUri, false); + } + }); + mActionEncryptText.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + encrypt(mDataUri, true); + } + }); + mActionVerify.setOnClickListener(new View.OnClickListener() { + public void onClick(View view) { + certify(mDataUri); + } + }); + mActionEdit.setOnClickListener(new View.OnClickListener() { + public void onClick(View view) { + editKey(mDataUri); + } + }); + + mFab.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (mIsSecret) { + startSafeSlinger(mDataUri); + } else { + certify(mDataUri); + } + } + }); + + mQrCode.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + showQrCodeDialog(); + } + }); + + // Prepare the loaders. Either re-connect with an existing ones, // or start new ones. getSupportLoaderManager().initLoader(LOADER_ID_UNIFIED, null, this); @@ -199,6 +247,13 @@ public class ViewKeyActivity extends BaseActivity implements advancedIntent.setData(mDataUri); startActivity(advancedIntent); } + case R.id.menu_key_view_refresh: { + try { + updateFromKeyserver(mDataUri, mProviderHelper); + } catch (ProviderHelper.NotFoundException e) { + Notify.showNotify(this, R.string.error_key_not_found, Notify.Style.ERROR); + } + } } } catch (ProviderHelper.NotFoundException e) { Notify.showNotify(this, R.string.error_key_not_found, Notify.Style.ERROR); @@ -207,6 +262,12 @@ public class ViewKeyActivity extends BaseActivity implements return super.onOptionsItemSelected(item); } + private void showQrCodeDialog() { + Intent qrCodeIntent = new Intent(this, QrCodeViewActivity.class); + qrCodeIntent.setData(mDataUri); + startActivity(qrCodeIntent); + } + private void exportToFile(Uri dataUri, ExportHelper exportHelper, ProviderHelper providerHelper) throws ProviderHelper.NotFoundException { Uri baseUri = KeychainContract.KeyRings.buildUnifiedKeyRingUri(dataUri); @@ -248,6 +309,119 @@ public class ViewKeyActivity extends BaseActivity implements } } + private void encrypt(Uri dataUri, boolean text) { + // If there is no encryption key, don't bother. + if (!mHasEncrypt) { + Notify.showNotify(this, R.string.error_no_encrypt_subkey, Notify.Style.ERROR); + return; + } + try { + long keyId = new ProviderHelper(this) + .getCachedPublicKeyRing(dataUri) + .extractOrGetMasterKeyId(); + long[] encryptionKeyIds = new long[]{keyId}; + Intent intent; + if (text) { + intent = new Intent(this, EncryptTextActivity.class); + intent.setAction(EncryptTextActivity.ACTION_ENCRYPT_TEXT); + intent.putExtra(EncryptTextActivity.EXTRA_ENCRYPTION_KEY_IDS, encryptionKeyIds); + } else { + intent = new Intent(this, EncryptFilesActivity.class); + intent.setAction(EncryptFilesActivity.ACTION_ENCRYPT_DATA); + intent.putExtra(EncryptFilesActivity.EXTRA_ENCRYPTION_KEY_IDS, encryptionKeyIds); + } + // used instead of startActivity set actionbar based on callingPackage + startActivityForResult(intent, 0); + } catch (PgpKeyNotFoundException e) { + Log.e(Constants.TAG, "key not found!", e); + } + } + + private void updateFromKeyserver(Uri dataUri, ProviderHelper providerHelper) + throws ProviderHelper.NotFoundException { + byte[] blob = (byte[]) providerHelper.getGenericData( + KeychainContract.KeyRings.buildUnifiedKeyRingUri(dataUri), + KeychainContract.Keys.FINGERPRINT, ProviderHelper.FIELD_TYPE_BLOB); + String fingerprint = KeyFormattingUtils.convertFingerprintToHex(blob); + + Intent queryIntent = new Intent(this, ImportKeysActivity.class); + queryIntent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_RESULT); + queryIntent.putExtra(ImportKeysActivity.EXTRA_FINGERPRINT, fingerprint); + + startActivityForResult(queryIntent, 0); + } + + private void certify(Uri dataUri) { + long keyId = 0; + try { + keyId = new ProviderHelper(this) + .getCachedPublicKeyRing(dataUri) + .extractOrGetMasterKeyId(); + } catch (PgpKeyNotFoundException e) { + Log.e(Constants.TAG, "key not found!", e); + } + Intent certifyIntent = new Intent(this, CertifyKeyActivity.class); + certifyIntent.putExtra(CertifyKeyActivity.EXTRA_KEY_IDS, new long[]{keyId}); + startActivityForResult(certifyIntent, 0); + } + + private void editKey(Uri dataUri) { + Intent editIntent = new Intent(this, EditKeyActivity.class); + editIntent.setData(KeychainContract.KeyRingData.buildSecretKeyRingUri(dataUri)); + startActivityForResult(editIntent, 0); + } + + private void startSafeSlinger(Uri dataUri) { + long keyId = 0; + try { + keyId = new ProviderHelper(this) + .getCachedPublicKeyRing(dataUri) + .extractOrGetMasterKeyId(); + } catch (PgpKeyNotFoundException e) { + Log.e(Constants.TAG, "key not found!", e); + } + Intent safeSlingerIntent = new Intent(this, SafeSlingerActivity.class); + safeSlingerIntent.putExtra(SafeSlingerActivity.EXTRA_MASTER_KEY_ID, keyId); + startActivityForResult(safeSlingerIntent, 0); + } + + + /** + * Load QR Code asynchronously and with a fade in animation + * + * @param fingerprint + */ + private void loadQrCode(final String fingerprint) { + AsyncTask loadTask = + new AsyncTask() { + protected Bitmap doInBackground(Void... unused) { + String qrCodeContent = Constants.FINGERPRINT_SCHEME + ":" + fingerprint; + // render with minimal size + return QrCodeUtils.getQRCodeBitmap(qrCodeContent, 0); + } + + protected void onPostExecute(Bitmap qrCode) { + // only change view, if fragment is attached to activity +// if (ViewKeyFragment.this.isAdded()) { + + // scale the image up to our actual size. we do this in code rather + // than let the ImageView do this because we don't require filtering. + Bitmap scaled = Bitmap.createScaledBitmap(qrCode, + mQrCode.getHeight(), mQrCode.getHeight(), + false); + mQrCode.setImageBitmap(scaled); + + // simple fade-in animation + AlphaAnimation anim = new AlphaAnimation(0.0f, 1.0f); + anim.setDuration(200); + mQrCode.startAnimation(anim); + } +// } + }; + + loadTask.execute(); + } + /** * NFC: Initialize NFC sharing if OS and device supports it */ @@ -347,7 +521,8 @@ public class ViewKeyActivity extends BaseActivity implements KeychainContract.KeyRings.EXPIRY, KeychainContract.KeyRings.VERIFIED, KeychainContract.KeyRings.HAS_ANY_SECRET, - KeychainContract.KeyRings.FINGERPRINT + KeychainContract.KeyRings.FINGERPRINT, + KeychainContract.KeyRings.HAS_ENCRYPT }; static final int INDEX_MASTER_KEY_ID = 1; @@ -357,6 +532,7 @@ public class ViewKeyActivity extends BaseActivity implements static final int INDEX_VERIFIED = 5; static final int INDEX_HAS_ANY_SECRET = 6; static final int INDEX_FINGERPRINT = 7; + static final int INDEX_HAS_ENCRYPT = 8; @Override public Loader onCreateLoader(int id, Bundle args) { @@ -395,12 +571,26 @@ public class ViewKeyActivity extends BaseActivity implements String fingerprint = KeyFormattingUtils.convertFingerprintToHex(data.getBlob(INDEX_FINGERPRINT)); - boolean isSecret = data.getInt(INDEX_HAS_ANY_SECRET) != 0; + mIsSecret = data.getInt(INDEX_HAS_ANY_SECRET) != 0; + mHasEncrypt = data.getInt(INDEX_HAS_ENCRYPT) != 0; boolean isRevoked = data.getInt(INDEX_IS_REVOKED) > 0; boolean isExpired = !data.isNull(INDEX_EXPIRY) && new Date(data.getLong(INDEX_EXPIRY) * 1000).before(new Date()); boolean isVerified = data.getInt(INDEX_VERIFIED) > 0; + + AsyncTask photoTask = + new AsyncTask() { + protected Bitmap doInBackground(String... fingerprint) { + return ContactHelper.photoFromFingerprint(getContentResolver(), fingerprint[0]); + } + + protected void onPostExecute(Bitmap photo) { + mPhoto.setImageBitmap(photo); + mPhoto.setVisibility(View.VISIBLE); + } + }; + // Note: order is important int color; if (isRevoked) { @@ -409,55 +599,53 @@ public class ViewKeyActivity extends BaseActivity implements KeyFormattingUtils.setStatusImage(this, mStatusImage, mStatusText, KeyFormattingUtils.STATE_REVOKED, R.color.icons, true); color = getResources().getColor(R.color.android_red_light); - mActionEncryptFile.setVisibility(View.INVISIBLE); - mActionEncryptText.setVisibility(View.INVISIBLE); - mActionVerify.setVisibility(View.INVISIBLE); - mFab.setVisibility(View.INVISIBLE); + mActionEncryptFile.setVisibility(View.GONE); + mActionEncryptText.setVisibility(View.GONE); + mActionVerify.setVisibility(View.GONE); + mActionEdit.setVisibility(View.GONE); + mFab.setVisibility(View.GONE); + mQrCode.setVisibility(View.GONE); } else if (isExpired) { mStatusText.setText(R.string.view_key_expired); mStatusImage.setVisibility(View.VISIBLE); KeyFormattingUtils.setStatusImage(this, mStatusImage, mStatusText, KeyFormattingUtils.STATE_EXPIRED, R.color.icons, true); color = getResources().getColor(R.color.android_red_light); - mActionEncryptFile.setVisibility(View.INVISIBLE); - mActionEncryptText.setVisibility(View.INVISIBLE); - mActionVerify.setVisibility(View.INVISIBLE); - mFab.setVisibility(View.INVISIBLE); - } else if (isSecret) { + mActionEncryptFile.setVisibility(View.GONE); + mActionEncryptText.setVisibility(View.GONE); + mActionVerify.setVisibility(View.GONE); + mActionEdit.setVisibility(View.GONE); + mFab.setVisibility(View.GONE); + mQrCode.setVisibility(View.GONE); + } else if (mIsSecret) { mStatusText.setText(R.string.view_key_my_key); - mStatusImage.setVisibility(View.INVISIBLE); + mStatusImage.setVisibility(View.GONE); color = getResources().getColor(R.color.primary); + photoTask.execute(fingerprint); + loadQrCode(fingerprint); + mQrCode.setVisibility(View.VISIBLE); mActionEncryptFile.setVisibility(View.VISIBLE); mActionEncryptText.setVisibility(View.VISIBLE); - mActionVerify.setVisibility(View.INVISIBLE); - mFab.setVisibility(View.INVISIBLE); // TODO + mActionVerify.setVisibility(View.GONE); + mActionEdit.setVisibility(View.VISIBLE); + mFab.setVisibility(View.VISIBLE); + mFab.setIconDrawable(getResources().getDrawable(R.drawable.ic_swap_vert_white_24dp)); } else { mActionEncryptFile.setVisibility(View.VISIBLE); mActionEncryptText.setVisibility(View.VISIBLE); + mActionEdit.setVisibility(View.GONE); + mQrCode.setVisibility(View.GONE); if (isVerified) { mStatusText.setText(R.string.view_key_verified); mStatusImage.setVisibility(View.VISIBLE); KeyFormattingUtils.setStatusImage(this, mStatusImage, mStatusText, KeyFormattingUtils.STATE_VERIFIED, R.color.icons, true); color = getResources().getColor(R.color.primary); - - AsyncTask photoTask = - new AsyncTask() { - protected Bitmap doInBackground(String... fingerprint) { - return ContactHelper.photoFromFingerprint(getContentResolver(), fingerprint[0]); - } - - protected void onPostExecute(Bitmap photo) { - mPhoto.setImageBitmap(photo); - mPhoto.setVisibility(View.VISIBLE); - } - }; - photoTask.execute(fingerprint); - mActionVerify.setVisibility(View.INVISIBLE); - mFab.setVisibility(View.INVISIBLE); + mActionVerify.setVisibility(View.GONE); + mFab.setVisibility(View.GONE); } else { mStatusText.setText(R.string.view_key_unverified); mStatusImage.setVisibility(View.VISIBLE); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyFragment.java index 9ae656b2d..571c86b82 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyFragment.java @@ -18,84 +18,36 @@ package org.sufficientlysecure.keychain.ui; -import android.annotation.TargetApi; -import android.content.Intent; import android.database.Cursor; -import android.graphics.Bitmap; -import android.graphics.PorterDuff; import android.net.Uri; -import android.os.AsyncTask; -import android.os.Build; import android.os.Bundle; -import android.provider.Settings; import android.support.v4.app.LoaderManager; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.view.animation.AlphaAnimation; import android.widget.AdapterView; -import android.widget.ImageButton; -import android.widget.ImageView; import android.widget.ListView; -import android.widget.TextView; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.compatibility.ClipboardReflection; import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround; -import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; -import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; -import org.sufficientlysecure.keychain.provider.KeychainContract; -import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets; import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.provider.ProviderHelper.NotFoundException; import org.sufficientlysecure.keychain.ui.adapter.UserIdsAdapter; -import org.sufficientlysecure.keychain.ui.dialog.ShareNfcDialogFragment; import org.sufficientlysecure.keychain.ui.dialog.UserIdInfoDialogFragment; -import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; -import org.sufficientlysecure.keychain.ui.util.Notify; -import org.sufficientlysecure.keychain.ui.util.QrCodeUtils; import org.sufficientlysecure.keychain.util.Log; -import java.io.IOException; -import java.util.Date; - public class ViewKeyFragment extends LoaderFragment implements LoaderManager.LoaderCallbacks { public static final String ARG_DATA_URI = "uri"; - private View mActionEdit; - private View mActionEditDivider; - private View mActionEncryptFiles; - private View mActionEncryptText; - private View mActionEncryptTextText; - private View mActionCertify; - private View mActionCertifyText; - private ImageView mActionCertifyImage; - private View mActionUpdate; - - private TextView mFingerprint; - private ImageView mFingerprintQrCode; - private View mFingerprintShareButton; - private View mFingerprintClipboardButton; - private View mKeyShareButton; - private View mKeyClipboardButton; - private ImageButton mKeySafeSlingerButton; - private View mNfcHelpButton; - private View mNfcPrefsButton; - private View mKeyUploadButton; private ListView mUserIds; - private static final int LOADER_ID_UNIFIED = 0; private static final int LOADER_ID_USER_IDS = 1; - // conservative attitude - private boolean mHasEncrypt = true; - private UserIdsAdapter mUserIdsAdapter; private Uri mDataUri; @@ -123,18 +75,7 @@ public class ViewKeyFragment extends LoaderFragment implements mProviderHelper = new ProviderHelper(getActivity()); mUserIds = (ListView) view.findViewById(R.id.view_key_user_ids); - mActionEdit = view.findViewById(R.id.view_key_action_edit); - mActionEditDivider = view.findViewById(R.id.view_key_action_edit_divider); - mActionEncryptText = view.findViewById(R.id.view_key_action_encrypt_text); - mActionEncryptTextText = view.findViewById(R.id.view_key_action_encrypt_text_text); - mActionEncryptFiles = view.findViewById(R.id.view_key_action_encrypt_files); - mActionCertify = view.findViewById(R.id.view_key_action_certify); - mActionCertifyText = view.findViewById(R.id.view_key_action_certify_text); - mActionCertifyImage = (ImageView) view.findViewById(R.id.view_key_action_certify_image); - // make certify image gray, like action icons - mActionCertifyImage.setColorFilter(getResources().getColor(R.color.tertiary_text_light), - PorterDuff.Mode.SRC_IN); - mActionUpdate = view.findViewById(R.id.view_key_action_update); + mUserIds.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override @@ -143,176 +84,10 @@ public class ViewKeyFragment extends LoaderFragment implements } }); - mFingerprint = (TextView) view.findViewById(R.id.view_key_fingerprint); - mFingerprintQrCode = (ImageView) view.findViewById(R.id.view_key_fingerprint_qr_code_image); - mFingerprintShareButton = view.findViewById(R.id.view_key_action_fingerprint_share); - mFingerprintClipboardButton = view.findViewById(R.id.view_key_action_fingerprint_clipboard); - mKeyShareButton = view.findViewById(R.id.view_key_action_key_share); - mKeyClipboardButton = view.findViewById(R.id.view_key_action_key_clipboard); - mKeySafeSlingerButton = (ImageButton) view.findViewById(R.id.view_key_action_key_safeslinger); - mNfcHelpButton = view.findViewById(R.id.view_key_action_nfc_help); - mNfcPrefsButton = view.findViewById(R.id.view_key_action_nfc_prefs); - mKeyUploadButton = view.findViewById(R.id.view_key_action_upload); - - mKeySafeSlingerButton.setColorFilter(getResources().getColor(R.color.tertiary_text_light), - PorterDuff.Mode.SRC_IN); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { - mNfcPrefsButton.setVisibility(View.VISIBLE); - } else { - mNfcPrefsButton.setVisibility(View.GONE); - } - - mFingerprintQrCode.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - showQrCodeDialog(); - } - }); - - mFingerprintShareButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - share(mDataUri, mProviderHelper, true, false); - } - }); - mFingerprintClipboardButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - share(mDataUri, mProviderHelper, true, true); - } - }); - mKeyShareButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - share(mDataUri, mProviderHelper, false, false); - } - }); - mKeyClipboardButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - share(mDataUri, mProviderHelper, false, true); - } - }); - mKeySafeSlingerButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - startSafeSlinger(mDataUri); - } - }); - mNfcHelpButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - showNfcHelpDialog(); - } - }); - mNfcPrefsButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - showNfcPrefs(); - } - }); - mKeyUploadButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - uploadToKeyserver(); - } - }); - return root; } - private void startSafeSlinger(Uri dataUri) { - long keyId = 0; - try { - keyId = new ProviderHelper(getActivity()) - .getCachedPublicKeyRing(dataUri) - .extractOrGetMasterKeyId(); - } catch (PgpKeyNotFoundException e) { - Log.e(Constants.TAG, "key not found!", e); - } - Intent safeSlingerIntent = new Intent(getActivity(), SafeSlingerActivity.class); - safeSlingerIntent.putExtra(SafeSlingerActivity.EXTRA_MASTER_KEY_ID, keyId); - startActivityForResult(safeSlingerIntent, 0); - } - - private void share(Uri dataUri, ProviderHelper providerHelper, boolean fingerprintOnly, - boolean toClipboard) { - try { - String content; - if (fingerprintOnly) { - byte[] data = (byte[]) providerHelper.getGenericData( - KeyRings.buildUnifiedKeyRingUri(dataUri), - KeychainContract.Keys.FINGERPRINT, ProviderHelper.FIELD_TYPE_BLOB); - String fingerprint = KeyFormattingUtils.convertFingerprintToHex(data); - if (!toClipboard) { - content = Constants.FINGERPRINT_SCHEME + ":" + fingerprint; - } else { - content = fingerprint; - } - } else { - Uri uri = KeychainContract.KeyRingData.buildPublicKeyRingUri(dataUri); - // get public keyring as ascii armored string - content = providerHelper.getKeyRingAsArmoredString(uri); - } - - if (toClipboard) { - ClipboardReflection.copyToClipboard(getActivity(), content); - String message; - if (fingerprintOnly) { - message = getResources().getString(R.string.fingerprint_copied_to_clipboard); - } else { - message = getResources().getString(R.string.key_copied_to_clipboard); - } - Notify.showNotify(getActivity(), message, Notify.Style.OK); - } else { - // Android will fail with android.os.TransactionTooLargeException if key is too big - // see http://www.lonestarprod.com/?p=34 - if (content.length() >= 86389) { - Notify.showNotify(getActivity(), R.string.key_too_big_for_sharing, - Notify.Style.ERROR); - return; - } - - // let user choose application - Intent sendIntent = new Intent(Intent.ACTION_SEND); - sendIntent.putExtra(Intent.EXTRA_TEXT, content); - sendIntent.setType("text/plain"); - String title; - if (fingerprintOnly) { - title = getResources().getString(R.string.title_share_fingerprint_with); - } else { - title = getResources().getString(R.string.title_share_key); - } - startActivity(Intent.createChooser(sendIntent, title)); - } - } catch (PgpGeneralException | IOException e) { - Log.e(Constants.TAG, "error processing key!", e); - Notify.showNotify(getActivity(), R.string.error_key_processing, Notify.Style.ERROR); - } catch (ProviderHelper.NotFoundException e) { - Log.e(Constants.TAG, "key not found!", e); - Notify.showNotify(getActivity(), R.string.error_key_not_found, Notify.Style.ERROR); - } - } - - private void showQrCodeDialog() { - Intent qrCodeIntent = new Intent(getActivity(), QrCodeViewActivity.class); - qrCodeIntent.setData(mDataUri); - startActivity(qrCodeIntent); - } - - private void showNfcHelpDialog() { - ShareNfcDialogFragment dialog = ShareNfcDialogFragment.newInstance(); - dialog.show(getActivity().getSupportFragmentManager(), "shareNfcDialog"); - } - - @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) - private void showNfcPrefs() { - Intent intentSettings = new Intent( - Settings.ACTION_NFCSHARING_SETTINGS); - startActivity(intentSettings); - } private void showUserIdInfo(final int position) { final boolean isRevoked = mUserIdsAdapter.getIsRevoked(position); @@ -347,82 +122,21 @@ public class ViewKeyFragment extends LoaderFragment implements Log.i(Constants.TAG, "mDataUri: " + mDataUri.toString()); - mActionEncryptFiles.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - encrypt(mDataUri, false); - } - }); - mActionEncryptText.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - encrypt(mDataUri, true); - } - }); - mActionCertify.setOnClickListener(new View.OnClickListener() { - public void onClick(View view) { - certify(mDataUri); - } - }); - mActionEdit.setOnClickListener(new View.OnClickListener() { - public void onClick(View view) { - editKey(mDataUri); - } - }); - mActionUpdate.setOnClickListener(new View.OnClickListener() { - public void onClick(View view) { - try { - updateFromKeyserver(mDataUri, new ProviderHelper(getActivity())); - } catch (NotFoundException e) { - Notify.showNotify(getActivity(), R.string.error_key_not_found, Notify.Style.ERROR); - } - } - }); - mUserIdsAdapter = new UserIdsAdapter(getActivity(), null, 0); mUserIds.setAdapter(mUserIdsAdapter); // Prepare the loaders. Either re-connect with an existing ones, // or start new ones. - getLoaderManager().initLoader(LOADER_ID_UNIFIED, null, this); getLoaderManager().initLoader(LOADER_ID_USER_IDS, null, this); } - static final String[] UNIFIED_PROJECTION = new String[]{ - KeyRings._ID, KeyRings.MASTER_KEY_ID, KeyRings.HAS_ANY_SECRET, - KeyRings.USER_ID, KeyRings.FINGERPRINT, - KeyRings.ALGORITHM, KeyRings.KEY_SIZE, KeyRings.CREATION, KeyRings.EXPIRY, - KeyRings.IS_REVOKED, KeyRings.HAS_ENCRYPT, - - }; - static final int INDEX_UNIFIED_MASTER_KEY_ID = 1; - static final int INDEX_UNIFIED_HAS_ANY_SECRET = 2; - static final int INDEX_UNIFIED_USER_ID = 3; - static final int INDEX_UNIFIED_FINGERPRINT = 4; - static final int INDEX_UNIFIED_ALGORITHM = 5; - static final int INDEX_UNIFIED_KEY_SIZE = 6; - static final int INDEX_UNIFIED_CREATION = 7; - static final int INDEX_UNIFIED_EXPIRY = 8; - static final int INDEX_UNIFIED_IS_REVOKED = 9; - static final int INDEX_UNIFIED_HAS_ENCRYPT = 10; public Loader onCreateLoader(int id, Bundle args) { setContentShown(false); - switch (id) { - case LOADER_ID_UNIFIED: { - Uri baseUri = KeyRings.buildUnifiedKeyRingUri(mDataUri); - return new CursorLoader(getActivity(), baseUri, UNIFIED_PROJECTION, null, null, null); - } - case LOADER_ID_USER_IDS: { - Uri baseUri = UserPackets.buildUserIdsUri(mDataUri); - return new CursorLoader(getActivity(), baseUri, - UserIdsAdapter.USER_IDS_PROJECTION, null, null, null); - } - - default: - return null; - } + Uri baseUri = UserPackets.buildUserIdsUri(mDataUri); + return new CursorLoader(getActivity(), baseUri, + UserIdsAdapter.USER_IDS_PROJECTION, null, null, null); } public void onLoadFinished(Loader loader, Cursor data) { @@ -435,63 +149,8 @@ public class ViewKeyFragment extends LoaderFragment implements } // Swap the new cursor in. (The framework will take care of closing the // old cursor once we return.) - switch (loader.getId()) { - case LOADER_ID_UNIFIED: { - if (data.moveToFirst()) { - byte[] fingerprintBlob = data.getBlob(INDEX_UNIFIED_FINGERPRINT); - String fingerprint = KeyFormattingUtils.convertFingerprintToHex(fingerprintBlob); - mFingerprint.setText(KeyFormattingUtils.colorizeFingerprint(fingerprint)); - - loadQrCode(fingerprint); - - if (data.getInt(INDEX_UNIFIED_HAS_ANY_SECRET) != 0) { - // edit button - mActionEdit.setVisibility(View.VISIBLE); - mActionEditDivider.setVisibility(View.VISIBLE); - } else { - // edit button - mActionEdit.setVisibility(View.GONE); - mActionEditDivider.setVisibility(View.GONE); - } - - // If this key is revoked, it cannot be used for anything! - if (data.getInt(INDEX_UNIFIED_IS_REVOKED) != 0) { - mActionEdit.setEnabled(false); - mActionCertify.setEnabled(false); - mActionCertifyText.setEnabled(false); - mActionEncryptText.setEnabled(false); - mActionEncryptTextText.setEnabled(false); - mActionEncryptFiles.setEnabled(false); - } else { - mActionEdit.setEnabled(true); - - Date expiryDate = new Date(data.getLong(INDEX_UNIFIED_EXPIRY) * 1000); - if (!data.isNull(INDEX_UNIFIED_EXPIRY) && expiryDate.before(new Date())) { - mActionCertify.setEnabled(false); - mActionCertifyText.setEnabled(false); - mActionEncryptText.setEnabled(false); - mActionEncryptTextText.setEnabled(false); - mActionEncryptFiles.setEnabled(false); - } else { - mActionCertify.setEnabled(true); - mActionCertifyText.setEnabled(true); - mActionEncryptText.setEnabled(true); - mActionEncryptTextText.setEnabled(true); - mActionEncryptFiles.setEnabled(true); - } - } - - mHasEncrypt = data.getInt(INDEX_UNIFIED_HAS_ENCRYPT) != 0; - - break; - } - } - - case LOADER_ID_USER_IDS: - mUserIdsAdapter.swapCursor(data); - break; - } + mUserIdsAdapter.swapCursor(data); setContentShown(true); } @@ -507,109 +166,4 @@ public class ViewKeyFragment extends LoaderFragment implements } } - - /** - * Load QR Code asynchronously and with a fade in animation - * - * @param fingerprint - */ - private void loadQrCode(final String fingerprint) { - AsyncTask loadTask = - new AsyncTask() { - protected Bitmap doInBackground(Void... unused) { - String qrCodeContent = Constants.FINGERPRINT_SCHEME + ":" + fingerprint; - // render with minimal size - return QrCodeUtils.getQRCodeBitmap(qrCodeContent, 0); - } - - protected void onPostExecute(Bitmap qrCode) { - // only change view, if fragment is attached to activity - if (ViewKeyFragment.this.isAdded()) { - - // scale the image up to our actual size. we do this in code rather - // than let the ImageView do this because we don't require filtering. - Bitmap scaled = Bitmap.createScaledBitmap(qrCode, - mFingerprintQrCode.getHeight(), mFingerprintQrCode.getHeight(), - false); - mFingerprintQrCode.setImageBitmap(scaled); - - // simple fade-in animation - AlphaAnimation anim = new AlphaAnimation(0.0f, 1.0f); - anim.setDuration(200); - mFingerprintQrCode.startAnimation(anim); - } - } - }; - - loadTask.execute(); - } - - private void uploadToKeyserver() { - Intent uploadIntent = new Intent(getActivity(), UploadKeyActivity.class); - uploadIntent.setData(mDataUri); - startActivityForResult(uploadIntent, 0); - } - - private void encrypt(Uri dataUri, boolean text) { - // If there is no encryption key, don't bother. - if (!mHasEncrypt) { - Notify.showNotify(getActivity(), R.string.error_no_encrypt_subkey, Notify.Style.ERROR); - return; - } - try { - long keyId = new ProviderHelper(getActivity()) - .getCachedPublicKeyRing(dataUri) - .extractOrGetMasterKeyId(); - long[] encryptionKeyIds = new long[]{keyId}; - Intent intent; - if (text) { - intent = new Intent(getActivity(), EncryptTextActivity.class); - intent.setAction(EncryptTextActivity.ACTION_ENCRYPT_TEXT); - intent.putExtra(EncryptTextActivity.EXTRA_ENCRYPTION_KEY_IDS, encryptionKeyIds); - } else { - intent = new Intent(getActivity(), EncryptFilesActivity.class); - intent.setAction(EncryptFilesActivity.ACTION_ENCRYPT_DATA); - intent.putExtra(EncryptFilesActivity.EXTRA_ENCRYPTION_KEY_IDS, encryptionKeyIds); - } - // used instead of startActivity set actionbar based on callingPackage - startActivityForResult(intent, 0); - } catch (PgpKeyNotFoundException e) { - Log.e(Constants.TAG, "key not found!", e); - } - } - - private void updateFromKeyserver(Uri dataUri, ProviderHelper providerHelper) - throws NotFoundException { - byte[] blob = (byte[]) providerHelper.getGenericData( - KeyRings.buildUnifiedKeyRingUri(dataUri), - KeychainContract.Keys.FINGERPRINT, ProviderHelper.FIELD_TYPE_BLOB); - String fingerprint = KeyFormattingUtils.convertFingerprintToHex(blob); - - Intent queryIntent = new Intent(getActivity(), ImportKeysActivity.class); - queryIntent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_RESULT); - queryIntent.putExtra(ImportKeysActivity.EXTRA_FINGERPRINT, fingerprint); - - startActivityForResult(queryIntent, 0); - } - - private void certify(Uri dataUri) { - long keyId = 0; - try { - keyId = new ProviderHelper(getActivity()) - .getCachedPublicKeyRing(dataUri) - .extractOrGetMasterKeyId(); - } catch (PgpKeyNotFoundException e) { - Log.e(Constants.TAG, "key not found!", e); - } - Intent certifyIntent = new Intent(getActivity(), CertifyKeyActivity.class); - certifyIntent.putExtra(CertifyKeyActivity.EXTRA_KEY_IDS, new long[]{keyId}); - startActivityForResult(certifyIntent, 0); - } - - private void editKey(Uri dataUri) { - Intent editIntent = new Intent(getActivity(), EditKeyActivity.class); - editIntent.setData(KeychainContract.KeyRingData.buildSecretKeyRingUri(dataUri)); - startActivityForResult(editIntent, 0); - } - } -- cgit v1.2.3 From 8ddca4f8fec566de898fa1ec296aa63ec0410c0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Wed, 25 Feb 2015 13:49:54 +0100 Subject: Fix menu --- .../main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java | 2 ++ 1 file changed, 2 insertions(+) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java index 5454e4f3e..c16a52e9c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java @@ -246,6 +246,7 @@ public class ViewKeyActivity extends BaseActivity implements Intent advancedIntent = new Intent(this, ViewKeyAdvActivity.class); advancedIntent.setData(mDataUri); startActivity(advancedIntent); + return true; } case R.id.menu_key_view_refresh: { try { @@ -253,6 +254,7 @@ public class ViewKeyActivity extends BaseActivity implements } catch (ProviderHelper.NotFoundException e) { Notify.showNotify(this, R.string.error_key_not_found, Notify.Style.ERROR); } + return true; } } } catch (ProviderHelper.NotFoundException e) { -- cgit v1.2.3 From 27263edda5ffba4241e54e2f64f35eb1058663e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Wed, 25 Feb 2015 18:37:31 +0100 Subject: CardView and more header design --- .../keychain/ui/ViewKeyActivity.java | 33 ++++++++++++++-------- .../keychain/ui/ViewKeyAdvActivity.java | 12 ++++++++ .../keychain/ui/ViewKeyFragment.java | 5 ++-- .../keychain/ui/util/QrCodeUtils.java | 2 +- 4 files changed, 37 insertions(+), 15 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java index c16a52e9c..efa526e33 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java @@ -36,6 +36,7 @@ import android.provider.ContactsContract; import android.support.v4.app.LoaderManager; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; +import android.support.v7.widget.CardView; import android.view.Menu; import android.view.MenuItem; import android.view.View; @@ -87,6 +88,7 @@ public class ViewKeyActivity extends BaseActivity implements private FloatingActionButton mFab; private AspectRatioImageView mPhoto; private ImageButton mQrCode; + private CardView mQrCodeLayout; // NFC private NfcAdapter mNfcAdapter; @@ -121,6 +123,7 @@ public class ViewKeyActivity extends BaseActivity implements mFab = (FloatingActionButton) findViewById(R.id.fab); mPhoto = (AspectRatioImageView) findViewById(R.id.view_key_photo); mQrCode = (ImageButton) findViewById(R.id.view_key_qr_code); + mQrCodeLayout = (CardView) findViewById(R.id.view_key_qr_code_layout); mDataUri = getIntent().getData(); if (mDataUri == null) { @@ -169,7 +172,7 @@ public class ViewKeyActivity extends BaseActivity implements if (mIsSecret) { startSafeSlinger(mDataUri); } else { - certify(mDataUri); + scanQrCode(); } } }); @@ -264,6 +267,12 @@ public class ViewKeyActivity extends BaseActivity implements return super.onOptionsItemSelected(item); } + private void scanQrCode() { + Intent scanQrCode = new Intent(this, QrCodeScanActivity.class); + scanQrCode.setAction(QrCodeScanActivity.ACTION_SCAN_WITH_RESULT); + startActivityForResult(scanQrCode, 0); + } + private void showQrCodeDialog() { Intent qrCodeIntent = new Intent(this, QrCodeViewActivity.class); qrCodeIntent.setData(mDataUri); @@ -403,9 +412,6 @@ public class ViewKeyActivity extends BaseActivity implements } protected void onPostExecute(Bitmap qrCode) { - // only change view, if fragment is attached to activity -// if (ViewKeyFragment.this.isAdded()) { - // scale the image up to our actual size. we do this in code rather // than let the ImageView do this because we don't require filtering. Bitmap scaled = Bitmap.createScaledBitmap(qrCode, @@ -418,7 +424,6 @@ public class ViewKeyActivity extends BaseActivity implements anim.setDuration(200); mQrCode.startAnimation(anim); } -// } }; loadTask.execute(); @@ -580,7 +585,6 @@ public class ViewKeyActivity extends BaseActivity implements && new Date(data.getLong(INDEX_EXPIRY) * 1000).before(new Date()); boolean isVerified = data.getInt(INDEX_VERIFIED) > 0; - AsyncTask photoTask = new AsyncTask() { protected Bitmap doInBackground(String... fingerprint) { @@ -606,9 +610,15 @@ public class ViewKeyActivity extends BaseActivity implements mActionVerify.setVisibility(View.GONE); mActionEdit.setVisibility(View.GONE); mFab.setVisibility(View.GONE); - mQrCode.setVisibility(View.GONE); + mQrCodeLayout.setVisibility(View.GONE); } else if (isExpired) { - mStatusText.setText(R.string.view_key_expired); + if (mIsSecret) { + mStatusText.setText(R.string.view_key_expired_secret); + mActionEdit.setVisibility(View.VISIBLE); + } else { + mStatusText.setText(R.string.view_key_expired); + mActionEdit.setVisibility(View.GONE); + } mStatusImage.setVisibility(View.VISIBLE); KeyFormattingUtils.setStatusImage(this, mStatusImage, mStatusText, KeyFormattingUtils.STATE_EXPIRED, R.color.icons, true); color = getResources().getColor(R.color.android_red_light); @@ -616,16 +626,15 @@ public class ViewKeyActivity extends BaseActivity implements mActionEncryptFile.setVisibility(View.GONE); mActionEncryptText.setVisibility(View.GONE); mActionVerify.setVisibility(View.GONE); - mActionEdit.setVisibility(View.GONE); mFab.setVisibility(View.GONE); - mQrCode.setVisibility(View.GONE); + mQrCodeLayout.setVisibility(View.GONE); } else if (mIsSecret) { mStatusText.setText(R.string.view_key_my_key); mStatusImage.setVisibility(View.GONE); color = getResources().getColor(R.color.primary); photoTask.execute(fingerprint); loadQrCode(fingerprint); - mQrCode.setVisibility(View.VISIBLE); + mQrCodeLayout.setVisibility(View.VISIBLE); mActionEncryptFile.setVisibility(View.VISIBLE); mActionEncryptText.setVisibility(View.VISIBLE); @@ -637,7 +646,7 @@ public class ViewKeyActivity extends BaseActivity implements mActionEncryptFile.setVisibility(View.VISIBLE); mActionEncryptText.setVisibility(View.VISIBLE); mActionEdit.setVisibility(View.GONE); - mQrCode.setVisibility(View.GONE); + mQrCodeLayout.setVisibility(View.GONE); if (isVerified) { mStatusText.setText(R.string.view_key_verified); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvActivity.java index 840dea471..37f9113bb 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvActivity.java @@ -33,6 +33,7 @@ import com.astuetz.PagerSlidingTabStrip; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.pgp.KeyRing; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.ProviderHelper; @@ -237,4 +238,15 @@ public class ViewKeyAdvActivity extends BaseActivity implements public void onLoaderReset(Loader loader) { } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + // if a result has been returned, display a notify + if (data != null && data.hasExtra(OperationResult.EXTRA_RESULT)) { + OperationResult result = data.getParcelableExtra(OperationResult.EXTRA_RESULT); + result.createNotify(this).show(); + } else { + super.onActivityResult(requestCode, resultCode, data); + } + } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyFragment.java index 571c86b82..f30ab2b33 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyFragment.java @@ -88,7 +88,6 @@ public class ViewKeyFragment extends LoaderFragment implements return root; } - private void showUserIdInfo(final int position) { final boolean isRevoked = mUserIdsAdapter.getIsRevoked(position); final int isVerified = mUserIdsAdapter.getIsVerified(position); @@ -130,13 +129,15 @@ public class ViewKeyFragment extends LoaderFragment implements getLoaderManager().initLoader(LOADER_ID_USER_IDS, null, this); } + // don't show revoked user ids here, irrelevant for average users + public static final String WHERE = UserPackets.IS_REVOKED + " = 0"; public Loader onCreateLoader(int id, Bundle args) { setContentShown(false); Uri baseUri = UserPackets.buildUserIdsUri(mDataUri); return new CursorLoader(getActivity(), baseUri, - UserIdsAdapter.USER_IDS_PROJECTION, null, null, null); + UserIdsAdapter.USER_IDS_PROJECTION, WHERE, null, null); } public void onLoadFinished(Loader loader, Cursor data) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/QrCodeUtils.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/QrCodeUtils.java index 0bb4100c5..b8d4ea7d2 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/QrCodeUtils.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/QrCodeUtils.java @@ -59,7 +59,7 @@ public class QrCodeUtils { for (int y = 0; y < height; y++) { final int offset = y * width; for (int x = 0; x < width; x++) { - pixels[offset + x] = result.get(x, y) ? Color.BLACK : Color.WHITE; + pixels[offset + x] = result.get(x, y) ? Color.BLACK : Color.TRANSPARENT; } } -- cgit v1.2.3 From 57fa702cbf28368994810c33dcc9afeebf60932d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Wed, 25 Feb 2015 19:38:13 +0100 Subject: Design fixes for header, QR Code shared element transitions --- .../keychain/ui/QrCodeViewActivity.java | 43 +++++++------------- .../keychain/ui/ViewKeyActivity.java | 47 +++++++++++++++++++--- .../keychain/ui/util/FormattingUtils.java | 10 +---- 3 files changed, 58 insertions(+), 42 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeViewActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeViewActivity.java index 204ea1d38..b24ee84a4 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeViewActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeViewActivity.java @@ -20,6 +20,7 @@ package org.sufficientlysecure.keychain.ui; import android.graphics.Bitmap; import android.net.Uri; import android.os.Bundle; +import android.support.v4.app.ActivityCompat; import android.view.View; import android.view.ViewTreeObserver.OnGlobalLayoutListener; import android.widget.ImageView; @@ -48,7 +49,7 @@ public class QrCodeViewActivity extends BaseActivity { @Override public void onClick(View v) { // "Done" - finish(); + ActivityCompat.finishAfterTransition(QrCodeViewActivity.this); } } ); @@ -56,7 +57,7 @@ public class QrCodeViewActivity extends BaseActivity { Uri dataUri = getIntent().getData(); if (dataUri == null) { Log.e(Constants.TAG, "Data missing. Should be Uri of key!"); - finish(); + ActivityCompat.finishAfterTransition(QrCodeViewActivity.this); return; } @@ -65,7 +66,7 @@ public class QrCodeViewActivity extends BaseActivity { mFingerprintQrCode.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - finish(); + ActivityCompat.finishAfterTransition(QrCodeViewActivity.this); } }); @@ -77,7 +78,7 @@ public class QrCodeViewActivity extends BaseActivity { if (blob == null) { Log.e(Constants.TAG, "key not found!"); Notify.showNotify(this, R.string.error_key_not_found, Style.ERROR); - finish(); + ActivityCompat.finishAfterTransition(QrCodeViewActivity.this); } String fingerprint = KeyFormattingUtils.convertFingerprintToHex(blob); @@ -88,18 +89,18 @@ public class QrCodeViewActivity extends BaseActivity { mFingerprintQrCode.getViewTreeObserver().addOnGlobalLayoutListener( new OnGlobalLayoutListener() { - @Override - public void onGlobalLayout() { - // create actual bitmap in display dimensions - Bitmap scaled = Bitmap.createScaledBitmap(qrCode, - mFingerprintQrCode.getWidth(), mFingerprintQrCode.getWidth(), false); - mFingerprintQrCode.setImageBitmap(scaled); - } - }); + @Override + public void onGlobalLayout() { + // create actual bitmap in display dimensions + Bitmap scaled = Bitmap.createScaledBitmap(qrCode, + mFingerprintQrCode.getWidth(), mFingerprintQrCode.getWidth(), false); + mFingerprintQrCode.setImageBitmap(scaled); + } + }); } catch (ProviderHelper.NotFoundException e) { Log.e(Constants.TAG, "key not found!", e); Notify.showNotify(this, R.string.error_key_not_found, Style.ERROR); - finish(); + ActivityCompat.finishAfterTransition(QrCodeViewActivity.this); } } @@ -108,20 +109,4 @@ public class QrCodeViewActivity extends BaseActivity { setContentView(R.layout.qr_code_activity); } - @Override - protected void onResume() { - super.onResume(); - - // custom activity transition to get zoom in effect - this.overridePendingTransition(R.anim.qr_code_zoom_enter, android.R.anim.fade_out); - } - - @Override - protected void onPause() { - super.onPause(); - - // custom activity transition to get zoom out effect - this.overridePendingTransition(0, R.anim.qr_code_zoom_exit); - } - } \ No newline at end of file diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java index efa526e33..df586c11c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java @@ -19,6 +19,7 @@ package org.sufficientlysecure.keychain.ui; import android.annotation.TargetApi; +import android.app.ActivityOptions; import android.content.Intent; import android.database.Cursor; import android.graphics.Bitmap; @@ -33,6 +34,7 @@ import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.provider.ContactsContract; +import android.support.v4.app.ActivityCompat; import android.support.v4.app.LoaderManager; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; @@ -57,6 +59,7 @@ import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; +import org.sufficientlysecure.keychain.ui.util.FormattingUtils; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.ui.util.QrCodeUtils; @@ -275,8 +278,18 @@ public class ViewKeyActivity extends BaseActivity implements private void showQrCodeDialog() { Intent qrCodeIntent = new Intent(this, QrCodeViewActivity.class); + + // create the transition animation - the images in the layouts + // of both activities are defined with android:transitionName="qr_code" + Bundle opts = null; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + ActivityOptions options = ActivityOptions + .makeSceneTransitionAnimation(this, mQrCodeLayout, "qr_code"); + opts = options.toBundle(); + } + qrCodeIntent.setData(mDataUri); - startActivity(qrCodeIntent); + ActivityCompat.startActivity(this, qrCodeIntent, opts); } private void exportToFile(Uri dataUri, ExportHelper exportHelper, ProviderHelper providerHelper) @@ -602,7 +615,8 @@ public class ViewKeyActivity extends BaseActivity implements if (isRevoked) { mStatusText.setText(R.string.view_key_revoked); mStatusImage.setVisibility(View.VISIBLE); - KeyFormattingUtils.setStatusImage(this, mStatusImage, mStatusText, KeyFormattingUtils.STATE_REVOKED, R.color.icons, true); + KeyFormattingUtils.setStatusImage(this, mStatusImage, mStatusText, + KeyFormattingUtils.STATE_REVOKED, R.color.icons, true); color = getResources().getColor(R.color.android_red_light); mActionEncryptFile.setVisibility(View.GONE); @@ -620,7 +634,8 @@ public class ViewKeyActivity extends BaseActivity implements mActionEdit.setVisibility(View.GONE); } mStatusImage.setVisibility(View.VISIBLE); - KeyFormattingUtils.setStatusImage(this, mStatusImage, mStatusText, KeyFormattingUtils.STATE_EXPIRED, R.color.icons, true); + KeyFormattingUtils.setStatusImage(this, mStatusImage, mStatusText, + KeyFormattingUtils.STATE_EXPIRED, R.color.icons, true); color = getResources().getColor(R.color.android_red_light); mActionEncryptFile.setVisibility(View.GONE); @@ -636,6 +651,26 @@ public class ViewKeyActivity extends BaseActivity implements loadQrCode(fingerprint); mQrCodeLayout.setVisibility(View.VISIBLE); + // and place leftOf qr code + RelativeLayout.LayoutParams nameParams = (RelativeLayout.LayoutParams) + mName.getLayoutParams(); + // remove right margin + nameParams.setMargins(FormattingUtils.dpToPx(this, 48), 0, 0, 0); + if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + nameParams.setMarginEnd(0); + } + nameParams.addRule(RelativeLayout.LEFT_OF, R.id.view_key_qr_code_layout); + mName.setLayoutParams(nameParams); + + RelativeLayout.LayoutParams statusParams = (RelativeLayout.LayoutParams) + mStatusText.getLayoutParams(); + statusParams.setMargins(FormattingUtils.dpToPx(this, 48), 0, 0, 0); + if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + statusParams.setMarginEnd(0); + } + statusParams.addRule(RelativeLayout.LEFT_OF, R.id.view_key_qr_code_layout); + mStatusText.setLayoutParams(statusParams); + mActionEncryptFile.setVisibility(View.VISIBLE); mActionEncryptText.setVisibility(View.VISIBLE); mActionVerify.setVisibility(View.GONE); @@ -651,7 +686,8 @@ public class ViewKeyActivity extends BaseActivity implements if (isVerified) { mStatusText.setText(R.string.view_key_verified); mStatusImage.setVisibility(View.VISIBLE); - KeyFormattingUtils.setStatusImage(this, mStatusImage, mStatusText, KeyFormattingUtils.STATE_VERIFIED, R.color.icons, true); + KeyFormattingUtils.setStatusImage(this, mStatusImage, mStatusText, + KeyFormattingUtils.STATE_VERIFIED, R.color.icons, true); color = getResources().getColor(R.color.primary); photoTask.execute(fingerprint); @@ -660,7 +696,8 @@ public class ViewKeyActivity extends BaseActivity implements } else { mStatusText.setText(R.string.view_key_unverified); mStatusImage.setVisibility(View.VISIBLE); - KeyFormattingUtils.setStatusImage(this, mStatusImage, mStatusText, KeyFormattingUtils.STATE_UNVERIFIED, R.color.icons, true); + KeyFormattingUtils.setStatusImage(this, mStatusImage, mStatusText, + KeyFormattingUtils.STATE_UNVERIFIED, R.color.icons, true); color = getResources().getColor(R.color.android_orange_light); mActionVerify.setVisibility(View.VISIBLE); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/FormattingUtils.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/FormattingUtils.java index 3f84bf490..eb5c3df45 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/FormattingUtils.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/FormattingUtils.java @@ -24,18 +24,12 @@ import android.text.style.StrikethroughSpan; public class FormattingUtils { - public static SpannableStringBuilder strikeOutText(CharSequence text) { - SpannableStringBuilder sb = new SpannableStringBuilder(text); - sb.setSpan(new StrikethroughSpan(), 0, text.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE); - return sb; - } - public static int dpToPx(Context context, int dp) { - return (int) ((dp * context.getResources().getDisplayMetrics().density) + 0.5); + return (int) ((dp * context.getResources().getDisplayMetrics().density) + 0.5f); } public static int pxToDp(Context context, int px) { - return (int) ((px / context.getResources().getDisplayMetrics().density) + 0.5); + return (int) ((px / context.getResources().getDisplayMetrics().density) + 0.5f); } } -- cgit v1.2.3 From 0931c7742bdb238d222362fee3b865bfa33dfc22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Wed, 25 Feb 2015 20:20:39 +0100 Subject: Other icon for key exchange --- .../main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java index df586c11c..4e8a14008 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java @@ -676,7 +676,7 @@ public class ViewKeyActivity extends BaseActivity implements mActionVerify.setVisibility(View.GONE); mActionEdit.setVisibility(View.VISIBLE); mFab.setVisibility(View.VISIBLE); - mFab.setIconDrawable(getResources().getDrawable(R.drawable.ic_swap_vert_white_24dp)); + mFab.setIconDrawable(getResources().getDrawable(R.drawable.ic_repeat_white_24dp)); } else { mActionEncryptFile.setVisibility(View.VISIBLE); mActionEncryptText.setVisibility(View.VISIBLE); -- cgit v1.2.3 From b521162ef049d223987af4c424083a8355c9bfb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Wed, 25 Feb 2015 20:50:34 +0100 Subject: Invoke NFC button --- .../keychain/ui/ViewKeyActivity.java | 28 ++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java index 4e8a14008..3ddaccad3 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java @@ -88,6 +88,7 @@ public class ViewKeyActivity extends BaseActivity implements private ImageButton mActionEncryptText; private ImageButton mActionVerify; private ImageButton mActionEdit; + private ImageButton mActionNfc; private FloatingActionButton mFab; private AspectRatioImageView mPhoto; private ImageButton mQrCode; @@ -123,6 +124,7 @@ public class ViewKeyActivity extends BaseActivity implements mActionEncryptText = (ImageButton) findViewById(R.id.view_key_action_encrypt_text); mActionVerify = (ImageButton) findViewById(R.id.view_key_action_verify); mActionEdit = (ImageButton) findViewById(R.id.view_key_action_edit); + mActionNfc = (ImageButton) findViewById(R.id.view_key_action_nfc); mFab = (FloatingActionButton) findViewById(R.id.fab); mPhoto = (AspectRatioImageView) findViewById(R.id.view_key_photo); mQrCode = (ImageButton) findViewById(R.id.view_key_qr_code); @@ -187,6 +189,13 @@ public class ViewKeyActivity extends BaseActivity implements } }); + mActionNfc.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + invokeNfcBeam(); + } + }); + // Prepare the loaders. Either re-connect with an existing ones, // or start new ones. @@ -270,6 +279,15 @@ public class ViewKeyActivity extends BaseActivity implements return super.onOptionsItemSelected(item); } + @TargetApi(Build.VERSION_CODES.LOLLIPOP) + private void invokeNfcBeam() { + // Check for available NFC Adapter + mNfcAdapter = NfcAdapter.getDefaultAdapter(this); + if (mNfcAdapter != null) { + mNfcAdapter.invokeBeam(this); + } + } + private void scanQrCode() { Intent scanQrCode = new Intent(this, QrCodeScanActivity.class); scanQrCode.setAction(QrCodeScanActivity.ACTION_SCAN_WITH_RESULT); @@ -623,6 +641,7 @@ public class ViewKeyActivity extends BaseActivity implements mActionEncryptText.setVisibility(View.GONE); mActionVerify.setVisibility(View.GONE); mActionEdit.setVisibility(View.GONE); + mActionNfc.setVisibility(View.GONE); mFab.setVisibility(View.GONE); mQrCodeLayout.setVisibility(View.GONE); } else if (isExpired) { @@ -641,6 +660,7 @@ public class ViewKeyActivity extends BaseActivity implements mActionEncryptFile.setVisibility(View.GONE); mActionEncryptText.setVisibility(View.GONE); mActionVerify.setVisibility(View.GONE); + mActionNfc.setVisibility(View.GONE); mFab.setVisibility(View.GONE); mQrCodeLayout.setVisibility(View.GONE); } else if (mIsSecret) { @@ -675,6 +695,13 @@ public class ViewKeyActivity extends BaseActivity implements mActionEncryptText.setVisibility(View.VISIBLE); mActionVerify.setVisibility(View.GONE); mActionEdit.setVisibility(View.VISIBLE); + + // invokeBeam is available from API 21 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + mActionNfc.setVisibility(View.VISIBLE); + } else { + mActionNfc.setVisibility(View.GONE); + } mFab.setVisibility(View.VISIBLE); mFab.setIconDrawable(getResources().getDrawable(R.drawable.ic_repeat_white_24dp)); } else { @@ -682,6 +709,7 @@ public class ViewKeyActivity extends BaseActivity implements mActionEncryptText.setVisibility(View.VISIBLE); mActionEdit.setVisibility(View.GONE); mQrCodeLayout.setVisibility(View.GONE); + mActionNfc.setVisibility(View.GONE); if (isVerified) { mStatusText.setText(R.string.view_key_verified); -- cgit v1.2.3 From a38f84a40169a65bf0eac1e06165a844df9b642c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Wed, 25 Feb 2015 21:53:46 +0100 Subject: Dont show verification icons in my key view, hide edit button for non-secret keys --- .../keychain/ui/ViewKeyActivity.java | 57 ++++++++--- .../keychain/ui/ViewKeyAdvMainFragment.java | 3 +- .../keychain/ui/ViewKeyFragment.java | 108 ++++++++++++++++----- .../keychain/ui/adapter/UserIdsAdapter.java | 22 ++++- 4 files changed, 145 insertions(+), 45 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java index 3ddaccad3..c67fde8e1 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java @@ -34,6 +34,7 @@ import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.provider.ContactsContract; +import android.provider.Settings; import android.support.v4.app.ActivityCompat; import android.support.v4.app.LoaderManager; import android.support.v4.content.CursorLoader; @@ -87,7 +88,6 @@ public class ViewKeyActivity extends BaseActivity implements private ImageButton mActionEncryptFile; private ImageButton mActionEncryptText; private ImageButton mActionVerify; - private ImageButton mActionEdit; private ImageButton mActionNfc; private FloatingActionButton mFab; private AspectRatioImageView mPhoto; @@ -103,8 +103,8 @@ public class ViewKeyActivity extends BaseActivity implements private static final int LOADER_ID_UNIFIED = 0; - private boolean mIsSecret; - private boolean mHasEncrypt; + private boolean mIsSecret = false; + private boolean mHasEncrypt = false; @Override protected void onCreate(Bundle savedInstanceState) { @@ -123,7 +123,6 @@ public class ViewKeyActivity extends BaseActivity implements mActionEncryptFile = (ImageButton) findViewById(R.id.view_key_action_encrypt_files); mActionEncryptText = (ImageButton) findViewById(R.id.view_key_action_encrypt_text); mActionVerify = (ImageButton) findViewById(R.id.view_key_action_verify); - mActionEdit = (ImageButton) findViewById(R.id.view_key_action_edit); mActionNfc = (ImageButton) findViewById(R.id.view_key_action_nfc); mFab = (FloatingActionButton) findViewById(R.id.fab); mPhoto = (AspectRatioImageView) findViewById(R.id.view_key_photo); @@ -165,11 +164,6 @@ public class ViewKeyActivity extends BaseActivity implements certify(mDataUri); } }); - mActionEdit.setOnClickListener(new View.OnClickListener() { - public void onClick(View view) { - editKey(mDataUri); - } - }); mFab.setOnClickListener(new View.OnClickListener() { @Override @@ -271,6 +265,10 @@ public class ViewKeyActivity extends BaseActivity implements } return true; } + case R.id.menu_key_view_edit: { + editKey(mDataUri); + return true; + } } } catch (ProviderHelper.NotFoundException e) { Notify.showNotify(this, R.string.error_key_not_found, Notify.Style.ERROR); @@ -279,13 +277,42 @@ public class ViewKeyActivity extends BaseActivity implements return super.onOptionsItemSelected(item); } + @Override + public boolean onPrepareOptionsMenu(Menu menu) { + MenuItem register = menu.findItem(R.id.menu_key_view_edit); + register.setVisible(mIsSecret); + return true; + } + @TargetApi(Build.VERSION_CODES.LOLLIPOP) private void invokeNfcBeam() { // Check for available NFC Adapter mNfcAdapter = NfcAdapter.getDefaultAdapter(this); - if (mNfcAdapter != null) { - mNfcAdapter.invokeBeam(this); + if (mNfcAdapter == null || !mNfcAdapter.isEnabled()) { + Notify.createNotify(this, R.string.error_nfc_needed, Notify.LENGTH_LONG, Notify.Style.ERROR, new Notify.ActionListener() { + @Override + public void onAction() { + Intent intentSettings = new Intent(Settings.ACTION_NFC_SETTINGS); + startActivity(intentSettings); + } + }, R.string.menu_nfc_preferences).show(); + + return; + } + + if (!mNfcAdapter.isNdefPushEnabled()) { + Notify.createNotify(this, R.string.error_beam_needed, Notify.LENGTH_LONG, Notify.Style.ERROR, new Notify.ActionListener() { + @Override + public void onAction() { + Intent intentSettings = new Intent(Settings.ACTION_NFCSHARING_SETTINGS); + startActivity(intentSettings); + } + }, R.string.menu_beam_preferences).show(); + + return; } + + mNfcAdapter.invokeBeam(this); } private void scanQrCode() { @@ -640,17 +667,14 @@ public class ViewKeyActivity extends BaseActivity implements mActionEncryptFile.setVisibility(View.GONE); mActionEncryptText.setVisibility(View.GONE); mActionVerify.setVisibility(View.GONE); - mActionEdit.setVisibility(View.GONE); mActionNfc.setVisibility(View.GONE); mFab.setVisibility(View.GONE); mQrCodeLayout.setVisibility(View.GONE); } else if (isExpired) { if (mIsSecret) { mStatusText.setText(R.string.view_key_expired_secret); - mActionEdit.setVisibility(View.VISIBLE); } else { mStatusText.setText(R.string.view_key_expired); - mActionEdit.setVisibility(View.GONE); } mStatusImage.setVisibility(View.VISIBLE); KeyFormattingUtils.setStatusImage(this, mStatusImage, mStatusText, @@ -664,6 +688,9 @@ public class ViewKeyActivity extends BaseActivity implements mFab.setVisibility(View.GONE); mQrCodeLayout.setVisibility(View.GONE); } else if (mIsSecret) { + // re-create options menu to see edit button + supportInvalidateOptionsMenu(); + mStatusText.setText(R.string.view_key_my_key); mStatusImage.setVisibility(View.GONE); color = getResources().getColor(R.color.primary); @@ -694,7 +721,6 @@ public class ViewKeyActivity extends BaseActivity implements mActionEncryptFile.setVisibility(View.VISIBLE); mActionEncryptText.setVisibility(View.VISIBLE); mActionVerify.setVisibility(View.GONE); - mActionEdit.setVisibility(View.VISIBLE); // invokeBeam is available from API 21 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { @@ -707,7 +733,6 @@ public class ViewKeyActivity extends BaseActivity implements } else { mActionEncryptFile.setVisibility(View.VISIBLE); mActionEncryptText.setVisibility(View.VISIBLE); - mActionEdit.setVisibility(View.GONE); mQrCodeLayout.setVisibility(View.GONE); mActionNfc.setVisibility(View.GONE); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvMainFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvMainFragment.java index abed59aa9..c9d20f9f4 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvMainFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvMainFragment.java @@ -265,9 +265,10 @@ public class ViewKeyAdvMainFragment extends LoaderFragment implements } } - case LOADER_ID_USER_IDS: + case LOADER_ID_USER_IDS: { mUserIdsAdapter.swapCursor(data); break; + } } setContentShown(true); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyFragment.java index f30ab2b33..453bfd499 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyFragment.java @@ -33,12 +33,15 @@ import android.widget.ListView; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround; +import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.ui.adapter.UserIdsAdapter; import org.sufficientlysecure.keychain.ui.dialog.UserIdInfoDialogFragment; import org.sufficientlysecure.keychain.util.Log; +import java.util.Date; + public class ViewKeyFragment extends LoaderFragment implements LoaderManager.LoaderCallbacks { @@ -46,6 +49,9 @@ public class ViewKeyFragment extends LoaderFragment implements private ListView mUserIds; + boolean mIsSecret = false; + + private static final int LOADER_ID_UNIFIED = 0; private static final int LOADER_ID_USER_IDS = 1; private UserIdsAdapter mUserIdsAdapter; @@ -76,7 +82,6 @@ public class ViewKeyFragment extends LoaderFragment implements mUserIds = (ListView) view.findViewById(R.id.view_key_user_ids); - mUserIds.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView parent, View view, int position, long id) { @@ -84,22 +89,23 @@ public class ViewKeyFragment extends LoaderFragment implements } }); - return root; } private void showUserIdInfo(final int position) { - final boolean isRevoked = mUserIdsAdapter.getIsRevoked(position); - final int isVerified = mUserIdsAdapter.getIsVerified(position); - - DialogFragmentWorkaround.INTERFACE.runnableRunDelayed(new Runnable() { - public void run() { - UserIdInfoDialogFragment dialogFragment = - UserIdInfoDialogFragment.newInstance(isRevoked, isVerified); - - dialogFragment.show(getActivity().getSupportFragmentManager(), "userIdInfoDialog"); - } - }); + if (!mIsSecret) { + final boolean isRevoked = mUserIdsAdapter.getIsRevoked(position); + final int isVerified = mUserIdsAdapter.getIsVerified(position); + + DialogFragmentWorkaround.INTERFACE.runnableRunDelayed(new Runnable() { + public void run() { + UserIdInfoDialogFragment dialogFragment = + UserIdInfoDialogFragment.newInstance(isRevoked, isVerified); + + dialogFragment.show(getActivity().getSupportFragmentManager(), "userIdInfoDialog"); + } + }); + } } @Override @@ -116,28 +122,59 @@ public class ViewKeyFragment extends LoaderFragment implements loadData(dataUri); } + + // These are the rows that we will retrieve. + static final String[] UNIFIED_PROJECTION = new String[]{ + KeychainContract.KeyRings._ID, + KeychainContract.KeyRings.MASTER_KEY_ID, + KeychainContract.KeyRings.USER_ID, + KeychainContract.KeyRings.IS_REVOKED, + KeychainContract.KeyRings.EXPIRY, + KeychainContract.KeyRings.VERIFIED, + KeychainContract.KeyRings.HAS_ANY_SECRET, + KeychainContract.KeyRings.FINGERPRINT, + KeychainContract.KeyRings.HAS_ENCRYPT + }; + + static final int INDEX_MASTER_KEY_ID = 1; + static final int INDEX_USER_ID = 2; + static final int INDEX_IS_REVOKED = 3; + static final int INDEX_EXPIRY = 4; + static final int INDEX_VERIFIED = 5; + static final int INDEX_HAS_ANY_SECRET = 6; + static final int INDEX_FINGERPRINT = 7; + static final int INDEX_HAS_ENCRYPT = 8; + private void loadData(Uri dataUri) { mDataUri = dataUri; Log.i(Constants.TAG, "mDataUri: " + mDataUri.toString()); - mUserIdsAdapter = new UserIdsAdapter(getActivity(), null, 0); - mUserIds.setAdapter(mUserIdsAdapter); - // Prepare the loaders. Either re-connect with an existing ones, // or start new ones. - getLoaderManager().initLoader(LOADER_ID_USER_IDS, null, this); + getLoaderManager().initLoader(LOADER_ID_UNIFIED, null, this); } // don't show revoked user ids here, irrelevant for average users - public static final String WHERE = UserPackets.IS_REVOKED + " = 0"; + public static final String USER_IDS_WHERE = UserPackets.IS_REVOKED + " = 0"; public Loader onCreateLoader(int id, Bundle args) { setContentShown(false); - Uri baseUri = UserPackets.buildUserIdsUri(mDataUri); - return new CursorLoader(getActivity(), baseUri, - UserIdsAdapter.USER_IDS_PROJECTION, WHERE, null, null); + switch (id) { + case LOADER_ID_UNIFIED: { + Uri baseUri = KeychainContract.KeyRings.buildUnifiedKeyRingUri(mDataUri); + return new CursorLoader(getActivity(), baseUri, UNIFIED_PROJECTION, null, null, null); + } + case LOADER_ID_USER_IDS: { + Uri baseUri = UserPackets.buildUserIdsUri(mDataUri); + return new CursorLoader(getActivity(), baseUri, + UserIdsAdapter.USER_IDS_PROJECTION, USER_IDS_WHERE, null, null); + } + + default: + return null; + } } public void onLoadFinished(Loader loader, Cursor data) { @@ -150,8 +187,32 @@ public class ViewKeyFragment extends LoaderFragment implements } // Swap the new cursor in. (The framework will take care of closing the // old cursor once we return.) + switch (loader.getId()) { + case LOADER_ID_UNIFIED: { + if (data.moveToFirst()) { + + mIsSecret = data.getInt(INDEX_HAS_ANY_SECRET) != 0; + boolean hasEncrypt = data.getInt(INDEX_HAS_ENCRYPT) != 0; + boolean isRevoked = data.getInt(INDEX_IS_REVOKED) > 0; + boolean isExpired = !data.isNull(INDEX_EXPIRY) + && new Date(data.getLong(INDEX_EXPIRY) * 1000).before(new Date()); + boolean isVerified = data.getInt(INDEX_VERIFIED) > 0; + + // load user ids after we know if it's a secret key + mUserIdsAdapter = new UserIdsAdapter(getActivity(), null, 0, false, !mIsSecret, null); + mUserIds.setAdapter(mUserIdsAdapter); + getLoaderManager().initLoader(LOADER_ID_USER_IDS, null, this); + + break; + } + } - mUserIdsAdapter.swapCursor(data); + case LOADER_ID_USER_IDS: { + mUserIdsAdapter.swapCursor(data); + break; + } + + } setContentShown(true); } @@ -161,9 +222,10 @@ public class ViewKeyFragment extends LoaderFragment implements */ public void onLoaderReset(Loader loader) { switch (loader.getId()) { - case LOADER_ID_USER_IDS: + case LOADER_ID_USER_IDS: { mUserIdsAdapter.swapCursor(null); break; + } } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java index 8e86efebe..ad7c9e430 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java @@ -43,6 +43,7 @@ public class UserIdsAdapter extends CursorAdapter implements AdapterView.OnItemC private LayoutInflater mInflater; private final ArrayList mCheckStates; private SaveKeyringParcel mSaveKeyringParcel; + private boolean mShowStatusImages; public static final String[] USER_IDS_PROJECTION = new String[]{ UserPackets._ID, @@ -60,24 +61,30 @@ public class UserIdsAdapter extends CursorAdapter implements AdapterView.OnItemC private static final int INDEX_IS_REVOKED = 5; public UserIdsAdapter(Context context, Cursor c, int flags, boolean showCheckBoxes, - SaveKeyringParcel saveKeyringParcel) { + boolean showStatusImages, SaveKeyringParcel saveKeyringParcel) { super(context, c, flags); mInflater = LayoutInflater.from(context); mCheckStates = showCheckBoxes ? new ArrayList() : null; mSaveKeyringParcel = saveKeyringParcel; + mShowStatusImages = showStatusImages; + } + + public UserIdsAdapter(Context context, Cursor c, int flags, boolean showCheckBoxes, + SaveKeyringParcel saveKeyringParcel) { + this(context, c, flags, showCheckBoxes, false, saveKeyringParcel); } public UserIdsAdapter(Context context, Cursor c, int flags, boolean showCheckBoxes) { - this(context, c, flags, showCheckBoxes, null); + this(context, c, flags, showCheckBoxes, false, null); } public UserIdsAdapter(Context context, Cursor c, int flags, SaveKeyringParcel saveKeyringParcel) { - this(context, c, flags, false, saveKeyringParcel); + this(context, c, flags, false, false, saveKeyringParcel); } public UserIdsAdapter(Context context, Cursor c, int flags) { - this(context, c, flags, false, null); + this(context, c, flags, false, false, null); } @Override @@ -157,7 +164,12 @@ public class UserIdsAdapter extends CursorAdapter implements AdapterView.OnItemC vVerifiedLayout.setVisibility(View.GONE); } else { vEditImage.setVisibility(View.GONE); - vVerifiedLayout.setVisibility(View.VISIBLE); + + if (mShowStatusImages) { + vVerifiedLayout.setVisibility(View.VISIBLE); + } else { + vVerifiedLayout.setVisibility(View.GONE); + } } if (isRevoked) { -- cgit v1.2.3 From 72acaaa41f88c729b651575a2c014cff11ca0fe4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Thu, 26 Feb 2015 02:06:57 +0100 Subject: Fingerprint verification, design fixes for qr code card --- .../keychain/ui/CertifyFingerprintActivity.java | 92 +++++++++++ .../keychain/ui/CertifyFingerprintFragment.java | 184 +++++++++++++++++++++ .../keychain/ui/QrCodeViewActivity.java | 15 +- .../keychain/ui/ViewKeyActivity.java | 60 +++---- 4 files changed, 309 insertions(+), 42 deletions(-) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyFingerprintActivity.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyFingerprintFragment.java (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyFingerprintActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyFingerprintActivity.java new file mode 100644 index 000000000..777288e69 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyFingerprintActivity.java @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2015 Dominik Schürmann + * + * 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 . + */ + +package org.sufficientlysecure.keychain.ui; + +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.view.View; + +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.operations.results.OperationResult; +import org.sufficientlysecure.keychain.util.Log; + +public class CertifyFingerprintActivity extends BaseActivity { + + protected Uri mDataUri; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + mDataUri = getIntent().getData(); + if (mDataUri == null) { + Log.e(Constants.TAG, "Data missing. Should be uri of key!"); + finish(); + return; + } + + setFullScreenDialogClose(new View.OnClickListener() { + @Override + public void onClick(View v) { + finish(); + } + }); + + Log.i(Constants.TAG, "mDataUri: " + mDataUri.toString()); + + startFragment(savedInstanceState, mDataUri); + } + + @Override + protected void initLayout() { + setContentView(R.layout.certify_fingerprint_activity); + } + + private void startFragment(Bundle savedInstanceState, Uri dataUri) { + // However, if we're being restored from a previous state, + // then we don't need to do anything and should return or else + // we could end up with overlapping fragments. + if (savedInstanceState != null) { + return; + } + + // Create an instance of the fragment + CertifyFingerprintFragment frag = CertifyFingerprintFragment.newInstance(dataUri); + + // Add the fragment to the 'fragment_container' FrameLayout + // NOTE: We use commitAllowingStateLoss() to prevent weird crashes! + getSupportFragmentManager().beginTransaction() + .replace(R.id.certify_fingerprint_fragment, frag) + .commitAllowingStateLoss(); + // do it immediately! + getSupportFragmentManager().executePendingTransactions(); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + // if a result has been returned, display a notify + if (data != null && data.hasExtra(OperationResult.EXTRA_RESULT)) { + OperationResult result = data.getParcelableExtra(OperationResult.EXTRA_RESULT); + result.createNotify(this).show(); + } else { + super.onActivityResult(requestCode, resultCode, data); + } + } +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyFingerprintFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyFingerprintFragment.java new file mode 100644 index 000000000..aef705ee9 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyFingerprintFragment.java @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2015 Dominik Schürmann + * + * 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 . + */ + +package org.sufficientlysecure.keychain.ui; + +import android.content.Intent; +import android.database.Cursor; +import android.net.Uri; +import android.os.Bundle; +import android.support.v4.app.LoaderManager; +import android.support.v4.content.CursorLoader; +import android.support.v4.content.Loader; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; +import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; +import org.sufficientlysecure.keychain.provider.ProviderHelper; +import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; +import org.sufficientlysecure.keychain.util.Log; + + +public class CertifyFingerprintFragment extends LoaderFragment implements + LoaderManager.LoaderCallbacks { + + public static final String ARG_DATA_URI = "uri"; + + private TextView mFingerprint; + + private static final int LOADER_ID_UNIFIED = 0; + + private Uri mDataUri; + + private View mActionNo; + private View mActionYes; + + /** + * Creates new instance of this fragment + */ + public static CertifyFingerprintFragment newInstance(Uri dataUri) { + CertifyFingerprintFragment frag = new CertifyFingerprintFragment(); + Bundle args = new Bundle(); + args.putParcelable(ARG_DATA_URI, dataUri); + + frag.setArguments(args); + + return frag; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup superContainer, Bundle savedInstanceState) { + View root = super.onCreateView(inflater, superContainer, savedInstanceState); + View view = inflater.inflate(R.layout.certify_fingerprint_fragment, getContainer()); + + mActionNo = view.findViewById(R.id.certify_fingerprint_button_no); + mActionYes = view.findViewById(R.id.certify_fingerprint_button_yes); + + mFingerprint = (TextView) view.findViewById(R.id.certify_fingerprint_fingerprint); + + mActionNo.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + getActivity().finish(); + } + }); + mActionYes.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + certify(mDataUri); + } + }); + + return root; + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + Uri dataUri = getArguments().getParcelable(ARG_DATA_URI); + if (dataUri == null) { + Log.e(Constants.TAG, "Data missing. Should be Uri of key!"); + getActivity().finish(); + return; + } + + loadData(dataUri); + } + + private void loadData(Uri dataUri) { + mDataUri = dataUri; + + Log.i(Constants.TAG, "mDataUri: " + mDataUri.toString()); + + // Prepare the loaders. Either re-connect with an existing ones, + // or start new ones. + getLoaderManager().initLoader(LOADER_ID_UNIFIED, null, this); + } + + static final String[] UNIFIED_PROJECTION = new String[]{ + KeyRings._ID, KeyRings.FINGERPRINT, + + }; + static final int INDEX_UNIFIED_FINGERPRINT = 1; + + public Loader onCreateLoader(int id, Bundle args) { + setContentShown(false); + switch (id) { + case LOADER_ID_UNIFIED: { + Uri baseUri = KeyRings.buildUnifiedKeyRingUri(mDataUri); + return new CursorLoader(getActivity(), baseUri, UNIFIED_PROJECTION, null, null, null); + } + + default: + return null; + } + } + + public void onLoadFinished(Loader loader, Cursor data) { + /* TODO better error handling? May cause problems when a key is deleted, + * because the notification triggers faster than the activity closes. + */ + // Avoid NullPointerExceptions... + if (data.getCount() == 0) { + return; + } + // Swap the new cursor in. (The framework will take care of closing the + // old cursor once we return.) + switch (loader.getId()) { + case LOADER_ID_UNIFIED: { + if (data.moveToFirst()) { + + byte[] fingerprintBlob = data.getBlob(INDEX_UNIFIED_FINGERPRINT); + String fingerprint = KeyFormattingUtils.convertFingerprintToHex(fingerprintBlob); + mFingerprint.setText(KeyFormattingUtils.colorizeFingerprint(fingerprint)); + + break; + } + } + + } + setContentShown(true); + } + + /** + * This is called when the last Cursor provided to onLoadFinished() above is about to be closed. + * We need to make sure we are no longer using it. + */ + public void onLoaderReset(Loader loader) { + } + + private void certify(Uri dataUri) { + long keyId = 0; + try { + keyId = new ProviderHelper(getActivity()) + .getCachedPublicKeyRing(dataUri) + .extractOrGetMasterKeyId(); + } catch (PgpKeyNotFoundException e) { + Log.e(Constants.TAG, "key not found!", e); + } + Intent certifyIntent = new Intent(getActivity(), CertifyKeyActivity.class); + certifyIntent.putExtra(CertifyKeyActivity.EXTRA_KEY_IDS, new long[]{keyId}); + startActivityForResult(certifyIntent, 0); + } + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeViewActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeViewActivity.java index b24ee84a4..d3c1d971a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeViewActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeViewActivity.java @@ -21,6 +21,7 @@ import android.graphics.Bitmap; import android.net.Uri; import android.os.Bundle; import android.support.v4.app.ActivityCompat; +import android.support.v7.widget.CardView; import android.view.View; import android.view.ViewTreeObserver.OnGlobalLayoutListener; import android.widget.ImageView; @@ -37,7 +38,8 @@ import org.sufficientlysecure.keychain.util.Log; public class QrCodeViewActivity extends BaseActivity { - private ImageView mFingerprintQrCode; + private ImageView mQrCode; + private CardView mQrCodeLayout; @Override public void onCreate(Bundle savedInstanceState) { @@ -61,9 +63,10 @@ public class QrCodeViewActivity extends BaseActivity { return; } - mFingerprintQrCode = (ImageView) findViewById(R.id.qr_code_image); + mQrCode = (ImageView) findViewById(R.id.qr_code_image); + mQrCodeLayout = (CardView) findViewById(R.id.qr_code_image_layout); - mFingerprintQrCode.setOnClickListener(new View.OnClickListener() { + mQrCodeLayout.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { ActivityCompat.finishAfterTransition(QrCodeViewActivity.this); @@ -87,14 +90,14 @@ public class QrCodeViewActivity extends BaseActivity { // create a minimal size qr code, we can keep this in ram no problem final Bitmap qrCode = QrCodeUtils.getQRCodeBitmap(qrCodeContent, 0); - mFingerprintQrCode.getViewTreeObserver().addOnGlobalLayoutListener( + mQrCode.getViewTreeObserver().addOnGlobalLayoutListener( new OnGlobalLayoutListener() { @Override public void onGlobalLayout() { // create actual bitmap in display dimensions Bitmap scaled = Bitmap.createScaledBitmap(qrCode, - mFingerprintQrCode.getWidth(), mFingerprintQrCode.getWidth(), false); - mFingerprintQrCode.setImageBitmap(scaled); + mQrCode.getWidth(), mQrCode.getWidth(), false); + mQrCode.setImageBitmap(scaled); } }); } catch (ProviderHelper.NotFoundException e) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java index c67fde8e1..e1a8981c4 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java @@ -87,11 +87,10 @@ public class ViewKeyActivity extends BaseActivity implements private ImageButton mActionEncryptFile; private ImageButton mActionEncryptText; - private ImageButton mActionVerify; private ImageButton mActionNfc; private FloatingActionButton mFab; private AspectRatioImageView mPhoto; - private ImageButton mQrCode; + private ImageView mQrCode; private CardView mQrCodeLayout; // NFC @@ -105,6 +104,7 @@ public class ViewKeyActivity extends BaseActivity implements private boolean mIsSecret = false; private boolean mHasEncrypt = false; + private boolean mIsVerified = false; @Override protected void onCreate(Bundle savedInstanceState) { @@ -122,11 +122,10 @@ public class ViewKeyActivity extends BaseActivity implements mActionEncryptFile = (ImageButton) findViewById(R.id.view_key_action_encrypt_files); mActionEncryptText = (ImageButton) findViewById(R.id.view_key_action_encrypt_text); - mActionVerify = (ImageButton) findViewById(R.id.view_key_action_verify); mActionNfc = (ImageButton) findViewById(R.id.view_key_action_nfc); mFab = (FloatingActionButton) findViewById(R.id.fab); mPhoto = (AspectRatioImageView) findViewById(R.id.view_key_photo); - mQrCode = (ImageButton) findViewById(R.id.view_key_qr_code); + mQrCode = (ImageView) findViewById(R.id.view_key_qr_code); mQrCodeLayout = (CardView) findViewById(R.id.view_key_qr_code_layout); mDataUri = getIntent().getData(); @@ -159,11 +158,6 @@ public class ViewKeyActivity extends BaseActivity implements encrypt(mDataUri, true); } }); - mActionVerify.setOnClickListener(new View.OnClickListener() { - public void onClick(View view) { - certify(mDataUri); - } - }); mFab.setOnClickListener(new View.OnClickListener() { @Override @@ -176,7 +170,7 @@ public class ViewKeyActivity extends BaseActivity implements } }); - mQrCode.setOnClickListener(new View.OnClickListener() { + mQrCodeLayout.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { showQrCodeDialog(); @@ -269,6 +263,10 @@ public class ViewKeyActivity extends BaseActivity implements editKey(mDataUri); return true; } + case R.id.menu_key_view_certify_fingerprint: { + certifyFingeprint(mDataUri); + return true; + } } } catch (ProviderHelper.NotFoundException e) { Notify.showNotify(this, R.string.error_key_not_found, Notify.Style.ERROR); @@ -279,8 +277,11 @@ public class ViewKeyActivity extends BaseActivity implements @Override public boolean onPrepareOptionsMenu(Menu menu) { - MenuItem register = menu.findItem(R.id.menu_key_view_edit); - register.setVisible(mIsSecret); + MenuItem editKey = menu.findItem(R.id.menu_key_view_edit); + editKey.setVisible(mIsSecret); + MenuItem certifyFingerprint = menu.findItem(R.id.menu_key_view_certify_fingerprint); + certifyFingerprint.setVisible(!mIsSecret && !mIsVerified); + return true; } @@ -321,6 +322,12 @@ public class ViewKeyActivity extends BaseActivity implements startActivityForResult(scanQrCode, 0); } + private void certifyFingeprint(Uri dataUri) { + Intent intent = new Intent(this, CertifyFingerprintActivity.class); + intent.setData(dataUri); + startActivityForResult(intent, 0); + } + private void showQrCodeDialog() { Intent qrCodeIntent = new Intent(this, QrCodeViewActivity.class); @@ -420,20 +427,6 @@ public class ViewKeyActivity extends BaseActivity implements startActivityForResult(queryIntent, 0); } - private void certify(Uri dataUri) { - long keyId = 0; - try { - keyId = new ProviderHelper(this) - .getCachedPublicKeyRing(dataUri) - .extractOrGetMasterKeyId(); - } catch (PgpKeyNotFoundException e) { - Log.e(Constants.TAG, "key not found!", e); - } - Intent certifyIntent = new Intent(this, CertifyKeyActivity.class); - certifyIntent.putExtra(CertifyKeyActivity.EXTRA_KEY_IDS, new long[]{keyId}); - startActivityForResult(certifyIntent, 0); - } - private void editKey(Uri dataUri) { Intent editIntent = new Intent(this, EditKeyActivity.class); editIntent.setData(KeychainContract.KeyRingData.buildSecretKeyRingUri(dataUri)); @@ -641,7 +634,10 @@ public class ViewKeyActivity extends BaseActivity implements boolean isRevoked = data.getInt(INDEX_IS_REVOKED) > 0; boolean isExpired = !data.isNull(INDEX_EXPIRY) && new Date(data.getLong(INDEX_EXPIRY) * 1000).before(new Date()); - boolean isVerified = data.getInt(INDEX_VERIFIED) > 0; + mIsVerified = data.getInt(INDEX_VERIFIED) > 0; + + // re-create options menu based on mIsSecret, mIsVerified + supportInvalidateOptionsMenu(); AsyncTask photoTask = new AsyncTask() { @@ -666,7 +662,6 @@ public class ViewKeyActivity extends BaseActivity implements mActionEncryptFile.setVisibility(View.GONE); mActionEncryptText.setVisibility(View.GONE); - mActionVerify.setVisibility(View.GONE); mActionNfc.setVisibility(View.GONE); mFab.setVisibility(View.GONE); mQrCodeLayout.setVisibility(View.GONE); @@ -683,14 +678,10 @@ public class ViewKeyActivity extends BaseActivity implements mActionEncryptFile.setVisibility(View.GONE); mActionEncryptText.setVisibility(View.GONE); - mActionVerify.setVisibility(View.GONE); mActionNfc.setVisibility(View.GONE); mFab.setVisibility(View.GONE); mQrCodeLayout.setVisibility(View.GONE); } else if (mIsSecret) { - // re-create options menu to see edit button - supportInvalidateOptionsMenu(); - mStatusText.setText(R.string.view_key_my_key); mStatusImage.setVisibility(View.GONE); color = getResources().getColor(R.color.primary); @@ -720,7 +711,6 @@ public class ViewKeyActivity extends BaseActivity implements mActionEncryptFile.setVisibility(View.VISIBLE); mActionEncryptText.setVisibility(View.VISIBLE); - mActionVerify.setVisibility(View.GONE); // invokeBeam is available from API 21 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { @@ -736,7 +726,7 @@ public class ViewKeyActivity extends BaseActivity implements mQrCodeLayout.setVisibility(View.GONE); mActionNfc.setVisibility(View.GONE); - if (isVerified) { + if (mIsVerified) { mStatusText.setText(R.string.view_key_verified); mStatusImage.setVisibility(View.VISIBLE); KeyFormattingUtils.setStatusImage(this, mStatusImage, mStatusText, @@ -744,7 +734,6 @@ public class ViewKeyActivity extends BaseActivity implements color = getResources().getColor(R.color.primary); photoTask.execute(fingerprint); - mActionVerify.setVisibility(View.GONE); mFab.setVisibility(View.GONE); } else { mStatusText.setText(R.string.view_key_unverified); @@ -753,7 +742,6 @@ public class ViewKeyActivity extends BaseActivity implements KeyFormattingUtils.STATE_UNVERIFIED, R.color.icons, true); color = getResources().getColor(R.color.android_orange_light); - mActionVerify.setVisibility(View.VISIBLE); mFab.setVisibility(View.VISIBLE); } } -- cgit v1.2.3 From ad8209bd9425c71e21d3c43c2520bd57957115d7 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Thu, 26 Feb 2015 10:48:17 +0100 Subject: pre-select certification key if only one is available --- .../sufficientlysecure/keychain/ui/widget/CertifyKeySpinner.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/CertifyKeySpinner.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/CertifyKeySpinner.java index 25033658d..6d0e6556f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/CertifyKeySpinner.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/CertifyKeySpinner.java @@ -86,16 +86,17 @@ public class CertifyKeySpinner extends KeySpinner { super.onLoadFinished(loader, data); if (loader.getId() == LOADER_ID) { + mIndexHasCertify = data.getColumnIndex(KeychainContract.KeyRings.HAS_CERTIFY); + mIndexIsRevoked = data.getColumnIndex(KeychainContract.KeyRings.IS_REVOKED); + mIndexIsExpired = data.getColumnIndex(KeychainContract.KeyRings.IS_EXPIRED); + // If there is only one choice, pick it by default if (mAdapter.getCount() == 2) { // preselect if key can certify - if (data.moveToPosition(1) && !data.isNull(mIndexHasCertify)) { + if (data.moveToPosition(0) && !data.isNull(mIndexHasCertify)) { setSelection(1); } } - mIndexHasCertify = data.getColumnIndex(KeychainContract.KeyRings.HAS_CERTIFY); - mIndexIsRevoked = data.getColumnIndex(KeychainContract.KeyRings.IS_REVOKED); - mIndexIsExpired = data.getColumnIndex(KeychainContract.KeyRings.IS_EXPIRED); } } -- cgit v1.2.3 From 4c4782bd5eb54b1f67a66b9065ce48a585ed2d0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Thu, 26 Feb 2015 17:32:08 +0100 Subject: Hopefully fixes drop down icon for spinners on Android lower 5 --- .../org/sufficientlysecure/keychain/ui/widget/KeySpinner.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeySpinner.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeySpinner.java index 17bfbef57..c8eceea50 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeySpinner.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/KeySpinner.java @@ -24,13 +24,13 @@ import android.support.v4.app.FragmentActivity; import android.support.v4.app.LoaderManager; import android.support.v4.content.Loader; import android.support.v4.widget.CursorAdapter; +import android.support.v7.internal.widget.TintSpinner; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.BaseAdapter; import android.widget.ImageView; -import android.widget.Spinner; import android.widget.SpinnerAdapter; import android.widget.TextView; @@ -41,7 +41,11 @@ import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.util.Log; -public abstract class KeySpinner extends Spinner implements LoaderManager.LoaderCallbacks { +/** + * Use TintSpinner from AppCompat lib instead of Spinner. Fixes white dropdown icon. + * Related: http://stackoverflow.com/a/27713090 + */ +public abstract class KeySpinner extends TintSpinner implements LoaderManager.LoaderCallbacks { public interface OnKeyChangedListener { public void onKeyChanged(long masterKeyId); } -- cgit v1.2.3 From 1210a80a96d9f862829ac1122e94b68fe8b8b5d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Thu, 26 Feb 2015 17:37:28 +0100 Subject: Remove old Holo design resources --- .../main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java | 3 --- 1 file changed, 3 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java index f60ddcef6..3da185dd2 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java @@ -498,9 +498,6 @@ public class KeyListFragment extends LoaderFragment // Execute this when searching mSearchView.setOnQueryTextListener(this); - View searchPlate = mSearchView.findViewById(android.support.v7.appcompat.R.id.search_plate); - searchPlate.setBackgroundResource(R.drawable.keychaintheme_searchview_holo_light); - // Erase search result without focus MenuItemCompat.setOnActionExpandListener(searchItem, new MenuItemCompat.OnActionExpandListener() { @Override -- cgit v1.2.3 From d7888d46668a68a138743e30c64be45b35b5211a Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Thu, 26 Feb 2015 18:52:54 +0100 Subject: ignore revoked user ids for primary key expiry --- .../keychain/pgp/CanonicalizedKeyRing.java | 5 +- .../keychain/pgp/CanonicalizedPublicKey.java | 74 ++++++++++++++++++++++ .../keychain/pgp/PgpKeyOperation.java | 4 +- .../keychain/pgp/UncachedPublicKey.java | 18 ------ .../keychain/pgp/WrappedSignature.java | 4 ++ 5 files changed, 82 insertions(+), 23 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedKeyRing.java index bbf136dac..4adacaf23 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedKeyRing.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedKeyRing.java @@ -79,9 +79,8 @@ public abstract class CanonicalizedKeyRing extends KeyRing { public boolean isExpired() { // Is the master key expired? - Date creationDate = getRing().getPublicKey().getCreationTime(); - Date expiryDate = getRing().getPublicKey().getValidSeconds() > 0 - ? new Date(creationDate.getTime() + getRing().getPublicKey().getValidSeconds() * 1000) : null; + Date creationDate = getPublicKey().getCreationTime(); + Date expiryDate = getPublicKey().getExpiryTime(); Date now = new Date(); return creationDate.after(now) || (expiryDate != null && expiryDate.before(now)); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKey.java index b026d9257..303070333 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKey.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKey.java @@ -20,8 +20,16 @@ package org.sufficientlysecure.keychain.pgp; import org.spongycastle.bcpg.sig.KeyFlags; import org.spongycastle.openpgp.PGPPublicKey; +import org.spongycastle.openpgp.PGPSignature; import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodGenerator; +import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.util.IterableIterator; +import org.sufficientlysecure.keychain.util.Log; + +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.Iterator; /** Wrapper for a PGPPublicKey. * @@ -100,6 +108,72 @@ public class CanonicalizedPublicKey extends UncachedPublicKey { return false; } + public boolean isRevoked() { + return mPublicKey.getSignaturesOfType(isMasterKey() + ? PGPSignature.KEY_REVOCATION + : PGPSignature.SUBKEY_REVOCATION).hasNext(); + } + + public boolean isExpired () { + Date expiry = getExpiryTime(); + return expiry != null && expiry.before(new Date()); + } + + public long getValidSeconds() { + + long seconds; + + // the getValidSeconds method is unreliable for master keys. we need to iterate all + // user ids, then use the most recent certification from a non-revoked user id + if (isMasterKey()) { + Date latestCreation = null; + seconds = 0; + + for (byte[] rawUserId : getUnorderedRawUserIds()) { + Iterator sigs = getSignaturesForRawId(rawUserId); + + // there is always a certification, so this call is safe + WrappedSignature sig = sigs.next(); + + // we know a user id has at most two sigs: one certification, one revocation. + // if the sig is a revocation, or there is another sig (which is a revocation), + // the data in this uid is not relevant + if (sig.isRevocation() || sigs.hasNext()) { + continue; + } + + // this is our revocation, UNLESS there is a newer certificate! + if (latestCreation == null || latestCreation.before(sig.getCreationTime())) { + latestCreation = sig.getCreationTime(); + seconds = sig.getKeyExpirySeconds(); + } + } + } else { + seconds = mPublicKey.getValidSeconds(); + } + + return seconds; + } + + public Date getExpiryTime() { + long seconds = getValidSeconds(); + + if (seconds > Integer.MAX_VALUE) { + Log.e(Constants.TAG, "error, expiry time too large"); + return null; + } + if (seconds == 0) { + // no expiry + return null; + } + Date creationDate = getCreationTime(); + Calendar calendar = GregorianCalendar.getInstance(); + calendar.setTime(creationDate); + calendar.add(Calendar.SECOND, (int) seconds); + + return calendar.getTime(); + } + /** Same method as superclass, but we make it public. */ public Integer getKeyUsage() { return super.getKeyUsage(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java index aebb52a03..1a251eb79 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java @@ -439,8 +439,8 @@ public class PgpKeyOperation { // since this is the master key, this contains at least CERTIFY_OTHER PGPPublicKey masterPublicKey = masterSecretKey.getPublicKey(); int masterKeyFlags = readKeyFlags(masterPublicKey) | KeyFlags.CERTIFY_OTHER; - long masterKeyExpiry = masterPublicKey.getValidSeconds() == 0L ? 0L : - masterPublicKey.getCreationTime().getTime() / 1000 + masterPublicKey.getValidSeconds(); + Date expiryTime = wsKR.getPublicKey().getExpiryTime(); + long masterKeyExpiry = expiryTime != null ? expiryTime.getTime() / 1000 : 0L; return internal(sKR, masterSecretKey, masterKeyFlags, masterKeyExpiry, saveParcel, passphrase, log); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java index 0fe1ccdb6..d29169cc4 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java @@ -60,24 +60,6 @@ public class UncachedPublicKey { return mPublicKey.getCreationTime(); } - public Date getExpiryTime() { - long seconds = mPublicKey.getValidSeconds(); - if (seconds > Integer.MAX_VALUE) { - Log.e(Constants.TAG, "error, expiry time too large"); - return null; - } - if (seconds == 0) { - // no expiry - return null; - } - Date creationDate = getCreationTime(); - Calendar calendar = GregorianCalendar.getInstance(); - calendar.setTime(creationDate); - calendar.add(Calendar.SECOND, (int) seconds); - - return calendar.getTime(); - } - public boolean isExpired() { Date creationDate = mPublicKey.getCreationTime(); Date expiryDate = mPublicKey.getValidSeconds() > 0 diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java index ade075d55..c6fad1a73 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java @@ -78,6 +78,10 @@ public class WrappedSignature { return mSig.getCreationTime(); } + public long getKeyExpirySeconds() { + return mSig.getHashedSubPackets().getKeyExpirationTime(); + } + public ArrayList getEmbeddedSignatures() { ArrayList sigs = new ArrayList<>(); if (!mSig.hasSubpackets()) { -- cgit v1.2.3 From e5bb7a35b5202cf8ef13325d86ef82f2583700b7 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Thu, 26 Feb 2015 18:53:16 +0100 Subject: save revocation instead of self-cert for revoked uids --- .../keychain/provider/ProviderHelper.java | 31 +++++++++++++--------- 1 file changed, 19 insertions(+), 12 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java index 18efa2b80..d947ae053 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java @@ -473,7 +473,7 @@ public class ProviderHelper { item.selfCert = cert; item.isPrimary = cert.isPrimaryUserId(); } else { - item.isRevoked = true; + item.selfRevocation = cert; log(LogType.MSG_IP_UID_REVOKED); } continue; @@ -569,10 +569,11 @@ public class ProviderHelper { // NOTE self-certificates are already verified during canonicalization, // AND we know there is at most one cert plus at most one revocation + // AND the revocation only exists if there is no newer certification if (!cert.isRevocation()) { item.selfCert = cert; } else { - item.isRevoked = true; + item.selfRevocation = cert; log(LogType.MSG_IP_UAT_REVOKED); } continue; @@ -643,16 +644,21 @@ public class ProviderHelper { for (int userIdRank = 0; userIdRank < uids.size(); userIdRank++) { UserPacketItem item = uids.get(userIdRank); operations.add(buildUserIdOperations(masterKeyId, item, userIdRank)); - if (item.selfCert != null) { - // TODO get rid of "self verified" status? this cannot even happen anymore! - operations.add(buildCertOperations(masterKeyId, userIdRank, item.selfCert, - selfCertsAreTrusted ? Certs.VERIFIED_SECRET : Certs.VERIFIED_SELF)); + + if (item.selfCert == null) { + throw new AssertionError("User ids MUST be self-certified at this point!!"); } - // don't bother with trusted certs if the uid is revoked, anyways - if (item.isRevoked) { + + if (item.selfRevocation != null) { + operations.add(buildCertOperations(masterKeyId, userIdRank, item.selfRevocation, + Certs.VERIFIED_SELF)); + // don't bother with trusted certs if the uid is revoked, anyways continue; } + operations.add(buildCertOperations(masterKeyId, userIdRank, item.selfCert, + selfCertsAreTrusted ? Certs.VERIFIED_SECRET : Certs.VERIFIED_SELF)); + // iterate over signatures for (int i = 0; i < item.trustedCerts.size() ; i++) { WrappedSignature sig = item.trustedCerts.valueAt(i); @@ -711,15 +717,16 @@ public class ProviderHelper { String userId; byte[] attributeData; boolean isPrimary = false; - boolean isRevoked = false; WrappedSignature selfCert; + WrappedSignature selfRevocation; LongSparseArray trustedCerts = new LongSparseArray<>(); @Override public int compareTo(UserPacketItem o) { // revoked keys always come last! - if (isRevoked != o.isRevoked) { - return isRevoked ? 1 : -1; + //noinspection DoubleNegation + if ( (selfRevocation != null) != (o.selfRevocation != null)) { + return selfRevocation != null ? 1 : -1; } // if one is a user id, but the other isn't, the user id always comes first. // we compare for null values here, so != is the correct operator! @@ -1353,7 +1360,7 @@ public class ProviderHelper { values.put(UserPackets.USER_ID, item.userId); values.put(UserPackets.ATTRIBUTE_DATA, item.attributeData); values.put(UserPackets.IS_PRIMARY, item.isPrimary); - values.put(UserPackets.IS_REVOKED, item.isRevoked); + values.put(UserPackets.IS_REVOKED, item.selfRevocation != null); values.put(UserPackets.RANK, rank); Uri uri = UserPackets.buildUserIdsUri(masterKeyId); -- cgit v1.2.3 From 55dd6526a607c35ac31e56e1e26deb151b950218 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Thu, 26 Feb 2015 18:53:42 +0100 Subject: split up and mark unsafe expiry-related methods --- .../keychain/keyimport/ImportKeysListEntry.java | 4 ++-- .../pgp/OpenPgpSignatureResultBuilder.java | 4 ++-- .../keychain/pgp/UncachedPublicKey.java | 25 ++++++++++++++++++++-- 3 files changed, 27 insertions(+), 6 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java index 591408c8b..79065604a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java @@ -294,8 +294,8 @@ public class ImportKeysListEntry implements Serializable, Parcelable { mKeyId = key.getKeyId(); mKeyIdHex = KeyFormattingUtils.convertKeyIdToHex(mKeyId); - mRevoked = key.isRevoked(); - mExpired = key.isExpired(); + mRevoked = key.isMaybeRevoked(); + mExpired = key.isMaybeExpired(); mFingerprintHex = KeyFormattingUtils.convertFingerprintToHex(key.getFingerprint()); mBitStrength = key.getBitStrength(); mCurveOid = key.getCurveOid(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/OpenPgpSignatureResultBuilder.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/OpenPgpSignatureResultBuilder.java index ed4715681..46defebf7 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/OpenPgpSignatureResultBuilder.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/OpenPgpSignatureResultBuilder.java @@ -104,8 +104,8 @@ public class OpenPgpSignatureResultBuilder { setUserIds(signingRing.getUnorderedUserIds()); // either master key is expired/revoked or this specific subkey is expired/revoked - setKeyExpired(signingRing.isExpired() || signingKey.isExpired()); - setKeyRevoked(signingRing.isRevoked() || signingKey.isRevoked()); + setKeyExpired(signingRing.isExpired() || signingKey.isMaybeExpired()); + setKeyRevoked(signingRing.isRevoked() || signingKey.isMaybeRevoked()); } public OpenPgpSignatureResult build() { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java index d29169cc4..9276cba10 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java @@ -50,7 +50,7 @@ public class UncachedPublicKey { } /** The revocation signature is NOT checked here, so this may be false! */ - public boolean isRevoked() { + public boolean isMaybeRevoked() { return mPublicKey.getSignaturesOfType(isMasterKey() ? PGPSignature.KEY_REVOCATION : PGPSignature.SUBKEY_REVOCATION).hasNext(); @@ -60,7 +60,8 @@ public class UncachedPublicKey { return mPublicKey.getCreationTime(); } - public boolean isExpired() { + /** The revocation signature is NOT checked here, so this may be false! */ + public boolean isMaybeExpired() { Date creationDate = mPublicKey.getCreationTime(); Date expiryDate = mPublicKey.getValidSeconds() > 0 ? new Date(creationDate.getTime() + mPublicKey.getValidSeconds() * 1000) : null; @@ -340,4 +341,24 @@ public class UncachedPublicKey { return mCacheUsage; } + // this method relies on UNSAFE assumptions about the keyring, and should ONLY be used for + // TEST CASES!! + Date getUnsafeExpiryTimeForTesting () { + long valid = mPublicKey.getValidSeconds(); + + if (valid > Integer.MAX_VALUE) { + Log.e(Constants.TAG, "error, expiry time too large"); + return null; + } + if (valid == 0) { + // no expiry + return null; + } + Date creationDate = getCreationTime(); + Calendar calendar = GregorianCalendar.getInstance(); + calendar.setTime(creationDate); + calendar.add(Calendar.SECOND, (int) valid); + + return calendar.getTime(); + } } -- cgit v1.2.3 From 8230fb11799fb2476edafe834b15de56ec6ee112 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Fri, 27 Feb 2015 01:26:26 +0100 Subject: Remove unused BadImportKeyDialogFragment --- .../ui/dialog/BadImportKeyDialogFragment.java | 67 ---------------------- 1 file changed, 67 deletions(-) delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/BadImportKeyDialogFragment.java (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/BadImportKeyDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/BadImportKeyDialogFragment.java deleted file mode 100644 index 19cf27259..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/BadImportKeyDialogFragment.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2012-2014 Dominik Schürmann - * - * 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 . - */ - -package org.sufficientlysecure.keychain.ui.dialog; - -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); - - CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(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.show(); - } -} -- cgit v1.2.3 From b90335f901c66424dcfc9d1790495357700509b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Fri, 27 Feb 2015 01:30:32 +0100 Subject: Simplify delete key dialog --- .../org/sufficientlysecure/keychain/ui/ViewKeyActivity.java | 2 -- .../keychain/ui/dialog/DeleteKeyDialogFragment.java | 11 +++++++++-- 2 files changed, 9 insertions(+), 4 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java index e1a8981c4..5c7a4448b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java @@ -184,7 +184,6 @@ public class ViewKeyActivity extends BaseActivity implements } }); - // Prepare the loaders. Either re-connect with an existing ones, // or start new ones. getSupportLoaderManager().initLoader(LOADER_ID_UNIFIED, null, this); @@ -447,7 +446,6 @@ public class ViewKeyActivity extends BaseActivity implements startActivityForResult(safeSlingerIntent, 0); } - /** * Load QR Code asynchronously and with a fade in animation * diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java index 5b96ea231..802f0c11b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/DeleteKeyDialogFragment.java @@ -33,6 +33,7 @@ import android.widget.TextView; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.pgp.KeyRing; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.service.KeychainIntentService; @@ -100,14 +101,20 @@ public class DeleteKeyDialogFragment extends DialogFragment { ProviderHelper.FIELD_TYPE_INTEGER } ); - String userId = (String) data.get(KeyRings.USER_ID); + String name; + String[] mainUserId = KeyRing.splitUserId((String) data.get(KeyRings.USER_ID)); + if (mainUserId[0] != null) { + name = mainUserId[0]; + } else { + name = getString(R.string.user_id_no_name); + } hasSecret = ((Long) data.get(KeyRings.HAS_ANY_SECRET)) == 1; // Set message depending on which key it is. mMainMessage.setText(getString( hasSecret ? R.string.secret_key_deletion_confirmation : R.string.public_key_deletetion_confirmation, - userId + name )); } catch (ProviderHelper.NotFoundException e) { dismiss(); -- cgit v1.2.3 From 4ccd9f9bb148a75e9cde48648216d1037a617c03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Fri, 27 Feb 2015 01:38:57 +0100 Subject: Uncluttering advanced key view --- .../keychain/ui/ViewKeyAdvMainFragment.java | 115 --------------------- .../keychain/ui/ViewKeyAdvShareFragment.java | 38 ------- .../keychain/ui/dialog/ShareNfcDialogFragment.java | 97 ----------------- 3 files changed, 250 deletions(-) delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareNfcDialogFragment.java (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvMainFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvMainFragment.java index c9d20f9f4..fc107d794 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvMainFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvMainFragment.java @@ -37,15 +37,11 @@ import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround; import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; -import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets; import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.provider.ProviderHelper.NotFoundException; import org.sufficientlysecure.keychain.ui.adapter.UserIdsAdapter; import org.sufficientlysecure.keychain.ui.dialog.UserIdInfoDialogFragment; -import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; -import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.util.Log; import java.util.Date; @@ -55,24 +51,15 @@ public class ViewKeyAdvMainFragment extends LoaderFragment implements public static final String ARG_DATA_URI = "uri"; - private View mActionEdit; - private View mActionEditDivider; - private View mActionEncryptFiles; - private View mActionEncryptText; - private View mActionEncryptTextText; private View mActionCertify; private View mActionCertifyText; private ImageView mActionCertifyImage; - private View mActionUpdate; private ListView mUserIds; private static final int LOADER_ID_UNIFIED = 0; private static final int LOADER_ID_USER_IDS = 1; - // conservative attitude - private boolean mHasEncrypt = true; - private UserIdsAdapter mUserIdsAdapter; private Uri mDataUri; @@ -83,18 +70,12 @@ public class ViewKeyAdvMainFragment extends LoaderFragment implements View view = inflater.inflate(R.layout.view_key_adv_main_fragment, getContainer()); mUserIds = (ListView) view.findViewById(R.id.view_key_user_ids); - mActionEdit = view.findViewById(R.id.view_key_action_edit); - mActionEditDivider = view.findViewById(R.id.view_key_action_edit_divider); - mActionEncryptText = view.findViewById(R.id.view_key_action_encrypt_text); - mActionEncryptTextText = view.findViewById(R.id.view_key_action_encrypt_text_text); - mActionEncryptFiles = view.findViewById(R.id.view_key_action_encrypt_files); mActionCertify = view.findViewById(R.id.view_key_action_certify); mActionCertifyText = view.findViewById(R.id.view_key_action_certify_text); mActionCertifyImage = (ImageView) view.findViewById(R.id.view_key_action_certify_image); // make certify image gray, like action icons mActionCertifyImage.setColorFilter(getResources().getColor(R.color.tertiary_text_light), PorterDuff.Mode.SRC_IN); - mActionUpdate = view.findViewById(R.id.view_key_action_update); mUserIds.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override @@ -139,37 +120,11 @@ public class ViewKeyAdvMainFragment extends LoaderFragment implements Log.i(Constants.TAG, "mDataUri: " + mDataUri.toString()); - mActionEncryptFiles.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - encrypt(mDataUri, false); - } - }); - mActionEncryptText.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - encrypt(mDataUri, true); - } - }); mActionCertify.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { certify(mDataUri); } }); - mActionEdit.setOnClickListener(new View.OnClickListener() { - public void onClick(View view) { - editKey(mDataUri); - } - }); - mActionUpdate.setOnClickListener(new View.OnClickListener() { - public void onClick(View view) { - try { - updateFromKeyserver(mDataUri, new ProviderHelper(getActivity())); - } catch (NotFoundException e) { - Notify.showNotify(getActivity(), R.string.error_key_not_found, Notify.Style.ERROR); - } - } - }); mUserIdsAdapter = new UserIdsAdapter(getActivity(), null, 0); mUserIds.setAdapter(mUserIdsAdapter); @@ -222,45 +177,23 @@ public class ViewKeyAdvMainFragment extends LoaderFragment implements switch (loader.getId()) { case LOADER_ID_UNIFIED: { if (data.moveToFirst()) { - if (data.getInt(INDEX_UNIFIED_HAS_ANY_SECRET) != 0) { - // edit button - mActionEdit.setVisibility(View.VISIBLE); - mActionEditDivider.setVisibility(View.VISIBLE); - } else { - // edit button - mActionEdit.setVisibility(View.GONE); - mActionEditDivider.setVisibility(View.GONE); - } // If this key is revoked, it cannot be used for anything! if (data.getInt(INDEX_UNIFIED_IS_REVOKED) != 0) { - mActionEdit.setEnabled(false); mActionCertify.setEnabled(false); mActionCertifyText.setEnabled(false); - mActionEncryptText.setEnabled(false); - mActionEncryptTextText.setEnabled(false); - mActionEncryptFiles.setEnabled(false); } else { - mActionEdit.setEnabled(true); Date expiryDate = new Date(data.getLong(INDEX_UNIFIED_EXPIRY) * 1000); if (!data.isNull(INDEX_UNIFIED_EXPIRY) && expiryDate.before(new Date())) { mActionCertify.setEnabled(false); mActionCertifyText.setEnabled(false); - mActionEncryptText.setEnabled(false); - mActionEncryptTextText.setEnabled(false); - mActionEncryptFiles.setEnabled(false); } else { mActionCertify.setEnabled(true); mActionCertifyText.setEnabled(true); - mActionEncryptText.setEnabled(true); - mActionEncryptTextText.setEnabled(true); - mActionEncryptFiles.setEnabled(true); } } - mHasEncrypt = data.getInt(INDEX_UNIFIED_HAS_ENCRYPT) != 0; - break; } } @@ -286,48 +219,6 @@ public class ViewKeyAdvMainFragment extends LoaderFragment implements } } - private void encrypt(Uri dataUri, boolean text) { - // If there is no encryption key, don't bother. - if (!mHasEncrypt) { - Notify.showNotify(getActivity(), R.string.error_no_encrypt_subkey, Notify.Style.ERROR); - return; - } - try { - long keyId = new ProviderHelper(getActivity()) - .getCachedPublicKeyRing(dataUri) - .extractOrGetMasterKeyId(); - long[] encryptionKeyIds = new long[]{keyId}; - Intent intent; - if (text) { - intent = new Intent(getActivity(), EncryptTextActivity.class); - intent.setAction(EncryptTextActivity.ACTION_ENCRYPT_TEXT); - intent.putExtra(EncryptTextActivity.EXTRA_ENCRYPTION_KEY_IDS, encryptionKeyIds); - } else { - intent = new Intent(getActivity(), EncryptFilesActivity.class); - intent.setAction(EncryptFilesActivity.ACTION_ENCRYPT_DATA); - intent.putExtra(EncryptFilesActivity.EXTRA_ENCRYPTION_KEY_IDS, encryptionKeyIds); - } - // used instead of startActivity set actionbar based on callingPackage - startActivityForResult(intent, 0); - } catch (PgpKeyNotFoundException e) { - Log.e(Constants.TAG, "key not found!", e); - } - } - - private void updateFromKeyserver(Uri dataUri, ProviderHelper providerHelper) - throws ProviderHelper.NotFoundException { - byte[] blob = (byte[]) providerHelper.getGenericData( - KeychainContract.KeyRings.buildUnifiedKeyRingUri(dataUri), - KeychainContract.Keys.FINGERPRINT, ProviderHelper.FIELD_TYPE_BLOB); - String fingerprint = KeyFormattingUtils.convertFingerprintToHex(blob); - - Intent queryIntent = new Intent(getActivity(), ImportKeysActivity.class); - queryIntent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_RESULT); - queryIntent.putExtra(ImportKeysActivity.EXTRA_FINGERPRINT, fingerprint); - - startActivityForResult(queryIntent, 0); - } - private void certify(Uri dataUri) { long keyId = 0; try { @@ -342,10 +233,4 @@ public class ViewKeyAdvMainFragment extends LoaderFragment implements startActivityForResult(certifyIntent, 0); } - private void editKey(Uri dataUri) { - Intent editIntent = new Intent(getActivity(), EditKeyActivity.class); - editIntent.setData(KeychainContract.KeyRingData.buildSecretKeyRingUri(dataUri)); - startActivityForResult(editIntent, 0); - } - } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java index 6208cff4e..6d019c5cd 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java @@ -17,16 +17,13 @@ package org.sufficientlysecure.keychain.ui; -import android.annotation.TargetApi; import android.content.Intent; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.PorterDuff; import android.net.Uri; import android.os.AsyncTask; -import android.os.Build; import android.os.Bundle; -import android.provider.Settings; import android.support.v4.app.LoaderManager; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; @@ -47,7 +44,6 @@ import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; import org.sufficientlysecure.keychain.provider.KeychainContract.Keys; import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.ui.dialog.ShareNfcDialogFragment; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.ui.util.QrCodeUtils; @@ -68,8 +64,6 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements private View mKeyShareButton; private View mKeyClipboardButton; private ImageButton mKeySafeSlingerButton; - private View mNfcHelpButton; - private View mNfcPrefsButton; private View mKeyUploadButton; ProviderHelper mProviderHelper; @@ -92,19 +86,11 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements mKeyShareButton = view.findViewById(R.id.view_key_action_key_share); mKeyClipboardButton = view.findViewById(R.id.view_key_action_key_clipboard); mKeySafeSlingerButton = (ImageButton) view.findViewById(R.id.view_key_action_key_safeslinger); - mNfcHelpButton = view.findViewById(R.id.view_key_action_nfc_help); - mNfcPrefsButton = view.findViewById(R.id.view_key_action_nfc_prefs); mKeyUploadButton = view.findViewById(R.id.view_key_action_upload); mKeySafeSlingerButton.setColorFilter(getResources().getColor(R.color.tertiary_text_light), PorterDuff.Mode.SRC_IN); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { - mNfcPrefsButton.setVisibility(View.VISIBLE); - } else { - mNfcPrefsButton.setVisibility(View.GONE); - } - mFingerprintQrCode.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { @@ -142,18 +128,6 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements startSafeSlinger(mDataUri); } }); - mNfcHelpButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - showNfcHelpDialog(); - } - }); - mNfcPrefsButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - showNfcPrefs(); - } - }); mKeyUploadButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { @@ -243,18 +217,6 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements startActivity(qrCodeIntent); } - private void showNfcHelpDialog() { - ShareNfcDialogFragment dialog = ShareNfcDialogFragment.newInstance(); - dialog.show(getActivity().getSupportFragmentManager(), "shareNfcDialog"); - } - - @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) - private void showNfcPrefs() { - Intent intentSettings = new Intent( - Settings.ACTION_NFCSHARING_SETTINGS); - startActivity(intentSettings); - } - @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareNfcDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareNfcDialogFragment.java deleted file mode 100644 index 961f92f03..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ShareNfcDialogFragment.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (C) 2013-2014 Dominik Schürmann - * - * 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 . - */ - -package org.sufficientlysecure.keychain.ui.dialog; - -import android.annotation.TargetApi; -import android.app.Dialog; -import android.content.DialogInterface; -import android.content.Intent; -import android.nfc.NfcAdapter; -import android.os.Build; -import android.os.Bundle; -import android.provider.Settings; -import android.support.v4.app.DialogFragment; -import android.support.v4.app.FragmentActivity; - -import org.sufficientlysecure.htmltextview.HtmlTextView; -import org.sufficientlysecure.keychain.R; - -@TargetApi(Build.VERSION_CODES.JELLY_BEAN) -public class ShareNfcDialogFragment extends DialogFragment { - - /** - * Creates new instance of this fragment - */ - public static ShareNfcDialogFragment newInstance() { - ShareNfcDialogFragment frag = new ShareNfcDialogFragment(); - - return frag; - } - - /** - * Creates dialog - */ - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - final FragmentActivity activity = getActivity(); - - CustomAlertDialogBuilder alert = new CustomAlertDialogBuilder(activity); - - alert.setTitle(R.string.share_nfc_dialog); - alert.setCancelable(true); - - alert.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int id) { - dismiss(); - } - }); - - HtmlTextView textView = new HtmlTextView(getActivity()); - textView.setPadding(8, 8, 8, 8); - alert.setView(textView); - - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { - textView.setText(getString(R.string.error) + ": " - + getString(R.string.error_jelly_bean_needed)); - } else { - // check if NFC Adapter is available - NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(getActivity()); - if (nfcAdapter == null) { - textView.setText(getString(R.string.error) + ": " - + getString(R.string.error_nfc_needed)); - } else { - // nfc works... - textView.setHtmlFromRawResource(getActivity(), R.raw.nfc_beam_share, true); - - alert.setNegativeButton(R.string.menu_beam_preferences, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int id) { - Intent intentSettings = new Intent( - Settings.ACTION_NFCSHARING_SETTINGS); - startActivity(intentSettings); - } - } - ); - } - } - - return alert.show(); - } -} -- cgit v1.2.3 From 11c34364545ff99268949e558cddcb853ea1810b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Fri, 27 Feb 2015 01:44:40 +0100 Subject: Prettify qr code in advanced key view --- .../keychain/ui/ViewKeyAdvShareFragment.java | 30 +++++++++++++++++----- 1 file changed, 23 insertions(+), 7 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java index 6d019c5cd..8d0a2dd1d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvShareFragment.java @@ -17,16 +17,20 @@ package org.sufficientlysecure.keychain.ui; +import android.app.ActivityOptions; import android.content.Intent; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.PorterDuff; import android.net.Uri; import android.os.AsyncTask; +import android.os.Build; import android.os.Bundle; +import android.support.v4.app.ActivityCompat; import android.support.v4.app.LoaderManager; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; +import android.support.v7.widget.CardView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -58,7 +62,8 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements public static final String ARG_DATA_URI = "uri"; private TextView mFingerprint; - private ImageView mFingerprintQrCode; + private ImageView mQrCode; + private CardView mQrCodeLayout; private View mFingerprintShareButton; private View mFingerprintClipboardButton; private View mKeyShareButton; @@ -80,7 +85,8 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements mProviderHelper = new ProviderHelper(ViewKeyAdvShareFragment.this.getActivity()); mFingerprint = (TextView) view.findViewById(R.id.view_key_fingerprint); - mFingerprintQrCode = (ImageView) view.findViewById(R.id.view_key_fingerprint_qr_code_image); + mQrCode = (ImageView) view.findViewById(R.id.view_key_qr_code); + mQrCodeLayout = (CardView) view.findViewById(R.id.view_key_qr_code_layout); mFingerprintShareButton = view.findViewById(R.id.view_key_action_fingerprint_share); mFingerprintClipboardButton = view.findViewById(R.id.view_key_action_fingerprint_clipboard); mKeyShareButton = view.findViewById(R.id.view_key_action_key_share); @@ -91,7 +97,7 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements mKeySafeSlingerButton.setColorFilter(getResources().getColor(R.color.tertiary_text_light), PorterDuff.Mode.SRC_IN); - mFingerprintQrCode.setOnClickListener(new View.OnClickListener() { + mQrCodeLayout.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { showQrCodeDialog(); @@ -213,8 +219,18 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements private void showQrCodeDialog() { Intent qrCodeIntent = new Intent(getActivity(), QrCodeViewActivity.class); + + // create the transition animation - the images in the layouts + // of both activities are defined with android:transitionName="qr_code" + Bundle opts = null; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + ActivityOptions options = ActivityOptions + .makeSceneTransitionAnimation(getActivity(), mQrCodeLayout, "qr_code"); + opts = options.toBundle(); + } + qrCodeIntent.setData(mDataUri); - startActivity(qrCodeIntent); + ActivityCompat.startActivity(getActivity(), qrCodeIntent, opts); } @Override @@ -325,14 +341,14 @@ public class ViewKeyAdvShareFragment extends LoaderFragment implements // scale the image up to our actual size. we do this in code rather // than let the ImageView do this because we don't require filtering. Bitmap scaled = Bitmap.createScaledBitmap(qrCode, - mFingerprintQrCode.getHeight(), mFingerprintQrCode.getHeight(), + mQrCode.getHeight(), mQrCode.getHeight(), false); - mFingerprintQrCode.setImageBitmap(scaled); + mQrCode.setImageBitmap(scaled); // simple fade-in animation AlphaAnimation anim = new AlphaAnimation(0.0f, 1.0f); anim.setDuration(200); - mFingerprintQrCode.startAnimation(anim); + mQrCode.startAnimation(anim); } } }; -- cgit v1.2.3 From 2cd7be6373015e7e05d8418c997fa0c063c40c5a Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Fri, 27 Feb 2015 18:05:36 +0100 Subject: go to directly to certify screen after nfc import --- .../keychain/ui/ImportKeysActivity.java | 63 ----- .../keychain/ui/ImportKeysProxyActivity.java | 272 +++++++++++++++++++++ .../keychain/ui/KeyListFragment.java | 4 +- .../keychain/ui/QrCodeScanActivity.java | 224 ----------------- .../keychain/ui/ViewKeyActivity.java | 4 +- 5 files changed, 276 insertions(+), 291 deletions(-) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysProxyActivity.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeScanActivity.java (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java index 6638c9944..71f6fd4bf 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java @@ -17,17 +17,12 @@ package org.sufficientlysecure.keychain.ui; -import android.annotation.TargetApi; import android.app.ProgressDialog; import android.content.Intent; import android.net.Uri; -import android.nfc.NdefMessage; -import android.nfc.NfcAdapter; -import android.os.Build; import android.os.Bundle; import android.os.Message; import android.os.Messenger; -import android.os.Parcelable; import android.support.v4.app.Fragment; import android.view.View; import android.view.View.OnClickListener; @@ -63,9 +58,6 @@ public class ImportKeysActivity extends BaseActivity { // Actions for internal use only: public static final String ACTION_IMPORT_KEY_FROM_FILE = Constants.INTENT_PREFIX + "IMPORT_KEY_FROM_FILE"; - public static final String ACTION_IMPORT_KEY_FROM_NFC = Constants.INTENT_PREFIX - + "IMPORT_KEY_FROM_NFC"; - public static final String EXTRA_RESULT = "result"; // only used by ACTION_IMPORT_KEY @@ -215,15 +207,6 @@ public class ImportKeysActivity extends BaseActivity { startListFragment(savedInstanceState, null, null, null); break; } - case ACTION_IMPORT_KEY_FROM_NFC: { - // NOTE: this only displays the appropriate fragment, no actions are taken - startFileFragment(savedInstanceState); - // TODO!!!!! - - // no immediate actions! - startListFragment(savedInstanceState, null, null, null); - break; - } default: { startCloudFragment(savedInstanceState, null, false); startListFragment(savedInstanceState, null, null, null); @@ -433,50 +416,4 @@ public class ImportKeysActivity extends BaseActivity { } } - /** - * NFC - */ - @Override - public void onResume() { - super.onResume(); - - // Check to see if the Activity started due to an Android Beam - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { - if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction())) { - handleActionNdefDiscovered(getIntent()); - } else { - Log.d(Constants.TAG, "NFC: No NDEF discovered!"); - } - } else { - Log.e(Constants.TAG, "Android Beam not supported by Android < 4.1"); - } - } - - /** - * NFC - */ - @Override - public void onNewIntent(Intent intent) { - // onResume gets called after this to handle the intent - setIntent(intent); - } - - /** - * NFC: Parses the NDEF Message from the intent and prints to the TextView - */ - @TargetApi(Build.VERSION_CODES.JELLY_BEAN) - void handleActionNdefDiscovered(Intent intent) { - Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES); - // only one message sent during the beam - NdefMessage msg = (NdefMessage) rawMsgs[0]; - // record 0 contains the MIME type, record 1 is the AAR, if present - byte[] receivedKeyringBytes = msg.getRecords()[0].getPayload(); - - Intent importIntent = new Intent(this, ImportKeysActivity.class); - importIntent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY); - importIntent.putExtra(ImportKeysActivity.EXTRA_KEY_BYTES, receivedKeyringBytes); - - handleActions(null, importIntent); - } - } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysProxyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysProxyActivity.java new file mode 100644 index 000000000..4cb6c69e0 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysProxyActivity.java @@ -0,0 +1,272 @@ +/* + * Copyright (C) 2014 Dominik Schürmann + * + * 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 . + */ + +package org.sufficientlysecure.keychain.ui; + +import android.annotation.TargetApi; +import android.app.ProgressDialog; +import android.content.Intent; +import android.net.Uri; +import android.nfc.NdefMessage; +import android.nfc.NfcAdapter; +import android.os.Build; +import android.os.Bundle; +import android.os.Message; +import android.os.Messenger; +import android.os.Parcelable; +import android.support.v4.app.FragmentActivity; +import android.widget.Toast; + +import com.google.zxing.integration.android.IntentIntegrator; +import com.google.zxing.integration.android.IntentResult; + +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.api.OpenKeychainIntents; +import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing; +import org.sufficientlysecure.keychain.operations.results.ImportKeyResult; +import org.sufficientlysecure.keychain.operations.results.OperationResult; +import org.sufficientlysecure.keychain.operations.results.SingletonResult; +import org.sufficientlysecure.keychain.service.KeychainIntentService; +import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; +import org.sufficientlysecure.keychain.util.IntentIntegratorSupportV4; +import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.Preferences; + +import java.util.ArrayList; +import java.util.Locale; + +/** + * Proxy activity (just a transparent content view) to scan QR Codes using the Barcode Scanner app + */ +public class ImportKeysProxyActivity extends FragmentActivity { + + public static final String ACTION_QR_CODE_API = OpenKeychainIntents.IMPORT_KEY_FROM_QR_CODE; + public static final String ACTION_SCAN_WITH_RESULT = Constants.INTENT_PREFIX + "SCAN_QR_CODE_WITH_RESULT"; + + boolean returnResult; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + // this activity itself has no content view (see manifest) + + handleActions(getIntent()); + } + + protected void handleActions(Intent intent) { + String action = intent.getAction(); + Uri dataUri = intent.getData(); + String scheme = intent.getScheme(); + + if (scheme != null && scheme.toLowerCase(Locale.ENGLISH).equals(Constants.FINGERPRINT_SCHEME)) { + // Scanning a fingerprint directly with Barcode Scanner, thus we already have scanned + + returnResult = false; + startCertify(dataUri); + } else if (ACTION_SCAN_WITH_RESULT.equals(action)) { + // scan using xzing's Barcode Scanner and return result parcel in OpenKeychain + + returnResult = true; + IntentIntegrator integrator = new IntentIntegrator(this); + integrator.setDesiredBarcodeFormats(IntentIntegrator.QR_CODE_TYPES) + .setPrompt(getString(R.string.import_qr_code_text)) + .setResultDisplayDuration(0) + .initiateScan(); + } else if (ACTION_QR_CODE_API.equals(action)) { + // scan using xzing's Barcode Scanner from outside OpenKeychain + + returnResult = false; + new IntentIntegrator(this).initiateScan(); + } else if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction())) { + // Check to see if the Activity started due to an Android Beam + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { + returnResult = false; + handleActionNdefDiscovered(getIntent()); + } else { + Log.e(Constants.TAG, "Android Beam not supported by Android < 4.1"); + finish(); + } + } else { + Log.e(Constants.TAG, "No valid scheme or action given!"); + finish(); + } + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + if (requestCode == IntentIntegratorSupportV4.REQUEST_CODE) { + IntentResult scanResult = IntentIntegratorSupportV4.parseActivityResult(requestCode, + resultCode, data); + if (scanResult != null && scanResult.getFormatName() != null) { + String scannedContent = scanResult.getContents(); + Log.d(Constants.TAG, "scannedContent: " + scannedContent); + + startCertify(Uri.parse(scanResult.getContents())); + } else { + Log.e(Constants.TAG, "scanResult or formatName null! Should not happen!"); + finish(); + } + + return; + } + // if a result has been returned, return it down to other activity + if (data != null && data.hasExtra(OperationResult.EXTRA_RESULT)) { + returnResult(data); + } else { + super.onActivityResult(requestCode, resultCode, data); + finish(); + } + } + + public void returnResult(Intent data) { + if (returnResult) { + setResult(RESULT_OK, data); + finish(); + } else { + // display last log message but as Toast for calls from outside OpenKeychain + OperationResult result = data.getParcelableExtra(OperationResult.EXTRA_RESULT); + String str = getString(result.getLog().getLast().mType.getMsgId()); + Toast.makeText(this, str, Toast.LENGTH_LONG).show(); + finish(); + } + } + + public void startCertify(Uri dataUri) { + // example: openpgp4fpr:73EE2314F65FA92EC2390D3A718C070100012282 + if (dataUri.getScheme().equals(Constants.FINGERPRINT_SCHEME)) { + String fingerprint = dataUri.getEncodedSchemeSpecificPart().toLowerCase(Locale.ENGLISH); + importKeys(fingerprint); + } else { + SingletonResult result = new SingletonResult( + SingletonResult.RESULT_ERROR, OperationResult.LogType.MSG_WRONG_QR_CODE); + Intent intent = new Intent(); + intent.putExtra(SingletonResult.EXTRA_RESULT, result); + returnResult(intent); + } + } + + public void importKeys(byte[] keyringData) { + + ParcelableKeyRing keyEntry = new ParcelableKeyRing(keyringData); + ArrayList selectedEntries = new ArrayList<>(); + selectedEntries.add(keyEntry); + + startImportService(selectedEntries); + + } + + public void importKeys(String fingerprint) { + + ParcelableKeyRing keyEntry = new ParcelableKeyRing(fingerprint, null, null); + ArrayList selectedEntries = new ArrayList<>(); + selectedEntries.add(keyEntry); + + startImportService(selectedEntries); + + } + + private void startImportService (ArrayList keyRings) { + + // Message is received after importing is done in KeychainIntentService + KeychainIntentServiceHandler serviceHandler = new KeychainIntentServiceHandler( + this, + getString(R.string.progress_importing), + ProgressDialog.STYLE_HORIZONTAL, + true) { + public void handleMessage(Message message) { + // handle messages by standard KeychainIntentServiceHandler first + super.handleMessage(message); + + if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) { + // get returned data bundle + Bundle returnData = message.getData(); + if (returnData == null) { + finish(); + return; + } + final ImportKeyResult result = + returnData.getParcelable(OperationResult.EXTRA_RESULT); + if (result == null) { + Log.e(Constants.TAG, "result == null"); + finish(); + return; + } + + if (!result.success()) { + // only return if no success... + Intent data = new Intent(); + data.putExtras(returnData); + returnResult(data); + return; + } + + Intent certifyIntent = new Intent(ImportKeysProxyActivity.this, + CertifyKeyActivity.class); + certifyIntent.putExtra(CertifyKeyActivity.EXTRA_RESULT, result); + certifyIntent.putExtra(CertifyKeyActivity.EXTRA_KEY_IDS, + result.getImportedMasterKeyIds()); + startActivityForResult(certifyIntent, 0); + } + } + }; + + // fill values for this action + Bundle data = new Bundle(); + + // search config + { + Preferences prefs = Preferences.getPreferences(this); + Preferences.CloudSearchPrefs cloudPrefs = + new Preferences.CloudSearchPrefs(true, true, prefs.getPreferredKeyserver()); + data.putString(KeychainIntentService.IMPORT_KEY_SERVER, cloudPrefs.keyserver); + } + + data.putParcelableArrayList(KeychainIntentService.IMPORT_KEY_LIST, keyRings); + + // Send all information needed to service to query keys in other thread + Intent intent = new Intent(this, KeychainIntentService.class); + intent.setAction(KeychainIntentService.ACTION_IMPORT_KEYRING); + intent.putExtra(KeychainIntentService.EXTRA_DATA, data); + + // Create a new Messenger for the communication back + Messenger messenger = new Messenger(serviceHandler); + intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger); + + // show progress dialog + serviceHandler.showProgressDialog(this); + + // start service with intent + startService(intent); + + } + + /** + * NFC: Parses the NDEF Message from the intent and prints to the TextView + */ + @TargetApi(Build.VERSION_CODES.JELLY_BEAN) + void handleActionNdefDiscovered(Intent intent) { + Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES); + // only one message sent during the beam + NdefMessage msg = (NdefMessage) rawMsgs[0]; + // record 0 contains the MIME type, record 1 is the AAR, if present + byte[] receivedKeyringBytes = msg.getRecords()[0].getPayload(); + importKeys(receivedKeyringBytes); + } + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java index 3da185dd2..99714b4a0 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java @@ -602,8 +602,8 @@ public class KeyListFragment extends LoaderFragment } private void scanQrCode() { - Intent scanQrCode = new Intent(getActivity(), QrCodeScanActivity.class); - scanQrCode.setAction(QrCodeScanActivity.ACTION_SCAN_WITH_RESULT); + Intent scanQrCode = new Intent(getActivity(), ImportKeysProxyActivity.class); + scanQrCode.setAction(ImportKeysProxyActivity.ACTION_SCAN_WITH_RESULT); startActivityForResult(scanQrCode, 0); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeScanActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeScanActivity.java deleted file mode 100644 index 1a7a028c6..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/QrCodeScanActivity.java +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Copyright (C) 2014 Dominik Schürmann - * - * 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 . - */ - -package org.sufficientlysecure.keychain.ui; - -import android.app.ProgressDialog; -import android.content.Intent; -import android.net.Uri; -import android.os.Bundle; -import android.os.Message; -import android.os.Messenger; -import android.support.v4.app.FragmentActivity; -import android.widget.Toast; - -import com.google.zxing.integration.android.IntentIntegrator; -import com.google.zxing.integration.android.IntentResult; - -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.api.OpenKeychainIntents; -import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing; -import org.sufficientlysecure.keychain.operations.results.ImportKeyResult; -import org.sufficientlysecure.keychain.operations.results.OperationResult; -import org.sufficientlysecure.keychain.operations.results.SingletonResult; -import org.sufficientlysecure.keychain.service.KeychainIntentService; -import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; -import org.sufficientlysecure.keychain.util.IntentIntegratorSupportV4; -import org.sufficientlysecure.keychain.util.Log; -import org.sufficientlysecure.keychain.util.Preferences; - -import java.util.ArrayList; -import java.util.Locale; - -/** - * Proxy activity (just a transparent content view) to scan QR Codes using the Barcode Scanner app - */ -public class QrCodeScanActivity extends FragmentActivity { - - public static final String ACTION_QR_CODE_API = OpenKeychainIntents.IMPORT_KEY_FROM_QR_CODE; - public static final String ACTION_SCAN_WITH_RESULT = Constants.INTENT_PREFIX + "SCAN_QR_CODE_WITH_RESULT"; - - boolean returnResult; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - // this activity itself has no content view (see manifest) - - handleActions(getIntent()); - } - - protected void handleActions(Intent intent) { - String action = intent.getAction(); - Uri dataUri = intent.getData(); - String scheme = intent.getScheme(); - - if (scheme != null && scheme.toLowerCase(Locale.ENGLISH).equals(Constants.FINGERPRINT_SCHEME)) { - // Scanning a fingerprint directly with Barcode Scanner, thus we already have scanned - - returnResult = false; - startCertify(dataUri); - } else if (ACTION_SCAN_WITH_RESULT.equals(action)) { - // scan using xzing's Barcode Scanner and return result parcel in OpenKeychain - - returnResult = true; - IntentIntegrator integrator = new IntentIntegrator(this); - integrator.setDesiredBarcodeFormats(IntentIntegrator.QR_CODE_TYPES) - .setPrompt(getString(R.string.import_qr_code_text)) - .setResultDisplayDuration(0) - .initiateScan(); - } else if (ACTION_QR_CODE_API.equals(action)) { - // scan using xzing's Barcode Scanner from outside OpenKeychain - - returnResult = false; - new IntentIntegrator(this).initiateScan(); - } else { - Log.e(Constants.TAG, "No valid scheme or action given!"); - finish(); - } - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - if (requestCode == IntentIntegratorSupportV4.REQUEST_CODE) { - IntentResult scanResult = IntentIntegratorSupportV4.parseActivityResult(requestCode, - resultCode, data); - if (scanResult != null && scanResult.getFormatName() != null) { - String scannedContent = scanResult.getContents(); - Log.d(Constants.TAG, "scannedContent: " + scannedContent); - - startCertify(Uri.parse(scanResult.getContents())); - } else { - Log.e(Constants.TAG, "scanResult or formatName null! Should not happen!"); - finish(); - } - - return; - } - // if a result has been returned, return it down to other activity - if (data != null && data.hasExtra(OperationResult.EXTRA_RESULT)) { - returnResult(data); - } else { - super.onActivityResult(requestCode, resultCode, data); - } - } - - public void returnResult(Intent data) { - if (returnResult) { - setResult(RESULT_OK, data); - finish(); - } else { - // display last log message but as Toast for calls from outside OpenKeychain - OperationResult result = data.getParcelableExtra(OperationResult.EXTRA_RESULT); - String str = getString(result.getLog().getLast().mType.getMsgId()); - Toast.makeText(this, str, Toast.LENGTH_LONG).show(); - finish(); - } - } - - public void startCertify(Uri dataUri) { - // example: openpgp4fpr:73EE2314F65FA92EC2390D3A718C070100012282 - if (dataUri.getScheme().equals(Constants.FINGERPRINT_SCHEME)) { - String fingerprint = dataUri.getEncodedSchemeSpecificPart().toLowerCase(Locale.ENGLISH); - importKeys(fingerprint); - } else { - SingletonResult result = new SingletonResult( - SingletonResult.RESULT_ERROR, OperationResult.LogType.MSG_WRONG_QR_CODE); - Intent intent = new Intent(); - intent.putExtra(SingletonResult.EXTRA_RESULT, result); - returnResult(intent); - } - } - - public void importKeys(String fingerprint) { - // Message is received after importing is done in KeychainIntentService - KeychainIntentServiceHandler serviceHandler = new KeychainIntentServiceHandler( - this, - getString(R.string.progress_importing), - ProgressDialog.STYLE_HORIZONTAL, - true) { - public void handleMessage(Message message) { - // handle messages by standard KeychainIntentServiceHandler first - super.handleMessage(message); - - if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) { - // get returned data bundle - Bundle returnData = message.getData(); - if (returnData == null) { - finish(); - return; - } - final ImportKeyResult result = - returnData.getParcelable(OperationResult.EXTRA_RESULT); - if (result == null) { - Log.e(Constants.TAG, "result == null"); - finish(); - return; - } - - if (!result.success()) { - // only return if no success... - Intent data = new Intent(); - data.putExtras(returnData); - returnResult(data); - return; - } - - Intent certifyIntent = new Intent(QrCodeScanActivity.this, CertifyKeyActivity.class); - certifyIntent.putExtra(CertifyKeyActivity.EXTRA_RESULT, result); - certifyIntent.putExtra(CertifyKeyActivity.EXTRA_KEY_IDS, result.getImportedMasterKeyIds()); - startActivityForResult(certifyIntent, 0); - } - } - }; - - // search config - Preferences prefs = Preferences.getPreferences(this); - Preferences.CloudSearchPrefs cloudPrefs = new Preferences.CloudSearchPrefs(true, true, prefs.getPreferredKeyserver()); - - // Send all information needed to service to query keys in other thread - Intent intent = new Intent(this, KeychainIntentService.class); - - intent.setAction(KeychainIntentService.ACTION_IMPORT_KEYRING); - - // fill values for this action - Bundle data = new Bundle(); - - data.putString(KeychainIntentService.IMPORT_KEY_SERVER, cloudPrefs.keyserver); - - ParcelableKeyRing keyEntry = new ParcelableKeyRing(fingerprint, null, null); - ArrayList selectedEntries = new ArrayList<>(); - selectedEntries.add(keyEntry); - - data.putParcelableArrayList(KeychainIntentService.IMPORT_KEY_LIST, selectedEntries); - - intent.putExtra(KeychainIntentService.EXTRA_DATA, data); - - // Create a new Messenger for the communication back - Messenger messenger = new Messenger(serviceHandler); - intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger); - - // show progress dialog - serviceHandler.showProgressDialog(this); - - // start service with intent - startService(intent); - } - -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java index 5c7a4448b..afb742079 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java @@ -316,8 +316,8 @@ public class ViewKeyActivity extends BaseActivity implements } private void scanQrCode() { - Intent scanQrCode = new Intent(this, QrCodeScanActivity.class); - scanQrCode.setAction(QrCodeScanActivity.ACTION_SCAN_WITH_RESULT); + Intent scanQrCode = new Intent(this, ImportKeysProxyActivity.class); + scanQrCode.setAction(ImportKeysProxyActivity.ACTION_SCAN_WITH_RESULT); startActivityForResult(scanQrCode, 0); } -- cgit v1.2.3 From fe31883f661d55c20903cf1b249dc46395b57c12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Fri, 27 Feb 2015 22:40:52 +0100 Subject: Keybase header text --- .../java/org/sufficientlysecure/keychain/ui/ViewKeyTrustFragment.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyTrustFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyTrustFragment.java index 5483d16b8..25edc7a02 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyTrustFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyTrustFragment.java @@ -80,7 +80,7 @@ public class ViewKeyTrustFragment extends LoaderFragment implements @Override public View onCreateView(LayoutInflater inflater, ViewGroup superContainer, Bundle savedInstanceState) { View root = super.onCreateView(inflater, superContainer, savedInstanceState); - View view = inflater.inflate(R.layout.view_key_trust_fragment, getContainer()); + View view = inflater.inflate(R.layout.view_key_adv_keybase_fragment, getContainer()); mInflater = inflater; mTrustReadout = (TextView) view.findViewById(R.id.view_key_trust_readout); @@ -299,7 +299,7 @@ public class ViewKeyTrustFragment extends LoaderFragment implements int rowNumber = 1; for (CharSequence s : result.mProofs) { - TableRow row = (TableRow) mInflater.inflate(R.layout.view_key_keybase_proof, null); + TableRow row = (TableRow) mInflater.inflate(R.layout.view_key_adv_keybase_proof, null); TextView number = (TextView) row.findViewById(R.id.proof_number); TextView text = (TextView) row.findViewById(R.id.proof_text); number.setText(Integer.toString(rowNumber++) + ". "); -- cgit v1.2.3 From 80c159056d8efc4dd82c36a2c168511d34d6e8b4 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Fri, 27 Feb 2015 22:46:40 +0100 Subject: show refresh key progress inline --- .../service/KeychainIntentServiceHandler.java | 7 +- .../keychain/ui/ViewKeyActivity.java | 132 +++++++++++++++++++-- 2 files changed, 131 insertions(+), 8 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java index ceb0a2d2b..635fe86f1 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java @@ -78,6 +78,10 @@ public class KeychainIntentServiceHandler extends Handler { } public void showProgressDialog(FragmentActivity activity) { + if (mProgressDialogFragment == null) { + return; + } + // TODO: This is a hack!, see // http://stackoverflow.com/questions/10114324/show-dialogfragment-from-onactivityresult final FragmentManager manager = activity.getSupportFragmentManager(); @@ -94,7 +98,8 @@ public class KeychainIntentServiceHandler extends Handler { Bundle data = message.getData(); if (mProgressDialogFragment == null) { - Log.e(Constants.TAG, "Progress has not been updated because mProgressDialogFragment was null!"); + // Log.e(Constants.TAG, + // "Progress has not been updated because mProgressDialogFragment was null!"); return; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java index afb742079..f6c56d965 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java @@ -33,6 +33,7 @@ import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.Message; +import android.os.Messenger; import android.provider.ContactsContract; import android.provider.Settings; import android.support.v4.app.ActivityCompat; @@ -44,6 +45,9 @@ import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.animation.AlphaAnimation; +import android.view.animation.Animation; +import android.view.animation.Animation.AnimationListener; +import android.view.animation.AnimationUtils; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.RelativeLayout; @@ -54,11 +58,14 @@ import com.getbase.floatingactionbutton.FloatingActionButton; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing; +import org.sufficientlysecure.keychain.operations.results.ImportKeyResult; import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.pgp.KeyRing; import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.ProviderHelper; +import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; import org.sufficientlysecure.keychain.ui.util.FormattingUtils; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; @@ -68,7 +75,9 @@ import org.sufficientlysecure.keychain.ui.widget.AspectRatioImageView; import org.sufficientlysecure.keychain.util.ContactHelper; import org.sufficientlysecure.keychain.util.ExportHelper; import org.sufficientlysecure.keychain.util.Log; +import org.sufficientlysecure.keychain.util.Preferences; +import java.util.ArrayList; import java.util.Date; import java.util.HashMap; @@ -105,6 +114,10 @@ public class ViewKeyActivity extends BaseActivity implements private boolean mIsSecret = false; private boolean mHasEncrypt = false; private boolean mIsVerified = false; + private MenuItem mRefreshItem; + private boolean mIsRefreshing; + private Animation mRotate, mRotateSpin; + private View mRefresh; @Override protected void onCreate(Bundle savedInstanceState) { @@ -128,6 +141,51 @@ public class ViewKeyActivity extends BaseActivity implements mQrCode = (ImageView) findViewById(R.id.view_key_qr_code); mQrCodeLayout = (CardView) findViewById(R.id.view_key_qr_code_layout); + mRotateSpin = AnimationUtils.loadAnimation(this, R.anim.rotate_spin); + mRotateSpin.setAnimationListener(new AnimationListener() { + @Override + public void onAnimationStart(Animation animation) { + + } + + @Override + public void onAnimationEnd(Animation animation) { + mRefreshItem.getActionView().clearAnimation(); + mRefreshItem.setActionView(null); + mRefreshItem.setEnabled(true); + + // this is a deferred call + supportInvalidateOptionsMenu(); + } + + @Override + public void onAnimationRepeat(Animation animation) { + + } + }); + mRotate = AnimationUtils.loadAnimation(this, R.anim.rotate); + mRotate.setRepeatCount(Animation.INFINITE); + mRotate.setAnimationListener(new Animation.AnimationListener() { + @Override + public void onAnimationStart(Animation animation) { + + } + + @Override + public void onAnimationEnd(Animation animation) { + + } + + @Override + public void onAnimationRepeat(Animation animation) { + if (!mIsRefreshing) { + mRefreshItem.getActionView().clearAnimation(); + mRefreshItem.getActionView().startAnimation(mRotateSpin); + } + } + }); + mRefresh = getLayoutInflater().inflate(R.layout.indeterminate_progress, null); + mDataUri = getIntent().getData(); if (mDataUri == null) { Log.e(Constants.TAG, "Data missing. Should be uri of key!"); @@ -222,7 +280,7 @@ public class ViewKeyActivity extends BaseActivity implements public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); getMenuInflater().inflate(R.menu.key_view, menu); - + mRefreshItem = menu.findItem(R.id.menu_key_view_refresh); return true; } @@ -414,16 +472,72 @@ public class ViewKeyActivity extends BaseActivity implements private void updateFromKeyserver(Uri dataUri, ProviderHelper providerHelper) throws ProviderHelper.NotFoundException { + + mIsRefreshing = true; + mRefreshItem.setEnabled(false); + mRefreshItem.setActionView(mRefresh); + mRefresh.startAnimation(mRotate); + byte[] blob = (byte[]) providerHelper.getGenericData( KeychainContract.KeyRings.buildUnifiedKeyRingUri(dataUri), KeychainContract.Keys.FINGERPRINT, ProviderHelper.FIELD_TYPE_BLOB); String fingerprint = KeyFormattingUtils.convertFingerprintToHex(blob); - Intent queryIntent = new Intent(this, ImportKeysActivity.class); - queryIntent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_RESULT); - queryIntent.putExtra(ImportKeysActivity.EXTRA_FINGERPRINT, fingerprint); + ParcelableKeyRing keyEntry = new ParcelableKeyRing(fingerprint, null, null); + ArrayList entries = new ArrayList<>(); + entries.add(keyEntry); + + // Message is received after importing is done in KeychainIntentService + KeychainIntentServiceHandler serviceHandler = new KeychainIntentServiceHandler(this) { + public void handleMessage(Message message) { + // handle messages by standard KeychainIntentServiceHandler first + super.handleMessage(message); + + if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) { + // get returned data bundle + Bundle returnData = message.getData(); + + mIsRefreshing = false; + + if (returnData == null) { + finish(); + return; + } + final ImportKeyResult result = + returnData.getParcelable(OperationResult.EXTRA_RESULT); + result.createNotify(ViewKeyActivity.this).show(); + } + } + }; + + // fill values for this action + Bundle data = new Bundle(); + + // search config + { + Preferences prefs = Preferences.getPreferences(this); + Preferences.CloudSearchPrefs cloudPrefs = + new Preferences.CloudSearchPrefs(true, true, prefs.getPreferredKeyserver()); + data.putString(KeychainIntentService.IMPORT_KEY_SERVER, cloudPrefs.keyserver); + } + + data.putParcelableArrayList(KeychainIntentService.IMPORT_KEY_LIST, entries); + + // Send all information needed to service to query keys in other thread + Intent intent = new Intent(this, KeychainIntentService.class); + intent.setAction(KeychainIntentService.ACTION_IMPORT_KEYRING); + intent.putExtra(KeychainIntentService.EXTRA_DATA, data); + + // Create a new Messenger for the communication back + Messenger messenger = new Messenger(serviceHandler); + intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger); + + // show progress dialog + serviceHandler.showProgressDialog(this); + + // start service with intent + startService(intent); - startActivityForResult(queryIntent, 0); } private void editKey(Uri dataUri) { @@ -634,8 +748,12 @@ public class ViewKeyActivity extends BaseActivity implements && new Date(data.getLong(INDEX_EXPIRY) * 1000).before(new Date()); mIsVerified = data.getInt(INDEX_VERIFIED) > 0; - // re-create options menu based on mIsSecret, mIsVerified - supportInvalidateOptionsMenu(); + // if the refresh animation isn't playing + if (!mRotate.hasStarted() && !mRotateSpin.hasStarted()) { + // re-create options menu based on mIsSecret, mIsVerified + supportInvalidateOptionsMenu(); + // this is done at the end of the animation otherwise + } AsyncTask photoTask = new AsyncTask() { -- cgit v1.2.3 From fd2f858b12974629c612d366017669f640bf3254 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Fri, 27 Feb 2015 22:47:39 +0100 Subject: Fix status images in user id adapter --- .../sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java index ad7c9e430..8c0ab9165 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/adapter/UserIdsAdapter.java @@ -72,19 +72,19 @@ public class UserIdsAdapter extends CursorAdapter implements AdapterView.OnItemC public UserIdsAdapter(Context context, Cursor c, int flags, boolean showCheckBoxes, SaveKeyringParcel saveKeyringParcel) { - this(context, c, flags, showCheckBoxes, false, saveKeyringParcel); + this(context, c, flags, showCheckBoxes, true, saveKeyringParcel); } public UserIdsAdapter(Context context, Cursor c, int flags, boolean showCheckBoxes) { - this(context, c, flags, showCheckBoxes, false, null); + this(context, c, flags, showCheckBoxes, true, null); } public UserIdsAdapter(Context context, Cursor c, int flags, SaveKeyringParcel saveKeyringParcel) { - this(context, c, flags, false, false, saveKeyringParcel); + this(context, c, flags, false, true, saveKeyringParcel); } public UserIdsAdapter(Context context, Cursor c, int flags) { - this(context, c, flags, false, false, null); + this(context, c, flags, false, true, null); } @Override -- cgit v1.2.3 From 863f4e6ac18edbeb0dde5c79b5a4808f7915dd0c Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Fri, 27 Feb 2015 23:09:17 +0100 Subject: hand through result in CertifyFingerprintActivity --- .../sufficientlysecure/keychain/ui/CertifyFingerprintActivity.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyFingerprintActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyFingerprintActivity.java index 777288e69..c75f6d838 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyFingerprintActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyFingerprintActivity.java @@ -83,8 +83,8 @@ public class CertifyFingerprintActivity extends BaseActivity { protected void onActivityResult(int requestCode, int resultCode, Intent data) { // if a result has been returned, display a notify if (data != null && data.hasExtra(OperationResult.EXTRA_RESULT)) { - OperationResult result = data.getParcelableExtra(OperationResult.EXTRA_RESULT); - result.createNotify(this).show(); + setResult(RESULT_OK, data); + finish(); } else { super.onActivityResult(requestCode, resultCode, data); } -- cgit v1.2.3 From aec9bdfc1e30c590a22d4860b9e955c5cb570a3a Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Fri, 27 Feb 2015 23:09:35 +0100 Subject: transition status color in key view --- .../keychain/ui/ViewKeyActivity.java | 33 ++++++++++++++++++++-- 1 file changed, 30 insertions(+), 3 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java index f6c56d965..d14455511 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java @@ -18,11 +18,14 @@ package org.sufficientlysecure.keychain.ui; +import android.animation.ArgbEvaluator; +import android.animation.ObjectAnimator; import android.annotation.TargetApi; import android.app.ActivityOptions; import android.content.Intent; import android.database.Cursor; import android.graphics.Bitmap; +import android.graphics.Color; import android.net.Uri; import android.nfc.NdefMessage; import android.nfc.NdefRecord; @@ -717,6 +720,8 @@ public class ViewKeyActivity extends BaseActivity implements } } + int mPreviousColor = 0; + @Override public void onLoadFinished(Loader loader, Cursor data) { /* TODO better error handling? May cause problems when a key is deleted, @@ -861,9 +866,31 @@ public class ViewKeyActivity extends BaseActivity implements mFab.setVisibility(View.VISIBLE); } } - mToolbar.setBackgroundColor(color); - mStatusBar.setBackgroundColor(color); - mBigToolbar.setBackgroundColor(color); + + if (mPreviousColor == 0 || mPreviousColor == color) { + mToolbar.setBackgroundColor(color); + mStatusBar.setBackgroundColor(color); + mBigToolbar.setBackgroundColor(color); + mPreviousColor = color; + } else { + ObjectAnimator colorFade1 = + ObjectAnimator.ofObject(mToolbar, "backgroundColor", + new ArgbEvaluator(), mPreviousColor, color); + ObjectAnimator colorFade2 = + ObjectAnimator.ofObject(mStatusBar, "backgroundColor", + new ArgbEvaluator(), mPreviousColor, color); + ObjectAnimator colorFade3 = + ObjectAnimator.ofObject(mBigToolbar, "backgroundColor", + new ArgbEvaluator(), mPreviousColor, color); + + colorFade1.setDuration(800); + colorFade2.setDuration(800); + colorFade3.setDuration(800); + colorFade1.start(); + colorFade2.start(); + colorFade3.start(); + mPreviousColor = color; + } mStatusImage.setAlpha(80); -- cgit v1.2.3 From 200d4a6bb6185242afa566d09d10d5b0ba62d58c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Fri, 27 Feb 2015 23:39:36 +0100 Subject: Remove swipte to refresh src, fix padding in key list --- .../keychain/ui/KeyListFragment.java | 68 --------------- .../ui/widget/ListAwareSwipeRefreshLayout.java | 99 ---------------------- 2 files changed, 167 deletions(-) delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/ListAwareSwipeRefreshLayout.java (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java index 99714b4a0..ba9a96b28 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java @@ -36,8 +36,6 @@ import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; import android.support.v4.view.MenuItemCompat; import android.support.v4.widget.CursorAdapter; -import android.support.v4.widget.NoScrollableSwipeRefreshLayout; -import android.support.v7.app.ActionBar; import android.support.v7.app.ActionBarActivity; import android.support.v7.widget.SearchView; import android.view.ActionMode; @@ -45,7 +43,6 @@ import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; -import android.view.MotionEvent; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; @@ -73,7 +70,6 @@ import org.sufficientlysecure.keychain.ui.dialog.DeleteKeyDialogFragment; import org.sufficientlysecure.keychain.ui.util.Highlighter; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.Notify; -import org.sufficientlysecure.keychain.ui.widget.ListAwareSwipeRefreshLayout; import org.sufficientlysecure.keychain.util.ExportHelper; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Preferences; @@ -97,7 +93,6 @@ public class KeyListFragment extends LoaderFragment private KeyListAdapter mAdapter; private StickyListHeadersListView mStickyList; - private ListAwareSwipeRefreshLayout mSwipeRefreshLayout; // saves the mode object for multiselect, needed for reset at some point private ActionMode mActionMode = null; @@ -152,73 +147,10 @@ public class KeyListFragment extends LoaderFragment } }); - mSwipeRefreshLayout = (ListAwareSwipeRefreshLayout) view.findViewById(R.id.key_list_swipe_container); - mSwipeRefreshLayout.setOnRefreshListener(new NoScrollableSwipeRefreshLayout.OnRefreshListener() { - @Override - public void onRefresh() { - KeychainIntentServiceHandler finishedHandler = new KeychainIntentServiceHandler(getActivity()) { - public void handleMessage(Message message) { - if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) { - mSwipeRefreshLayout.setRefreshing(false); - } - } - }; - // new KeyUpdateHelper().updateAllKeys(getActivity(), finishedHandler); - updateActionbarForSwipe(false); - } - }); - mSwipeRefreshLayout.setColorScheme( - R.color.android_purple_dark, - R.color.android_purple_light, - R.color.android_purple_dark, - R.color.android_purple_light); - mSwipeRefreshLayout.setStickyListHeadersListView(mStickyList); - mSwipeRefreshLayout.setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - if (event.getAction() == MotionEvent.ACTION_MOVE) { - updateActionbarForSwipe(true); - } else { - updateActionbarForSwipe(false); - } - return false; - } - }); - // Just disable for now - mSwipeRefreshLayout.setIsLocked(true); return root; } - private void updateActionbarForSwipe(boolean show) { - ActionBarActivity activity = (ActionBarActivity) getActivity(); - ActionBar bar = activity.getSupportActionBar(); - - if (show) { - bar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM); - bar.setDisplayUseLogoEnabled(false); - bar.setCustomView(R.layout.custom_actionbar); - TextView title = (TextView) getActivity().findViewById(R.id.custom_actionbar_text); - title.setText(R.string.swipe_to_update); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { -// hideMenu = true; -// activity.invalidateOptionsMenu(); - } - } else { - bar.setTitle(getActivity().getTitle()); - bar.setDisplayHomeAsUpEnabled(true); - bar.setDisplayShowTitleEnabled(true); - bar.setDisplayUseLogoEnabled(true); - bar.setDisplayShowHomeEnabled(true); - bar.setDisplayShowCustomEnabled(false); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { -// hideMenu = false; -// activity.invalidateOptionsMenu(); - } - } - } - /** * Define Adapter and Loader on create of Activity */ diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/ListAwareSwipeRefreshLayout.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/ListAwareSwipeRefreshLayout.java deleted file mode 100644 index 3403208d7..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/widget/ListAwareSwipeRefreshLayout.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (C) 2014 Daniel Albert - * - * 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 . - */ - -package org.sufficientlysecure.keychain.ui.widget; - -import android.content.Context; -import android.support.v4.widget.NoScrollableSwipeRefreshLayout; -import android.util.AttributeSet; -import android.view.MotionEvent; - -import se.emilsjolander.stickylistheaders.StickyListHeadersListView; - -public class ListAwareSwipeRefreshLayout extends NoScrollableSwipeRefreshLayout { - - private StickyListHeadersListView mStickyListHeadersListView = null; - private boolean mIsLocked = false; - - /** - * Constructors - */ - public ListAwareSwipeRefreshLayout(Context context) { - super(context); - } - - public ListAwareSwipeRefreshLayout(Context context, AttributeSet attrs) { - super(context, attrs); - } - - /** - * Getters / Setters - */ - public void setStickyListHeadersListView(StickyListHeadersListView stickyListHeadersListView) { - mStickyListHeadersListView = stickyListHeadersListView; - } - - public StickyListHeadersListView getStickyListHeadersListView() { - return mStickyListHeadersListView; - } - - public void setIsLocked(boolean locked) { - mIsLocked = locked; - } - - public boolean getIsLocked() { - return mIsLocked; - } - - @Override - public boolean canChildScrollUp() { - if (mStickyListHeadersListView == null) { - return super.canChildScrollUp(); - } - - return (mIsLocked || ( - mStickyListHeadersListView.getWrappedList().getChildCount() > 0 - && (mStickyListHeadersListView.getWrappedList().getChildAt(0).getTop() < 0 - || mStickyListHeadersListView.getFirstVisiblePosition() > 0) - ) - ); - } - - /** Called on a touch event, this method exempts a small area in the upper right from pull to - * refresh handling. - * - * If the touch event happens somewhere in the upper right corner of the screen, we return false - * to indicate that the event was not handled. This ensures events in that area are always - * handed through to the list scrollbar handle. For all other cases, we pass the message through - * to the pull to refresh handler. - */ - @Override - public boolean onTouchEvent(MotionEvent event) { - // The device may be null. This actually happens - if (event.getDevice() != null) { - // MotionEvent.AXIS_X is api level 12, for some reason, so we use a constant 0 here - float ratioX = event.getX() / event.getDevice().getMotionRange(0).getMax(); - float ratioY = event.getY() / event.getDevice().getMotionRange(1).getMax(); - // if this is the upper right corner, don't handle as pull to refresh event - if (ratioX > 0.85f && ratioY < 0.15f) { - return false; - } - } - return super.onTouchEvent(event); - } - -} \ No newline at end of file -- cgit v1.2.3 From f2a9a41840a370864537239e106da2e932aa9d87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Fri, 27 Feb 2015 23:47:15 +0100 Subject: Enable multi line snackbar option --- .../main/java/org/sufficientlysecure/keychain/ui/util/Notify.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/Notify.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/Notify.java index 6f8c477c0..f6c979139 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/Notify.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/Notify.java @@ -24,6 +24,7 @@ import android.graphics.Color; import com.nispok.snackbar.Snackbar; import com.nispok.snackbar.Snackbar.SnackbarDuration; import com.nispok.snackbar.SnackbarManager; +import com.nispok.snackbar.enums.SnackbarType; import com.nispok.snackbar.listeners.ActionClickListener; import org.sufficientlysecure.keychain.R; @@ -48,6 +49,7 @@ public class Notify { Snackbar bar = Snackbar.with(activity) .text(text) + .type(SnackbarType.MULTI_LINE) .duration(SnackbarDuration.LENGTH_LONG); switch (style) { @@ -67,7 +69,8 @@ public class Notify { public static Showable createNotify (Activity activity, int resId, int duration, Style style) { final Snackbar bar = Snackbar.with(activity) - .text(resId); + .text(resId) + .type(SnackbarType.MULTI_LINE); if (duration == LENGTH_INDEFINITE) { bar.duration(SnackbarDuration.LENGTH_INDEFINITE); } else { @@ -104,6 +107,7 @@ public class Notify { final Snackbar bar = Snackbar.with(activity) .text(msg) .actionLabel(resIdAction) + .type(SnackbarType.MULTI_LINE) .actionListener(new ActionClickListener() { @Override public void onActionClicked(Snackbar snackbar) { -- cgit v1.2.3 From 8cfba4c0fb3ebf7b24c0c8ede6887b3bde43259f Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Fri, 27 Feb 2015 23:52:51 +0100 Subject: slightly longer color fade duration --- .../java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java index d14455511..bbf35e497 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java @@ -883,9 +883,9 @@ public class ViewKeyActivity extends BaseActivity implements ObjectAnimator.ofObject(mBigToolbar, "backgroundColor", new ArgbEvaluator(), mPreviousColor, color); - colorFade1.setDuration(800); - colorFade2.setDuration(800); - colorFade3.setDuration(800); + colorFade1.setDuration(1200); + colorFade2.setDuration(1200); + colorFade3.setDuration(1200); colorFade1.start(); colorFade2.start(); colorFade3.start(); -- cgit v1.2.3 From 582caaba97c288de88b7a957cdf1b6f5bc84ed31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Fri, 27 Feb 2015 23:56:53 +0100 Subject: Reorder advanced key view --- .../keychain/ui/ViewKeyAdvActivity.java | 12 +- .../keychain/ui/ViewKeyAdvMainFragment.java | 236 --------------------- .../keychain/ui/ViewKeyAdvUserIdsFragment.java | 184 ++++++++++++++++ 3 files changed, 190 insertions(+), 242 deletions(-) delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvMainFragment.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvUserIdsFragment.java (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvActivity.java index 894529cc5..9d79b377c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvActivity.java @@ -124,16 +124,16 @@ public class ViewKeyAdvActivity extends BaseActivity implements mTabsAdapter = new PagerTabStripAdapter(this); mViewPager.setAdapter(mTabsAdapter); - Bundle mainBundle = new Bundle(); - mainBundle.putParcelable(ViewKeyAdvMainFragment.ARG_DATA_URI, dataUri); - mTabsAdapter.addTab(ViewKeyAdvMainFragment.class, - mainBundle, getString(R.string.key_view_tab_main)); - Bundle shareBundle = new Bundle(); - shareBundle.putParcelable(ViewKeyAdvMainFragment.ARG_DATA_URI, dataUri); + shareBundle.putParcelable(ViewKeyAdvUserIdsFragment.ARG_DATA_URI, dataUri); mTabsAdapter.addTab(ViewKeyAdvShareFragment.class, shareBundle, getString(R.string.key_view_tab_share)); + Bundle userIdsBundle = new Bundle(); + userIdsBundle.putParcelable(ViewKeyAdvUserIdsFragment.ARG_DATA_URI, dataUri); + mTabsAdapter.addTab(ViewKeyAdvUserIdsFragment.class, + userIdsBundle, getString(R.string.section_user_ids)); + Bundle keysBundle = new Bundle(); keysBundle.putParcelable(ViewKeyAdvSubkeysFragment.ARG_DATA_URI, dataUri); mTabsAdapter.addTab(ViewKeyAdvSubkeysFragment.class, diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvMainFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvMainFragment.java deleted file mode 100644 index fc107d794..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvMainFragment.java +++ /dev/null @@ -1,236 +0,0 @@ -/* - * Copyright (C) 2014 Dominik Schürmann - * Copyright (C) 2014 Vincent Breitmoser - * - * 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 . - */ - -package org.sufficientlysecure.keychain.ui; - -import android.content.Intent; -import android.database.Cursor; -import android.graphics.PorterDuff; -import android.net.Uri; -import android.os.Bundle; -import android.support.v4.app.LoaderManager; -import android.support.v4.content.CursorLoader; -import android.support.v4.content.Loader; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.AdapterView; -import android.widget.ImageView; -import android.widget.ListView; - -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround; -import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; -import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; -import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets; -import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.ui.adapter.UserIdsAdapter; -import org.sufficientlysecure.keychain.ui.dialog.UserIdInfoDialogFragment; -import org.sufficientlysecure.keychain.util.Log; - -import java.util.Date; - -public class ViewKeyAdvMainFragment extends LoaderFragment implements - LoaderManager.LoaderCallbacks { - - public static final String ARG_DATA_URI = "uri"; - - private View mActionCertify; - private View mActionCertifyText; - private ImageView mActionCertifyImage; - - private ListView mUserIds; - - private static final int LOADER_ID_UNIFIED = 0; - private static final int LOADER_ID_USER_IDS = 1; - - private UserIdsAdapter mUserIdsAdapter; - - private Uri mDataUri; - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup superContainer, Bundle savedInstanceState) { - View root = super.onCreateView(inflater, superContainer, savedInstanceState); - View view = inflater.inflate(R.layout.view_key_adv_main_fragment, getContainer()); - - mUserIds = (ListView) view.findViewById(R.id.view_key_user_ids); - mActionCertify = view.findViewById(R.id.view_key_action_certify); - mActionCertifyText = view.findViewById(R.id.view_key_action_certify_text); - mActionCertifyImage = (ImageView) view.findViewById(R.id.view_key_action_certify_image); - // make certify image gray, like action icons - mActionCertifyImage.setColorFilter(getResources().getColor(R.color.tertiary_text_light), - PorterDuff.Mode.SRC_IN); - - mUserIds.setOnItemClickListener(new AdapterView.OnItemClickListener() { - @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { - showUserIdInfo(position); - } - }); - - return root; - } - - private void showUserIdInfo(final int position) { - final boolean isRevoked = mUserIdsAdapter.getIsRevoked(position); - final int isVerified = mUserIdsAdapter.getIsVerified(position); - - DialogFragmentWorkaround.INTERFACE.runnableRunDelayed(new Runnable() { - public void run() { - UserIdInfoDialogFragment dialogFragment = - UserIdInfoDialogFragment.newInstance(isRevoked, isVerified); - - dialogFragment.show(getActivity().getSupportFragmentManager(), "userIdInfoDialog"); - } - }); - } - - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - - Uri dataUri = getArguments().getParcelable(ARG_DATA_URI); - if (dataUri == null) { - Log.e(Constants.TAG, "Data missing. Should be Uri of key!"); - getActivity().finish(); - return; - } - - loadData(dataUri); - } - - private void loadData(Uri dataUri) { - mDataUri = dataUri; - - Log.i(Constants.TAG, "mDataUri: " + mDataUri.toString()); - - mActionCertify.setOnClickListener(new View.OnClickListener() { - public void onClick(View view) { - certify(mDataUri); - } - }); - - mUserIdsAdapter = new UserIdsAdapter(getActivity(), null, 0); - mUserIds.setAdapter(mUserIdsAdapter); - - // Prepare the loaders. Either re-connect with an existing ones, - // or start new ones. - getLoaderManager().initLoader(LOADER_ID_UNIFIED, null, this); - getLoaderManager().initLoader(LOADER_ID_USER_IDS, null, this); - } - - static final String[] UNIFIED_PROJECTION = new String[]{ - KeyRings._ID, KeyRings.MASTER_KEY_ID, - KeyRings.HAS_ANY_SECRET, KeyRings.IS_REVOKED, KeyRings.EXPIRY, KeyRings.HAS_ENCRYPT - }; - static final int INDEX_UNIFIED_MASTER_KEY_ID = 1; - static final int INDEX_UNIFIED_HAS_ANY_SECRET = 2; - static final int INDEX_UNIFIED_IS_REVOKED = 3; - static final int INDEX_UNIFIED_EXPIRY = 4; - static final int INDEX_UNIFIED_HAS_ENCRYPT = 5; - - public Loader onCreateLoader(int id, Bundle args) { - setContentShown(false); - - switch (id) { - case LOADER_ID_UNIFIED: { - Uri baseUri = KeyRings.buildUnifiedKeyRingUri(mDataUri); - return new CursorLoader(getActivity(), baseUri, UNIFIED_PROJECTION, null, null, null); - } - case LOADER_ID_USER_IDS: { - Uri baseUri = UserPackets.buildUserIdsUri(mDataUri); - return new CursorLoader(getActivity(), baseUri, - UserIdsAdapter.USER_IDS_PROJECTION, null, null, null); - } - - default: - return null; - } - } - - public void onLoadFinished(Loader loader, Cursor data) { - /* TODO better error handling? May cause problems when a key is deleted, - * because the notification triggers faster than the activity closes. - */ - // Avoid NullPointerExceptions... - if (data.getCount() == 0) { - return; - } - // Swap the new cursor in. (The framework will take care of closing the - // old cursor once we return.) - switch (loader.getId()) { - case LOADER_ID_UNIFIED: { - if (data.moveToFirst()) { - - // If this key is revoked, it cannot be used for anything! - if (data.getInt(INDEX_UNIFIED_IS_REVOKED) != 0) { - mActionCertify.setEnabled(false); - mActionCertifyText.setEnabled(false); - } else { - - Date expiryDate = new Date(data.getLong(INDEX_UNIFIED_EXPIRY) * 1000); - if (!data.isNull(INDEX_UNIFIED_EXPIRY) && expiryDate.before(new Date())) { - mActionCertify.setEnabled(false); - mActionCertifyText.setEnabled(false); - } else { - mActionCertify.setEnabled(true); - mActionCertifyText.setEnabled(true); - } - } - - break; - } - } - - case LOADER_ID_USER_IDS: { - mUserIdsAdapter.swapCursor(data); - break; - } - - } - setContentShown(true); - } - - /** - * This is called when the last Cursor provided to onLoadFinished() above is about to be closed. - * We need to make sure we are no longer using it. - */ - public void onLoaderReset(Loader loader) { - switch (loader.getId()) { - case LOADER_ID_USER_IDS: - mUserIdsAdapter.swapCursor(null); - break; - } - } - - private void certify(Uri dataUri) { - long keyId = 0; - try { - keyId = new ProviderHelper(getActivity()) - .getCachedPublicKeyRing(dataUri) - .extractOrGetMasterKeyId(); - } catch (PgpKeyNotFoundException e) { - Log.e(Constants.TAG, "key not found!", e); - } - Intent certifyIntent = new Intent(getActivity(), CertifyKeyActivity.class); - certifyIntent.putExtra(CertifyKeyActivity.EXTRA_KEY_IDS, new long[]{keyId}); - startActivityForResult(certifyIntent, 0); - } - -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvUserIdsFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvUserIdsFragment.java new file mode 100644 index 000000000..c4e6639a8 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyAdvUserIdsFragment.java @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2014 Dominik Schürmann + * Copyright (C) 2014 Vincent Breitmoser + * + * 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 . + */ + +package org.sufficientlysecure.keychain.ui; + +import android.database.Cursor; +import android.net.Uri; +import android.os.Bundle; +import android.support.v4.app.LoaderManager; +import android.support.v4.content.CursorLoader; +import android.support.v4.content.Loader; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.ListView; + +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.compatibility.DialogFragmentWorkaround; +import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; +import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets; +import org.sufficientlysecure.keychain.ui.adapter.UserIdsAdapter; +import org.sufficientlysecure.keychain.ui.dialog.UserIdInfoDialogFragment; +import org.sufficientlysecure.keychain.util.Log; + +public class ViewKeyAdvUserIdsFragment extends LoaderFragment implements + LoaderManager.LoaderCallbacks { + + public static final String ARG_DATA_URI = "uri"; + + private ListView mUserIds; + + private static final int LOADER_ID_UNIFIED = 0; + private static final int LOADER_ID_USER_IDS = 1; + + private UserIdsAdapter mUserIdsAdapter; + + private Uri mDataUri; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup superContainer, Bundle savedInstanceState) { + View root = super.onCreateView(inflater, superContainer, savedInstanceState); + View view = inflater.inflate(R.layout.view_key_adv_main_fragment, getContainer()); + + mUserIds = (ListView) view.findViewById(R.id.view_key_user_ids); + + mUserIds.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + showUserIdInfo(position); + } + }); + + return root; + } + + private void showUserIdInfo(final int position) { + final boolean isRevoked = mUserIdsAdapter.getIsRevoked(position); + final int isVerified = mUserIdsAdapter.getIsVerified(position); + + DialogFragmentWorkaround.INTERFACE.runnableRunDelayed(new Runnable() { + public void run() { + UserIdInfoDialogFragment dialogFragment = + UserIdInfoDialogFragment.newInstance(isRevoked, isVerified); + + dialogFragment.show(getActivity().getSupportFragmentManager(), "userIdInfoDialog"); + } + }); + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + Uri dataUri = getArguments().getParcelable(ARG_DATA_URI); + if (dataUri == null) { + Log.e(Constants.TAG, "Data missing. Should be Uri of key!"); + getActivity().finish(); + return; + } + + loadData(dataUri); + } + + private void loadData(Uri dataUri) { + mDataUri = dataUri; + + Log.i(Constants.TAG, "mDataUri: " + mDataUri.toString()); + + mUserIdsAdapter = new UserIdsAdapter(getActivity(), null, 0); + mUserIds.setAdapter(mUserIdsAdapter); + + // Prepare the loaders. Either re-connect with an existing ones, + // or start new ones. + getLoaderManager().initLoader(LOADER_ID_UNIFIED, null, this); + getLoaderManager().initLoader(LOADER_ID_USER_IDS, null, this); + } + + static final String[] UNIFIED_PROJECTION = new String[]{ + KeyRings._ID, KeyRings.MASTER_KEY_ID, + KeyRings.HAS_ANY_SECRET, KeyRings.IS_REVOKED, KeyRings.EXPIRY, KeyRings.HAS_ENCRYPT + }; + static final int INDEX_UNIFIED_MASTER_KEY_ID = 1; + static final int INDEX_UNIFIED_HAS_ANY_SECRET = 2; + static final int INDEX_UNIFIED_IS_REVOKED = 3; + static final int INDEX_UNIFIED_EXPIRY = 4; + static final int INDEX_UNIFIED_HAS_ENCRYPT = 5; + + public Loader onCreateLoader(int id, Bundle args) { + setContentShown(false); + + switch (id) { + case LOADER_ID_UNIFIED: { + Uri baseUri = KeyRings.buildUnifiedKeyRingUri(mDataUri); + return new CursorLoader(getActivity(), baseUri, UNIFIED_PROJECTION, null, null, null); + } + case LOADER_ID_USER_IDS: { + Uri baseUri = UserPackets.buildUserIdsUri(mDataUri); + return new CursorLoader(getActivity(), baseUri, + UserIdsAdapter.USER_IDS_PROJECTION, null, null, null); + } + + default: + return null; + } + } + + public void onLoadFinished(Loader loader, Cursor data) { + /* TODO better error handling? May cause problems when a key is deleted, + * because the notification triggers faster than the activity closes. + */ + // Avoid NullPointerExceptions... + if (data.getCount() == 0) { + return; + } + // Swap the new cursor in. (The framework will take care of closing the + // old cursor once we return.) + switch (loader.getId()) { + case LOADER_ID_UNIFIED: { + if (data.moveToFirst()) { + + + break; + } + } + + case LOADER_ID_USER_IDS: { + mUserIdsAdapter.swapCursor(data); + break; + } + + } + setContentShown(true); + } + + /** + * This is called when the last Cursor provided to onLoadFinished() above is about to be closed. + * We need to make sure we are no longer using it. + */ + public void onLoaderReset(Loader loader) { + switch (loader.getId()) { + case LOADER_ID_USER_IDS: + mUserIdsAdapter.swapCursor(null); + break; + } + } + +} -- cgit v1.2.3 From 0669193e7517920972e4bb577c1bec04fa7b594f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Sat, 28 Feb 2015 00:22:31 +0100 Subject: Simplify MainActivity --- .../keychain/ui/MainActivity.java | 25 ++++++++++- .../keychain/ui/NavDrawerActivity.java | 50 ---------------------- 2 files changed, 23 insertions(+), 52 deletions(-) delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NavDrawerActivity.java (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java index 2f29f9360..04350a57d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java @@ -23,13 +23,34 @@ import android.os.Bundle; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.operations.results.OperationResult; +import org.sufficientlysecure.keychain.remote.ui.AppsListFragment; import org.sufficientlysecure.keychain.util.Preferences; -public class MainActivity extends NavDrawerActivity { +import it.neokree.materialnavigationdrawer.MaterialNavigationDrawer; + +public class MainActivity extends MaterialNavigationDrawer { @Override public void init(Bundle savedInstanceState) { - super.init(savedInstanceState); + // don't open drawer on first run + disableLearningPattern(); + +// addMultiPaneSupport(); + + // set the header image + // create and set the header + setDrawerHeaderImage(R.drawable.drawer_header); + + // create sections + addSection(newSection(getString(R.string.nav_keys), R.drawable.ic_vpn_key_black_24dp, new KeyListFragment())); + addSection(newSection(getString(R.string.nav_encrypt_decrypt), R.drawable.ic_lock_black_24dp, new EncryptDecryptOverviewFragment())); + addSection(newSection(getString(R.string.title_api_registered_apps), R.drawable.ic_apps_black_24dp, new AppsListFragment())); + + // create bottom section + addBottomSection(newSection(getString(R.string.menu_preferences), R.drawable.ic_settings_black_24dp, new Intent(this, SettingsActivity.class))); + addBottomSection(newSection(getString(R.string.menu_help), R.drawable.ic_help_black_24dp, new Intent(this, HelpActivity.class))); + + // if this is the first time show first time activity Preferences prefs = Preferences.getPreferences(this); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NavDrawerActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NavDrawerActivity.java deleted file mode 100644 index fb23c7d3a..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/NavDrawerActivity.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2015 Dominik Schürmann - * - * 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 . - */ - -package org.sufficientlysecure.keychain.ui; - -import android.content.Intent; -import android.os.Bundle; - -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.remote.ui.AppsListFragment; - -import it.neokree.materialnavigationdrawer.MaterialNavigationDrawer; - -public abstract class NavDrawerActivity extends MaterialNavigationDrawer { - - @Override - public void init(Bundle savedInstanceState) { - // don't open drawer on first run - disableLearningPattern(); - -// addMultiPaneSupport(); - - // set the header image - // create and set the header - setDrawerHeaderImage(R.drawable.drawer_header); - - // create sections - addSection(newSection(getString(R.string.nav_keys), R.drawable.ic_vpn_key_black_24dp, new KeyListFragment())); - addSection(newSection(getString(R.string.nav_encrypt_decrypt), R.drawable.ic_lock_black_24dp, new EncryptDecryptOverviewFragment())); - addSection(newSection(getString(R.string.title_api_registered_apps), R.drawable.ic_apps_black_24dp, new AppsListFragment())); - - // create bottom section - addBottomSection(newSection(getString(R.string.menu_preferences), R.drawable.ic_settings_black_24dp, new Intent(this, SettingsActivity.class))); - addBottomSection(newSection(getString(R.string.menu_help), R.drawable.ic_help_black_24dp, new Intent(this, HelpActivity.class))); - } -} -- cgit v1.2.3 From 9c62c3fd3985958a43707c7a25f07744a6cfcb95 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Sat, 28 Feb 2015 00:28:20 +0100 Subject: control flow for moving the fab up with snackbar --- .../keychain/ui/KeyListFragment.java | 31 ++++++++++++++++- .../keychain/ui/MainActivity.java | 20 +++++++++-- .../keychain/ui/util/Notify.java | 39 ++++++++++++++++++++-- 3 files changed, 85 insertions(+), 5 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java index ba9a96b28..bf3498f2f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java @@ -46,14 +46,19 @@ import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; +import android.view.ViewGroup.LayoutParams; +import android.view.ViewGroup.MarginLayoutParams; +import android.view.animation.TranslateAnimation; import android.widget.AbsListView.MultiChoiceModeListener; import android.widget.AdapterView; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.ListView; +import android.widget.RelativeLayout; import android.widget.TextView; import com.getbase.floatingactionbutton.FloatingActionButton; +import com.getbase.floatingactionbutton.FloatingActionsMenu; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; @@ -71,6 +76,7 @@ import org.sufficientlysecure.keychain.ui.util.Highlighter; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.util.ExportHelper; +import org.sufficientlysecure.keychain.util.FabContainer; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Preferences; @@ -87,7 +93,7 @@ import se.emilsjolander.stickylistheaders.StickyListHeadersListView; */ public class KeyListFragment extends LoaderFragment implements SearchView.OnQueryTextListener, AdapterView.OnItemClickListener, - LoaderManager.LoaderCallbacks { + LoaderManager.LoaderCallbacks, FabContainer { ExportHelper mExportHelper; @@ -102,6 +108,8 @@ public class KeyListFragment extends LoaderFragment private String mQuery; private SearchView mSearchView; + private FloatingActionsMenu mFab; + private FloatingActionButton mFabQrCode; private FloatingActionButton mFabCloud; private FloatingActionButton mFabFile; @@ -124,6 +132,8 @@ public class KeyListFragment extends LoaderFragment mStickyList = (StickyListHeadersListView) view.findViewById(R.id.key_list_list); mStickyList.setOnItemClickListener(this); + mFab = (FloatingActionsMenu) view.findViewById(R.id.fab_main); + mFabQrCode = (FloatingActionButton) view.findViewById(R.id.fab_add_qr_code); mFabCloud = (FloatingActionButton) view.findViewById(R.id.fab_add_cloud); mFabFile = (FloatingActionButton) view.findViewById(R.id.fab_add_file); @@ -609,6 +619,25 @@ public class KeyListFragment extends LoaderFragment } } + LayoutParams mFabOrigin = null; + @Override + public void fabMoveUp(int height) { + if (mFabOrigin == null) { + mFabOrigin = mFab.getLayoutParams(); + } + + // TODO reposition properly! + MarginLayoutParams marginParams = new MarginLayoutParams(mFabOrigin); + marginParams.setMargins(0, 0, 16, 16+height); + RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(marginParams); + mFab.setLayoutParams(layoutParams); + } + + @Override + public void fabRestorePosition() { + mFab.setLayoutParams(mFabOrigin); + } + /** * Implements StickyListHeadersAdapter from library */ diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java index 04350a57d..fd2f1b1d2 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java @@ -25,10 +25,11 @@ import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.remote.ui.AppsListFragment; import org.sufficientlysecure.keychain.util.Preferences; +import org.sufficientlysecure.keychain.util.FabContainer; import it.neokree.materialnavigationdrawer.MaterialNavigationDrawer; -public class MainActivity extends MaterialNavigationDrawer { +public class MainActivity extends MaterialNavigationDrawer implements FabContainer { @Override public void init(Bundle savedInstanceState) { @@ -51,7 +52,6 @@ public class MainActivity extends MaterialNavigationDrawer { addBottomSection(newSection(getString(R.string.menu_help), R.drawable.ic_help_black_24dp, new Intent(this, HelpActivity.class))); - // if this is the first time show first time activity Preferences prefs = Preferences.getPreferences(this); if (prefs.isFirstTime()) { @@ -68,4 +68,20 @@ public class MainActivity extends MaterialNavigationDrawer { } } + @Override + public void fabMoveUp(int height) { + Object fragment = getCurrentSection().getTargetFragment(); + if (fragment instanceof FabContainer) { + ((FabContainer) fragment).fabMoveUp(height); + } + } + + @Override + public void fabRestorePosition() { + Object fragment = getCurrentSection().getTargetFragment(); + if (fragment instanceof FabContainer) { + ((FabContainer) fragment).fabRestorePosition(); + } + } + } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/Notify.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/Notify.java index f6c979139..1c6f3bd3e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/Notify.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/Notify.java @@ -19,15 +19,16 @@ package org.sufficientlysecure.keychain.ui.util; import android.app.Activity; import android.content.res.Resources; -import android.graphics.Color; import com.nispok.snackbar.Snackbar; import com.nispok.snackbar.Snackbar.SnackbarDuration; import com.nispok.snackbar.SnackbarManager; import com.nispok.snackbar.enums.SnackbarType; import com.nispok.snackbar.listeners.ActionClickListener; +import com.nispok.snackbar.listeners.EventListener; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.util.FabContainer; /** * Notify wrapper which allows a more easy use of different notification libraries @@ -45,13 +46,47 @@ public class Notify { * @param text Text to show * @param style Notification styling */ - public static void showNotify(Activity activity, CharSequence text, Style style) { + public static void showNotify(final Activity activity, CharSequence text, Style style) { Snackbar bar = Snackbar.with(activity) .text(text) .type(SnackbarType.MULTI_LINE) .duration(SnackbarDuration.LENGTH_LONG); + if (activity instanceof FabContainer) { + bar.eventListener(new EventListener() { + @Override + public void onShow(Snackbar snackbar) { + ((FabContainer) activity).fabMoveUp(snackbar.getHeight()); + } + + @Override + public void onShowByReplace(Snackbar snackbar) { + + } + + @Override + public void onShown(Snackbar snackbar) { + + } + + @Override + public void onDismiss(Snackbar snackbar) { + ((FabContainer) activity).fabRestorePosition(); + } + + @Override + public void onDismissByReplace(Snackbar snackbar) { + + } + + @Override + public void onDismissed(Snackbar snackbar) { + + } + }); + } + switch (style) { case OK: break; -- cgit v1.2.3 From 453b67f7a8cb274d794843e54d6d050a7ef7a98a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Sat, 28 Feb 2015 00:38:53 +0100 Subject: Update from transifex --- .../src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java | 2 -- 1 file changed, 2 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java index 04350a57d..ed9f3a02d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/MainActivity.java @@ -50,8 +50,6 @@ public class MainActivity extends MaterialNavigationDrawer { addBottomSection(newSection(getString(R.string.menu_preferences), R.drawable.ic_settings_black_24dp, new Intent(this, SettingsActivity.class))); addBottomSection(newSection(getString(R.string.menu_help), R.drawable.ic_help_black_24dp, new Intent(this, HelpActivity.class))); - - // if this is the first time show first time activity Preferences prefs = Preferences.getPreferences(this); if (prefs.isFirstTime()) { -- cgit v1.2.3 From 67093ccba244a1ba24c12acd4ce294d37aa09254 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Sat, 28 Feb 2015 00:39:55 +0100 Subject: forgot to commit FabContainer --- .../java/org/sufficientlysecure/keychain/util/FabContainer.java | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/FabContainer.java (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/FabContainer.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/FabContainer.java new file mode 100644 index 000000000..116b98d1e --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/FabContainer.java @@ -0,0 +1,8 @@ +package org.sufficientlysecure.keychain.util; + +public interface FabContainer { + + void fabMoveUp(int height); + void fabRestorePosition(); + +} -- cgit v1.2.3 From d64b8f47d10b15903978a378bc6acf998ae3f890 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Sat, 28 Feb 2015 01:17:45 +0100 Subject: animate FAB to move up and down when a snackbar appears --- .../keychain/ui/KeyListFragment.java | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java index bf3498f2f..6e2b46da0 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java @@ -18,6 +18,7 @@ package org.sufficientlysecure.keychain.ui; +import android.animation.ObjectAnimator; import android.annotation.TargetApi; import android.app.ProgressDialog; import android.content.Context; @@ -619,23 +620,21 @@ public class KeyListFragment extends LoaderFragment } } - LayoutParams mFabOrigin = null; @Override public void fabMoveUp(int height) { - if (mFabOrigin == null) { - mFabOrigin = mFab.getLayoutParams(); - } - - // TODO reposition properly! - MarginLayoutParams marginParams = new MarginLayoutParams(mFabOrigin); - marginParams.setMargins(0, 0, 16, 16+height); - RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(marginParams); - mFab.setLayoutParams(layoutParams); + ObjectAnimator anim = ObjectAnimator.ofFloat(mFab, "translationY", 0, -height); + // we're a little behind, so skip 1/10 of the time + anim.setDuration(270); + anim.start(); } @Override public void fabRestorePosition() { - mFab.setLayoutParams(mFabOrigin); + ObjectAnimator anim = ObjectAnimator.ofFloat(mFab, "translationY", 0); + // we're a little ahead, so wait a few ms + anim.setStartDelay(70); + anim.setDuration(300); + anim.start(); } /** -- cgit v1.2.3 From cc5b0dae06d2be11c9c677734d9d7dcfaf4f6078 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Sat, 28 Feb 2015 01:31:24 +0100 Subject: collapse fab on action selected closes #1057 --- .../main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java | 3 +++ 1 file changed, 3 insertions(+) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java index 6e2b46da0..0c53a3bc1 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java @@ -142,18 +142,21 @@ public class KeyListFragment extends LoaderFragment mFabQrCode.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { + mFab.collapse(); scanQrCode(); } }); mFabCloud.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { + mFab.collapse(); searchCloud(); } }); mFabFile.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { + mFab.collapse(); importFile(); } }); -- cgit v1.2.3 From 6ba03c0f13bb1301f40abf4bca2d2ec432186642 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Sat, 28 Feb 2015 01:32:15 +0100 Subject: clean up warnings in KeyListFragment --- .../keychain/ui/KeyListFragment.java | 42 ++++++---------------- 1 file changed, 10 insertions(+), 32 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java index 0c53a3bc1..496048582 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java @@ -37,7 +37,6 @@ import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; import android.support.v4.view.MenuItemCompat; import android.support.v4.widget.CursorAdapter; -import android.support.v7.app.ActionBarActivity; import android.support.v7.widget.SearchView; import android.view.ActionMode; import android.view.LayoutInflater; @@ -47,15 +46,11 @@ import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; -import android.view.ViewGroup.LayoutParams; -import android.view.ViewGroup.MarginLayoutParams; -import android.view.animation.TranslateAnimation; import android.widget.AbsListView.MultiChoiceModeListener; import android.widget.AdapterView; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.ListView; -import android.widget.RelativeLayout; import android.widget.TextView; import com.getbase.floatingactionbutton.FloatingActionButton; @@ -104,17 +99,10 @@ public class KeyListFragment extends LoaderFragment // saves the mode object for multiselect, needed for reset at some point private ActionMode mActionMode = null; - private boolean mShowAllKeys = true; - private String mQuery; - private SearchView mSearchView; private FloatingActionsMenu mFab; - private FloatingActionButton mFabQrCode; - private FloatingActionButton mFabCloud; - private FloatingActionButton mFabFile; - @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -135,25 +123,25 @@ public class KeyListFragment extends LoaderFragment mFab = (FloatingActionsMenu) view.findViewById(R.id.fab_main); - mFabQrCode = (FloatingActionButton) view.findViewById(R.id.fab_add_qr_code); - mFabCloud = (FloatingActionButton) view.findViewById(R.id.fab_add_cloud); - mFabFile = (FloatingActionButton) view.findViewById(R.id.fab_add_file); + FloatingActionButton fabQrCode = (FloatingActionButton) view.findViewById(R.id.fab_add_qr_code); + FloatingActionButton fabCloud = (FloatingActionButton) view.findViewById(R.id.fab_add_cloud); + FloatingActionButton fabFile = (FloatingActionButton) view.findViewById(R.id.fab_add_file); - mFabQrCode.setOnClickListener(new OnClickListener() { + fabQrCode.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { mFab.collapse(); scanQrCode(); } }); - mFabCloud.setOnClickListener(new OnClickListener() { + fabCloud.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { mFab.collapse(); searchCloud(); } }); - mFabFile.setOnClickListener(new OnClickListener() { + fabFile.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { mFab.collapse(); @@ -221,7 +209,7 @@ public class KeyListFragment extends LoaderFragment } case R.id.menu_key_list_multi_export: { ids = mAdapter.getCurrentSelectedMasterKeyIds(); - ExportHelper mExportHelper = new ExportHelper((ActionBarActivity) getActivity()); + ExportHelper mExportHelper = new ExportHelper(getActivity()); mExportHelper.showExportKeysDialog(ids, Constants.Path.APP_DIR_FILE, mAdapter.isAnySecretSelected()); break; @@ -247,7 +235,7 @@ public class KeyListFragment extends LoaderFragment public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) { if (checked) { - mAdapter.setNewSelection(position, checked); + mAdapter.setNewSelection(position, true); } else { mAdapter.removeSelection(position); } @@ -316,14 +304,6 @@ public class KeyListFragment extends LoaderFragment whereArgs[i] = "%" + words[i] + "%"; } } - if (!mShowAllKeys) { - if (where == null) { - where = ""; - } else { - where += " AND "; - } - where += KeyRings.VERIFIED + " != 0"; - } // Now create and return a CursorLoader that will take care of // creating a Cursor for the data being displayed. @@ -387,7 +367,6 @@ public class KeyListFragment extends LoaderFragment /** * Show dialog to delete key * - * @param masterKeyIds * @param hasSecret must contain whether the list of masterKeyIds contains a secret key or not */ public void showDeleteKeyDialog(final ActionMode mode, long[] masterKeyIds, boolean hasSecret) { @@ -439,10 +418,10 @@ public class KeyListFragment extends LoaderFragment // Get the searchview MenuItem searchItem = menu.findItem(R.id.menu_key_list_search); - mSearchView = (SearchView) MenuItemCompat.getActionView(searchItem); + SearchView searchView = (SearchView) MenuItemCompat.getActionView(searchItem); // Execute this when searching - mSearchView.setOnQueryTextListener(this); + searchView.setOnQueryTextListener(this); // Erase search result without focus MenuItemCompat.setOnActionExpandListener(searchItem, new MenuItemCompat.OnActionExpandListener() { @@ -540,7 +519,6 @@ public class KeyListFragment extends LoaderFragment return true; } - private void searchCloud() { Intent importIntent = new Intent(getActivity(), ImportKeysActivity.class); importIntent.putExtra(ImportKeysActivity.EXTRA_QUERY, (String) null); // hack to show only cloud tab -- cgit v1.2.3 From e4d91de8d299e01b11faf8e72278025c428eac8e Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Sat, 28 Feb 2015 01:37:57 +0100 Subject: small Notify cleanup --- .../keychain/ui/util/Notify.java | 26 ++-------------------- 1 file changed, 2 insertions(+), 24 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/Notify.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/Notify.java index 1c6f3bd3e..1c35ec9cc 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/Notify.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/Notify.java @@ -25,7 +25,7 @@ import com.nispok.snackbar.Snackbar.SnackbarDuration; import com.nispok.snackbar.SnackbarManager; import com.nispok.snackbar.enums.SnackbarType; import com.nispok.snackbar.listeners.ActionClickListener; -import com.nispok.snackbar.listeners.EventListener; +import com.nispok.snackbar.listeners.EventListenerAdapter; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.util.FabContainer; @@ -42,7 +42,6 @@ public class Notify { /** * Shows a simple in-layout notification with the CharSequence given as parameter - * @param activity * @param text Text to show * @param style Notification styling */ @@ -54,36 +53,16 @@ public class Notify { .duration(SnackbarDuration.LENGTH_LONG); if (activity instanceof FabContainer) { - bar.eventListener(new EventListener() { + bar.eventListener(new EventListenerAdapter() { @Override public void onShow(Snackbar snackbar) { ((FabContainer) activity).fabMoveUp(snackbar.getHeight()); } - @Override - public void onShowByReplace(Snackbar snackbar) { - - } - - @Override - public void onShown(Snackbar snackbar) { - - } - @Override public void onDismiss(Snackbar snackbar) { ((FabContainer) activity).fabRestorePosition(); } - - @Override - public void onDismissByReplace(Snackbar snackbar) { - - } - - @Override - public void onDismissed(Snackbar snackbar) { - - } }); } @@ -178,7 +157,6 @@ public class Notify { /** * Shows a simple in-layout notification with the resource text from given id - * @param activity * @param resId ResourceId of notification text * @param style Notification styling * @throws Resources.NotFoundException -- cgit v1.2.3 From f3710b12f6a9c40b43f973c02790136fb17065ac Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Sat, 28 Feb 2015 02:30:59 +0100 Subject: fab support for all notify types --- .../keychain/ui/util/Notify.java | 52 ++++++++++++---------- 1 file changed, 29 insertions(+), 23 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/Notify.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/Notify.java index 1c35ec9cc..8686b605f 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/Notify.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/Notify.java @@ -47,24 +47,8 @@ public class Notify { */ public static void showNotify(final Activity activity, CharSequence text, Style style) { - Snackbar bar = Snackbar.with(activity) - .text(text) - .type(SnackbarType.MULTI_LINE) - .duration(SnackbarDuration.LENGTH_LONG); - - if (activity instanceof FabContainer) { - bar.eventListener(new EventListenerAdapter() { - @Override - public void onShow(Snackbar snackbar) { - ((FabContainer) activity).fabMoveUp(snackbar.getHeight()); - } - - @Override - public void onDismiss(Snackbar snackbar) { - ((FabContainer) activity).fabRestorePosition(); - } - }); - } + Snackbar bar = getSnackbar(activity) + .text(text); switch (style) { case OK: @@ -82,9 +66,9 @@ public class Notify { } public static Showable createNotify (Activity activity, int resId, int duration, Style style) { - final Snackbar bar = Snackbar.with(activity) - .text(resId) - .type(SnackbarType.MULTI_LINE); + final Snackbar bar = getSnackbar(activity) + .text(resId); + if (duration == LENGTH_INDEFINITE) { bar.duration(SnackbarDuration.LENGTH_INDEFINITE); } else { @@ -118,16 +102,17 @@ public class Notify { public static Showable createNotify(Activity activity, String msg, int duration, Style style, final ActionListener listener, int resIdAction) { - final Snackbar bar = Snackbar.with(activity) + + final Snackbar bar = getSnackbar(activity) .text(msg) .actionLabel(resIdAction) - .type(SnackbarType.MULTI_LINE) .actionListener(new ActionClickListener() { @Override public void onActionClicked(Snackbar snackbar) { listener.onAction(); } }); + if (duration == LENGTH_INDEFINITE) { bar.duration(SnackbarDuration.LENGTH_INDEFINITE); } else { @@ -165,6 +150,27 @@ public class Notify { showNotify(activity, activity.getResources().getText(resId), style); } + private static Snackbar getSnackbar(final Activity activity) { + Snackbar bar = Snackbar.with(activity) + .type(SnackbarType.MULTI_LINE) + .duration(SnackbarDuration.LENGTH_LONG); + + if (activity instanceof FabContainer) { + bar.eventListener(new EventListenerAdapter() { + @Override + public void onShow(Snackbar snackbar) { + ((FabContainer) activity).fabMoveUp(snackbar.getHeight()); + } + + @Override + public void onDismiss(Snackbar snackbar) { + ((FabContainer) activity).fabRestorePosition(); + } + }); + } + return bar; + } + public interface Showable { public void show(); -- cgit v1.2.3 From 2ae4d6ce05e6ca1585239b779b1dd6f39f58050a Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Sat, 28 Feb 2015 04:28:21 +0100 Subject: pass through messenger to certify service from ViewKeyActivity the idea here is to handle progress and result of the CertifyActivity directly in ViewKeyActivity by passing a messenger through to it. this allows smoother transition from an uncertified to certified state. --- .../keychain/ui/CertifyFingerprintActivity.java | 12 --- .../keychain/ui/CertifyFingerprintFragment.java | 16 +++- .../keychain/ui/CertifyKeyFragment.java | 86 +++++++++++++--------- .../keychain/ui/ViewKeyActivity.java | 22 +++++- 4 files changed, 87 insertions(+), 49 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyFingerprintActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyFingerprintActivity.java index c75f6d838..b7c80c1ed 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyFingerprintActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyFingerprintActivity.java @@ -17,14 +17,12 @@ package org.sufficientlysecure.keychain.ui; -import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.view.View; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.util.Log; public class CertifyFingerprintActivity extends BaseActivity { @@ -79,14 +77,4 @@ public class CertifyFingerprintActivity extends BaseActivity { getSupportFragmentManager().executePendingTransactions(); } - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - // if a result has been returned, display a notify - if (data != null && data.hasExtra(OperationResult.EXTRA_RESULT)) { - setResult(RESULT_OK, data); - finish(); - } else { - super.onActivityResult(requestCode, resultCode, data); - } - } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyFingerprintFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyFingerprintFragment.java index aef705ee9..a6b8a0e85 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyFingerprintFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyFingerprintFragment.java @@ -41,6 +41,8 @@ import org.sufficientlysecure.keychain.util.Log; public class CertifyFingerprintFragment extends LoaderFragment implements LoaderManager.LoaderCallbacks { + static final int REQUEST_CERTIFY = 1; + public static final String ARG_DATA_URI = "uri"; private TextView mFingerprint; @@ -177,8 +179,20 @@ public class CertifyFingerprintFragment extends LoaderFragment implements Log.e(Constants.TAG, "key not found!", e); } Intent certifyIntent = new Intent(getActivity(), CertifyKeyActivity.class); + certifyIntent.putExtras(getActivity().getIntent()); certifyIntent.putExtra(CertifyKeyActivity.EXTRA_KEY_IDS, new long[]{keyId}); - startActivityForResult(certifyIntent, 0); + startActivityForResult(certifyIntent, REQUEST_CERTIFY); + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + // always just pass this one through + if (requestCode == REQUEST_CERTIFY) { + getActivity().setResult(resultCode, data); + getActivity().finish(); + return; + } + super.onActivityResult(requestCode, resultCode, data); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java index 50d5e3229..e1467ec61 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java @@ -31,6 +31,7 @@ import android.os.Bundle; import android.os.Message; import android.os.Messenger; import android.os.Parcel; +import android.os.Parcelable; import android.support.v4.app.LoaderManager; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; @@ -94,6 +95,7 @@ public class CertifyKeyFragment extends LoaderFragment private static final int INDEX_IS_REVOKED = 4; private MultiUserIdsAdapter mUserIdsAdapter; + private Messenger mPassthroughMessenger; @Override public void onActivityCreated(Bundle savedInstanceState) { @@ -109,6 +111,9 @@ public class CertifyKeyFragment extends LoaderFragment return; } + mPassthroughMessenger = getActivity().getIntent().getParcelableExtra( + KeychainIntentService.EXTRA_MESSENGER); + // preselect certify key id if given long certifyKeyId = getActivity().getIntent().getLongExtra(CertifyKeyActivity.EXTRA_CERTIFY_KEY_ID, Constants.key.none); if (certifyKeyId != Constants.key.none) { @@ -332,7 +337,6 @@ public class CertifyKeyFragment extends LoaderFragment } } - @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { @@ -362,51 +366,63 @@ public class CertifyKeyFragment extends LoaderFragment return; } + Bundle data = new Bundle(); + { + // fill values for this action + CertifyActionsParcel parcel = new CertifyActionsParcel(mSignMasterKeyId); + parcel.mCertifyActions.addAll(certifyActions); + + data.putParcelable(KeychainIntentService.CERTIFY_PARCEL, parcel); + if (mUploadKeyCheckbox.isChecked()) { + String keyserver = Preferences.getPreferences(getActivity()).getPreferredKeyserver(); + data.putString(KeychainIntentService.UPLOAD_KEY_SERVER, keyserver); + } + } + // Send all information needed to service to sign key in other thread Intent intent = new Intent(getActivity(), KeychainIntentService.class); - intent.setAction(KeychainIntentService.ACTION_CERTIFY_KEYRING); - - // fill values for this action - CertifyActionsParcel parcel = new CertifyActionsParcel(mSignMasterKeyId); - parcel.mCertifyActions.addAll(certifyActions); - - Bundle data = new Bundle(); - data.putParcelable(KeychainIntentService.CERTIFY_PARCEL, parcel); - if (mUploadKeyCheckbox.isChecked()) { - String keyserver = Preferences.getPreferences(getActivity()).getPreferredKeyserver(); - data.putString(KeychainIntentService.UPLOAD_KEY_SERVER, keyserver); - } intent.putExtra(KeychainIntentService.EXTRA_DATA, data); - // Message is received after signing is done in KeychainIntentService - KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(getActivity(), - getString(R.string.progress_certifying), ProgressDialog.STYLE_SPINNER, true) { - public void handleMessage(Message message) { - // handle messages by standard KeychainIntentServiceHandler first - super.handleMessage(message); - - if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) { - Bundle data = message.getData(); - CertifyResult result = data.getParcelable(CertifyResult.EXTRA_RESULT); - - Intent intent = new Intent(); - intent.putExtra(CertifyResult.EXTRA_RESULT, result); - getActivity().setResult(Activity.RESULT_OK, intent); - getActivity().finish(); + if (mPassthroughMessenger != null) { + intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, mPassthroughMessenger); + } else { + + // Message is received after signing is done in KeychainIntentService + KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(getActivity(), + getString(R.string.progress_certifying), ProgressDialog.STYLE_SPINNER, true) { + public void handleMessage(Message message) { + // handle messages by standard KeychainIntentServiceHandler first + super.handleMessage(message); + + if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) { + Bundle data = message.getData(); + CertifyResult result = data.getParcelable(CertifyResult.EXTRA_RESULT); + + Intent intent = new Intent(); + intent.putExtra(CertifyResult.EXTRA_RESULT, result); + getActivity().setResult(Activity.RESULT_OK, intent); + getActivity().finish(); + } } - } - }; + }; - // Create a new Messenger for the communication back - Messenger messenger = new Messenger(saveHandler); - intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger); + // Create a new Messenger for the communication back + Messenger messenger = new Messenger(saveHandler); + intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger); - // show progress dialog - saveHandler.showProgressDialog(getActivity()); + // show progress dialog + saveHandler.showProgressDialog(getActivity()); + } // start service with intent getActivity().startService(intent); + + if (mPassthroughMessenger != null) { + getActivity().setResult(Activity.RESULT_OK); + getActivity().finish(); + } + } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java index bbf35e497..f7d402c0b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java @@ -21,11 +21,11 @@ package org.sufficientlysecure.keychain.ui; import android.animation.ArgbEvaluator; import android.animation.ObjectAnimator; import android.annotation.TargetApi; +import android.app.Activity; import android.app.ActivityOptions; import android.content.Intent; import android.database.Cursor; import android.graphics.Bitmap; -import android.graphics.Color; import android.net.Uri; import android.nfc.NdefMessage; import android.nfc.NdefRecord; @@ -62,6 +62,7 @@ import com.getbase.floatingactionbutton.FloatingActionButton; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing; +import org.sufficientlysecure.keychain.operations.results.CertifyResult; import org.sufficientlysecure.keychain.operations.results.ImportKeyResult; import org.sufficientlysecure.keychain.operations.results.OperationResult; import org.sufficientlysecure.keychain.pgp.KeyRing; @@ -385,6 +386,25 @@ public class ViewKeyActivity extends BaseActivity implements private void certifyFingeprint(Uri dataUri) { Intent intent = new Intent(this, CertifyFingerprintActivity.class); intent.setData(dataUri); + + // Message is received after signing is done in KeychainIntentService + KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(this) { + public void handleMessage(Message message) { + // handle messages by standard KeychainIntentServiceHandler first + super.handleMessage(message); + + if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) { + Bundle data = message.getData(); + CertifyResult result = data.getParcelable(CertifyResult.EXTRA_RESULT); + + result.createNotify(ViewKeyActivity.this).show(); + } + } + }; + // Create a new Messenger for the communication back + Messenger messenger = new Messenger(saveHandler); + intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger); + startActivityForResult(intent, 0); } -- cgit v1.2.3 From 0557e0680e3cdedc32f8ebe35105b772c7b3935b Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Sat, 28 Feb 2015 15:58:26 +0100 Subject: some changes to qr scan logic --- .../keychain/ui/ImportKeysProxyActivity.java | 73 +++++++++++++++------- .../keychain/ui/KeyListFragment.java | 2 +- .../keychain/ui/ViewKeyActivity.java | 52 +++++++++++++-- .../keychain/ui/util/Notify.java | 23 ++++--- 4 files changed, 113 insertions(+), 37 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysProxyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysProxyActivity.java index 4cb6c69e0..94eaa8171 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysProxyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysProxyActivity.java @@ -57,6 +57,9 @@ public class ImportKeysProxyActivity extends FragmentActivity { public static final String ACTION_QR_CODE_API = OpenKeychainIntents.IMPORT_KEY_FROM_QR_CODE; public static final String ACTION_SCAN_WITH_RESULT = Constants.INTENT_PREFIX + "SCAN_QR_CODE_WITH_RESULT"; + public static final String ACTION_SCAN_IMPORT = Constants.INTENT_PREFIX + "SCAN_QR_CODE_IMPORT"; + + public static final String EXTRA_FINGERPRINT = "fingerprint"; boolean returnResult; @@ -78,10 +81,15 @@ public class ImportKeysProxyActivity extends FragmentActivity { // Scanning a fingerprint directly with Barcode Scanner, thus we already have scanned returnResult = false; - startCertify(dataUri); + processScannedContent(dataUri); + } else if (ACTION_SCAN_IMPORT.equals(action)) { + returnResult = false; + IntentIntegrator integrator = new IntentIntegrator(this); + integrator.setDesiredBarcodeFormats(IntentIntegrator.QR_CODE_TYPES) + .setPrompt(getString(R.string.import_qr_code_text)) + .setResultDisplayDuration(0) + .initiateScan(); } else if (ACTION_SCAN_WITH_RESULT.equals(action)) { - // scan using xzing's Barcode Scanner and return result parcel in OpenKeychain - returnResult = true; IntentIntegrator integrator = new IntentIntegrator(this); integrator.setDesiredBarcodeFormats(IntentIntegrator.QR_CODE_TYPES) @@ -113,16 +121,16 @@ public class ImportKeysProxyActivity extends FragmentActivity { if (requestCode == IntentIntegratorSupportV4.REQUEST_CODE) { IntentResult scanResult = IntentIntegratorSupportV4.parseActivityResult(requestCode, resultCode, data); - if (scanResult != null && scanResult.getFormatName() != null) { - String scannedContent = scanResult.getContents(); - Log.d(Constants.TAG, "scannedContent: " + scannedContent); - startCertify(Uri.parse(scanResult.getContents())); - } else { + if (scanResult == null || scanResult.getFormatName() == null) { Log.e(Constants.TAG, "scanResult or formatName null! Should not happen!"); finish(); + return; } + String scannedContent = scanResult.getContents(); + processScannedContent(scannedContent); + return; } // if a result has been returned, return it down to other activity @@ -134,6 +142,41 @@ public class ImportKeysProxyActivity extends FragmentActivity { } } + private void processScannedContent(String content) { + Uri uri = Uri.parse(content); + processScannedContent(uri); + } + + private void processScannedContent(Uri uri) { + + Log.d(Constants.TAG, "scanned: " + uri.toString()); + + String fingerprint = null; + + // example: openpgp4fpr:73EE2314F65FA92EC2390D3A718C070100012282 + if (uri.getScheme().toLowerCase(Locale.ENGLISH).equals(Constants.FINGERPRINT_SCHEME)) { + fingerprint = uri.getEncodedSchemeSpecificPart().toLowerCase(Locale.ENGLISH); + } + + if (fingerprint == null) { + SingletonResult result = new SingletonResult( + SingletonResult.RESULT_ERROR, OperationResult.LogType.MSG_WRONG_QR_CODE); + Intent intent = new Intent(); + intent.putExtra(SingletonResult.EXTRA_RESULT, result); + returnResult(intent); + return; + } + + if (returnResult) { + Intent result = new Intent(); + result.putExtra(EXTRA_FINGERPRINT, fingerprint); + setResult(RESULT_OK, result); + finish(); + } else { + importKeys(fingerprint); + } + } + public void returnResult(Intent data) { if (returnResult) { setResult(RESULT_OK, data); @@ -147,20 +190,6 @@ public class ImportKeysProxyActivity extends FragmentActivity { } } - public void startCertify(Uri dataUri) { - // example: openpgp4fpr:73EE2314F65FA92EC2390D3A718C070100012282 - if (dataUri.getScheme().equals(Constants.FINGERPRINT_SCHEME)) { - String fingerprint = dataUri.getEncodedSchemeSpecificPart().toLowerCase(Locale.ENGLISH); - importKeys(fingerprint); - } else { - SingletonResult result = new SingletonResult( - SingletonResult.RESULT_ERROR, OperationResult.LogType.MSG_WRONG_QR_CODE); - Intent intent = new Intent(); - intent.putExtra(SingletonResult.EXTRA_RESULT, result); - returnResult(intent); - } - } - public void importKeys(byte[] keyringData) { ParcelableKeyRing keyEntry = new ParcelableKeyRing(keyringData); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java index 496048582..b56da463a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/KeyListFragment.java @@ -527,7 +527,7 @@ public class KeyListFragment extends LoaderFragment private void scanQrCode() { Intent scanQrCode = new Intent(getActivity(), ImportKeysProxyActivity.class); - scanQrCode.setAction(ImportKeysProxyActivity.ACTION_SCAN_WITH_RESULT); + scanQrCode.setAction(ImportKeysProxyActivity.ACTION_SCAN_IMPORT); startActivityForResult(scanQrCode, 0); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java index f7d402c0b..3bc207419 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java @@ -88,6 +88,8 @@ import java.util.HashMap; public class ViewKeyActivity extends BaseActivity implements LoaderManager.LoaderCallbacks { + static final int REQUEST_QR_FINGERPRINT = 1; + ExportHelper mExportHelper; ProviderHelper mProviderHelper; @@ -122,6 +124,8 @@ public class ViewKeyActivity extends BaseActivity implements private boolean mIsRefreshing; private Animation mRotate, mRotateSpin; private View mRefresh; + private String mFingerprint; + private long mMasterKeyId; @Override protected void onCreate(Bundle savedInstanceState) { @@ -380,13 +384,24 @@ public class ViewKeyActivity extends BaseActivity implements private void scanQrCode() { Intent scanQrCode = new Intent(this, ImportKeysProxyActivity.class); scanQrCode.setAction(ImportKeysProxyActivity.ACTION_SCAN_WITH_RESULT); - startActivityForResult(scanQrCode, 0); + startActivityForResult(scanQrCode, REQUEST_QR_FINGERPRINT); } private void certifyFingeprint(Uri dataUri) { Intent intent = new Intent(this, CertifyFingerprintActivity.class); intent.setData(dataUri); + startCertifyIntent(intent); + } + + private void certifyImmediate() { + Intent intent = new Intent(this, CertifyKeyActivity.class); + intent.putExtra(CertifyKeyActivity.EXTRA_KEY_IDS, new long[]{ mMasterKeyId }); + + startCertifyIntent(intent); + } + + private void startCertifyIntent (Intent intent) { // Message is received after signing is done in KeychainIntentService KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(this) { public void handleMessage(Message message) { @@ -456,7 +471,31 @@ public class ViewKeyActivity extends BaseActivity implements @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { - // if a result has been returned, display a notify + if (requestCode == REQUEST_QR_FINGERPRINT && resultCode == Activity.RESULT_OK) { + + // If there is an EXTRA_RESULT, that's an error. Just show it. + if (data.hasExtra(OperationResult.EXTRA_RESULT)) { + OperationResult result = data.getParcelableExtra(OperationResult.EXTRA_RESULT); + result.createNotify(this).show(); + return; + } + + String fp = data.getStringExtra(ImportKeysProxyActivity.EXTRA_FINGERPRINT); + if (fp == null) { + Notify.createNotify(this, "Error scanning fingerprint!", + Notify.LENGTH_LONG, Notify.Style.ERROR).show(); + return; + } + if (mFingerprint.equalsIgnoreCase(fp)) { + certifyImmediate(); + } else { + Notify.createNotify(this, "Fingerprints did not match!", + Notify.LENGTH_LONG, Notify.Style.ERROR).show(); + } + + return; + } + if (data != null && data.hasExtra(OperationResult.EXTRA_RESULT)) { OperationResult result = data.getParcelableExtra(OperationResult.EXTRA_RESULT); result.createNotify(this).show(); @@ -764,7 +803,8 @@ public class ViewKeyActivity extends BaseActivity implements mName.setText(R.string.user_id_no_name); } - String fingerprint = KeyFormattingUtils.convertFingerprintToHex(data.getBlob(INDEX_FINGERPRINT)); + mMasterKeyId = data.getLong(INDEX_MASTER_KEY_ID); + mFingerprint = KeyFormattingUtils.convertFingerprintToHex(data.getBlob(INDEX_FINGERPRINT)); mIsSecret = data.getInt(INDEX_HAS_ANY_SECRET) != 0; mHasEncrypt = data.getInt(INDEX_HAS_ENCRYPT) != 0; @@ -826,8 +866,8 @@ public class ViewKeyActivity extends BaseActivity implements mStatusText.setText(R.string.view_key_my_key); mStatusImage.setVisibility(View.GONE); color = getResources().getColor(R.color.primary); - photoTask.execute(fingerprint); - loadQrCode(fingerprint); + photoTask.execute(mFingerprint); + loadQrCode(mFingerprint); mQrCodeLayout.setVisibility(View.VISIBLE); // and place leftOf qr code @@ -873,7 +913,7 @@ public class ViewKeyActivity extends BaseActivity implements KeyFormattingUtils.setStatusImage(this, mStatusImage, mStatusText, KeyFormattingUtils.STATE_VERIFIED, R.color.icons, true); color = getResources().getColor(R.color.primary); - photoTask.execute(fingerprint); + photoTask.execute(mFingerprint); mFab.setVisibility(View.GONE); } else { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/Notify.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/Notify.java index 8686b605f..3bc29edb6 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/Notify.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/util/Notify.java @@ -100,18 +100,25 @@ public class Notify { return createNotify(activity, activity.getString(resId), duration, style, listener, resIdAction); } + public static Showable createNotify(Activity activity, String msg, int duration, Style style) { + return createNotify(activity, msg, duration, style, null, 0); + } + public static Showable createNotify(Activity activity, String msg, int duration, Style style, final ActionListener listener, int resIdAction) { final Snackbar bar = getSnackbar(activity) - .text(msg) - .actionLabel(resIdAction) - .actionListener(new ActionClickListener() { - @Override - public void onActionClicked(Snackbar snackbar) { - listener.onAction(); - } - }); + .text(msg); + + if (listener != null) { + bar.actionLabel(resIdAction); + bar.actionListener(new ActionClickListener() { + @Override + public void onActionClicked(Snackbar snackbar) { + listener.onAction(); + } + }); + } if (duration == LENGTH_INDEFINITE) { bar.duration(SnackbarDuration.LENGTH_INDEFINITE); -- cgit v1.2.3 From 4e29d027af05fc574dc5398d2fb3afcdf3defc70 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Sat, 28 Feb 2015 17:49:09 +0100 Subject: fix a couple lint errors --- .../sufficientlysecure/keychain/ui/ImportKeysProxyActivity.java | 2 +- .../java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) (limited to 'OpenKeychain/src/main/java') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysProxyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysProxyActivity.java index 94eaa8171..948da94d8 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysProxyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysProxyActivity.java @@ -149,7 +149,7 @@ public class ImportKeysProxyActivity extends FragmentActivity { private void processScannedContent(Uri uri) { - Log.d(Constants.TAG, "scanned: " + uri.toString()); + Log.d(Constants.TAG, "scanned: " + uri); String fingerprint = null; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java index 3bc207419..742cde75c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ViewKeyActivity.java @@ -20,6 +20,7 @@ package org.sufficientlysecure.keychain.ui; import android.animation.ArgbEvaluator; import android.animation.ObjectAnimator; +import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.app.Activity; import android.app.ActivityOptions; @@ -127,6 +128,7 @@ public class ViewKeyActivity extends BaseActivity implements private String mFingerprint; private long mMasterKeyId; + @SuppressLint("InflateParams") @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -210,7 +212,7 @@ public class ViewKeyActivity extends BaseActivity implements } } - Log.i(Constants.TAG, "mDataUri: " + mDataUri.toString()); + Log.i(Constants.TAG, "mDataUri: " + mDataUri); mActionEncryptFile.setOnClickListener(new View.OnClickListener() { @Override @@ -624,8 +626,6 @@ public class ViewKeyActivity extends BaseActivity implements /** * Load QR Code asynchronously and with a fade in animation - * - * @param fingerprint */ private void loadQrCode(final String fingerprint) { AsyncTask loadTask = @@ -952,6 +952,7 @@ public class ViewKeyActivity extends BaseActivity implements mPreviousColor = color; } + //noinspection deprecation mStatusImage.setAlpha(80); break; -- cgit v1.2.3