add cancel prevention mechanism, improve cancellation for key import

This commit is contained in:
Vincent Breitmoser 2014-08-31 20:05:19 +02:00
parent d17b478a9e
commit e9a2f256b9
5 changed files with 67 additions and 21 deletions

View File

@ -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<ParcelableKeyRing> entries,
AtomicBoolean cancelled) {
return importKeyRings(entries.iterator(), entries.size(), cancelled);
}
public ImportKeyResult importKeyRings(List<ParcelableKeyRing> entries) {
return importKeyRings(entries.iterator(), entries.size(), null);
return importKeyRings(entries.iterator(), entries.size());
}
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.
@ -154,8 +156,7 @@ public class PgpImportExport {
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!");
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;
}

View File

@ -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();

View File

@ -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;

View File

@ -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 {

View File

@ -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.