From 68e31a985f988d23130241ba90e5de2378043754 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Tue, 10 May 2016 16:00:41 +0200 Subject: [PATCH] messageview: cancel operation when fragment is destroyed --- .../k9/ui/crypto/MessageCryptoHelper.java | 25 +++++++- .../ui/messageview/MessageViewFragment.java | 10 ++++ .../openintents/openpgp/util/OpenPgpApi.java | 59 +++++++++++++++++-- .../util/ParcelFileDescriptorUtil.java | 16 ++--- 4 files changed, 89 insertions(+), 21 deletions(-) diff --git a/k9mail/src/main/java/com/fsck/k9/ui/crypto/MessageCryptoHelper.java b/k9mail/src/main/java/com/fsck/k9/ui/crypto/MessageCryptoHelper.java index 8c07767e6c..c6158e87d2 100644 --- a/k9mail/src/main/java/com/fsck/k9/ui/crypto/MessageCryptoHelper.java +++ b/k9mail/src/main/java/com/fsck/k9/ui/crypto/MessageCryptoHelper.java @@ -42,6 +42,7 @@ import org.openintents.openpgp.OpenPgpDecryptionResult; import org.openintents.openpgp.OpenPgpError; import org.openintents.openpgp.OpenPgpSignatureResult; import org.openintents.openpgp.util.OpenPgpApi; +import org.openintents.openpgp.util.OpenPgpApi.CancelableBackgroundOperation; import org.openintents.openpgp.util.OpenPgpApi.IOpenPgpSinkResultCallback; import org.openintents.openpgp.util.OpenPgpApi.OpenPgpDataSink; import org.openintents.openpgp.util.OpenPgpApi.OpenPgpDataSource; @@ -69,6 +70,8 @@ public class MessageCryptoHelper { private Intent userInteractionResultIntent; private LocalMessage currentMessage; private boolean secondPassStarted; + private CancelableBackgroundOperation cancelableBackgroundOperation; + private boolean isCancelled; public MessageCryptoHelper(Activity activity, Account account, MessageCryptoCallback callback) { @@ -151,6 +154,10 @@ public class MessageCryptoHelper { } private void decryptOrVerifyNextPart() { + if (isCancelled) { + return; + } + if (partsToDecryptOrVerify.isEmpty()) { runSecondPassOrReturnResultToFragment(); return; @@ -232,7 +239,8 @@ public class MessageCryptoHelper { OpenPgpDataSource dataSource = getDataSourceForEncryptedOrInlineData(); OpenPgpDataSink dataSink = getDataSinkForDecryptedInlineData(); - openPgpApi.executeApiAsync(intent, dataSource, dataSink, new IOpenPgpSinkResultCallback() { + cancelableBackgroundOperation = openPgpApi.executeApiAsync(intent, dataSource, dataSink, + new IOpenPgpSinkResultCallback() { @Override public void onProgress(int current, int max) { Log.d(K9.LOG_TAG, "received progress status: " + current + " / " + max); @@ -247,6 +255,13 @@ public class MessageCryptoHelper { }); } + public void cancelIfRunning() { + isCancelled = true; + if (cancelableBackgroundOperation != null) { + cancelableBackgroundOperation.cancelOperation(); + } + } + private OpenPgpDataSink getDataSinkForDecryptedInlineData() { return new OpenPgpDataSink() { @Override @@ -269,7 +284,8 @@ public class MessageCryptoHelper { OpenPgpDataSource dataSource = getDataSourceForEncryptedOrInlineData(); OpenPgpDataSink openPgpDataSink = getDataSinkForDecryptedData(); - openPgpApi.executeApiAsync(intent, dataSource, openPgpDataSink, new IOpenPgpSinkResultCallback() { + cancelableBackgroundOperation = openPgpApi.executeApiAsync(intent, dataSource, openPgpDataSink, + new IOpenPgpSinkResultCallback() { @Override public void onReturn(Intent result, MimeBodyPart decryptedPart) { currentCryptoResult = result; @@ -462,6 +478,10 @@ public class MessageCryptoHelper { } public void onActivityResult(int requestCode, int resultCode, Intent data) { + if (isCancelled) { + return; + } + if (requestCode != REQUEST_CODE_USER_INTERACTION) { throw new IllegalStateException("got an activity result that wasn't meant for us. this is a bug!"); } @@ -526,7 +546,6 @@ public class MessageCryptoHelper { callback.onCryptoOperationsFinished(messageAnnotations); } - private static class CryptoPart { public final CryptoPartType type; public final Part part; diff --git a/k9mail/src/main/java/com/fsck/k9/ui/messageview/MessageViewFragment.java b/k9mail/src/main/java/com/fsck/k9/ui/messageview/MessageViewFragment.java index aba7e4e7ec..60f0c4c239 100644 --- a/k9mail/src/main/java/com/fsck/k9/ui/messageview/MessageViewFragment.java +++ b/k9mail/src/main/java/com/fsck/k9/ui/messageview/MessageViewFragment.java @@ -19,6 +19,7 @@ import android.content.Loader; import android.net.Uri; import android.os.Bundle; import android.os.Handler; +import android.support.annotation.UiThread; import android.text.TextUtils; import android.util.Log; import android.view.ContextThemeWrapper; @@ -144,6 +145,14 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF mInitialized = true; } + @UiThread + private void cancelAndClearMessageCryptoHelper() { + if (messageCryptoHelper != null) { + messageCryptoHelper.cancelIfRunning(); + messageCryptoHelper = null; + } + } + @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -233,6 +242,7 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF getLoaderManager().initLoader(LOCAL_MESSAGE_LOADER_ID, null, localMessageLoaderCallback); } + @UiThread private void onLoadMessageFromDatabaseFinished(LocalMessage message) { displayMessageHeader(message); diff --git a/plugins/openpgp-api-lib/openpgp-api/src/main/java/org/openintents/openpgp/util/OpenPgpApi.java b/plugins/openpgp-api-lib/openpgp-api/src/main/java/org/openintents/openpgp/util/OpenPgpApi.java index 834a72db76..770bcd73b5 100644 --- a/plugins/openpgp-api-lib/openpgp-api/src/main/java/org/openintents/openpgp/util/OpenPgpApi.java +++ b/plugins/openpgp-api-lib/openpgp-api/src/main/java/org/openintents/openpgp/util/OpenPgpApi.java @@ -35,6 +35,7 @@ import android.util.Log; import org.openintents.openpgp.IOpenPgpService2; import org.openintents.openpgp.OpenPgpError; import org.openintents.openpgp.util.ParcelFileDescriptorUtil.DataSinkTransferThread; +import org.openintents.openpgp.util.ParcelFileDescriptorUtil.DataSourceTransferThread; @SuppressWarnings("unused") @@ -288,7 +289,12 @@ public class OpenPgpApi { void onReturn(final Intent result, T sinkResult); } - private class OpenPgpSourceSinkAsyncTask extends AsyncTask> { + public interface CancelableBackgroundOperation { + void cancelOperation(); + } + + private class OpenPgpSourceSinkAsyncTask extends AsyncTask> + implements CancelableBackgroundOperation { Intent data; OpenPgpDataSource dataSource; OpenPgpDataSink dataSink; @@ -310,6 +316,14 @@ public class OpenPgpApi { protected void onPostExecute(OpenPgpDataResult result) { callback.onReturn(result.apiResult, result.sinkResult); } + + @Override + public void cancelOperation() { + cancel(true); + if (dataSource != null) { + dataSource.cancel(); + } + } } private class OpenPgpAsyncTask extends AsyncTask { @@ -335,8 +349,8 @@ public class OpenPgpApi { } } - public void executeApiAsync(Intent data, OpenPgpDataSource dataSource, OpenPgpDataSink dataSink, - final IOpenPgpSinkResultCallback callback) { + public CancelableBackgroundOperation executeApiAsync(Intent data, OpenPgpDataSource dataSource, + OpenPgpDataSink dataSink, final IOpenPgpSinkResultCallback callback) { Messenger messenger = new Messenger(new Handler(new Handler.Callback() { @Override public boolean handleMessage(Message message) { @@ -356,9 +370,10 @@ public class OpenPgpApi { task.execute((Void[]) null); } + return task; } - public void executeApiAsync(Intent data, OpenPgpDataSource dataSource, IOpenPgpSinkResultCallback callback) { + public AsyncTask executeApiAsync(Intent data, OpenPgpDataSource dataSource, IOpenPgpSinkResultCallback callback) { OpenPgpSourceSinkAsyncTask task = new OpenPgpSourceSinkAsyncTask<>(data, dataSource, null, callback); // don't serialize async tasks! @@ -369,6 +384,7 @@ public class OpenPgpApi { task.execute((Void[]) null); } + return task; } public void executeApiAsync(Intent data, InputStream is, OutputStream os, IOpenPgpCallback callback) { @@ -404,7 +420,7 @@ public class OpenPgpApi { } else { data.removeExtra(EXTRA_PROGRESS_MESSENGER); } - input = ParcelFileDescriptorUtil.asyncPipeFromDataSource(dataSource); + input = dataSource.startPumpThread(); } DataSinkTransferThread pumpThread = null; @@ -487,10 +503,41 @@ public class OpenPgpApi { } public static abstract class OpenPgpDataSource { + private boolean isCancelled; + private ParcelFileDescriptor writeSidePfd; + + public abstract void writeTo(OutputStream os) throws IOException; + public Long getSizeForProgress() { return null; } + + public boolean isCancelled() { + return isCancelled; + } + + private ParcelFileDescriptor startPumpThread() throws IOException { + if (writeSidePfd != null) { + throw new IllegalStateException("startPumpThread() must only be called once!"); + } + ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe(); + ParcelFileDescriptor readSidePfd = pipe[0]; + writeSidePfd = pipe[1]; + + new DataSourceTransferThread(this, new ParcelFileDescriptor.AutoCloseOutputStream(writeSidePfd)).start(); + + return readSidePfd; + } + + private void cancel() { + isCancelled = true; + try { + writeSidePfd.close(); + } catch (IOException e) { + // this is fine + } + } } public interface OpenPgpDataSink { @@ -508,7 +555,7 @@ public class OpenPgpApi { } else { data.removeExtra(EXTRA_PROGRESS_MESSENGER); } - input = ParcelFileDescriptorUtil.asyncPipeFromDataSource(dataSource); + input = dataSource.startPumpThread(); } Thread pumpThread = null; diff --git a/plugins/openpgp-api-lib/openpgp-api/src/main/java/org/openintents/openpgp/util/ParcelFileDescriptorUtil.java b/plugins/openpgp-api-lib/openpgp-api/src/main/java/org/openintents/openpgp/util/ParcelFileDescriptorUtil.java index b81fd7a3c2..dc0fdab70f 100644 --- a/plugins/openpgp-api-lib/openpgp-api/src/main/java/org/openintents/openpgp/util/ParcelFileDescriptorUtil.java +++ b/plugins/openpgp-api-lib/openpgp-api/src/main/java/org/openintents/openpgp/util/ParcelFileDescriptorUtil.java @@ -99,16 +99,6 @@ public class ParcelFileDescriptorUtil { return dataSinkTransferThread; } - public static ParcelFileDescriptor asyncPipeFromDataSource(OpenPgpDataSource dataSource) throws IOException { - ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe(); - ParcelFileDescriptor readSide = pipe[0]; - ParcelFileDescriptor writeSide = pipe[1]; - - new DataSourceTransferThread(dataSource, new ParcelFileDescriptor.AutoCloseOutputStream(writeSide)).start(); - - return readSide; - } - static class DataSourceTransferThread extends Thread { final OpenPgpDataSource dataSource; final OutputStream outputStream; @@ -125,8 +115,10 @@ public class ParcelFileDescriptorUtil { try { dataSource.writeTo(outputStream); } catch (IOException e) { - if (isIOExceptionCausedByEPIPE(e)) { - Log.e(OpenPgpApi.TAG, "Stopped writing due to broken pipe (other end closed pipe?)"); + if (dataSource.isCancelled()) { + Log.d(OpenPgpApi.TAG, "Stopped writing because operation was cancelled."); + } else if (isIOExceptionCausedByEPIPE(e)) { + Log.d(OpenPgpApi.TAG, "Stopped writing due to broken pipe (other end closed pipe?)"); } else { Log.e(OpenPgpApi.TAG, "IOException when writing to out", e); }