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

View File

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

View File

@@ -29,7 +29,7 @@ import android.os.SystemClock;
import android.support.annotation.UiThread; import android.support.annotation.UiThread;
import android.support.v4.app.Fragment; import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity; 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.InputPendingResult;
import org.sufficientlysecure.keychain.operations.results.OperationResult; 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.PassphraseDialogActivity;
import org.sufficientlysecure.keychain.ui.RetryUploadDialogActivity; import org.sufficientlysecure.keychain.ui.RetryUploadDialogActivity;
import org.sufficientlysecure.keychain.ui.SecurityTokenOperationActivity; import org.sufficientlysecure.keychain.ui.SecurityTokenOperationActivity;
import org.sufficientlysecure.keychain.ui.dialog.ProgressDialogFragment;
import timber.log.Timber; import timber.log.Timber;
@@ -264,28 +263,6 @@ public class CryptoOperationHelper<T extends Parcelable, S extends OperationResu
return true; 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) { public void cryptoOperation(final CryptoInputParcel cryptoInput) {
FragmentActivity activity = mUseFragment ? mFragment.getActivity() : mActivity; FragmentActivity activity = mUseFragment ? mFragment.getActivity() : mActivity;
@@ -298,14 +275,12 @@ public class CryptoOperationHelper<T extends Parcelable, S extends OperationResu
ProgressDialogManager progressDialogManager; ProgressDialogManager progressDialogManager;
if (mProgressMessageResource != null) { if (mProgressMessageResource != null) {
progressDialogManager = new ProgressDialogManager(activity); progressDialogManager = new ProgressDialogManager(activity);
progressDialogManager.showProgressDialog(
activity.getString(mProgressMessageResource), ProgressDialog.STYLE_HORIZONTAL, mCancellable);
} else { } else {
progressDialogManager = null; progressDialogManager = null;
} }
KeychainServiceTask keychainServiceTask = KeychainServiceTask.create(activity); KeychainServiceTask keychainServiceTask = KeychainServiceTask.create(activity);
keychainServiceTask.startOperationInBackground(operationInput, cryptoInput, new OperationCallback() { OperationCallback operationCallback = new OperationCallback() {
@Override @Override
public void operationFinished(OperationResult result) { public void operationFinished(OperationResult result) {
if (progressDialogManager != null) { if (progressDialogManager != null) {
@@ -331,7 +306,15 @@ public class CryptoOperationHelper<T extends Parcelable, S extends OperationResu
progressDialogManager.setPreventCancel(); 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() { public void cryptoOperation() {

View File

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