Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 675b1673 authored by Vincent Breitmoser's avatar Vincent Breitmoser Committed by Vincent Breitmoser
Browse files

messageview: retain MessageCryptoHelper over configuration changes

parent 573bfc4b
Loading
Loading
Loading
Loading
+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
+47 −19
Original line number Diff line number Diff line
@@ -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)) {
@@ -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();
    }
@@ -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) {
@@ -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) {
@@ -250,6 +260,7 @@ public class MessageCryptoHelper {

            @Override
            public void onReturn(Intent result, MimeBodyPart bodyPart) {
                cancelableBackgroundOperation = null;
                currentCryptoResult = result;
                onCryptoOperationReturned(bodyPart);
            }
@@ -289,6 +300,7 @@ public class MessageCryptoHelper {
                new IOpenPgpSinkResultCallback<MimeBodyPart>() {
            @Override
            public void onReturn(Intent result, MimeBodyPart decryptedPart) {
                cancelableBackgroundOperation = null;
                currentCryptoResult = result;
                onCryptoOperationReturned(decryptedPart);
            }
@@ -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);
            }
@@ -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) {
@@ -489,7 +502,7 @@ public class MessageCryptoHelper {
        }
    }

    private void onCryptoSuccess(CryptoResultAnnotation resultAnnotation) {
    private void onCryptoOperationSuccess(CryptoResultAnnotation resultAnnotation) {
        addCryptoResultAnnotationToMessage(resultAnnotation);
        onCryptoFinished();
    }
@@ -525,6 +538,7 @@ public class MessageCryptoHelper {
    }

    private void onCryptoFinished() {
        currentCryptoPart = null;
        partsToDecryptOrVerify.removeFirst();
        decryptOrVerifyNextPart();
    }
@@ -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) {
@@ -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();
@@ -562,7 +586,11 @@ public class MessageCryptoHelper {

    private void callbackReturnResult() {
        synchronized (callbackLock) {
            queuedMessageAnnotations = messageAnnotations;
            cleanupAfterProcessingFinished();

            queuedResult = messageAnnotations;
            messageAnnotations = null;

            deliverResult();
        }
    }
@@ -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);
+38 −3
Original line number Diff line number Diff line
@@ -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;
@@ -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();
@@ -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
@@ -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));
    }
@@ -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);
    }
@@ -751,7 +785,8 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF

    @Override
    public void restartMessageCryptoProcessing() {
        messageCryptoHelper.decryptOrVerifyMessagePartsIfNecessary(mMessage);
        cancelAndClearMessageCryptoHelper();
        startOrResumeProcessingInCryptoHelper(mMessage);
    }

    @Override