Use CancellationSignal for cancellation in UI code

This commit is contained in:
Vincent Breitmoser
2018-07-17 14:13:03 +02:00
parent 9e079329d5
commit 1fcc1889ec
4 changed files with 118 additions and 122 deletions

View File

@@ -24,6 +24,7 @@ import android.annotation.SuppressLint;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Parcelable;
import android.support.v4.os.CancellationSignal;
import org.sufficientlysecure.keychain.daos.KeyWritableRepository;
import org.sufficientlysecure.keychain.operations.BackupOperation;
@@ -64,90 +65,101 @@ public class KeychainServiceTask {
private final KeyWritableRepository keyRepository;
@SuppressLint("StaticFieldLeak")
public void startOperationInBackground(
public CancellationSignal startOperationInBackground(
Parcelable inputParcel, CryptoInputParcel cryptoInput, OperationCallback operationCallback) {
new AsyncTask<Void,ProgressUpdate,OperationResult>() {
private AtomicBoolean operationCancelledBoolean = new AtomicBoolean(false);
AtomicBoolean operationCancelledBoolean = new AtomicBoolean(false);
@Override
protected OperationResult doInBackground(Void... voids) {
BaseOperation op;
AsyncTask<Void, ProgressUpdate, OperationResult> asyncTask =
new AsyncTask<Void, ProgressUpdate, OperationResult>() {
@Override
protected OperationResult doInBackground(Void... voids) {
BaseOperation op;
if (inputParcel instanceof SignEncryptParcel) {
op = new SignEncryptOperation(context, keyRepository, asyncProgressable, operationCancelledBoolean);
} else if (inputParcel instanceof PgpDecryptVerifyInputParcel) {
op = new PgpDecryptVerifyOperation(context, keyRepository, asyncProgressable);
} else if (inputParcel instanceof SaveKeyringParcel) {
op = new EditKeyOperation(context, keyRepository, asyncProgressable, operationCancelledBoolean);
} else if (inputParcel instanceof ChangeUnlockParcel) {
op = new ChangeUnlockOperation(context, keyRepository, asyncProgressable);
} else if (inputParcel instanceof RevokeKeyringParcel) {
op = new RevokeOperation(context, keyRepository, asyncProgressable);
} else if (inputParcel instanceof CertifyActionsParcel) {
op = new CertifyOperation(context, keyRepository, asyncProgressable, operationCancelledBoolean);
} else if (inputParcel instanceof DeleteKeyringParcel) {
op = new DeleteOperation(context, keyRepository, asyncProgressable);
} else if (inputParcel instanceof PromoteKeyringParcel) {
op = new PromoteKeyOperation(context, keyRepository, asyncProgressable, operationCancelledBoolean);
} else if (inputParcel instanceof ImportKeyringParcel) {
op = new ImportOperation(context, keyRepository, asyncProgressable, operationCancelledBoolean);
} else if (inputParcel instanceof BackupKeyringParcel) {
op = new BackupOperation(context, keyRepository, asyncProgressable, operationCancelledBoolean);
} else if (inputParcel instanceof UploadKeyringParcel) {
op = new UploadOperation(context, keyRepository, asyncProgressable, operationCancelledBoolean);
} else if (inputParcel instanceof KeybaseVerificationParcel) {
op = new KeybaseVerificationOperation(context, keyRepository, asyncProgressable);
} else if (inputParcel instanceof InputDataParcel) {
op = new InputDataOperation(context, keyRepository, asyncProgressable);
} else if (inputParcel instanceof BenchmarkInputParcel) {
op = new BenchmarkOperation(context, keyRepository, asyncProgressable);
} else if (inputParcel instanceof KeySyncParcel) {
op = new KeySyncOperation(context, keyRepository, asyncProgressable, operationCancelledBoolean);
} else {
throw new AssertionError("Unrecognized input parcel in KeychainService!");
}
if (inputParcel instanceof SignEncryptParcel) {
op = new SignEncryptOperation(context, keyRepository, asyncProgressable,
operationCancelledBoolean);
} else if (inputParcel instanceof PgpDecryptVerifyInputParcel) {
op = new PgpDecryptVerifyOperation(context, keyRepository, asyncProgressable);
} else if (inputParcel instanceof SaveKeyringParcel) {
op = new EditKeyOperation(context, keyRepository, asyncProgressable,
operationCancelledBoolean);
} else if (inputParcel instanceof ChangeUnlockParcel) {
op = new ChangeUnlockOperation(context, keyRepository, asyncProgressable);
} else if (inputParcel instanceof RevokeKeyringParcel) {
op = new RevokeOperation(context, keyRepository, asyncProgressable);
} else if (inputParcel instanceof CertifyActionsParcel) {
op = new CertifyOperation(context, keyRepository, asyncProgressable,
operationCancelledBoolean);
} else if (inputParcel instanceof DeleteKeyringParcel) {
op = new DeleteOperation(context, keyRepository, asyncProgressable);
} else if (inputParcel instanceof PromoteKeyringParcel) {
op = new PromoteKeyOperation(context, keyRepository, asyncProgressable,
operationCancelledBoolean);
} else if (inputParcel instanceof ImportKeyringParcel) {
op = new ImportOperation(context, keyRepository, asyncProgressable,
operationCancelledBoolean);
} else if (inputParcel instanceof BackupKeyringParcel) {
op = new BackupOperation(context, keyRepository, asyncProgressable,
operationCancelledBoolean);
} else if (inputParcel instanceof UploadKeyringParcel) {
op = new UploadOperation(context, keyRepository, asyncProgressable,
operationCancelledBoolean);
} else if (inputParcel instanceof KeybaseVerificationParcel) {
op = new KeybaseVerificationOperation(context, keyRepository, asyncProgressable);
} else if (inputParcel instanceof InputDataParcel) {
op = new InputDataOperation(context, keyRepository, asyncProgressable);
} else if (inputParcel instanceof BenchmarkInputParcel) {
op = new BenchmarkOperation(context, keyRepository, asyncProgressable);
} else if (inputParcel instanceof KeySyncParcel) {
op = new KeySyncOperation(context, keyRepository, asyncProgressable,
operationCancelledBoolean);
} else {
throw new AssertionError("Unrecognized input parcel in KeychainService!");
}
if (isCancelled()) {
return null;
}
if (isCancelled()) {
return null;
}
// noinspection unchecked, we make sure it's the correct op above
return op.execute(inputParcel, cryptoInput);
}
// noinspection unchecked, we make sure it's the correct op above
return op.execute(inputParcel, cryptoInput);
}
Progressable asyncProgressable = new Progressable() {
@Override
public void setPreventCancel() {
publishProgress((ProgressUpdate) null);
}
Progressable asyncProgressable = new Progressable() {
@Override
public void setPreventCancel() {
publishProgress((ProgressUpdate) null);
}
@Override
public void setProgress(Integer resourceId, int current, int total) {
publishProgress(new ProgressUpdate(resourceId, current, total));
}
};
@Override
public void setProgress(Integer resourceId, int current, int total) {
publishProgress(new ProgressUpdate(resourceId, current, total));
}
};
@Override
protected void onProgressUpdate(ProgressUpdate... values) {
ProgressUpdate progressUpdate = values[0];
if (progressUpdate == null) {
operationCallback.setPreventCancel();
} else {
operationCallback.setProgress(progressUpdate.resourceId, progressUpdate.current, progressUpdate.total);
}
}
@Override
protected void onProgressUpdate(ProgressUpdate... values) {
ProgressUpdate progressUpdate = values[0];
if (progressUpdate == null) {
operationCallback.setPreventCancel();
} else {
operationCallback.setProgress(progressUpdate.resourceId, progressUpdate.current,
progressUpdate.total);
}
}
@Override
protected void onCancelled() {
super.onCancelled();
operationCancelledBoolean.set(true);
}
@Override
protected void onPostExecute(OperationResult result) {
operationCallback.operationFinished(result);
}
};
asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
@Override
protected void onPostExecute(OperationResult result) {
operationCallback.operationFinished(result);
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
CancellationSignal cancellationSignal = new CancellationSignal();
cancellationSignal.setOnCancelListener(() -> {
operationCancelledBoolean.set(true);
});
return cancellationSignal;
}
public interface OperationCallback {

View File

@@ -22,6 +22,7 @@ import android.app.ProgressDialog;
import android.os.Handler;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.os.CancellationSignal;
import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment;
@@ -36,16 +37,16 @@ public class ProgressDialogManager {
}
public void showProgressDialog() {
showProgressDialog("", ProgressDialog.STYLE_SPINNER, false);
showProgressDialog("", ProgressDialog.STYLE_SPINNER, null);
}
public void showProgressDialog(
String progressDialogMessage, int progressDialogStyle, boolean cancelable) {
String progressDialogMessage, int progressDialogStyle, CancellationSignal cancellationSignal) {
final ProgressDialogFragment frag = ProgressDialogFragment.newInstance(
progressDialogMessage,
progressDialogStyle,
cancelable);
progressDialogMessage, progressDialogStyle, cancellationSignal != null);
frag.setCancellationSignal(cancellationSignal);
// TODO: This is a hack!, see
// http://stackoverflow.com/questions/10114324/show-dialogfragment-from-onactivityresult
@@ -79,9 +80,7 @@ public class ProgressDialogManager {
progressDialogFragment.dismissAllowingStateLoss();
}
public void onSetProgress(Integer resourceInt, int progress, int max) {
ProgressDialogFragment progressDialogFragment =
(ProgressDialogFragment) activity.getSupportFragmentManager()
.findFragmentByTag(TAG_PROGRESS_DIALOG);
@@ -95,7 +94,5 @@ public class ProgressDialogManager {
} else {
progressDialogFragment.setProgress(progress, max);
}
}
}

View File

@@ -29,7 +29,7 @@ import android.os.SystemClock;
import android.support.annotation.UiThread;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.os.CancellationSignal;
import org.sufficientlysecure.keychain.operations.results.InputPendingResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult;
@@ -42,7 +42,6 @@ import org.sufficientlysecure.keychain.ui.OrbotRequiredDialogActivity;
import org.sufficientlysecure.keychain.ui.PassphraseDialogActivity;
import org.sufficientlysecure.keychain.ui.RetryUploadDialogActivity;
import org.sufficientlysecure.keychain.ui.SecurityTokenOperationActivity;
import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment;
import timber.log.Timber;
@@ -264,28 +263,6 @@ public class CryptoOperationHelper<T extends Parcelable, S extends OperationResu
return true;
}
protected void dismissProgress() {
FragmentManager fragmentManager =
mUseFragment ? mFragment.getFragmentManager() :
mActivity.getSupportFragmentManager();
if (fragmentManager == null) { // the fragment holding us has died
// fragmentManager was null when used with DialogFragments. (they close on click?)
return;
}
ProgressDialogFragment progressDialogFragment =
(ProgressDialogFragment) fragmentManager.findFragmentByTag(
ProgressDialogManager.TAG_PROGRESS_DIALOG);
if (progressDialogFragment == null) {
return;
}
progressDialogFragment.dismissAllowingStateLoss();
}
public void cryptoOperation(final CryptoInputParcel cryptoInput) {
FragmentActivity activity = mUseFragment ? mFragment.getActivity() : mActivity;
@@ -298,14 +275,12 @@ public class CryptoOperationHelper<T extends Parcelable, S extends OperationResu
ProgressDialogManager progressDialogManager;
if (mProgressMessageResource != null) {
progressDialogManager = new ProgressDialogManager(activity);
progressDialogManager.showProgressDialog(
activity.getString(mProgressMessageResource), ProgressDialog.STYLE_HORIZONTAL, mCancellable);
} else {
progressDialogManager = null;
}
KeychainServiceTask keychainServiceTask = KeychainServiceTask.create(activity);
keychainServiceTask.startOperationInBackground(operationInput, cryptoInput, new OperationCallback() {
OperationCallback operationCallback = new OperationCallback() {
@Override
public void operationFinished(OperationResult result) {
if (progressDialogManager != null) {
@@ -331,7 +306,15 @@ public class CryptoOperationHelper<T extends Parcelable, S extends OperationResu
progressDialogManager.setPreventCancel();
}
}
});
};
CancellationSignal cancellationSignal =
keychainServiceTask.startOperationInBackground(operationInput, cryptoInput, operationCallback);
if (progressDialogManager != null) {
progressDialogManager.showProgressDialog(activity.getString(mProgressMessageResource),
ProgressDialog.STYLE_HORIZONTAL, mCancellable ? cancellationSignal : null);
}
}
public void cryptoOperation() {

View File

@@ -17,6 +17,7 @@
package org.sufficientlysecure.keychain.ui.dialog;
import android.app.Activity;
import android.app.Dialog;
import android.app.ProgressDialog;
@@ -26,6 +27,7 @@ import android.graphics.Color;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.DialogFragment;
import android.support.v4.os.CancellationSignal;
import android.view.ContextThemeWrapper;
import android.view.KeyEvent;
import android.view.View;
@@ -33,7 +35,6 @@ import android.view.View.OnClickListener;
import android.widget.Button;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.service.KeychainServiceTask;
import org.sufficientlysecure.keychain.ui.util.ThemeChanger;
/**
@@ -43,15 +44,18 @@ 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 static final String ARG_SERVICE_TYPE = "service_class";
boolean mCanCancel = false, mPreventCancel = false, mIsCancelled = false;
private CancellationSignal cancellationSignal;
/**
* creates a new instance of this fragment
* @param message the message to be displayed initially above the progress bar
* @param style the progress bar style, as defined in ProgressDialog (horizontal or spinner)
* @param cancelable should we let the user cancel this operation
*
* @param message
* the message to be displayed initially above the progress bar
* @param style
* the progress bar style, as defined in ProgressDialog (horizontal or spinner)
*
* @return
*/
public static ProgressDialogFragment newInstance(String message, int style, boolean cancelable) {
@@ -156,6 +160,10 @@ public class ProgressDialogFragment extends DialogFragment {
negative.setEnabled(false);
}
public void setCancellationSignal(CancellationSignal cancellationSignal) {
this.cancellationSignal = cancellationSignal;
}
@Override
public void onStart() {
super.onStart();
@@ -166,7 +174,7 @@ public class ProgressDialogFragment extends DialogFragment {
@Override
public void onClick(View v) {
// nvm if we are already cancelled, or weren't able to begin with
if (mIsCancelled || ! mCanCancel) {
if (mIsCancelled || !mCanCancel || cancellationSignal == null) {
return;
}
@@ -175,8 +183,7 @@ public class ProgressDialogFragment extends DialogFragment {
negative.setClickable(false);
negative.setTextColor(Color.GRAY);
// TODO
// KeychainServiceTask.cancelRunningTask();
cancellationSignal.cancel();
// Set the progress bar accordingly
ProgressDialog dialog = (ProgressDialog) getDialog();
@@ -186,11 +193,8 @@ public class ProgressDialogFragment extends DialogFragment {
dialog.setIndeterminate(true);
dialog.setMessage(getString(R.string.progress_cancelling));
}
});
}
}