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

Commit 573bfc4b authored by Vincent Breitmoser's avatar Vincent Breitmoser Committed by Vincent Breitmoser
Browse files

messageview: make MessageCryptoHelper detachable

parent 68e31a98
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -9,5 +9,5 @@ public interface MessageCryptoCallback {
    void onCryptoHelperProgress(int current, int max);
    void onCryptoOperationsFinished(MessageCryptoAnnotations annotations);
    void startPendingIntentForCryptoHelper(IntentSender si, int requestCode, Intent fillIntent,
            int flagsMask, int flagValues, int extraFlags) throws IntentSender.SendIntentException;
            int flagsMask, int flagValues, int extraFlags);
}
+73 −25
Original line number Diff line number Diff line
@@ -13,7 +13,6 @@ import android.app.Activity;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.IntentSender.SendIntentException;
import android.support.annotation.Nullable;
import android.support.annotation.WorkerThread;
import android.util.Log;
@@ -58,8 +57,9 @@ public class MessageCryptoHelper {


    private final Context context;
    private final MessageCryptoCallback callback;
    private final Account account;
    private final String openPgpProviderPackage;
    @Nullable
    private MessageCryptoCallback callback;

    private Deque<CryptoPart> partsToDecryptOrVerify = new ArrayDeque<>();
    private OpenPgpApi openPgpApi;
@@ -71,21 +71,23 @@ public class MessageCryptoHelper {
    private LocalMessage currentMessage;
    private boolean secondPassStarted;
    private CancelableBackgroundOperation cancelableBackgroundOperation;
    private PendingIntent queuedPendingIntent;
    private MessageCryptoAnnotations queuedMessageAnnotations;
    private boolean isCancelled;


    public MessageCryptoHelper(Activity activity, Account account, MessageCryptoCallback callback) {
        this.context = activity.getApplicationContext();
    public MessageCryptoHelper(Context context, String openPgpProviderPackage,
            @Nullable MessageCryptoCallback callback) {
        this.context = context.getApplicationContext();
        this.callback = callback;
        this.account = account;
    }
        this.openPgpProviderPackage = openPgpProviderPackage;

    public void decryptOrVerifyMessagePartsIfNecessary(LocalMessage message) {
        if (!account.isOpenPgpProviderConfigured()) {
            returnResultToFragment();
            return;
        if (openPgpProviderPackage == null || Account.NO_OPENPGP_PROVIDER.equals(openPgpProviderPackage)) {
            throw new IllegalStateException("MessageCryptoHelper must only be called with a openpgp provider!");
        }
    }

    public void decryptOrVerifyMessagePartsIfNecessary(LocalMessage message) {
        this.messageAnnotations = new MessageCryptoAnnotations();
        this.currentMessage = message;

@@ -180,8 +182,7 @@ public class MessageCryptoHelper {
    }

    private void connectToCryptoProviderService() {
        String openPgpProvider = account.getOpenPgpProvider();
        new OpenPgpServiceConnection(context, openPgpProvider,
        new OpenPgpServiceConnection(context, openPgpProviderPackage,
                new OnBound() {
                    @Override
                    public void onBound(IOpenPgpService2 service) {
@@ -244,7 +245,7 @@ public class MessageCryptoHelper {
            @Override
            public void onProgress(int current, int max) {
                Log.d(K9.LOG_TAG, "received progress status: " + current + " / " + max);
                callback.onCryptoHelperProgress(current, max);
                callbackProgress(current, max);
            }

            @Override
@@ -295,7 +296,7 @@ public class MessageCryptoHelper {
            @Override
            public void onProgress(int current, int max) {
                Log.d(K9.LOG_TAG, "received progress status: " + current + " / " + max);
                callback.onCryptoHelperProgress(current, max);
                callbackProgress(current, max);
            }
        });
    }
@@ -316,7 +317,7 @@ public class MessageCryptoHelper {
            @Override
            public void onProgress(int current, int max) {
                Log.d(K9.LOG_TAG, "received progress status: " + current + " / " + max);
                callback.onCryptoHelperProgress(current, max);
                callbackProgress(current, max);
            }
        });
    }
@@ -447,12 +448,7 @@ public class MessageCryptoHelper {
            throw new AssertionError("Expecting PendingIntent on USER_INTERACTION_REQUIRED!");
        }

        try {
            callback.startPendingIntentForCryptoHelper(
                    pendingIntent.getIntentSender(), REQUEST_CODE_USER_INTERACTION, null, 0, 0, 0);
        } catch (SendIntentException e) {
            Log.e(K9.LOG_TAG, "Internal error on starting pendingintent!", e);
        }
        callbackPendingIntent(pendingIntent);
    }

    private void handleCryptoOperationError() {
@@ -535,15 +531,67 @@ public class MessageCryptoHelper {

    private void runSecondPassOrReturnResultToFragment() {
        if (secondPassStarted) {
            callback.onCryptoOperationsFinished(messageAnnotations);
            callbackReturnResult();
            return;
        }
        secondPassStarted = true;
        runSecondPass();
    }

    private void returnResultToFragment() {
        callback.onCryptoOperationsFinished(messageAnnotations);
    private final Object callbackLock = new Object();

    public void detachCallback() {
        synchronized (callbackLock) {
            callback = null;
        }
    }

    public void reattachCallback(MessageCryptoCallback callback) {
        synchronized (callbackLock) {
            this.callback = callback;
            deliverResult();
        }
    }

    private void callbackPendingIntent(PendingIntent pendingIntent) {
        synchronized (callbackLock) {
            queuedPendingIntent = pendingIntent;
            deliverResult();
        }
    }

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

    private void callbackProgress(int current, int max) {
        synchronized (callbackLock) {
            if (callback != null) {
                callback.onCryptoHelperProgress(current, max);
            }
        }
    }

    // This method must only be called inside a synchronized(callbackLock) block!
    private void deliverResult() {
        if (isCancelled) {
            return;
        }

        if (callback == null) {
            Log.d(K9.LOG_TAG, "Keeping crypto helper result in queue for later delivery");
            return;
        }
        if (queuedMessageAnnotations != null) {
            callback.onCryptoOperationsFinished(queuedMessageAnnotations);
        } else if (queuedPendingIntent != null) {
            callback.startPendingIntentForCryptoHelper(
                    queuedPendingIntent.getIntentSender(), REQUEST_CODE_USER_INTERACTION, null, 0, 0, 0);
            queuedPendingIntent = null;
        }
    }

    private static class CryptoPart {
+19 −12
Original line number Diff line number Diff line
@@ -200,10 +200,7 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF
            Log.d(K9.LOG_TAG, "MessageView displaying message " + mMessageReference);
        }

        Activity activity = getActivity();
        Context appContext = activity.getApplicationContext();
        mAccount = Preferences.getPreferences(appContext).getAccount(mMessageReference.getAccountUuid());
        messageCryptoHelper = new MessageCryptoHelper(activity, mAccount, this);
        mAccount = Preferences.getPreferences(getApplicationContext()).getAccount(mMessageReference.getAccountUuid());

        startLoadingMessageFromDatabase();

@@ -245,14 +242,20 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF
    @UiThread
    private void onLoadMessageFromDatabaseFinished(LocalMessage message) {
        displayMessageHeader(message);

        mMessageView.setToLoadingState();

        if (message.isBodyMissing()) {
            startDownloadingMessageBody();
        } else {
            return;
        }

        if (mAccount.isOpenPgpProviderConfigured()) {
            messageCryptoHelper = new MessageCryptoHelper(getActivity(), mAccount.getOpenPgpProvider(), this);
            messageCryptoHelper.decryptOrVerifyMessagePartsIfNecessary(message);
            return;
        }

        startExtractingTextAndAttachments();
    }

    private void onLoadMessageFromDatabaseFailed() {
@@ -292,11 +295,11 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF

    @Override
    public void onCryptoOperationsFinished(MessageCryptoAnnotations annotations) {
        startExtractingTextAndAttachments(annotations);
        this.messageAnnotations = annotations;
        startExtractingTextAndAttachments();
    }

    private void startExtractingTextAndAttachments(MessageCryptoAnnotations annotations) {
        this.messageAnnotations = annotations;
    private void startExtractingTextAndAttachments() {
        getLoaderManager().restartLoader(DECODE_MESSAGE_LOADER_ID, null, decodeMessageLoaderCallback);
    }

@@ -753,10 +756,14 @@ public class MessageViewFragment extends Fragment implements ConfirmationDialogF

    @Override
    public void startPendingIntentForCryptoHelper(IntentSender si, int requestCode, Intent fillIntent,
            int flagsMask, int flagValues, int extraFlags) throws SendIntentException {
            int flagsMask, int flagValues, int extraFlags) {
        requestCode |= REQUEST_MASK_CRYPTO_HELPER;
        try {
            getActivity().startIntentSenderForResult(
                    si, requestCode, fillIntent, flagsMask, flagValues, extraFlags);
        } catch (SendIntentException e) {
            Log.e(K9.LOG_TAG, "Irrecoverable error calling PendingIntent!", e);
        }
    }

    public interface MessageViewFragmentListener {