Loading k9mail/src/main/java/com/fsck/k9/helper/RetainFragment.java 0 → 100644 +58 −0 Original line number Diff line number Diff line package com.fsck.k9.helper; import android.app.Fragment; import android.app.FragmentManager; import android.os.Build.VERSION; import android.os.Build.VERSION_CODES; import android.os.Bundle; public class RetainFragment<T> extends Fragment { private T data; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setRetainInstance(true); } public T getData() { return data; } public boolean hasData() { return data != null; } public void setData(T data) { this.data = data; } public static <T> RetainFragment<T> findOrCreate(FragmentManager fm, String tag) { // noinspection unchecked, we know this is the the right type RetainFragment<T> retainFragment = (RetainFragment<T>) fm.findFragmentByTag(tag); if (retainFragment == null) { retainFragment = new RetainFragment<>(); fm.beginTransaction() .add(retainFragment, tag) .commitAllowingStateLoss(); } return retainFragment; } public void clearAndRemove(FragmentManager fm) { data = null; if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1 && fm.isDestroyed()) { return; } fm.beginTransaction() .remove(this) .commitAllowingStateLoss(); } } No newline at end of file k9mail/src/main/java/com/fsck/k9/ui/crypto/MessageCryptoHelper.java +47 −19 Original line number Diff line number Diff line Loading @@ -58,28 +58,31 @@ public class MessageCryptoHelper { private final Context context; private final String openPgpProviderPackage; private final Object callbackLock = new Object(); @Nullable private MessageCryptoCallback callback; private LocalMessage currentMessage; private MessageCryptoAnnotations queuedResult; private PendingIntent queuedPendingIntent; private MessageCryptoAnnotations messageAnnotations; private Deque<CryptoPart> partsToDecryptOrVerify = new ArrayDeque<>(); private OpenPgpApi openPgpApi; private CryptoPart currentCryptoPart; private Intent currentCryptoResult; private MessageCryptoAnnotations messageAnnotations; private Intent userInteractionResultIntent; private LocalMessage currentMessage; private boolean secondPassStarted; private CancelableBackgroundOperation cancelableBackgroundOperation; private PendingIntent queuedPendingIntent; private MessageCryptoAnnotations queuedMessageAnnotations; private boolean isCancelled; private OpenPgpApi openPgpApi; private OpenPgpServiceConnection openPgpServiceConnection; public MessageCryptoHelper(Context context, String openPgpProviderPackage, @Nullable MessageCryptoCallback callback) { public MessageCryptoHelper(Context context, String openPgpProviderPackage) { this.context = context.getApplicationContext(); this.callback = callback; this.openPgpProviderPackage = openPgpProviderPackage; if (openPgpProviderPackage == null || Account.NO_OPENPGP_PROVIDER.equals(openPgpProviderPackage)) { Loading @@ -87,9 +90,15 @@ public class MessageCryptoHelper { } } public void decryptOrVerifyMessagePartsIfNecessary(LocalMessage message) { public void asyncStartOrResumeProcessingMessage(LocalMessage message, MessageCryptoCallback callback) { if (this.currentMessage != null) { reattachCallback(message, callback); return; } this.messageAnnotations = new MessageCryptoAnnotations(); this.currentMessage = message; this.callback = callback; runFirstPass(); } Loading Loading @@ -182,7 +191,7 @@ public class MessageCryptoHelper { } private void connectToCryptoProviderService() { new OpenPgpServiceConnection(context, openPgpProviderPackage, openPgpServiceConnection = new OpenPgpServiceConnection(context, openPgpProviderPackage, new OnBound() { @Override public void onBound(IOpenPgpService2 service) { Loading @@ -195,7 +204,8 @@ public class MessageCryptoHelper { public void onError(Exception e) { Log.e(K9.LOG_TAG, "Couldn't connect to OpenPgpService", e); } }).bindToService(); }); openPgpServiceConnection.bindToService(); } private void decryptOrVerifyPart(CryptoPart cryptoPart) { Loading Loading @@ -250,6 +260,7 @@ public class MessageCryptoHelper { @Override public void onReturn(Intent result, MimeBodyPart bodyPart) { cancelableBackgroundOperation = null; currentCryptoResult = result; onCryptoOperationReturned(bodyPart); } Loading Loading @@ -289,6 +300,7 @@ public class MessageCryptoHelper { new IOpenPgpSinkResultCallback<MimeBodyPart>() { @Override public void onReturn(Intent result, MimeBodyPart decryptedPart) { cancelableBackgroundOperation = null; currentCryptoResult = result; onCryptoOperationReturned(decryptedPart); } Loading @@ -310,6 +322,7 @@ public class MessageCryptoHelper { openPgpApi.executeApiAsync(intent, dataSource, new IOpenPgpSinkResultCallback<Void>() { @Override public void onReturn(Intent result, Void dummy) { cancelableBackgroundOperation = null; currentCryptoResult = result; onCryptoOperationReturned(null); } Loading Loading @@ -470,7 +483,7 @@ public class MessageCryptoHelper { CryptoResultAnnotation resultAnnotation = CryptoResultAnnotation.createOpenPgpResultAnnotation( decryptionResult, signatureResult, pendingIntent, outputPart); onCryptoSuccess(resultAnnotation); onCryptoOperationSuccess(resultAnnotation); } public void onActivityResult(int requestCode, int resultCode, Intent data) { Loading @@ -489,7 +502,7 @@ public class MessageCryptoHelper { } } private void onCryptoSuccess(CryptoResultAnnotation resultAnnotation) { private void onCryptoOperationSuccess(CryptoResultAnnotation resultAnnotation) { addCryptoResultAnnotationToMessage(resultAnnotation); onCryptoFinished(); } Loading Loading @@ -525,6 +538,7 @@ public class MessageCryptoHelper { } private void onCryptoFinished() { currentCryptoPart = null; partsToDecryptOrVerify.removeFirst(); decryptOrVerifyNextPart(); } Loading @@ -538,7 +552,14 @@ public class MessageCryptoHelper { runSecondPass(); } private final Object callbackLock = new Object(); private void cleanupAfterProcessingFinished() { partsToDecryptOrVerify = null; openPgpApi = null; if (openPgpServiceConnection != null) { openPgpServiceConnection.unbindFromService(); } openPgpServiceConnection = null; } public void detachCallback() { synchronized (callbackLock) { Loading @@ -546,7 +567,10 @@ public class MessageCryptoHelper { } } public void reattachCallback(MessageCryptoCallback callback) { private void reattachCallback(LocalMessage message, MessageCryptoCallback callback) { if (!message.equals(currentMessage)) { throw new AssertionError("Callback may only be reattached for the same message!"); } synchronized (callbackLock) { this.callback = callback; deliverResult(); Loading @@ -562,7 +586,11 @@ public class MessageCryptoHelper { private void callbackReturnResult() { synchronized (callbackLock) { queuedMessageAnnotations = messageAnnotations; cleanupAfterProcessingFinished(); queuedResult = messageAnnotations; messageAnnotations = null; deliverResult(); } } Loading @@ -585,8 +613,8 @@ public class MessageCryptoHelper { Log.d(K9.LOG_TAG, "Keeping crypto helper result in queue for later delivery"); return; } if (queuedMessageAnnotations != null) { callback.onCryptoOperationsFinished(queuedMessageAnnotations); if (queuedResult != null) { callback.onCryptoOperationsFinished(queuedResult); } else if (queuedPendingIntent != null) { callback.startPendingIntentForCryptoHelper( queuedPendingIntent.getIntentSender(), REQUEST_CODE_USER_INTERACTION, null, 0, 0, 0); Loading k9mail/src/main/java/com/fsck/k9/ui/messageview/MessageViewFragment.java +38 −3 Original line number Diff line number Diff line Loading @@ -44,6 +44,7 @@ import com.fsck.k9.fragment.ConfirmationDialogFragment.ConfirmationDialogFragmen import com.fsck.k9.fragment.ProgressDialogFragment; import com.fsck.k9.helper.FileBrowserHelper; import com.fsck.k9.helper.FileBrowserHelper.FileBrowserFailOverCallback; import com.fsck.k9.helper.RetainFragment; import com.fsck.k9.mail.Flag; import com.fsck.k9.mail.MessagingException; import com.fsck.k9.mailstore.AttachmentViewInfo; Loading Loading @@ -73,6 +74,7 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF public static final int REQUEST_MASK_CRYPTO_HELPER = 1 << 8; public static final int REQUEST_MASK_CRYPTO_PRESENTER = 2 << 8; private RetainFragment<MessageCryptoHelper> retainCryptoHelperFragment; public static MessageViewFragment newInstance(MessageReference reference) { MessageViewFragment fragment = new MessageViewFragment(); Loading Loading @@ -145,12 +147,32 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF mInitialized = true; } @Override public void onDestroy() { super.onDestroy(); Activity activity = getActivity(); boolean isChangingConfigurations = activity != null && activity.isChangingConfigurations(); if (isChangingConfigurations) { messageCryptoHelper.detachCallback(); return; } if (messageCryptoHelper != null) { cancelAndClearMessageCryptoHelper(); } } @UiThread private void cancelAndClearMessageCryptoHelper() { if (messageCryptoHelper != null) { messageCryptoHelper.cancelIfRunning(); messageCryptoHelper = null; } if (retainCryptoHelperFragment != null) { retainCryptoHelperFragment.clearAndRemove(getFragmentManager()); retainCryptoHelperFragment = null; } } @Override Loading Loading @@ -250,14 +272,25 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF } if (mAccount.isOpenPgpProviderConfigured()) { messageCryptoHelper = new MessageCryptoHelper(getActivity(), mAccount.getOpenPgpProvider(), this); messageCryptoHelper.decryptOrVerifyMessagePartsIfNecessary(message); startOrResumeProcessingInCryptoHelper(message); return; } startExtractingTextAndAttachments(); } private void startOrResumeProcessingInCryptoHelper(LocalMessage message) { retainCryptoHelperFragment = RetainFragment.findOrCreate(getFragmentManager(), "crypto_helper_" + message.hashCode()); if (retainCryptoHelperFragment.hasData()) { messageCryptoHelper = retainCryptoHelperFragment.getData(); } else { messageCryptoHelper = new MessageCryptoHelper(getActivity(), mAccount.getOpenPgpProvider()); retainCryptoHelperFragment.setData(messageCryptoHelper); } messageCryptoHelper.asyncStartOrResumeProcessingMessage(message, this); } private void onLoadMessageFromDatabaseFailed() { // mMessageView.showStatusMessage(mContext.getString(R.string.status_invalid_id_error)); } Loading @@ -273,6 +306,7 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF LoaderManager loaderManager = getLoaderManager(); loaderManager.destroyLoader(LOCAL_MESSAGE_LOADER_ID); loaderManager.destroyLoader(DECODE_MESSAGE_LOADER_ID); cancelAndClearMessageCryptoHelper(); onLoadMessageFromDatabaseFinished(mMessage); } Loading Loading @@ -751,7 +785,8 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF @Override public void restartMessageCryptoProcessing() { messageCryptoHelper.decryptOrVerifyMessagePartsIfNecessary(mMessage); cancelAndClearMessageCryptoHelper(); startOrResumeProcessingInCryptoHelper(mMessage); } @Override Loading Loading
k9mail/src/main/java/com/fsck/k9/helper/RetainFragment.java 0 → 100644 +58 −0 Original line number Diff line number Diff line package com.fsck.k9.helper; import android.app.Fragment; import android.app.FragmentManager; import android.os.Build.VERSION; import android.os.Build.VERSION_CODES; import android.os.Bundle; public class RetainFragment<T> extends Fragment { private T data; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setRetainInstance(true); } public T getData() { return data; } public boolean hasData() { return data != null; } public void setData(T data) { this.data = data; } public static <T> RetainFragment<T> findOrCreate(FragmentManager fm, String tag) { // noinspection unchecked, we know this is the the right type RetainFragment<T> retainFragment = (RetainFragment<T>) fm.findFragmentByTag(tag); if (retainFragment == null) { retainFragment = new RetainFragment<>(); fm.beginTransaction() .add(retainFragment, tag) .commitAllowingStateLoss(); } return retainFragment; } public void clearAndRemove(FragmentManager fm) { data = null; if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN_MR1 && fm.isDestroyed()) { return; } fm.beginTransaction() .remove(this) .commitAllowingStateLoss(); } } No newline at end of file
k9mail/src/main/java/com/fsck/k9/ui/crypto/MessageCryptoHelper.java +47 −19 Original line number Diff line number Diff line Loading @@ -58,28 +58,31 @@ public class MessageCryptoHelper { private final Context context; private final String openPgpProviderPackage; private final Object callbackLock = new Object(); @Nullable private MessageCryptoCallback callback; private LocalMessage currentMessage; private MessageCryptoAnnotations queuedResult; private PendingIntent queuedPendingIntent; private MessageCryptoAnnotations messageAnnotations; private Deque<CryptoPart> partsToDecryptOrVerify = new ArrayDeque<>(); private OpenPgpApi openPgpApi; private CryptoPart currentCryptoPart; private Intent currentCryptoResult; private MessageCryptoAnnotations messageAnnotations; private Intent userInteractionResultIntent; private LocalMessage currentMessage; private boolean secondPassStarted; private CancelableBackgroundOperation cancelableBackgroundOperation; private PendingIntent queuedPendingIntent; private MessageCryptoAnnotations queuedMessageAnnotations; private boolean isCancelled; private OpenPgpApi openPgpApi; private OpenPgpServiceConnection openPgpServiceConnection; public MessageCryptoHelper(Context context, String openPgpProviderPackage, @Nullable MessageCryptoCallback callback) { public MessageCryptoHelper(Context context, String openPgpProviderPackage) { this.context = context.getApplicationContext(); this.callback = callback; this.openPgpProviderPackage = openPgpProviderPackage; if (openPgpProviderPackage == null || Account.NO_OPENPGP_PROVIDER.equals(openPgpProviderPackage)) { Loading @@ -87,9 +90,15 @@ public class MessageCryptoHelper { } } public void decryptOrVerifyMessagePartsIfNecessary(LocalMessage message) { public void asyncStartOrResumeProcessingMessage(LocalMessage message, MessageCryptoCallback callback) { if (this.currentMessage != null) { reattachCallback(message, callback); return; } this.messageAnnotations = new MessageCryptoAnnotations(); this.currentMessage = message; this.callback = callback; runFirstPass(); } Loading Loading @@ -182,7 +191,7 @@ public class MessageCryptoHelper { } private void connectToCryptoProviderService() { new OpenPgpServiceConnection(context, openPgpProviderPackage, openPgpServiceConnection = new OpenPgpServiceConnection(context, openPgpProviderPackage, new OnBound() { @Override public void onBound(IOpenPgpService2 service) { Loading @@ -195,7 +204,8 @@ public class MessageCryptoHelper { public void onError(Exception e) { Log.e(K9.LOG_TAG, "Couldn't connect to OpenPgpService", e); } }).bindToService(); }); openPgpServiceConnection.bindToService(); } private void decryptOrVerifyPart(CryptoPart cryptoPart) { Loading Loading @@ -250,6 +260,7 @@ public class MessageCryptoHelper { @Override public void onReturn(Intent result, MimeBodyPart bodyPart) { cancelableBackgroundOperation = null; currentCryptoResult = result; onCryptoOperationReturned(bodyPart); } Loading Loading @@ -289,6 +300,7 @@ public class MessageCryptoHelper { new IOpenPgpSinkResultCallback<MimeBodyPart>() { @Override public void onReturn(Intent result, MimeBodyPart decryptedPart) { cancelableBackgroundOperation = null; currentCryptoResult = result; onCryptoOperationReturned(decryptedPart); } Loading @@ -310,6 +322,7 @@ public class MessageCryptoHelper { openPgpApi.executeApiAsync(intent, dataSource, new IOpenPgpSinkResultCallback<Void>() { @Override public void onReturn(Intent result, Void dummy) { cancelableBackgroundOperation = null; currentCryptoResult = result; onCryptoOperationReturned(null); } Loading Loading @@ -470,7 +483,7 @@ public class MessageCryptoHelper { CryptoResultAnnotation resultAnnotation = CryptoResultAnnotation.createOpenPgpResultAnnotation( decryptionResult, signatureResult, pendingIntent, outputPart); onCryptoSuccess(resultAnnotation); onCryptoOperationSuccess(resultAnnotation); } public void onActivityResult(int requestCode, int resultCode, Intent data) { Loading @@ -489,7 +502,7 @@ public class MessageCryptoHelper { } } private void onCryptoSuccess(CryptoResultAnnotation resultAnnotation) { private void onCryptoOperationSuccess(CryptoResultAnnotation resultAnnotation) { addCryptoResultAnnotationToMessage(resultAnnotation); onCryptoFinished(); } Loading Loading @@ -525,6 +538,7 @@ public class MessageCryptoHelper { } private void onCryptoFinished() { currentCryptoPart = null; partsToDecryptOrVerify.removeFirst(); decryptOrVerifyNextPart(); } Loading @@ -538,7 +552,14 @@ public class MessageCryptoHelper { runSecondPass(); } private final Object callbackLock = new Object(); private void cleanupAfterProcessingFinished() { partsToDecryptOrVerify = null; openPgpApi = null; if (openPgpServiceConnection != null) { openPgpServiceConnection.unbindFromService(); } openPgpServiceConnection = null; } public void detachCallback() { synchronized (callbackLock) { Loading @@ -546,7 +567,10 @@ public class MessageCryptoHelper { } } public void reattachCallback(MessageCryptoCallback callback) { private void reattachCallback(LocalMessage message, MessageCryptoCallback callback) { if (!message.equals(currentMessage)) { throw new AssertionError("Callback may only be reattached for the same message!"); } synchronized (callbackLock) { this.callback = callback; deliverResult(); Loading @@ -562,7 +586,11 @@ public class MessageCryptoHelper { private void callbackReturnResult() { synchronized (callbackLock) { queuedMessageAnnotations = messageAnnotations; cleanupAfterProcessingFinished(); queuedResult = messageAnnotations; messageAnnotations = null; deliverResult(); } } Loading @@ -585,8 +613,8 @@ public class MessageCryptoHelper { Log.d(K9.LOG_TAG, "Keeping crypto helper result in queue for later delivery"); return; } if (queuedMessageAnnotations != null) { callback.onCryptoOperationsFinished(queuedMessageAnnotations); if (queuedResult != null) { callback.onCryptoOperationsFinished(queuedResult); } else if (queuedPendingIntent != null) { callback.startPendingIntentForCryptoHelper( queuedPendingIntent.getIntentSender(), REQUEST_CODE_USER_INTERACTION, null, 0, 0, 0); Loading
k9mail/src/main/java/com/fsck/k9/ui/messageview/MessageViewFragment.java +38 −3 Original line number Diff line number Diff line Loading @@ -44,6 +44,7 @@ import com.fsck.k9.fragment.ConfirmationDialogFragment.ConfirmationDialogFragmen import com.fsck.k9.fragment.ProgressDialogFragment; import com.fsck.k9.helper.FileBrowserHelper; import com.fsck.k9.helper.FileBrowserHelper.FileBrowserFailOverCallback; import com.fsck.k9.helper.RetainFragment; import com.fsck.k9.mail.Flag; import com.fsck.k9.mail.MessagingException; import com.fsck.k9.mailstore.AttachmentViewInfo; Loading Loading @@ -73,6 +74,7 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF public static final int REQUEST_MASK_CRYPTO_HELPER = 1 << 8; public static final int REQUEST_MASK_CRYPTO_PRESENTER = 2 << 8; private RetainFragment<MessageCryptoHelper> retainCryptoHelperFragment; public static MessageViewFragment newInstance(MessageReference reference) { MessageViewFragment fragment = new MessageViewFragment(); Loading Loading @@ -145,12 +147,32 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF mInitialized = true; } @Override public void onDestroy() { super.onDestroy(); Activity activity = getActivity(); boolean isChangingConfigurations = activity != null && activity.isChangingConfigurations(); if (isChangingConfigurations) { messageCryptoHelper.detachCallback(); return; } if (messageCryptoHelper != null) { cancelAndClearMessageCryptoHelper(); } } @UiThread private void cancelAndClearMessageCryptoHelper() { if (messageCryptoHelper != null) { messageCryptoHelper.cancelIfRunning(); messageCryptoHelper = null; } if (retainCryptoHelperFragment != null) { retainCryptoHelperFragment.clearAndRemove(getFragmentManager()); retainCryptoHelperFragment = null; } } @Override Loading Loading @@ -250,14 +272,25 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF } if (mAccount.isOpenPgpProviderConfigured()) { messageCryptoHelper = new MessageCryptoHelper(getActivity(), mAccount.getOpenPgpProvider(), this); messageCryptoHelper.decryptOrVerifyMessagePartsIfNecessary(message); startOrResumeProcessingInCryptoHelper(message); return; } startExtractingTextAndAttachments(); } private void startOrResumeProcessingInCryptoHelper(LocalMessage message) { retainCryptoHelperFragment = RetainFragment.findOrCreate(getFragmentManager(), "crypto_helper_" + message.hashCode()); if (retainCryptoHelperFragment.hasData()) { messageCryptoHelper = retainCryptoHelperFragment.getData(); } else { messageCryptoHelper = new MessageCryptoHelper(getActivity(), mAccount.getOpenPgpProvider()); retainCryptoHelperFragment.setData(messageCryptoHelper); } messageCryptoHelper.asyncStartOrResumeProcessingMessage(message, this); } private void onLoadMessageFromDatabaseFailed() { // mMessageView.showStatusMessage(mContext.getString(R.string.status_invalid_id_error)); } Loading @@ -273,6 +306,7 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF LoaderManager loaderManager = getLoaderManager(); loaderManager.destroyLoader(LOCAL_MESSAGE_LOADER_ID); loaderManager.destroyLoader(DECODE_MESSAGE_LOADER_ID); cancelAndClearMessageCryptoHelper(); onLoadMessageFromDatabaseFinished(mMessage); } Loading Loading @@ -751,7 +785,8 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF @Override public void restartMessageCryptoProcessing() { messageCryptoHelper.decryptOrVerifyMessagePartsIfNecessary(mMessage); cancelAndClearMessageCryptoHelper(); startOrResumeProcessingInCryptoHelper(mMessage); } @Override Loading