aboutsummaryrefslogtreecommitdiffstats
path: root/OpenKeychain
diff options
context:
space:
mode:
authorVincent Breitmoser <valodim@mugenguild.com>2014-08-31 17:32:13 +0200
committerVincent Breitmoser <valodim@mugenguild.com>2014-08-31 17:32:13 +0200
commit7da783228499ea9d5b0a98201e8ba5b17e30bb10 (patch)
tree610e3d5ef33d717eaa56d091ebe7d92c5b237bbb /OpenKeychain
parent38c6cf045c6e451b3a150bf9b659056c2252d27c (diff)
downloadopen-keychain-7da783228499ea9d5b0a98201e8ba5b17e30bb10.tar.gz
open-keychain-7da783228499ea9d5b0a98201e8ba5b17e30bb10.tar.bz2
open-keychain-7da783228499ea9d5b0a98201e8ba5b17e30bb10.zip
Add cancelable mechanism and support in key import
Closes #323
Diffstat (limited to 'OpenKeychain')
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/ExportHelper.java9
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java23
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java21
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java8
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java10
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResults.java35
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java5
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ProgressDialogFragment.java96
-rw-r--r--OpenKeychain/src/main/res/values/strings.xml2
9 files changed, 119 insertions, 90 deletions
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/ExportHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/ExportHelper.java
index bcd57b290..f065dbc6d 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/ExportHelper.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/helper/ExportHelper.java
@@ -121,14 +121,7 @@ public class ExportHelper {
// Message is received after exporting is done in KeychainIntentService
KeychainIntentServiceHandler exportHandler = new KeychainIntentServiceHandler(mActivity,
mActivity.getString(R.string.progress_exporting),
- ProgressDialog.STYLE_HORIZONTAL,
- true,
- new DialogInterface.OnCancelListener() {
- @Override
- public void onCancel(DialogInterface dialogInterface) {
- mActivity.stopService(intent);
- }
- }) {
+ ProgressDialog.STYLE_HORIZONTAL) {
public void handleMessage(Message message) {
// handle messages by standard KeychainIntentServiceHandler first
super.handleMessage(message);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java
index 0bc3ac0ab..669a7d37e 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java
@@ -46,6 +46,7 @@ import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
public class PgpImportExport {
@@ -125,11 +126,20 @@ public class PgpImportExport {
}
/** Imports keys from given data. If keyIds is given only those are imported */
+ public ImportKeyResult importKeyRings(List<ParcelableKeyRing> entries,
+ AtomicBoolean cancelled) {
+ return importKeyRings(entries.iterator(), entries.size(), cancelled);
+ }
+
public ImportKeyResult importKeyRings(List<ParcelableKeyRing> entries) {
- return importKeyRings(entries.iterator(), entries.size());
+ return importKeyRings(entries.iterator(), entries.size(), null);
}
public ImportKeyResult importKeyRings(Iterator<ParcelableKeyRing> entries, int num) {
+ return importKeyRings(entries, num, null);
+ }
+ public ImportKeyResult importKeyRings(Iterator<ParcelableKeyRing> entries, int num,
+ AtomicBoolean cancelled) {
updateProgress(R.string.progress_importing, 0, 100);
// If there aren't even any keys, do nothing here.
@@ -143,6 +153,12 @@ public class PgpImportExport {
int position = 0;
double progSteps = 100.0 / num;
for (ParcelableKeyRing entry : new IterableIterator<ParcelableKeyRing>(entries)) {
+ // Has this action been cancelled? If so, don't proceed any further
+ if (cancelled != null && cancelled.get()) {
+ Log.d(Constants.TAG, "CANCELLED!");
+ break;
+ }
+
try {
UncachedKeyRing key = UncachedKeyRing.decodeFromData(entry.getBytes());
@@ -208,9 +224,12 @@ public class PgpImportExport {
}
}
if (log.containsWarnings()) {
- resultType |= ImportKeyResult.RESULT_WITH_WARNINGS;
+ resultType |= ImportKeyResult.RESULT_WARNINGS;
}
}
+ if (cancelled != null && cancelled.get()) {
+ resultType |= ImportKeyResult.RESULT_CANCELLED;
+ }
return new ImportKeyResult(resultType, log, newKeys, oldKeys, badKeys, secret);
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 021e6bc07..bc570385a 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
@@ -72,6 +72,7 @@ import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
/**
* This Service contains all important long lasting operations for APG. It receives Intents with
@@ -110,6 +111,8 @@ public class KeychainIntentService extends IntentService
public static final String ACTION_CONSOLIDATE = Constants.INTENT_PREFIX + "CONSOLIDATE";
+ public static final String ACTION_CANCEL = Constants.INTENT_PREFIX + "CANCEL";
+
/* keys for data bundle */
// encrypt, decrypt, import export
@@ -196,6 +199,8 @@ public class KeychainIntentService extends IntentService
Messenger mMessenger;
private boolean mIsCanceled;
+ // this attribute can possibly merged with the one above? not sure...
+ private AtomicBoolean mActionCanceled = new AtomicBoolean(false);
public KeychainIntentService() {
super("KeychainIntentService");
@@ -214,6 +219,10 @@ public class KeychainIntentService extends IntentService
*/
@Override
protected void onHandleIntent(Intent intent) {
+
+ // We have not been cancelled! (yet)
+ mActionCanceled.set(false);
+
Bundle extras = intent.getExtras();
if (extras == null) {
Log.e(Constants.TAG, "Extras bundle is null!");
@@ -500,7 +509,7 @@ public class KeychainIntentService extends IntentService
ProviderHelper providerHelper = new ProviderHelper(this);
PgpImportExport pgpImportExport = new PgpImportExport(this, providerHelper, this);
- ImportKeyResult result = pgpImportExport.importKeyRings(entries);
+ ImportKeyResult result = pgpImportExport.importKeyRings(entries, mActionCanceled);
if (result.mSecret > 0) {
providerHelper.consolidateDatabaseStep1(this);
@@ -612,7 +621,6 @@ public class KeychainIntentService extends IntentService
ArrayList<ParcelableKeyRing> keyRings = new ArrayList<ParcelableKeyRing>(entries.size());
for (ImportKeysListEntry entry : entries) {
-
Keyserver server;
if (entry.getOrigin() == null) {
server = new HkpKeyserver(keyServer);
@@ -874,6 +882,15 @@ public class KeychainIntentService extends IntentService
}
}
+ @Override
+ public int onStartCommand(Intent intent, int flags, int startId) {
+ if (ACTION_CANCEL.equals(intent.getAction())) {
+ mActionCanceled.set(true);
+ return START_STICKY;
+ }
+ return super.onStartCommand(intent, flags, startId);
+ }
+
private String getOriginalFilename(Bundle data) throws PgpGeneralException, FileNotFoundException {
int target = data.getInt(TARGET);
switch (target) {
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 0cdbe708e..1772dc6ae 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java
@@ -60,18 +60,16 @@ public class KeychainIntentServiceHandler extends Handler {
public KeychainIntentServiceHandler(Activity activity, String progressDialogMessage,
int progressDialogStyle) {
- this(activity, progressDialogMessage, progressDialogStyle, false, null);
+ this(activity, progressDialogMessage, progressDialogStyle, false);
}
public KeychainIntentServiceHandler(Activity activity, String progressDialogMessage,
- int progressDialogStyle, boolean cancelable,
- OnCancelListener onCancelListener) {
+ int progressDialogStyle, boolean cancelable) {
this.mActivity = activity;
this.mProgressDialogFragment = ProgressDialogFragment.newInstance(
progressDialogMessage,
progressDialogStyle,
- cancelable,
- onCancelListener);
+ cancelable);
}
public void showProgressDialog(FragmentActivity activity) {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java
index fe699224b..151c1761e 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResultParcel.java
@@ -55,13 +55,17 @@ public class OperationResultParcel implements Parcelable {
public static final String EXTRA_RESULT = "operation_result";
- /** Holds the overall result, the number specifying varying degrees of success. The first bit
- * is 0 on overall success, 1 on overall failure. All other bits may be used for more specific
- * conditions. */
+ /** Holds the overall result, the number specifying varying degrees of success:
+ * - The first bit is 0 on overall success, 1 on overall failure
+ * - The second bit indicates if the action was cancelled - may still be an error or success!
+ * - The third bit should be set if the operation succeeded with warnings
+ * All other bits may be used for more specific conditions. */
final int mResult;
public static final int RESULT_OK = 0;
public static final int RESULT_ERROR = 1;
+ public static final int RESULT_CANCELLED = 2;
+ public static final int RESULT_WARNINGS = 4;
/// A list of log entries tied to the operation result.
final OperationLog mLog;
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResults.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResults.java
index f3d0b9e9b..822c069cc 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResults.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/OperationResults.java
@@ -26,6 +26,7 @@ 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;
@@ -44,16 +45,14 @@ public abstract class OperationResults {
public final int mNewKeys, mUpdatedKeys, mBadKeys, mSecret;
// At least one new key
- public static final int RESULT_OK_NEWKEYS = 2;
+ public static final int RESULT_OK_NEWKEYS = 8;
// At least one updated key
- public static final int RESULT_OK_UPDATED = 4;
+ public static final int RESULT_OK_UPDATED = 16;
// At least one key failed (might still be an overall success)
- public static final int RESULT_WITH_ERRORS = 8;
- // There are warnings in the log
- public static final int RESULT_WITH_WARNINGS = 16;
+ public static final int RESULT_WITH_ERRORS = 32;
// No keys to import...
- public static final int RESULT_FAIL_NOTHING = 32 + 1;
+ public static final int RESULT_FAIL_NOTHING = 64 + 1;
public boolean isOkBoth() {
return (mResult & (RESULT_OK_NEWKEYS | RESULT_OK_UPDATED))
@@ -119,15 +118,20 @@ public abstract class OperationResults {
if ((resultType & OperationResultParcel.RESULT_ERROR) == 0) {
String withWarnings;
+ duration = Duration.EXTRA_LONG;
+ color = Style.GREEN;
+ withWarnings = "";
+
// Any warnings?
- if ((resultType & ImportKeyResult.RESULT_WITH_WARNINGS) > 0) {
+ if ((resultType & ImportKeyResult.RESULT_WARNINGS) > 0) {
duration = 0;
color = Style.ORANGE;
- withWarnings = activity.getResources().getString(R.string.import_with_warnings);
- } else {
- duration = SuperToast.Duration.LONG;
- color = Style.GREEN;
- withWarnings = "";
+ withWarnings += activity.getString(R.string.import_with_warnings);
+ }
+ if ((resultType & ImportKeyResult.RESULT_CANCELLED) > 0) {
+ duration = 0;
+ color = Style.ORANGE;
+ withWarnings += activity.getString(R.string.import_with_cancelled);
}
// New and updated keys
@@ -152,13 +156,14 @@ public abstract class OperationResults {
duration = 0;
color = Style.RED;
if (isFailNothing()) {
- str = activity.getString(R.string.import_error_nothing);
+ str = activity.getString((resultType & ImportKeyResult.RESULT_CANCELLED) > 0
+ ? R.string.import_error_nothing_cancelled
+ : R.string.import_error_nothing);
} else {
str = activity.getString(R.string.import_error);
}
}
- // TODO: externalize into Notify class?
boolean button = getLog() != null && !getLog().isEmpty();
SuperCardToast toast = new SuperCardToast(activity,
button ? SuperToast.Type.BUTTON : SuperToast.Type.STANDARD,
@@ -243,7 +248,7 @@ public abstract class OperationResults {
}
// Some old key was updated
- public static final int UPDATED = 2;
+ public static final int UPDATED = 4;
// Public key was saved
public static final int SAVED_PUBLIC = 8;
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 96fa11363..7ad7d1007 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/ImportKeysActivity.java
@@ -19,6 +19,8 @@ package org.sufficientlysecure.keychain.ui;
import android.annotation.TargetApi;
import android.app.ProgressDialog;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnCancelListener;
import android.content.Intent;
import android.net.Uri;
import android.nfc.NdefMessage;
@@ -447,7 +449,8 @@ public class ImportKeysActivity extends ActionBarActivity {
KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(
this,
getString(R.string.progress_importing),
- ProgressDialog.STYLE_HORIZONTAL) {
+ ProgressDialog.STYLE_HORIZONTAL,
+ true) {
public void handleMessage(Message message) {
// handle messages by standard KeychainIntentServiceHandler first
super.handleMessage(message);
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ProgressDialogFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ProgressDialogFragment.java
index 0324dd3b9..49a8ac49f 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ProgressDialogFragment.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/dialog/ProgressDialogFragment.java
@@ -21,32 +21,26 @@ import android.app.Activity;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
-import android.content.DialogInterface.OnCancelListener;
import android.content.DialogInterface.OnKeyListener;
+import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import android.view.ContextThemeWrapper;
import android.view.KeyEvent;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
import org.sufficientlysecure.keychain.R;
+import org.sufficientlysecure.keychain.service.KeychainIntentService;
public class ProgressDialogFragment extends DialogFragment {
private static final String ARG_MESSAGE = "message";
private static final String ARG_STYLE = "style";
private static final String ARG_CANCELABLE = "cancelable";
- private OnCancelListener mOnCancelListener;
-
- /**
- * Creates new instance of this fragment
- *
- * @param message
- * @param style
- * @param cancelable
- * @return
- */
- public static ProgressDialogFragment newInstance(String message, int style, boolean cancelable,
- OnCancelListener onCancelListener) {
+ /** Creates new instance of this fragment */
+ public static ProgressDialogFragment newInstance(String message, int style, boolean cancelable) {
ProgressDialogFragment frag = new ProgressDialogFragment();
Bundle args = new Bundle();
args.putString(ARG_MESSAGE, message);
@@ -54,28 +48,16 @@ public class ProgressDialogFragment extends DialogFragment {
args.putBoolean(ARG_CANCELABLE, cancelable);
frag.setArguments(args);
- frag.mOnCancelListener = onCancelListener;
return frag;
}
- /**
- * Updates progress of dialog
- *
- * @param messageId
- * @param progress
- * @param max
- */
+ /** Updates progress of dialog */
public void setProgress(int messageId, int progress, int max) {
setProgress(getString(messageId), progress, max);
}
- /**
- * Updates progress of dialog
- *
- * @param progress
- * @param max
- */
+ /** Updates progress of dialog */
public void setProgress(int progress, int max) {
ProgressDialog dialog = (ProgressDialog) getDialog();
@@ -83,13 +65,7 @@ public class ProgressDialogFragment extends DialogFragment {
dialog.setMax(max);
}
- /**
- * Updates progress of dialog
- *
- * @param message
- * @param progress
- * @param max
- */
+ /** Updates progress of dialog */
public void setProgress(String message, int progress, int max) {
ProgressDialog dialog = (ProgressDialog) getDialog();
@@ -98,15 +74,6 @@ public class ProgressDialogFragment extends DialogFragment {
dialog.setMax(max);
}
- @Override
- public void onCancel(DialogInterface dialog) {
- super.onCancel(dialog);
-
- if (this.mOnCancelListener != null) {
- this.mOnCancelListener.onCancel(dialog);
- }
- }
-
/**
* Creates dialog
*/
@@ -121,41 +88,62 @@ public class ProgressDialogFragment extends DialogFragment {
ProgressDialog dialog = new ProgressDialog(context);
dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
+ // We never use the builtin cancel method
dialog.setCancelable(false);
dialog.setCanceledOnTouchOutside(false);
String message = getArguments().getString(ARG_MESSAGE);
int style = getArguments().getInt(ARG_STYLE);
- boolean cancelable = getArguments().getBoolean(ARG_CANCELABLE);
+ final boolean cancelable = getArguments().getBoolean(ARG_CANCELABLE);
dialog.setMessage(message);
dialog.setProgressStyle(style);
+ // If this is supposed to be cancelable, add our (custom) cancel mechanic
if (cancelable) {
+ // Just show the button, take care of the onClickListener afterwards (in onStart)
dialog.setButton(DialogInterface.BUTTON_NEGATIVE,
- activity.getString(R.string.progress_cancel),
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- dialog.cancel();
- }
- });
+ activity.getString(R.string.progress_cancel), (DialogInterface.OnClickListener) null);
}
- // Disable the back button
+ // Disable the back button regardless
OnKeyListener keyListener = new OnKeyListener() {
-
@Override
public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
+ if (cancelable) {
+ ((ProgressDialog) dialog).getButton(
+ DialogInterface.BUTTON_NEGATIVE).performClick();
+ }
+ // return true, indicating we handled this
return true;
}
return false;
}
-
};
dialog.setOnKeyListener(keyListener);
return dialog;
}
+
+ @Override
+ public void onStart() {
+ super.onStart();
+
+ // Override the default behavior so the dialog is NOT dismissed on click
+ Button negative = ((ProgressDialog) getDialog()).getButton(DialogInterface.BUTTON_NEGATIVE);
+ negative.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ // send a cancel message. note that this message will be handled by
+ // KeychainIntentService.onStartCommand, which runs in this thread,
+ // not the service one, and will not queue up a command.
+ Intent intent = new Intent(getActivity(), KeychainIntentService.class);
+ intent.setAction(KeychainIntentService.ACTION_CANCEL);
+ getActivity().startService(intent);
+ }
+ });
+
+ }
+
}
diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml
index 8eb452df6..270feb099 100644
--- a/OpenKeychain/src/main/res/values/strings.xml
+++ b/OpenKeychain/src/main/res/values/strings.xml
@@ -381,8 +381,10 @@
</plurals>
<string name="view_log">View Log</string>
<string name="import_error_nothing">Nothing to import.</string>
+ <string name="import_error_nothing_cancelled">Import cancelled.</string>
<string name="import_error">Error importing keys!</string>
<string name="import_with_warnings">, with warnings</string>
+ <string name="import_with_cancelled">, until cancelled</string>
<!-- Intent labels -->
<string name="intent_decrypt_file">Decrypt File with OpenKeychain</string>