From e9a2f256b9324cc898061d2a2ebde18446ce1dd1 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Sun, 31 Aug 2014 20:05:19 +0200 Subject: [PATCH] add cancel prevention mechanism, improve cancellation for key import --- .../keychain/pgp/PgpImportExport.java | 28 ++++++------ .../service/KeychainIntentService.java | 9 +++- .../service/KeychainIntentServiceHandler.java | 5 ++- .../keychain/ui/CreateKeyFinalFragment.java | 1 - .../ui/dialog/ProgressDialogFragment.java | 45 +++++++++++++++++-- 5 files changed, 67 insertions(+), 21 deletions(-) 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 669a7d37e..f5b2280c9 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java @@ -33,6 +33,8 @@ import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.service.KeychainIntentService; +import org.sufficientlysecure.keychain.service.OperationResultParcel.LogLevel; +import org.sufficientlysecure.keychain.service.OperationResultParcel.LogType; import org.sufficientlysecure.keychain.service.OperationResultParcel.OperationLog; import org.sufficientlysecure.keychain.service.OperationResults.ImportKeyResult; import org.sufficientlysecure.keychain.service.OperationResults.SaveKeyringResult; @@ -57,6 +59,7 @@ public class PgpImportExport { private Context mContext; private Progressable mProgressable; + private AtomicBoolean mCancelled; private KeychainServiceListener mKeychainServiceListener; @@ -73,6 +76,14 @@ public class PgpImportExport { this.mProviderHelper = providerHelper; } + public PgpImportExport(Context context, ProviderHelper providerHelper, Progressable progressable, AtomicBoolean cancelled) { + super(); + mContext = context; + mProgressable = progressable; + mProviderHelper = providerHelper; + mCancelled = cancelled; + } + public PgpImportExport(Context context, Progressable progressable, KeychainServiceListener keychainListener) { super(); @@ -126,20 +137,11 @@ public class PgpImportExport { } /** Imports keys from given data. If keyIds is given only those are imported */ - public ImportKeyResult importKeyRings(List entries, - AtomicBoolean cancelled) { - return importKeyRings(entries.iterator(), entries.size(), cancelled); - } - public ImportKeyResult importKeyRings(List entries) { - return importKeyRings(entries.iterator(), entries.size(), null); + return importKeyRings(entries.iterator(), entries.size()); } public ImportKeyResult importKeyRings(Iterator entries, int num) { - return importKeyRings(entries, num, null); - } - public ImportKeyResult importKeyRings(Iterator entries, int num, - AtomicBoolean cancelled) { updateProgress(R.string.progress_importing, 0, 100); // If there aren't even any keys, do nothing here. @@ -154,8 +156,7 @@ public class PgpImportExport { double progSteps = 100.0 / num; for (ParcelableKeyRing entry : new IterableIterator(entries)) { // Has this action been cancelled? If so, don't proceed any further - if (cancelled != null && cancelled.get()) { - Log.d(Constants.TAG, "CANCELLED!"); + if (mCancelled != null && mCancelled.get()) { break; } @@ -227,7 +228,8 @@ public class PgpImportExport { resultType |= ImportKeyResult.RESULT_WARNINGS; } } - if (cancelled != null && cancelled.get()) { + if (mCancelled != null && mCancelled.get()) { + log.add(LogLevel.CANCELLED, LogType.MSG_OPERATION_CANCELLED, 0); resultType |= ImportKeyResult.RESULT_CANCELLED; } 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 f865c58e2..2073d6a6c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -526,12 +526,17 @@ public class KeychainIntentService extends IntentService } ProviderHelper providerHelper = new ProviderHelper(this); - PgpImportExport pgpImportExport = new PgpImportExport(this, providerHelper, this); - ImportKeyResult result = pgpImportExport.importKeyRings(entries, mActionCanceled); + PgpImportExport pgpImportExport = new PgpImportExport( + this, providerHelper, this, mActionCanceled); + ImportKeyResult result = pgpImportExport.importKeyRings(entries); + // we do this even on failure or cancellation! if (result.mSecret > 0) { + // cannot cancel from here on out! + sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_PREVENT_CANCEL); providerHelper.consolidateDatabaseStep1(this); } + // make sure new data is synced into contacts ContactSyncAdapterService.requestSync(); 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 1772dc6ae..940777458 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java @@ -18,7 +18,6 @@ package org.sufficientlysecure.keychain.service; import android.app.Activity; -import android.content.DialogInterface.OnCancelListener; import android.os.Bundle; import android.os.Handler; import android.os.Message; @@ -37,6 +36,7 @@ public class KeychainIntentServiceHandler extends Handler { public static final int MESSAGE_OKAY = 1; public static final int MESSAGE_EXCEPTION = 2; public static final int MESSAGE_UPDATE_PROGRESS = 3; + public static final int MESSAGE_PREVENT_CANCEL = 4; // possible data keys for messages public static final String DATA_ERROR = "error"; @@ -124,6 +124,9 @@ public class KeychainIntentServiceHandler extends Handler { break; + case MESSAGE_PREVENT_CANCEL: + mProgressDialogFragment.setPreventCancel(true); + default: Log.e(Constants.TAG, "unknown handler message!"); break; 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 fbfa5ee08..ec4f2e337 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.OperationResults; import org.sufficientlysecure.keychain.service.SaveKeyringParcel; import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm; import org.sufficientlysecure.keychain.util.Log; -import org.sufficientlysecure.keychain.util.Notify; public class CreateKeyFinalFragment extends Fragment { 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 49a8ac49f..d09be2d51 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 @@ -23,6 +23,7 @@ import android.app.ProgressDialog; import android.content.DialogInterface; import android.content.DialogInterface.OnKeyListener; import android.content.Intent; +import android.graphics.Color; import android.os.Bundle; import android.support.v4.app.DialogFragment; import android.view.ContextThemeWrapper; @@ -39,6 +40,8 @@ public class ProgressDialogFragment extends DialogFragment { private static final String ARG_STYLE = "style"; private static final String ARG_CANCELABLE = "cancelable"; + boolean mCanCancel = false, mPreventCancel = false, mIsCancelled = false; + /** Creates new instance of this fragment */ public static ProgressDialogFragment newInstance(String message, int style, boolean cancelable) { ProgressDialogFragment frag = new ProgressDialogFragment(); @@ -59,6 +62,10 @@ public class ProgressDialogFragment extends DialogFragment { /** Updates progress of dialog */ public void setProgress(int progress, int max) { + if (mIsCancelled) { + return; + } + ProgressDialog dialog = (ProgressDialog) getDialog(); dialog.setProgress(progress); @@ -67,6 +74,10 @@ public class ProgressDialogFragment extends DialogFragment { /** Updates progress of dialog */ public void setProgress(String message, int progress, int max) { + if (mIsCancelled) { + return; + } + ProgressDialog dialog = (ProgressDialog) getDialog(); dialog.setMessage(message); @@ -94,13 +105,13 @@ public class ProgressDialogFragment extends DialogFragment { String message = getArguments().getString(ARG_MESSAGE); int style = getArguments().getInt(ARG_STYLE); - final boolean cancelable = getArguments().getBoolean(ARG_CANCELABLE); + mCanCancel = getArguments().getBoolean(ARG_CANCELABLE); dialog.setMessage(message); dialog.setProgressStyle(style); // If this is supposed to be cancelable, add our (custom) cancel mechanic - if (cancelable) { + if (mCanCancel) { // Just show the button, take care of the onClickListener afterwards (in onStart) dialog.setButton(DialogInterface.BUTTON_NEGATIVE, activity.getString(R.string.progress_cancel), (DialogInterface.OnClickListener) null); @@ -111,7 +122,7 @@ public class ProgressDialogFragment extends DialogFragment { @Override public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { - if (cancelable) { + if (mCanCancel) { ((ProgressDialog) dialog).getButton( DialogInterface.BUTTON_NEGATIVE).performClick(); } @@ -126,15 +137,41 @@ public class ProgressDialogFragment extends DialogFragment { return dialog; } + public void setPreventCancel(boolean preventCancel) { + // Don't care if we can't cancel anymore either way! + if (mIsCancelled || ! mCanCancel) { + return; + } + + mPreventCancel = preventCancel; + final Button negative = ((ProgressDialog) getDialog()).getButton(DialogInterface.BUTTON_NEGATIVE); + negative.setVisibility(preventCancel ? View.GONE : View.VISIBLE); + } + @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); + final Button negative = ((ProgressDialog) getDialog()).getButton(DialogInterface.BUTTON_NEGATIVE); negative.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { + // nvm if we are already cancelled, or weren't able to begin with + if (mIsCancelled || ! mCanCancel) { + return; + } + + // Remember this, and don't allow another click + mIsCancelled = true; + negative.setClickable(false); + negative.setTextColor(Color.GRAY); + + // Set the progress bar accordingly + ProgressDialog dialog = (ProgressDialog) getDialog(); + dialog.setIndeterminate(true); + dialog.setMessage(getString(R.string.progress_cancelling)); + // 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.