aboutsummaryrefslogtreecommitdiffstats
path: root/OpenKeychain/src/main/java
diff options
context:
space:
mode:
authorAdithya Abraham Philip <adithyaphilip@gmail.com>2015-06-23 15:04:10 +0530
committerAdithya Abraham Philip <adithyaphilip@gmail.com>2015-06-27 01:17:01 +0530
commitaa0bd4c9e06857b9e44b8feb284a4a1081f4abff (patch)
tree608922ade98d3afaa813f7a5fd320500004a9740 /OpenKeychain/src/main/java
parentdce2e0b19c3ebea299015afde0a7f2c8c15796b1 (diff)
downloadopen-keychain-aa0bd4c9e06857b9e44b8feb284a4a1081f4abff.tar.gz
open-keychain-aa0bd4c9e06857b9e44b8feb284a4a1081f4abff.tar.bz2
open-keychain-aa0bd4c9e06857b9e44b8feb284a4a1081f4abff.zip
introduced CryptoOperationHelper in ImportKeysActivity
Diffstat (limited to 'OpenKeychain/src/main/java')
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportExportOperation.java274
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java4
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ImportKeyringParcel.java74
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainNewService.java17
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainService.java291
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ServiceProgressHandler.java4
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java121
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationFragment.java197
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationHelper.java307
9 files changed, 778 insertions, 511 deletions
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 cdda42dae..c7f0ef423 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportExportOperation.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/ImportExportOperation.java
@@ -22,6 +22,7 @@ import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
+import android.os.Parcelable;
import org.spongycastle.bcpg.ArmoredOutputStream;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.R;
@@ -33,6 +34,7 @@ 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;
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult;
@@ -45,6 +47,9 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings;
import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.service.ContactSyncAdapterService;
+import org.sufficientlysecure.keychain.service.ImportKeyringParcel;
+import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
+import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.util.FileHelper;
import org.sufficientlysecure.keychain.util.Log;
@@ -59,9 +64,18 @@ import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
+import java.net.Proxy;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorCompletionService;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.SynchronousQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
/** An operation class which implements high level import and export
@@ -87,7 +101,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
* TODO rework uploadKeyRingToServer
*
*/
-public class ImportExportOperation extends BaseOperation {
+public class ImportExportOperation extends BaseOperation<ImportKeyringParcel> {
public ImportExportOperation(Context context, ProviderHelper providerHelper, Progressable progressable) {
super(context, providerHelper, progressable);
@@ -127,23 +141,41 @@ public class ImportExportOperation extends BaseOperation {
}
}
- public ImportKeyResult importKeyRings(List<ParcelableKeyRing> entries, String keyServerUri) {
+ // Overloaded functions for using progressable supplied in constructor during import
+ public ImportKeyResult serialKeyRingImport(Iterator<ParcelableKeyRing> entries, int num,
+ String keyServerUri) {
+ return serialKeyRingImport(entries, num, keyServerUri, mProgressable);
+ }
+
+ public ImportKeyResult serialKeyRingImport(List<ParcelableKeyRing> entries,
+ String keyServerUri) {
Iterator<ParcelableKeyRing> it = entries.iterator();
int numEntries = entries.size();
- return importKeyRings(it, numEntries, keyServerUri);
+ return serialKeyRingImport(it, numEntries, keyServerUri, mProgressable);
}
- public ImportKeyResult importKeyRings(ParcelableFileCache<ParcelableKeyRing> cache, String keyServerUri) {
+ public ImportKeyResult serialKeyRingImport(List<ParcelableKeyRing> entries, String keyServerUri,
+ Progressable progressable) {
+
+ Iterator<ParcelableKeyRing> it = entries.iterator();
+ int numEntries = entries.size();
+
+ return serialKeyRingImport(it, numEntries, keyServerUri, progressable);
+
+ }
+
+ public ImportKeyResult serialKeyRingImport(ParcelableFileCache<ParcelableKeyRing> cache,
+ String keyServerUri) {
// get entries from cached file
try {
IteratorWithSize<ParcelableKeyRing> it = cache.readCache();
int numEntries = it.getSize();
- return importKeyRings(it, numEntries, keyServerUri);
+ return serialKeyRingImport(it, numEntries, keyServerUri, mProgressable);
} catch (IOException e) {
// Special treatment here, we need a lot
@@ -157,15 +189,18 @@ public class ImportExportOperation extends BaseOperation {
}
/**
- * Since the introduction of multithreaded import, we expect calling functions to handle the key sync i,e
- * ContactSyncAdapterService.requestSync()
+ * Since the introduction of multithreaded import, we expect calling functions to handle the
+ * key sync i,eContactSyncAdapterService.requestSync()
*
- * @param entries keys to import
- * @param num number of keys to import
+ * @param entries keys to import
+ * @param num number of keys to import
* @param keyServerUri contains uri of keyserver to import from, if it is an import from cloud
+ * @param progressable Allows multi-threaded import to supply a progressable that ignores the
+ * progress of a single key being imported
* @return
*/
- public ImportKeyResult importKeyRings(Iterator<ParcelableKeyRing> entries, int num, String keyServerUri) {
+ public ImportKeyResult serialKeyRingImport(Iterator<ParcelableKeyRing> entries, int num,
+ String keyServerUri, Progressable progressable) {
updateProgress(R.string.progress_importing, 0, 100);
OperationLog log = new OperationLog();
@@ -224,7 +259,8 @@ public class ImportExportOperation extends BaseOperation {
byte[] data;
// Download by fingerprint, or keyId - whichever is available
if (entry.mExpectedFingerprint != null) {
- log.add(LogType.MSG_IMPORT_FETCH_KEYSERVER, 2, "0x" + entry.mExpectedFingerprint.substring(24));
+ log.add(LogType.MSG_IMPORT_FETCH_KEYSERVER, 2, "0x" +
+ entry.mExpectedFingerprint.substring(24));
data = keyServer.get("0x" + entry.mExpectedFingerprint).getBytes();
} else {
log.add(LogType.MSG_IMPORT_FETCH_KEYSERVER, 2, entry.mKeyIdHex);
@@ -302,10 +338,12 @@ public class ImportExportOperation extends BaseOperation {
mProviderHelper.clearLog();
if (key.isSecret()) {
result = mProviderHelper.saveSecretKeyRing(key,
- new ProgressScaler(mProgressable, (int)(position*progSteps), (int)((position+1)*progSteps), 100));
+ new ProgressScaler(progressable, (int)(position*progSteps),
+ (int)((position+1)*progSteps), 100));
} else {
result = mProviderHelper.savePublicKeyRing(key,
- new ProgressScaler(mProgressable, (int)(position*progSteps), (int)((position+1)*progSteps), 100));
+ new ProgressScaler(progressable, (int)(position*progSteps),
+ (int)((position+1)*progSteps), 100));
}
if (!result.success()) {
badKeys += 1;
@@ -333,7 +371,7 @@ public class ImportExportOperation extends BaseOperation {
// Special: consolidate on secret key import (cannot be cancelled!)
if (secret > 0) {
setPreventCancel();
- ConsolidateResult result = mProviderHelper.consolidateDatabaseStep1(mProgressable);
+ ConsolidateResult result = mProviderHelper.consolidateDatabaseStep1(progressable);
log.add(result, 1);
}
@@ -590,4 +628,210 @@ public class ImportExportOperation extends BaseOperation {
}
-}
+ @Override
+ public ImportKeyResult execute(ImportKeyringParcel input, CryptoInputParcel cryptoInput) {
+
+ return importKeys(input.mKeyList, input.mKeyserver);
+ }
+
+ public ImportKeyResult importKeys(ArrayList<ParcelableKeyRing> keyList, String keyServer) {
+
+ ImportKeyResult result;
+
+ if (keyList == null) {// import from file, do serially
+ ParcelableFileCache<ParcelableKeyRing> cache = new ParcelableFileCache<>(mContext,
+ "key_import.pcl");
+
+ result = serialKeyRingImport(cache, keyServer);
+ } else {
+ // if there is more than one key with the same fingerprint, we do a serial import to prevent
+ // https://github.com/open-keychain/open-keychain/issues/1221
+ HashSet<String> keyFingerprintSet = new HashSet<>();
+ for (int i = 0; i < keyList.size(); i++) {
+ keyFingerprintSet.add(keyList.get(i).mExpectedFingerprint);
+ }
+ if (keyFingerprintSet.size() == keyList.size()) {
+ // all keys have unique fingerprints
+ result = multiThreadedKeyImport(keyList.iterator(), keyList.size(), keyServer);
+ } else {
+ result = serialKeyRingImport(keyList, keyServer);
+ }
+ }
+
+ ContactSyncAdapterService.requestSync();
+ return result;
+ }
+
+ private ImportKeyResult multiThreadedKeyImport(Iterator<ParcelableKeyRing> keyListIterator,
+ int totKeys, final String keyServer) {
+ Log.d(Constants.TAG, "Multi-threaded key import starting");
+ if (keyListIterator != null) {
+ KeyImportAccumulator accumulator = new KeyImportAccumulator(totKeys, mProgressable);
+
+ final Progressable ignoreProgressable = new Progressable() {
+ @Override
+ public void setProgress(String message, int current, int total) {
+
+ }
+
+ @Override
+ public void setProgress(int resourceId, int current, int total) {
+
+ }
+
+ @Override
+ public void setProgress(int current, int total) {
+
+ }
+
+ @Override
+ public void setPreventCancel() {
+
+ }
+ };
+
+
+ final int maxThreads = 200;
+ ExecutorService importExecutor = new ThreadPoolExecutor(0, maxThreads,
+ 30L, TimeUnit.SECONDS,
+ new SynchronousQueue<Runnable>());
+
+ ExecutorCompletionService<ImportKeyResult> importCompletionService =
+ new ExecutorCompletionService(importExecutor);
+
+ while (keyListIterator.hasNext()) { // submit all key rings to be imported
+
+ final ParcelableKeyRing pkRing = keyListIterator.next();
+
+ Callable<ImportKeyResult> importOperationCallable = new Callable<ImportKeyResult>() {
+
+ @Override
+ public ImportKeyResult call() {
+
+ ArrayList<ParcelableKeyRing> list = new ArrayList<>();
+ list.add(pkRing);
+
+ return serialKeyRingImport(list, keyServer, ignoreProgressable);
+ }
+ };
+
+ importCompletionService.submit(importOperationCallable);
+ }
+
+ while (!accumulator.isImportFinished()) { // accumulate the results of each import
+ try {
+ accumulator.accumulateKeyImport(importCompletionService.take().get());
+ } catch (InterruptedException | ExecutionException e) {
+ Log.e(Constants.TAG, "A key could not be imported during multi-threaded import", e);
+ // do nothing?
+ if (e instanceof ExecutionException) {
+ // Since serialKeyRingImport does not throw any exceptions, this is what would have happened if
+ // we were importing the key on this thread
+ throw new RuntimeException();
+ }
+ }
+ }
+ return accumulator.getConsolidatedResult();
+ }
+ return null; // TODO: Decide if we should just crash instead of returning null
+ }
+
+ /**
+ * Used to accumulate the results of individual key imports
+ */
+ private class KeyImportAccumulator {
+ private OperationResult.OperationLog mImportLog = new OperationResult.OperationLog();
+ Progressable mProgressable;
+ private int mTotalKeys;
+ private int mImportedKeys = 0;
+ ArrayList<Long> mImportedMasterKeyIds = new ArrayList<Long>();
+ private int mBadKeys = 0;
+ private int mNewKeys = 0;
+ private int mUpdatedKeys = 0;
+ private int mSecret = 0;
+ private int mResultType = 0;
+
+ /**
+ * Accumulates keyring imports and updates the progressable whenever a new key is imported.
+ * Also sets the progress to 0 on instantiation.
+ *
+ * @param totalKeys total number of keys to be imported
+ * @param externalProgressable the external progressable to be updated every time a key is imported
+ */
+ public KeyImportAccumulator(int totalKeys, Progressable externalProgressable) {
+ mTotalKeys = totalKeys;
+ mProgressable = externalProgressable;
+ mProgressable.setProgress(0, totalKeys);
+ }
+
+ public int getTotalKeys() {
+ return mTotalKeys;
+ }
+
+ public int getImportedKeys() {
+ return mImportedKeys;
+ }
+
+ public synchronized void accumulateKeyImport(ImportKeyResult result) {
+ mImportedKeys++;
+
+ mProgressable.setProgress(mImportedKeys, mTotalKeys);
+
+ mImportLog.addAll(result.getLog().toList());//accumulates log
+ mBadKeys += result.mBadKeys;
+ mNewKeys += result.mNewKeys;
+ mUpdatedKeys += result.mUpdatedKeys;
+ mSecret += result.mSecret;
+
+ long[] masterKeyIds = result.getImportedMasterKeyIds();
+ for (long masterKeyId : masterKeyIds) {
+ mImportedMasterKeyIds.add(masterKeyId);
+ }
+
+ // if any key import has been cancelled, set result type to cancelled
+ // resultType is added to in getConsolidatedKayImport to account for remaining factors
+ mResultType |= result.getResult() & ImportKeyResult.RESULT_CANCELLED;
+ }
+
+ /**
+ * returns accumulated result of all imports so far
+ */
+ public ImportKeyResult getConsolidatedResult() {
+
+ // adding required information to mResultType
+ // special case,no keys requested for import
+ if (mBadKeys == 0 && mNewKeys == 0 && mUpdatedKeys == 0) {
+ mResultType = ImportKeyResult.RESULT_FAIL_NOTHING;
+ } else {
+ if (mNewKeys > 0) {
+ mResultType |= ImportKeyResult.RESULT_OK_NEWKEYS;
+ }
+ if (mUpdatedKeys > 0) {
+ mResultType |= ImportKeyResult.RESULT_OK_UPDATED;
+ }
+ if (mBadKeys > 0) {
+ mResultType |= ImportKeyResult.RESULT_WITH_ERRORS;
+ if (mNewKeys == 0 && mUpdatedKeys == 0) {
+ mResultType |= ImportKeyResult.RESULT_ERROR;
+ }
+ }
+ if (mImportLog.containsWarnings()) {
+ mResultType |= ImportKeyResult.RESULT_WARNINGS;
+ }
+ }
+
+ long masterKeyIds[] = new long[mImportedMasterKeyIds.size()];
+ for (int i = 0; i < masterKeyIds.length; i++) {
+ masterKeyIds[i] = mImportedMasterKeyIds.get(i);
+ }
+
+ return new ImportKeyResult(mResultType, mImportLog, mNewKeys, mUpdatedKeys, mBadKeys,
+ mSecret, masterKeyIds);
+ }
+
+ public boolean isImportFinished() {
+ return mTotalKeys == mImportedKeys;
+ }
+ }
+
+} \ No newline at end of file
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 bf7014853..5fbc7f6c7 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/provider/ProviderHelper.java
@@ -1250,7 +1250,7 @@ public class ProviderHelper {
ImportKeyResult result = new ImportExportOperation(mContext, this,
new ProgressFixedScaler(progress, 10, 25, 100, R.string.progress_con_reimport))
- .importKeyRings(itSecrets, numSecrets, null);
+ .serialKeyRingImport(itSecrets, numSecrets, null);
log.add(result, indent);
} else {
log.add(LogType.MSG_CON_REIMPORT_SECRET_SKIP, indent);
@@ -1278,7 +1278,7 @@ public class ProviderHelper {
ImportKeyResult result = new ImportExportOperation(mContext, this,
new ProgressFixedScaler(progress, 25, 99, 100, R.string.progress_con_reimport))
- .importKeyRings(itPublics, numPublics, null);
+ .serialKeyRingImport(itPublics, numPublics, null);
log.add(result, indent);
} else {
log.add(LogType.MSG_CON_REIMPORT_PUBLIC_SKIP, indent);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ImportKeyringParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ImportKeyringParcel.java
new file mode 100644
index 000000000..a41dd71cb
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ImportKeyringParcel.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2015 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2015 Adithya Abraham Philip <adithyaphilip@gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package org.sufficientlysecure.keychain.service;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;
+
+import java.util.ArrayList;
+
+public class ImportKeyringParcel implements Parcelable {
+ // if null, keys are expected to be read from a cache file in ImportExportOperations
+ public ArrayList<ParcelableKeyRing> mKeyList;
+ public String mKeyserver; // must be set if keys are to be imported from a keyserver
+
+ public ImportKeyringParcel (ArrayList<ParcelableKeyRing> keyList, String keyserver) {
+ mKeyList = keyList;
+ mKeyserver = keyserver;
+ }
+
+ protected ImportKeyringParcel(Parcel in) {
+ if (in.readByte() == 0x01) {
+ mKeyList = new ArrayList<>();
+ in.readList(mKeyList, ParcelableKeyRing.class.getClassLoader());
+ } else {
+ mKeyList = null;
+ }
+ mKeyserver = in.readString();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ if (mKeyList == null) {
+ dest.writeByte((byte) (0x00));
+ } else {
+ dest.writeByte((byte) (0x01));
+ dest.writeList(mKeyList);
+ }
+ dest.writeString(mKeyserver);
+ }
+
+ public static final Parcelable.Creator<ImportKeyringParcel> CREATOR = new Parcelable.Creator<ImportKeyringParcel>() {
+ @Override
+ public ImportKeyringParcel createFromParcel(Parcel in) {
+ return new ImportKeyringParcel(in);
+ }
+
+ @Override
+ public ImportKeyringParcel[] newArray(int size) {
+ return new ImportKeyringParcel[size];
+ }
+ };
+} \ No newline at end of file
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainNewService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainNewService.java
index 9e33a1421..822c2b12e 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainNewService.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainNewService.java
@@ -31,10 +31,7 @@ import android.os.Parcelable;
import android.os.RemoteException;
import org.sufficientlysecure.keychain.Constants;
-import org.sufficientlysecure.keychain.operations.BaseOperation;
-import org.sufficientlysecure.keychain.operations.CertifyOperation;
-import org.sufficientlysecure.keychain.operations.EditKeyOperation;
-import org.sufficientlysecure.keychain.operations.SignEncryptOperation;
+import org.sufficientlysecure.keychain.operations.*;
import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify;
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyInputParcel;
@@ -96,13 +93,19 @@ public class KeychainNewService extends Service implements Progressable {
// just for brevity
KeychainNewService outerThis = KeychainNewService.this;
if (inputParcel instanceof SignEncryptParcel) {
- op = new SignEncryptOperation(outerThis, new ProviderHelper(outerThis), outerThis, mActionCanceled);
+ op = new SignEncryptOperation(outerThis, new ProviderHelper(outerThis),
+ outerThis, mActionCanceled);
} else if (inputParcel instanceof PgpDecryptVerifyInputParcel) {
op = new PgpDecryptVerify(outerThis, new ProviderHelper(outerThis), outerThis);
} else if (inputParcel instanceof SaveKeyringParcel) {
- op = new EditKeyOperation(outerThis, new ProviderHelper(outerThis), outerThis, mActionCanceled);
+ op = new EditKeyOperation(outerThis, new ProviderHelper(outerThis), outerThis,
+ mActionCanceled);
} else if (inputParcel instanceof CertifyAction) {
- op = new CertifyOperation(outerThis, new ProviderHelper(outerThis), outerThis, mActionCanceled);
+ op = new CertifyOperation(outerThis, new ProviderHelper(outerThis), outerThis,
+ mActionCanceled);
+ } else if (inputParcel instanceof ImportKeyringParcel){
+ op = new ImportExportOperation(outerThis, new ProviderHelper(outerThis),
+ outerThis, mActionCanceled);
} else {
return;
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainService.java
index ba877c2a2..bcd5d837f 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainService.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainService.java
@@ -37,13 +37,10 @@ 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.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;
@@ -52,30 +49,21 @@ import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog;
import org.sufficientlysecure.keychain.operations.results.PromoteKeyResult;
-import org.sufficientlysecure.keychain.operations.results.SignEncryptResult;
import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing;
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify;
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyInputParcel;
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.ProviderHelper;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
import org.sufficientlysecure.keychain.service.ServiceProgressHandler.MessageStatus;
import org.sufficientlysecure.keychain.util.Log;
-import org.sufficientlysecure.keychain.util.ParcelableFileCache;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.Iterator;
import java.util.List;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.SynchronousQueue;
-import java.util.concurrent.ThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import de.measite.minidns.Client;
@@ -156,11 +144,6 @@ public class KeychainService extends Service implements Progressable {
// this attribute can possibly merged with the one above? not sure...
private AtomicBoolean mActionCanceled = new AtomicBoolean(false);
-
- private KeyImportAccumulator mKeyImportAccumulator;
-
- private KeychainService mKeychainService;
-
@Override
public IBinder onBind(Intent intent) {
return null;
@@ -171,7 +154,6 @@ public class KeychainService extends Service implements Progressable {
*/
@Override
public int onStartCommand(final Intent intent, int flags, int startId) {
- mKeychainService = this;
if (ACTION_CANCEL.equals(intent.getAction())) {
mActionCanceled.set(true);
@@ -208,7 +190,7 @@ public class KeychainService extends Service implements Progressable {
Log.logDebugBundle(data, "EXTRA_DATA");
- ProviderHelper providerHelper = new ProviderHelper(mKeychainService);
+ ProviderHelper providerHelper = new ProviderHelper(KeychainService.this);
String action = intent.getAction();
@@ -219,9 +201,9 @@ public class KeychainService extends Service implements Progressable {
// Operation
ConsolidateResult result;
if (data.containsKey(CONSOLIDATE_RECOVERY) && data.getBoolean(CONSOLIDATE_RECOVERY)) {
- result = providerHelper.consolidateDatabaseStep2(mKeychainService);
+ result = providerHelper.consolidateDatabaseStep2(KeychainService.this);
} else {
- result = providerHelper.consolidateDatabaseStep1(mKeychainService);
+ result = providerHelper.consolidateDatabaseStep1(KeychainService.this);
}
// Result
@@ -284,8 +266,8 @@ public class KeychainService extends Service implements Progressable {
}
}
- PgpDecryptVerify op = new PgpDecryptVerify(mKeychainService, providerHelper,
- mKeychainService);
+ PgpDecryptVerify op = new PgpDecryptVerify(KeychainService.this, providerHelper,
+ KeychainService.this);
PgpDecryptVerifyInputParcel input = new PgpDecryptVerifyInputParcel(messageBytes)
.setSignedLiteralData(true)
@@ -330,7 +312,7 @@ public class KeychainService extends Service implements Progressable {
boolean isSecret = data.getBoolean(DELETE_IS_SECRET);
// Operation
- DeleteOperation op = new DeleteOperation(mKeychainService, providerHelper, mKeychainService);
+ DeleteOperation op = new DeleteOperation(KeychainService.this, providerHelper, KeychainService.this);
DeleteResult result = op.execute(masterKeyIds, isSecret);
// Result
@@ -345,8 +327,8 @@ public class KeychainService extends Service implements Progressable {
CryptoInputParcel cryptoInput = data.getParcelable(EXTRA_CRYPTO_INPUT);
// Operation
- EditKeyOperation op = new EditKeyOperation(mKeychainService, providerHelper,
- mKeychainService, mActionCanceled);
+ EditKeyOperation op = new EditKeyOperation(KeychainService.this, providerHelper,
+ KeychainService.this, mActionCanceled);
OperationResult result = op.execute(saveParcel, cryptoInput);
// Result
@@ -363,7 +345,7 @@ public class KeychainService extends Service implements Progressable {
// Operation
PromoteKeyOperation op = new PromoteKeyOperation(
- mKeychainService, providerHelper, mKeychainService,
+ KeychainService.this, providerHelper, KeychainService.this,
mActionCanceled);
PromoteKeyResult result = op.execute(keyRingId, cardAid, subKeyIds);
@@ -384,7 +366,7 @@ public class KeychainService extends Service implements Progressable {
// Operation
ImportExportOperation importExportOperation = new ImportExportOperation(
- mKeychainService, providerHelper, mKeychainService);
+ KeychainService.this, providerHelper, KeychainService.this);
ExportResult result;
if (outputFile != null) {
result = importExportOperation.exportToFile(masterKeyIds, exportSecret, outputFile);
@@ -403,23 +385,16 @@ public class KeychainService extends Service implements Progressable {
String keyServer = data.getString(IMPORT_KEY_SERVER);
ArrayList<ParcelableKeyRing> keyList = data.getParcelableArrayList(IMPORT_KEY_LIST);
- // either keyList or cache must be null, no guarantees otherwise
- if (keyList == null) {// import from file, do serially
- serialKeyImport(null, keyServer, providerHelper);
- } else {
- // if there is more than one key with the same fingerprint, we do a serial import to prevent
- // https://github.com/open-keychain/open-keychain/issues/1221
- HashSet<String> keyFingerprintSet = new HashSet<>();
- for (int i = 0; i < keyList.size(); i++) {
- keyFingerprintSet.add(keyList.get(i).mExpectedFingerprint);
- }
- if (keyFingerprintSet.size() == keyList.size()) {
- // all keys have unique fingerprints
- multiThreadedKeyImport(keyList.iterator(), keyList.size(), keyServer);
- } else {
- serialKeyImport(keyList, keyServer, providerHelper);
- }
- }
+ ImportExportOperation importExportOperation = new ImportExportOperation(
+ KeychainService.this,
+ providerHelper, KeychainService.this, mActionCanceled);
+
+ ImportKeyringParcel inputParcel = new ImportKeyringParcel(keyList, keyServer);
+ CryptoInputParcel cryptoInputParcel = new CryptoInputParcel();
+
+ ImportKeyResult result = importExportOperation.execute(inputParcel, cryptoInputParcel);
+
+ sendMessageToHandler(MessageStatus.OKAY, result);
break;
}
@@ -434,8 +409,8 @@ public class KeychainService extends Service implements Progressable {
HkpKeyserver server = new HkpKeyserver(keyServer);
CanonicalizedPublicKeyRing keyring = providerHelper.getCanonicalizedPublicKeyRing(dataUri);
- ImportExportOperation importExportOperation = new ImportExportOperation(mKeychainService,
- providerHelper, mKeychainService);
+ ImportExportOperation importExportOperation = new ImportExportOperation(
+ KeychainService.this, providerHelper, KeychainService.this);
try {
importExportOperation.uploadKeyRingToServer(server, keyring);
@@ -450,16 +425,13 @@ public class KeychainService extends Service implements Progressable {
break;
}
}
- if (!intent.getAction().equals(ACTION_IMPORT_KEYRING)) {
- // import keyring handles stopping service on its own
- stopSelf();
- }
+ stopSelf();
}
};
Thread actionThread = new Thread(actionRunnable);
actionThread.start();
-
+
return START_NOT_STICKY;
}
@@ -484,7 +456,7 @@ public class KeychainService extends Service implements Progressable {
// contextualize the exception, if necessary
String message;
if (e instanceof PgpGeneralMsgIdException) {
- e = ((PgpGeneralMsgIdException) e).getContextualized(mKeychainService);
+ e = ((PgpGeneralMsgIdException) e).getContextualized(KeychainService.this);
message = e.getMessage();
} else {
message = e.getMessage();
@@ -563,215 +535,4 @@ public class KeychainService extends Service implements Progressable {
public void setPreventCancel() {
sendMessageToHandler(MessageStatus.PREVENT_CANCEL);
}
-
- public void serialKeyImport(ArrayList<ParcelableKeyRing> keyList, final String keyServer,
- ProviderHelper providerHelper) {
- Log.d(Constants.TAG, "serial key import starting");
- ParcelableFileCache<ParcelableKeyRing> cache =
- new ParcelableFileCache<>(mKeychainService, "key_import.pcl");
-
- // Operation
- ImportExportOperation importExportOperation = new ImportExportOperation(
- mKeychainService, providerHelper, mKeychainService,
- mActionCanceled);
- // Either list or cache must be null, no guarantees otherwise.
- ImportKeyResult result = keyList != null
- ? importExportOperation.importKeyRings(keyList, keyServer)
- : importExportOperation.importKeyRings(cache, keyServer);
-
- ContactSyncAdapterService.requestSync();
- // Result
- sendMessageToHandler(MessageStatus.OKAY, result);
-
- stopSelf();
- }
-
- public void multiThreadedKeyImport(Iterator<ParcelableKeyRing> keyListIterator, int totKeys, final String
- keyServer) {
- Log.d(Constants.TAG, "Multi-threaded key import starting");
- if (keyListIterator != null) {
- mKeyImportAccumulator = new KeyImportAccumulator(totKeys, mKeychainService);
- setProgress(0, totKeys);
-
- final int maxThreads = 200;
- ExecutorService importExecutor = new ThreadPoolExecutor(0, maxThreads,
- 30L, TimeUnit.SECONDS,
- new SynchronousQueue<Runnable>());
-
- while (keyListIterator.hasNext()) {
-
- final ParcelableKeyRing pkRing = keyListIterator.next();
-
- Runnable importOperationRunnable = new Runnable() {
-
- @Override
- public void run() {
- ImportKeyResult result = null;
- try {
- ImportExportOperation importExportOperation = new ImportExportOperation(
- mKeychainService,
- new ProviderHelper(mKeychainService),
- mKeyImportAccumulator.getImportProgressable(),
- mActionCanceled);
-
- ArrayList<ParcelableKeyRing> list = new ArrayList<>();
- list.add(pkRing);
-
- result = importExportOperation.importKeyRings(list,
- keyServer);
- } finally {
- // in the off-chance that importKeyRings does something to crash the
- // thread before it can call singleKeyRingImportCompleted, our imported
- // key count will go wrong. This will cause the service to never die,
- // and the progress dialog to stay displayed. The finally block was
- // originally meant to ensure singleKeyRingImportCompleted was called,
- // and checks for null were to be introduced, but in such a scenario,
- // knowing an uncaught error exists in importKeyRings is more important.
-
- // if a null gets passed, something wrong is happening. We want a crash.
-
- mKeyImportAccumulator.singleKeyRingImportCompleted(result);
- }
- }
- };
-
- importExecutor.execute(importOperationRunnable);
- }
- }
- }
-
- /**
- * Used to accumulate the results of individual key imports
- */
- private class KeyImportAccumulator {
- private OperationResult.OperationLog mImportLog = new OperationResult.OperationLog();
- private int mTotalKeys;
- private int mImportedKeys = 0;
- private Progressable mInternalProgressable;
- ArrayList<Long> mImportedMasterKeyIds = new ArrayList<Long>();
- private int mBadKeys = 0;
- private int mNewKeys = 0;
- private int mUpdatedKeys = 0;
- private int mSecret = 0;
- private int mResultType = 0;
-
- /**
- * meant to be used with a service due to stopSelf() in singleKeyRingImportCompleted. Remove this if
- * generalising.
- *
- * @param totalKeys total number of keys to be imported
- * @param externalProgressable the external progressable to be updated every time a key is imported
- */
- public KeyImportAccumulator(int totalKeys, Progressable externalProgressable) {
- mTotalKeys = totalKeys;
- // ignore updates from ImportExportOperation for now
- mInternalProgressable = new Progressable() {
- @Override
- public void setProgress(String message, int current, int total) {
-
- }
-
- @Override
- public void setProgress(int resourceId, int current, int total) {
-
- }
-
- @Override
- public void setProgress(int current, int total) {
-
- }
-
- @Override
- public void setPreventCancel() {
-
- }
- };
- }
-
- private synchronized void singleKeyRingImportCompleted(ImportKeyResult result) {
- // increase imported key count and accumulate log and bad, new etc. key counts from result
- mKeyImportAccumulator.accumulateKeyImport(result);
-
- setProgress(mKeyImportAccumulator.getImportedKeys(), mKeyImportAccumulator.getTotalKeys());
-
- if (mKeyImportAccumulator.isImportFinished()) {
- ContactSyncAdapterService.requestSync();
-
- sendMessageToHandler(ServiceProgressHandler.MessageStatus.OKAY,
- mKeyImportAccumulator.getConsolidatedImportKeyResult());
-
- stopSelf();//we're done here
- }
- }
-
- public Progressable getImportProgressable() {
- return mInternalProgressable;
- }
-
- public int getTotalKeys() {
- return mTotalKeys;
- }
-
- public int getImportedKeys() {
- return mImportedKeys;
- }
-
- public synchronized void accumulateKeyImport(ImportKeyResult result) {
- mImportedKeys++;
- mImportLog.addAll(result.getLog().toList());//accumulates log
- mBadKeys += result.mBadKeys;
- mNewKeys += result.mNewKeys;
- mUpdatedKeys += result.mUpdatedKeys;
- mSecret += result.mSecret;
-
- long[] masterKeyIds = result.getImportedMasterKeyIds();
- for (long masterKeyId : masterKeyIds) {
- mImportedMasterKeyIds.add(masterKeyId);
- }
-
- // if any key import has been cancelled, set result type to cancelled
- // resultType is added to in getConsolidatedKayImport to account for remaining factors
- mResultType |= result.getResult() & ImportKeyResult.RESULT_CANCELLED;
- }
-
- /**
- * returns accumulated result of all imports so far
- */
- public ImportKeyResult getConsolidatedImportKeyResult() {
-
- // adding required information to mResultType
- // special case,no keys requested for import
- if (mBadKeys == 0 && mNewKeys == 0 && mUpdatedKeys == 0) {
- mResultType = ImportKeyResult.RESULT_FAIL_NOTHING;
- } else {
- if (mNewKeys > 0) {
- mResultType |= ImportKeyResult.RESULT_OK_NEWKEYS;
- }
- if (mUpdatedKeys > 0) {
- mResultType |= ImportKeyResult.RESULT_OK_UPDATED;
- }
- if (mBadKeys > 0) {
- mResultType |= ImportKeyResult.RESULT_WITH_ERRORS;
- if (mNewKeys == 0 && mUpdatedKeys == 0) {
- mResultType |= ImportKeyResult.RESULT_ERROR;
- }
- }
- if (mImportLog.containsWarnings()) {
- mResultType |= ImportKeyResult.RESULT_WARNINGS;
- }
- }
-
- long masterKeyIds[] = new long[mImportedMasterKeyIds.size()];
- for (int i = 0; i < masterKeyIds.length; i++) {
- masterKeyIds[i] = mImportedMasterKeyIds.get(i);
- }
-
- return new ImportKeyResult(mResultType, mImportLog, mNewKeys, mUpdatedKeys, mBadKeys,
- mSecret, masterKeyIds);
- }
-
- public boolean isImportFinished() {
- return mTotalKeys == mImportedKeys;
- }
- }
-}
+} \ No newline at end of file
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ServiceProgressHandler.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ServiceProgressHandler.java
index 989b0c4bd..d294e5057 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ServiceProgressHandler.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/ServiceProgressHandler.java
@@ -64,6 +64,8 @@ public class ServiceProgressHandler extends Handler {
public static final String KEYBASE_PRESENCE_URL = "keybase_presence_url";
public static final String KEYBASE_PRESENCE_LABEL = "keybase_presence_label";
+ public static final String TAG_PROGRESS_DIALOG = "progressDialog";
+
FragmentActivity mActivity;
public ServiceProgressHandler(FragmentActivity activity) {
@@ -88,7 +90,7 @@ public class ServiceProgressHandler extends Handler {
Handler handler = new Handler();
handler.post(new Runnable() {
public void run() {
- frag.show(manager, "progressDialog");
+ frag.show(manager, TAG_PROGRESS_DIALOG);
}
});
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 07ab88b02..b05cc6f50 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java
@@ -17,12 +17,10 @@
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.Fragment;
import android.view.View;
import android.view.View.OnClickListener;
@@ -35,9 +33,10 @@ import org.sufficientlysecure.keychain.keyimport.ImportKeysListEntry;
import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;
import org.sufficientlysecure.keychain.operations.results.ImportKeyResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult;
-import org.sufficientlysecure.keychain.service.KeychainService;
+import org.sufficientlysecure.keychain.service.ImportKeyringParcel;
import org.sufficientlysecure.keychain.ui.base.BaseNfcActivity;
import org.sufficientlysecure.keychain.service.ServiceProgressHandler;
+import org.sufficientlysecure.keychain.ui.base.CryptoOperationHelper;
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
import org.sufficientlysecure.keychain.ui.util.Notify;
import org.sufficientlysecure.keychain.util.Log;
@@ -47,7 +46,8 @@ import org.sufficientlysecure.keychain.util.ParcelableFileCache.IteratorWithSize
import java.io.IOException;
import java.util.ArrayList;
-public class ImportKeysActivity extends BaseNfcActivity {
+public class ImportKeysActivity extends BaseNfcActivity
+ implements CryptoOperationHelper.Callback<ImportKeyringParcel, ImportKeyResult> {
public static final String ACTION_IMPORT_KEY = OpenKeychainIntents.IMPORT_KEY;
public static final String ACTION_IMPORT_KEY_FROM_KEYSERVER = OpenKeychainIntents.IMPORT_KEY_FROM_KEYSERVER;
@@ -82,6 +82,12 @@ public class ImportKeysActivity extends BaseNfcActivity {
private Fragment mTopFragment;
private View mImportButton;
+ // for CryptoOperationHelper.Callback
+ private String mKeyserver;
+ private ArrayList<ParcelableKeyRing> mKeyList;
+
+ private CryptoOperationHelper<ImportKeyringParcel, ImportKeyResult> mOperationHelper;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -388,23 +394,9 @@ public class ImportKeysActivity extends BaseNfcActivity {
return;
}
- ServiceProgressHandler serviceHandler = new ServiceProgressHandler(this) {
- @Override
- public void handleMessage(Message message) {
- // handle messages by standard KeychainIntentServiceHandler first
- super.handleMessage(message);
-
- ImportKeysActivity.this.handleMessage(message);
- }
- };
-
- // Send all information needed to service to import key in other thread
- Intent intent = new Intent(this, KeychainService.class);
-
- intent.setAction(KeychainService.ACTION_IMPORT_KEYRING);
-
- // fill values for this action
- Bundle data = new Bundle();
+ mOperationHelper = new CryptoOperationHelper<ImportKeyringParcel, ImportKeyResult>(
+ this, this, R.string.progress_importing
+ );
ImportKeysListFragment.LoaderState ls = mListFragment.getLoaderState();
if (ls instanceof ImportKeysListFragment.BytesLoaderState) {
@@ -423,30 +415,18 @@ public class ImportKeysActivity extends BaseNfcActivity {
new ParcelableFileCache<>(this, "key_import.pcl");
cache.writeCache(selectedEntries);
- intent.putExtra(KeychainService.EXTRA_DATA, data);
-
- // Create a new Messenger for the communication back
- Messenger messenger = new Messenger(serviceHandler);
- intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger);
+ mKeyList = null;
+ mKeyserver = null;
+ mOperationHelper.cryptoOperation();
- // show progress dialog
- serviceHandler.showProgressDialog(
- getString(R.string.progress_importing),
- ProgressDialog.STYLE_HORIZONTAL,
- true
- );
-
- // start service with intent
- startService(intent);
} catch (IOException e) {
Log.e(Constants.TAG, "Problem writing cache file", e);
Notify.create(this, "Problem writing cache file!", Notify.Style.ERROR)
.show((ViewGroup) findViewById(R.id.import_snackbar));
}
} else if (ls instanceof ImportKeysListFragment.CloudLoaderState) {
- ImportKeysListFragment.CloudLoaderState sls = (ImportKeysListFragment.CloudLoaderState) ls;
-
- data.putString(KeychainService.IMPORT_KEY_SERVER, sls.mCloudPrefs.keyserver);
+ ImportKeysListFragment.CloudLoaderState sls =
+ (ImportKeysListFragment.CloudLoaderState) ls;
// get selected key entries
ArrayList<ParcelableKeyRing> keys = new ArrayList<>();
@@ -459,22 +439,11 @@ public class ImportKeysActivity extends BaseNfcActivity {
);
}
}
- data.putParcelableArrayList(KeychainService.IMPORT_KEY_LIST, keys);
-
- intent.putExtra(KeychainService.EXTRA_DATA, data);
- // Create a new Messenger for the communication back
- Messenger messenger = new Messenger(serviceHandler);
- intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger);
+ mKeyList = keys;
+ mKeyserver = sls.mCloudPrefs.keyserver;
+ mOperationHelper.cryptoOperation();
- // show progress dialog
- serviceHandler.showProgressDialog(
- getString(R.string.progress_importing),
- ProgressDialog.STYLE_HORIZONTAL, true
- );
-
- // start service with intent
- startService(intent);
}
}
@@ -485,4 +454,52 @@ public class ImportKeysActivity extends BaseNfcActivity {
// either way, finish afterwards
finish();
}
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (mOperationHelper == null ||
+ !mOperationHelper.handleActivityResult(requestCode, resultCode, data)) {
+ super.onActivityResult(requestCode, resultCode, data);
+ }
+ }
+
+ public void handleResult (ImportKeyResult result) {
+ if (ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_RESULT.equals(getIntent().getAction())
+ || ACTION_IMPORT_KEY_FROM_FILE_AND_RETURN.equals(getIntent().getAction())) {
+ Intent intent = new Intent();
+ intent.putExtra(ImportKeyResult.EXTRA_RESULT, result);
+ ImportKeysActivity.this.setResult(RESULT_OK, intent);
+ ImportKeysActivity.this.finish();
+ return;
+ }
+ if (ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN_TO_SERVICE.equals(getIntent().getAction())) {
+ ImportKeysActivity.this.setResult(RESULT_OK, mPendingIntentData);
+ ImportKeysActivity.this.finish();
+ return;
+ }
+
+ result.createNotify(ImportKeysActivity.this)
+ .show((ViewGroup) findViewById(R.id.import_snackbar));
+ }
+ // methods from CryptoOperationHelper.Callback
+
+ @Override
+ public ImportKeyringParcel createOperationInput() {
+ return new ImportKeyringParcel(mKeyList, mKeyserver);
+ }
+
+ @Override
+ public void onCryptoOperationSuccess(ImportKeyResult result) {
+ handleResult(result);
+ }
+
+ @Override
+ public void onCryptoOperationCancelled() {
+ // do nothing
+ }
+
+ @Override
+ public void onCryptoOperationError(ImportKeyResult result) {
+ handleResult(result);
+ }
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationFragment.java
index 764602735..c00ebd915 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationFragment.java
@@ -18,185 +18,66 @@
package org.sufficientlysecure.keychain.ui.base;
-import android.app.Activity;
-import android.app.ProgressDialog;
import android.content.Intent;
-import android.os.Bundle;
-import android.os.Message;
-import android.os.Messenger;
import android.os.Parcelable;
import android.support.v4.app.Fragment;
-import org.sufficientlysecure.keychain.R;
-import org.sufficientlysecure.keychain.operations.results.InputPendingResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult;
-import org.sufficientlysecure.keychain.service.KeychainNewService;
-import org.sufficientlysecure.keychain.service.KeychainService;
-import org.sufficientlysecure.keychain.service.ServiceProgressHandler;
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
-import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
-import org.sufficientlysecure.keychain.ui.NfcOperationActivity;
-import org.sufficientlysecure.keychain.ui.PassphraseDialogActivity;
-import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment;
/**
* All fragments executing crypto operations need to extend this class.
*/
-public abstract class CryptoOperationFragment <T extends Parcelable, S extends OperationResult>
+public abstract class CryptoOperationFragment<T extends Parcelable, S extends OperationResult>
extends Fragment {
- public static final int REQUEST_CODE_PASSPHRASE = 0x00008001;
- public static final int REQUEST_CODE_NFC = 0x00008002;
+ private CryptoOperationHelper<T, S> mOperationHelper;
- private void initiateInputActivity(RequiredInputParcel requiredInput) {
+ public CryptoOperationFragment() {
+ // this is implemented here instead of by the fragment so that the corresponding methods in
+ // CryptoOperationFragment may continue using the "protected" modifier.
+ CryptoOperationHelper.Callback callback = new CryptoOperationHelper.Callback<T, S>() {
- switch (requiredInput.mType) {
- case NFC_KEYTOCARD:
- case NFC_DECRYPT:
- case NFC_SIGN: {
- Intent intent = new Intent(getActivity(), NfcOperationActivity.class);
- intent.putExtra(NfcOperationActivity.EXTRA_REQUIRED_INPUT, requiredInput);
- startActivityForResult(intent, REQUEST_CODE_NFC);
- return;
+ @Override
+ public T createOperationInput() {
+ return CryptoOperationFragment.this.createOperationInput();
}
- case PASSPHRASE:
- case PASSPHRASE_SYMMETRIC: {
- Intent intent = new Intent(getActivity(), PassphraseDialogActivity.class);
- intent.putExtra(PassphraseDialogActivity.EXTRA_REQUIRED_INPUT, requiredInput);
- startActivityForResult(intent, REQUEST_CODE_PASSPHRASE);
- return;
+ @Override
+ public void onCryptoOperationSuccess(S result) {
+ CryptoOperationFragment.this.onCryptoOperationSuccess(result);
}
- }
-
- throw new RuntimeException("Unhandled pending result!");
- }
- @Override
- public void onActivityResult(int requestCode, int resultCode, Intent data) {
- if (resultCode == Activity.RESULT_CANCELED) {
- onCryptoOperationCancelled();
- return;
- }
-
- switch (requestCode) {
- case REQUEST_CODE_PASSPHRASE: {
- if (resultCode == Activity.RESULT_OK && data != null) {
- CryptoInputParcel cryptoInput =
- data.getParcelableExtra(PassphraseDialogActivity.RESULT_CRYPTO_INPUT);
- cryptoOperation(cryptoInput);
- return;
- }
- break;
+ @Override
+ public void onCryptoOperationCancelled() {
+ CryptoOperationFragment.this.onCryptoOperationCancelled();
}
- case REQUEST_CODE_NFC: {
- if (resultCode == Activity.RESULT_OK && data != null) {
- CryptoInputParcel cryptoInput =
- data.getParcelableExtra(NfcOperationActivity.RESULT_DATA);
- cryptoOperation(cryptoInput);
- return;
- }
- break;
+ @Override
+ public void onCryptoOperationError(S result) {
+ CryptoOperationFragment.this.onCryptoOperationError(result);
}
+ };
- default: {
- super.onActivityResult(requestCode, resultCode, data);
- }
- }
+ mOperationHelper = new CryptoOperationHelper<>(this, callback);
}
- protected void dismissProgress() {
-
- ProgressDialogFragment progressDialogFragment =
- (ProgressDialogFragment) getFragmentManager().findFragmentByTag("progressDialog");
-
- if (progressDialogFragment == null) {
- return;
- }
-
- progressDialogFragment.dismissAllowingStateLoss();
-
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ mOperationHelper.handleActivityResult(requestCode, resultCode, data);
}
protected abstract T createOperationInput();
- protected void cryptoOperation(CryptoInputParcel cryptoInput) {
- cryptoOperation(cryptoInput, true);
- }
-
protected void cryptoOperation() {
cryptoOperation(new CryptoInputParcel());
}
- protected void cryptoOperation(CryptoInputParcel cryptoInput, boolean showProgress) {
-
- T operationInput = createOperationInput();
- if (operationInput == null) {
- return;
- }
-
- // Send all information needed to service to edit key in other thread
- Intent intent = new Intent(getActivity(), KeychainNewService.class);
-
- intent.putExtra(KeychainNewService.EXTRA_OPERATION_INPUT, operationInput);
- intent.putExtra(KeychainNewService.EXTRA_CRYPTO_INPUT, cryptoInput);
-
- ServiceProgressHandler saveHandler = new ServiceProgressHandler(getActivity()) {
- @Override
- public void handleMessage(Message message) {
- // handle messages by standard KeychainIntentServiceHandler first
- super.handleMessage(message);
-
- if (message.arg1 == MessageStatus.OKAY.ordinal()) {
-
- // get returned data bundle
- Bundle returnData = message.getData();
- if (returnData == null) {
- return;
- }
-
- final OperationResult result =
- returnData.getParcelable(OperationResult.EXTRA_RESULT);
-
- onHandleResult(result);
- }
- }
-
- @Override
- protected void onSetProgress(String msg, int progress, int max) {
- // allow handling of progress in fragment, or delegate upwards
- if ( ! onCryptoSetProgress(msg, progress, max)) {
- super.onSetProgress(msg, progress, max);
- }
- }
- };
-
- // Create a new Messenger for the communication back
- Messenger messenger = new Messenger(saveHandler);
- intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger);
-
- if (showProgress) {
- saveHandler.showProgressDialog(
- getString(R.string.progress_building_key),
- ProgressDialog.STYLE_HORIZONTAL, false);
- }
-
- getActivity().startService(intent);
-
- }
-
- protected void onCryptoOperationResult(S result) {
- if (result.success()) {
- onCryptoOperationSuccess(result);
- } else {
- onCryptoOperationError(result);
- }
+ protected void cryptoOperation(CryptoInputParcel cryptoInput) {
+ mOperationHelper.cryptoOperation(cryptoInput);
}
- abstract protected void onCryptoOperationSuccess(S result);
-
protected void onCryptoOperationError(S result) {
result.createNotify(getActivity()).show();
}
@@ -204,31 +85,9 @@ public abstract class CryptoOperationFragment <T extends Parcelable, S extends O
protected void onCryptoOperationCancelled() {
}
- public void onHandleResult(OperationResult result) {
-
- if (result instanceof InputPendingResult) {
- InputPendingResult pendingResult = (InputPendingResult) result;
- if (pendingResult.isPending()) {
- RequiredInputParcel requiredInput = pendingResult.getRequiredInputParcel();
- initiateInputActivity(requiredInput);
- return;
- }
- }
-
- dismissProgress();
-
- try {
- // noinspection unchecked, because type erasure :(
- onCryptoOperationResult((S) result);
- } catch (ClassCastException e) {
- throw new AssertionError("bad return class ("
- + result.getClass().getSimpleName() + "), this is a programming error!");
- }
-
- }
+ abstract protected void onCryptoOperationSuccess(S result);
- protected boolean onCryptoSetProgress(String msg, int progress, int max) {
- return false;
+ protected void onCryptoOperationResult(S result) {
+ mOperationHelper.onCryptoOperationResult(result);
}
-
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationHelper.java
new file mode 100644
index 000000000..ffbda330e
--- /dev/null
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/base/CryptoOperationHelper.java
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) 2015 Dominik Schürmann <dominik@dominikschuermann.de>
+ * Copyright (C) 2015 Vincent Breitmoser <v.breitmoser@mugenguild.com>
+ * Copyright (C) 2015 Adithya Abraham Philip <adithyaphilip@gmail.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package org.sufficientlysecure.keychain.ui.base;
+
+import android.app.Activity;
+import android.app.ProgressDialog;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.Parcelable;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentActivity;
+
+import android.support.v4.app.FragmentManager;
+import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.operations.results.InputPendingResult;
+import org.sufficientlysecure.keychain.operations.results.OperationResult;
+import org.sufficientlysecure.keychain.service.KeychainNewService;
+import org.sufficientlysecure.keychain.service.KeychainService;
+import org.sufficientlysecure.keychain.service.ServiceProgressHandler;
+import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
+import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
+import org.sufficientlysecure.keychain.ui.NfcOperationActivity;
+import org.sufficientlysecure.keychain.ui.PassphraseDialogActivity;
+import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment;
+import org.sufficientlysecure.keychain.util.Log;
+
+/**
+ * Designed to be integrated into activities or fragments used for CryptoOperations.
+ * Encapsulates the execution of a crypto operation and handling of input pending cases.s
+ *
+ * @param <T> The type of input parcel sent to the operation
+ * @param <S> The type of result returned by the operation
+ */
+public class CryptoOperationHelper<T extends Parcelable, S extends OperationResult> {
+
+ public interface Callback <T extends Parcelable, S extends OperationResult> {
+ T createOperationInput();
+ void onCryptoOperationSuccess(S result);
+ void onCryptoOperationCancelled();
+ void onCryptoOperationError(S result);
+ }
+
+ public static final int REQUEST_CODE_PASSPHRASE = 0x00008001;
+ public static final int REQUEST_CODE_NFC = 0x00008002;
+
+ // keeps track of request code used to start an activity from this CryptoOperationHelper.
+ // this is necessary when multiple CryptoOperationHelpers are used in the same fragment/activity
+ // otherwise all CryptoOperationHandlers may respond to the same onActivityResult
+ private int mRequestedCode = -1;
+
+ private int mProgressMessageString;
+
+ private FragmentActivity mActivity;
+ private Fragment mFragment;
+ private Callback<T, S> mCallback;
+
+ private boolean mUseFragment; // short hand for mActivity == null
+
+ /**
+ * If OperationHelper is being integrated into an activity
+ *
+ * @param activity
+ */
+ public CryptoOperationHelper(FragmentActivity activity, Callback<T, S> callback, int progressMessageString) {
+ mActivity = activity;
+ mUseFragment = false;
+ mCallback = callback;
+ mProgressMessageString = progressMessageString;
+ }
+
+ /**
+ * if OperationHelper is being integrated into a fragment
+ *
+ * @param fragment
+ */
+ public CryptoOperationHelper(Fragment fragment, Callback<T, S> callback, int progressMessageString) {
+ mFragment = fragment;
+ mUseFragment = true;
+ mProgressMessageString = progressMessageString;
+ mCallback = callback;
+ }
+
+ /**
+ * if OperationHelper is being integrated into a fragment with default message for the progress dialog
+ *
+ * @param fragment
+ */
+ public CryptoOperationHelper(Fragment fragment, Callback<T, S> callback) {
+ mFragment = fragment;
+ mUseFragment = true;
+ mProgressMessageString = R.string.progress_building_key;
+ mCallback = callback;
+ }
+
+ private void initiateInputActivity(RequiredInputParcel requiredInput) {
+
+ Activity activity = mUseFragment ? mFragment.getActivity() : mActivity;
+
+ Log.d("PHILIP", "Initating input " + requiredInput.mType);
+ switch (requiredInput.mType) {
+ case NFC_KEYTOCARD:
+ case NFC_DECRYPT:
+ case NFC_SIGN: {
+ Intent intent = new Intent(activity, NfcOperationActivity.class);
+ intent.putExtra(NfcOperationActivity.EXTRA_REQUIRED_INPUT, requiredInput);
+ mRequestedCode = REQUEST_CODE_NFC;
+ if (mUseFragment) {
+ mFragment.startActivityForResult(intent, mRequestedCode);
+ } else {
+ mActivity.startActivityForResult(intent, mRequestedCode);
+ }
+ return;
+ }
+
+ case PASSPHRASE:
+ case PASSPHRASE_SYMMETRIC: {
+ Intent intent = new Intent(activity, PassphraseDialogActivity.class);
+ intent.putExtra(PassphraseDialogActivity.EXTRA_REQUIRED_INPUT, requiredInput);
+ mRequestedCode = REQUEST_CODE_PASSPHRASE;
+ if (mUseFragment) {
+ mFragment.startActivityForResult(intent, mRequestedCode);
+ } else {
+ mActivity.startActivityForResult(intent, mRequestedCode);
+ }
+ return;
+ }
+ }
+
+ throw new RuntimeException("Unhandled pending result!");
+ }
+
+ /**
+ * Attempts the result of an activity started by this helper. Returns true if requestCode is recognized,
+ * false otherwise.
+ *
+ * @param requestCode
+ * @param resultCode
+ * @param data
+ * @return true if requestCode was recognized, false otherwise
+ */
+ public boolean handleActivityResult(int requestCode, int resultCode, Intent data) {
+ Log.d("PHILIP", "received activity result in OperationHelper");
+
+ if (mRequestedCode != requestCode) {
+ // this wasn't meant for us to handle
+ return false;
+ } else {
+ mRequestedCode = -1;
+ }
+ if (resultCode == Activity.RESULT_CANCELED) {
+ mCallback.onCryptoOperationCancelled();
+ return true;
+ }
+
+ switch (requestCode) {
+ case REQUEST_CODE_PASSPHRASE: {
+ if (resultCode == Activity.RESULT_OK && data != null) {
+ CryptoInputParcel cryptoInput =
+ data.getParcelableExtra(PassphraseDialogActivity.RESULT_CRYPTO_INPUT);
+ cryptoOperation(cryptoInput);
+ return true;
+ }
+ break;
+ }
+
+ case REQUEST_CODE_NFC: {
+ if (resultCode == Activity.RESULT_OK && data != null) {
+ CryptoInputParcel cryptoInput =
+ data.getParcelableExtra(NfcOperationActivity.RESULT_DATA);
+ cryptoOperation(cryptoInput);
+ return true;
+ }
+ break;
+ }
+
+ default: {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ protected void dismissProgress() {
+ FragmentManager fragmentManager =
+ mUseFragment ? mFragment.getFragmentManager() :
+ mActivity.getSupportFragmentManager();
+
+ ProgressDialogFragment progressDialogFragment =
+ (ProgressDialogFragment) fragmentManager.findFragmentByTag(
+ ServiceProgressHandler.TAG_PROGRESS_DIALOG);
+
+ if (progressDialogFragment == null) {
+ return;
+ }
+
+ progressDialogFragment.dismissAllowingStateLoss();
+
+ }
+
+ public void cryptoOperation(CryptoInputParcel cryptoInput) {
+
+ FragmentActivity activity = mUseFragment ? mFragment.getActivity() : mActivity;
+
+ T operationInput = mCallback.createOperationInput();
+ if (operationInput == null) {
+ return;
+ }
+
+ // Send all information needed to service to edit key in other thread
+ Intent intent = new Intent(activity, KeychainNewService.class);
+
+ intent.putExtra(KeychainNewService.EXTRA_OPERATION_INPUT, operationInput);
+ intent.putExtra(KeychainNewService.EXTRA_CRYPTO_INPUT, cryptoInput);
+
+ ServiceProgressHandler saveHandler = new ServiceProgressHandler(activity) {
+ @Override
+ public void handleMessage(Message message) {
+ // handle messages by standard KeychainIntentServiceHandler first
+ super.handleMessage(message);
+
+ if (message.arg1 == MessageStatus.OKAY.ordinal()) {
+
+ // get returned data bundle
+ Bundle returnData = message.getData();
+ if (returnData == null) {
+ return;
+ }
+
+ final OperationResult result =
+ returnData.getParcelable(OperationResult.EXTRA_RESULT);
+
+ onHandleResult(result);
+ }
+ }
+ };
+
+ saveHandler.showProgressDialog(
+ activity.getString(mProgressMessageString),
+ ProgressDialog.STYLE_HORIZONTAL, false);
+
+ // Create a new Messenger for the communication back
+ Messenger messenger = new Messenger(saveHandler);
+ intent.putExtra(KeychainService.EXTRA_MESSENGER, messenger);
+
+ activity.startService(intent);
+
+ }
+
+ public void cryptoOperation() {
+ cryptoOperation(new CryptoInputParcel());
+ }
+
+ protected void onCryptoOperationResult(S result) {
+ Log.d("PHILIP", "cryptoResult " + result.success());
+ if (result.success()) {
+ mCallback.onCryptoOperationSuccess(result);
+ } else {
+ mCallback.onCryptoOperationError(result);
+ }
+ }
+
+ public void onHandleResult(OperationResult result) {
+ Log.d("PHILIP", "Handling result in OperationHelper");
+
+ if (result instanceof InputPendingResult) {
+ Log.d("PHILIP", "is pending result");
+ InputPendingResult pendingResult = (InputPendingResult) result;
+ if (pendingResult.isPending()) {
+
+ Log.d("PHILIP", "Is pending");
+ RequiredInputParcel requiredInput = pendingResult.getRequiredInputParcel();
+ initiateInputActivity(requiredInput);
+ return;
+ }
+ }
+
+ dismissProgress();
+
+ try {
+ // noinspection unchecked, because type erasure :(
+ onCryptoOperationResult((S) result);
+ } catch (ClassCastException e) {
+ throw new AssertionError("bad return class ("
+ + result.getClass().getSimpleName() + "), this is a programming error!");
+ }
+
+ }
+} \ No newline at end of file