package com.fsck.k9.activity.compose;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import android.app.Activity;
import android.app.LoaderManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.VisibleForTesting;
import android.text.TextUtils;
import timber.log.Timber;
import android.view.Menu;
import com.fsck.k9.Account;
import com.fsck.k9.Identity;
import com.fsck.k9.K9;
import com.fsck.k9.R;
import com.fsck.k9.activity.compose.ComposeCryptoStatus.AttachErrorState;
import com.fsck.k9.activity.compose.ComposeCryptoStatus.ComposeCryptoStatusBuilder;
import com.fsck.k9.activity.compose.ComposeCryptoStatus.SendErrorState;
import com.fsck.k9.helper.Contacts;
import com.fsck.k9.helper.MailTo;
import com.fsck.k9.helper.ReplyToParser;
import com.fsck.k9.helper.ReplyToParser.ReplyToAddresses;
import com.fsck.k9.mail.Address;
import com.fsck.k9.mail.Flag;
import com.fsck.k9.mail.Message;
import com.fsck.k9.mail.Message.RecipientType;
import com.fsck.k9.message.ComposePgpInlineDecider;
import com.fsck.k9.message.PgpMessageBuilder;
import com.fsck.k9.view.RecipientSelectView.Recipient;
import org.openintents.openpgp.IOpenPgpService2;
import org.openintents.openpgp.util.OpenPgpApi;
import org.openintents.openpgp.util.OpenPgpApi.PermissionPingCallback;
import org.openintents.openpgp.util.OpenPgpServiceConnection;
import org.openintents.openpgp.util.OpenPgpServiceConnection.OnBound;
public class RecipientPresenter implements PermissionPingCallback {
private static final String STATE_KEY_CC_SHOWN = "state:ccShown";
private static final String STATE_KEY_BCC_SHOWN = "state:bccShown";
private static final String STATE_KEY_LAST_FOCUSED_TYPE = "state:lastFocusedType";
private static final String STATE_KEY_CURRENT_CRYPTO_MODE = "state:currentCryptoMode";
private static final String STATE_KEY_CRYPTO_ENABLE_PGP_INLINE = "state:cryptoEnablePgpInline";
private static final int CONTACT_PICKER_TO = 1;
private static final int CONTACT_PICKER_CC = 2;
private static final int CONTACT_PICKER_BCC = 3;
private static final int OPENPGP_USER_INTERACTION = 4;
private static final int PGP_DIALOG_DISPLAY_THRESHOLD = 2;
// transient state, which is either obtained during construction and initialization, or cached
private final Context context;
private final RecipientMvpView recipientMvpView;
private final ComposePgpInlineDecider composePgpInlineDecider;
private final RecipientsChangedListener listener;
private ReplyToParser replyToParser;
private Account account;
private String openPgpProvider;
private Boolean hasContactPicker;
private ComposeCryptoStatus cachedCryptoStatus;
private PendingIntent pendingUserInteractionIntent;
private CryptoProviderState cryptoProviderState = CryptoProviderState.UNCONFIGURED;
private OpenPgpServiceConnection openPgpServiceConnection;
// persistent state, saved during onSaveInstanceState
private RecipientType lastFocusedType = RecipientType.TO;
// TODO initialize cryptoMode to other values under some circumstances, e.g. if we reply to an encrypted e-mail
private CryptoMode currentCryptoMode = CryptoMode.OPPORTUNISTIC;
private boolean cryptoEnablePgpInline = false;
public RecipientPresenter(Context context, LoaderManager loaderManager, RecipientMvpView recipientMvpView,
Account account, ComposePgpInlineDecider composePgpInlineDecider, ReplyToParser replyToParser,
RecipientsChangedListener recipientsChangedListener) {
this.recipientMvpView = recipientMvpView;
this.context = context;
this.composePgpInlineDecider = composePgpInlineDecider;
this.replyToParser = replyToParser;
this.listener = recipientsChangedListener;
recipientMvpView.setPresenter(this);
recipientMvpView.setLoaderManager(loaderManager);
onSwitchAccount(account);
}
public List<Address> getToAddresses() {
return recipientMvpView.getToAddresses();
}
public List<Address> getCcAddresses() {
return recipientMvpView.getCcAddresses();
}
public List<Address> getBccAddresses() {
return recipientMvpView.getBccAddresses();
}
private List<Recipient> getAllRecipients() {
ArrayList<Recipient> result = new ArrayList<>();
result.addAll(recipientMvpView.getToRecipients());
result.addAll(recipientMvpView.getCcRecipients());
result.addAll(recipientMvpView.getBccRecipients());
return result;
}
public boolean checkRecipientsOkForSending() {
recipientMvpView.recipientToTryPerformCompletion();
recipientMvpView.recipientCcTryPerformCompletion();
recipientMvpView.recipientBccTryPerformCompletion();
if (recipientMvpView.recipientToHasUncompletedText()) {
recipientMvpView.showToUncompletedError();
return true;
}
if (recipientMvpView.recipientCcHasUncompletedText()) {
recipientMvpView.showCcUncompletedError();
return true;
}
if (recipientMvpView.recipientBccHasUncompletedText()) {
recipientMvpView.showBccUncompletedError();
return true;
}
if (getToAddresses().isEmpty() && getCcAddresses().isEmpty() && getBccAddresses().isEmpty()) {
recipientMvpView.showNoRecipientsError();
return true;
}
return false;
}
public void initFromReplyToMessage(Message message, boolean isReplyAll) {
ReplyToAddresses replyToAddresses = isReplyAll ?
replyToParser.getRecipientsToReplyAllTo(message, account) :
replyToParser.getRecipientsToReplyTo(message, account);
addToAddresses(replyToAddresses.to);
addCcAddresses(replyToAddresses.cc);
boolean shouldSendAsPgpInline = composePgpInlineDecider.shouldReplyInline(message);
if (shouldSendAsPgpInline) {
cryptoEnablePgpInline = true;
}
}
public void initFromMailto(MailTo mailTo) {
addToAddresses(mailTo.getTo());
addCcAddresses(mailTo.getCc());
addBccAddresses(mailTo.getBcc());
}
public void initFromSendOrViewIntent(Intent intent) {
String[] extraEmail = intent.getStringArrayExtra(Intent.EXTRA_EMAIL);
String[] extraCc = intent.getStringArrayExtra(Intent.EXTRA_CC);
String[] extraBcc = intent.getStringArrayExtra(Intent.EXTRA_BCC);
if (extraEmail != null) {
addToAddresses(addressFromStringArray(extraEmail));
}
if (extraCc != null) {
addCcAddresses(addressFromStringArray(extraCc));
}
if (extraBcc != null) {
addBccAddresses(addressFromStringArray(extraBcc));
}
}
public void onRestoreInstanceState(Bundle savedInstanceState) {
recipientMvpView.setCcVisibility(savedInstanceState.getBoolean(STATE_KEY_CC_SHOWN));
recipientMvpView.setBccVisibility(savedInstanceState.getBoolean(STATE_KEY_BCC_SHOWN));
lastFocusedType = RecipientType.valueOf(savedInstanceState.getString(STATE_KEY_LAST_FOCUSED_TYPE));
currentCryptoMode = CryptoMode.valueOf(savedInstanceState.getString(STATE_KEY_CURRENT_CRYPTO_MODE));
cryptoEnablePgpInline = savedInstanceState.getBoolean(STATE_KEY_CRYPTO_ENABLE_PGP_INLINE);
updateRecipientExpanderVisibility();
}
public void onSaveInstanceState(Bundle outState) {
outState.putBoolean(STATE_KEY_CC_SHOWN, recipientMvpView.isCcVisible());
outState.putBoolean(STATE_KEY_BCC_SHOWN, recipientMvpView.isBccVisible());
outState.putString(STATE_KEY_LAST_FOCUSED_TYPE, lastFocusedType.toString());
outState.putString(STATE_KEY_CURRENT_CRYPTO_MODE, currentCryptoMode.toString());
outState.putBoolean(STATE_KEY_CRYPTO_ENABLE_PGP_INLINE, cryptoEnablePgpInline);
}
public void initFromDraftMessage(Message message) {
initRecipientsFromDraftMessage(message);
initPgpInlineFromDraftMessage(message);
}
private void initRecipientsFromDraftMessage(Message message) {
addToAddresses(message.getRecipients(RecipientType.TO));
Address[] ccRecipients = message.getRecipients(RecipientType.CC);
addCcAddresses(ccRecipients);
Address[] bccRecipients = message.getRecipients(RecipientType.BCC);
addBccAddresses(bccRecipients);
}
private void initPgpInlineFromDraftMessage(Message message) {
cryptoEnablePgpInline = message.isSet(Flag.X_DRAFT_OPENPGP_INLINE);
}
private void addToAddresses(Address... toAddresses) {
addRecipientsFromAddresses(RecipientType.TO, toAddresses);
}
private void addCcAddresses(Address... ccAddresses) {
if (ccAddresses.length > 0) {
addRecipientsFromAddresses(RecipientType.CC, ccAddresses);
recipientMvpView.setCcVisibility(true);
updateRecipientExpanderVisibility();
}
}
public void addBccAddresses(Address... bccRecipients) {
if (bccRecipients.length > 0) {
addRecipientsFromAddresses(RecipientType.BCC, bccRecipients);
String bccAddress = account.getAlwaysBcc();
// If the auto-bcc is the only entry in the BCC list, don't show the Bcc fields.
boolean alreadyVisible = recipientMvpView.isBccVisible();
boolean singleBccRecipientFromAccount =
bccRecipients.length == 1 && bccRecipients[0].toString().equals(bccAddress);
recipientMvpView.setBccVisibility(alreadyVisible || !singleBccRecipientFromAccount);
updateRecipientExpanderVisibility();
}
}
public void onPrepareOptionsMenu(Menu menu) {
boolean isCryptoConfigured = cryptoProviderState != CryptoProviderState.UNCONFIGURED;
menu.findItem(R.id.openpgp_inline_enable).setVisible(isCryptoConfigured && !cryptoEnablePgpInline);
menu.findItem(R.id.openpgp_inline_disable).setVisible(isCryptoConfigured && cryptoEnablePgpInline);
boolean showSignOnly = isCryptoConfigured && K9.getOpenPgpSupportSignOnly();
boolean isSignOnly = cachedCryptoStatus.isSignOnly();
menu.findItem(R.id.openpgp_sign_only).setVisible(showSignOnly && !isSignOnly);
menu.findItem(R.id.openpgp_sign_only_disable).setVisible(showSignOnly && isSignOnly);
boolean noContactPickerAvailable = !hasContactPicker();
if (noContactPickerAvailable) {
menu.findItem(R.id.add_from_contacts).setVisible(false);
}
}
public void onSwitchAccount(Account account) {
this.account = account;
if (account.isAlwaysShowCcBcc()) {
recipientMvpView.setCcVisibility(true);
recipientMvpView.setBccVisibility(true);
updateRecipientExpanderVisibility();
}
// This does not strictly depend on the account, but this is as good a point to set this as any
setupCryptoProvider();
}
@SuppressWarnings("UnusedParameters")
public void onSwitchIdentity(Identity identity) {
// TODO decide what actually to do on identity switch?
/*
if (mIdentityChanged) {
mBccWrapper.setVisibility(View.VISIBLE);
}
mBccView.setText("");
mBccView.addAddress(new Address(mAccount.getAlwaysBcc(), ""));
*/
}
private static Address[] addressFromStringArray(String[] addresses) {
return addressFromStringArray(Arrays.asList(addresses));
}
private static Address[] addressFromStringArray(List<String> addresses) {
ArrayList<Address> result = new ArrayList<>(addresses.size());
for (String addressStr : addresses) {
Collections.addAll(result, Address.parseUnencoded(addressStr));
}
return result.toArray(new Address[result.size()]);
}
void onClickToLabel() {
recipientMvpView.requestFocusOnToField();
}
void onClickCcLabel() {
recipientMvpView.requestFocusOnCcField();
}
void onClickBccLabel() {
recipientMvpView.requestFocusOnBccField();
}
void onClickRecipientExpander() {
recipientMvpView.setCcVisibility(true);
recipientMvpView.setBccVisibility(true);
updateRecipientExpanderVisibility();
}
private void hideEmptyExtendedRecipientFields() {
if (recipientMvpView.getCcAddresses().isEmpty()) {
recipientMvpView.setCcVisibility(false);
if (lastFocusedType == RecipientType.CC) {
lastFocusedType = RecipientType.TO;
}
}
if (recipientMvpView.getBccAddresses().isEmpty()) {
recipientMvpView.setBccVisibility(false);
if (lastFocusedType == RecipientType.BCC) {
lastFocusedType = RecipientType.TO;
}
}
updateRecipientExpanderVisibility();
}
private void updateRecipientExpanderVisibility() {
boolean notBothAreVisible = !(recipientMvpView.isCcVisible() && recipientMvpView.isBccVisible());
recipientMvpView.setRecipientExpanderVisibility(notBothAreVisible);
}
public void updateCryptoStatus() {
cachedCryptoStatus = null;
boolean isOkStateButLostConnection = cryptoProviderState == CryptoProviderState.OK &&
(openPgpServiceConnection == null || !openPgpServiceConnection.isBound());
if (isOkStateButLostConnection) {
cryptoProviderState = CryptoProviderState.LOST_CONNECTION;
pendingUserInteractionIntent = null;
}
recipientMvpView.showCryptoStatus(getCurrentCryptoStatus().getCryptoStatusDisplayType());
recipientMvpView.showCryptoSpecialMode(getCurrentCryptoStatus().getCryptoSpecialModeDisplayType());
}
public ComposeCryptoStatus getCurrentCryptoStatus() {
if (cachedCryptoStatus == null) {
ComposeCryptoStatusBuilder builder = new ComposeCryptoStatusBuilder()
.setCryptoProviderState(cryptoProviderState)
.setCryptoMode(currentCryptoMode)
.setEnablePgpInline(cryptoEnablePgpInline)
.setRecipients(getAllRecipients());
long accountCryptoKey = account.getCryptoKey();
if (accountCryptoKey != Account.NO_OPENPGP_KEY) {
// TODO split these into individual settings? maybe after key is bound to identity
builder.setSigningKeyId(accountCryptoKey);
builder.setSelfEncryptId(accountCryptoKey);
}
cachedCryptoStatus = builder.build();
}
return cachedCryptoStatus;
}
public boolean isForceTextMessageFormat() {
if (cryptoEnablePgpInline) {
ComposeCryptoStatus cryptoStatus = getCurrentCryptoStatus();
return cryptoStatus.isEncryptionEnabled() || cryptoStatus.isSigningEnabled();
} else {
return false;
}
}
void onToTokenAdded() {
updateCryptoStatus();
listener.onRecipientsChanged();
}
void onToTokenRemoved() {
updateCryptoStatus();
listener.onRecipientsChanged();
}
void onToTokenChanged() {
updateCryptoStatus();
listener.onRecipientsChanged();
}
void onCcTokenAdded() {
updateCryptoStatus();
listener.onRecipientsChanged();
}
void onCcTokenRemoved() {
updateCryptoStatus();
listener.onRecipientsChanged();
}
void onCcTokenChanged() {
updateCryptoStatus();
listener.onRecipientsChanged();
}
void onBccTokenAdded() {
updateCryptoStatus();
listener.onRecipientsChanged();
}
void onBccTokenRemoved() {
updateCryptoStatus();
listener.onRecipientsChanged();
}
void onBccTokenChanged() {
updateCryptoStatus();
listener.onRecipientsChanged();
}
public void onCryptoModeChanged(CryptoMode cryptoMode) {
currentCryptoMode = cryptoMode;
updateCryptoStatus();
}
public void onCryptoPgpInlineChanged(boolean enablePgpInline) {
cryptoEnablePgpInline = enablePgpInline;
updateCryptoStatus();
}
private void addRecipientsFromAddresses(final RecipientType recipientType, final Address... addresses) {
new RecipientLoader(context, openPgpProvider, addresses) {
@Override
public void deliverResult(List<Recipient> result) {
Recipient[] recipientArray = result.toArray(new Recipient[result.size()]);
recipientMvpView.addRecipients(recipientType, recipientArray);
stopLoading();
abandon();
}
}.startLoading();
}
private void addRecipientFromContactUri(final RecipientType recipientType, final Uri uri) {
new RecipientLoader(context, openPgpProvider, uri, false) {
@Override
public void deliverResult(List<Recipient> result) {
// TODO handle multiple available mail addresses for a contact?
if (result.isEmpty()) {
recipientMvpView.showErrorContactNoAddress();
return;
}
Recipient recipient = result.get(0);
recipientMvpView.addRecipients(recipientType, recipient);
stopLoading();
abandon();
}
}.startLoading();
}
void onToFocused() {
lastFocusedType = RecipientType.TO;
}
void onCcFocused() {
lastFocusedType = RecipientType.CC;
}
void onBccFocused() {
lastFocusedType = RecipientType.BCC;
}
public void onMenuAddFromContacts() {
int requestCode = recipientTypeToRequestCode(lastFocusedType);
recipientMvpView.showContactPicker(requestCode);
}
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case CONTACT_PICKER_TO:
case CONTACT_PICKER_CC:
case CONTACT_PICKER_BCC:
if (resultCode != Activity.RESULT_OK || data == null) {
return;
}
RecipientType recipientType = recipientTypeFromRequestCode(requestCode);
addRecipientFromContactUri(recipientType, data.getData());
break;
case OPENPGP_USER_INTERACTION:
cryptoProviderBindOrCheckPermission();
break;
}
}
private static int recipientTypeToRequestCode(RecipientType type) {
switch (type) {
case TO: {
return CONTACT_PICKER_TO;
}
case CC: {
return CONTACT_PICKER_CC;
}
case BCC: {
return CONTACT_PICKER_BCC;
}
}
throw new AssertionError("Unhandled case: " + type);
}
private static RecipientType recipientTypeFromRequestCode(int type) {
switch (type) {
case CONTACT_PICKER_TO: {
return RecipientType.TO;
}
case CONTACT_PICKER_CC: {
return RecipientType.CC;
}
case CONTACT_PICKER_BCC: {
return RecipientType.BCC;
}
}
throw new AssertionError("Unhandled case: " + type);
}
public void onNonRecipientFieldFocused() {
if (!account.isAlwaysShowCcBcc()) {
hideEmptyExtendedRecipientFields();
}
}
void onClickCryptoStatus() {
switch (cryptoProviderState) {
case UNCONFIGURED:
Timber.e("click on crypto status while unconfigured - this should not really happen?!");
return;
case OK:
if (cachedCryptoStatus.isSignOnly()) {
recipientMvpView.showErrorIsSignOnly();
} else {
recipientMvpView.showCryptoDialog(currentCryptoMode);
}
return;
case LOST_CONNECTION:
case UNINITIALIZED:
case ERROR:
cryptoProviderBindOrCheckPermission();
}
}
/**
* Does the device actually have a Contacts application suitable for
* picking a contact. As hard as it is to believe, some vendors ship
* without it.
*
* @return True, if the device supports picking contacts. False, otherwise.
*/
private boolean hasContactPicker() {
if (hasContactPicker == null) {
Contacts contacts = Contacts.getInstance(context);
PackageManager packageManager = context.getPackageManager();
List<ResolveInfo> resolveInfoList = packageManager.queryIntentActivities(contacts.contactPickerIntent(), 0);
hasContactPicker = !resolveInfoList.isEmpty();
}
return hasContactPicker;
}
public void showPgpSendError(SendErrorState sendErrorState) {
switch (sendErrorState) {
case PROVIDER_ERROR:
recipientMvpView.showErrorOpenPgpConnection();
break;
case SIGN_KEY_NOT_CONFIGURED:
recipientMvpView.showErrorMissingSignKey();
break;
case PRIVATE_BUT_MISSING_KEYS:
recipientMvpView.showErrorPrivateButMissingKeys();
break;
default:
throw new AssertionError("not all error states handled, this is a bug!");
}
}
void showPgpAttachError(AttachErrorState attachErrorState) {
switch (attachErrorState) {
case IS_INLINE:
recipientMvpView.showErrorInlineAttach();
break;
default:
throw new AssertionError("not all error states handled, this is a bug!");
}
}
private void setupCryptoProvider() {
String openPgpProvider = K9.getOpenPgpProvider();
if (TextUtils.isEmpty(openPgpProvider)) {
openPgpProvider = null;
}
boolean providerIsBound = openPgpServiceConnection != null && openPgpServiceConnection.isBound();
boolean isSameProvider = openPgpProvider != null && openPgpProvider.equals(this.openPgpProvider);
if (isSameProvider && providerIsBound) {
cryptoProviderBindOrCheckPermission();
return;
}
if (providerIsBound) {
openPgpServiceConnection.unbindFromService();
openPgpServiceConnection = null;
}
this.openPgpProvider = openPgpProvider;
if (openPgpProvider == null) {
cryptoProviderState = CryptoProviderState.UNCONFIGURED;
return;
}
cryptoProviderState = CryptoProviderState.UNINITIALIZED;
openPgpServiceConnection = new OpenPgpServiceConnection(context, openPgpProvider, new OnBound() {
@Override
public void onBound(IOpenPgpService2 service) {
cryptoProviderBindOrCheckPermission();
}
@Override
public void onError(Exception e) {
onCryptoProviderError(e);
}
});
cryptoProviderBindOrCheckPermission();
recipientMvpView.setCryptoProvider(openPgpProvider);
}
private void cryptoProviderBindOrCheckPermission() {
if (openPgpServiceConnection == null) {
cryptoProviderState = CryptoProviderState.UNCONFIGURED;
return;
}
if (!openPgpServiceConnection.isBound()) {
pendingUserInteractionIntent = null;
openPgpServiceConnection.bindToService();
return;
}
if (pendingUserInteractionIntent != null) {
recipientMvpView
.launchUserInteractionPendingIntent(pendingUserInteractionIntent, OPENPGP_USER_INTERACTION);
pendingUserInteractionIntent = null;
return;
}
getOpenPgpApi().checkPermissionPing(this);
}
private void onCryptoProviderError(Exception e) {
// TODO handle error case better
recipientMvpView.showErrorOpenPgpConnection();
cryptoProviderState = CryptoProviderState.ERROR;
Timber.e(e, "error connecting to crypto provider!");
updateCryptoStatus();
}
@Override
public void onPgpPermissionCheckResult(Intent result) {
int resultCode = result.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR);
switch (resultCode) {
case OpenPgpApi.RESULT_CODE_SUCCESS:
cryptoProviderState = CryptoProviderState.OK;
break;
case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED:
recipientMvpView.showErrorOpenPgpUserInteractionRequired();
pendingUserInteractionIntent = result.getParcelableExtra(OpenPgpApi.RESULT_INTENT);
cryptoProviderState = CryptoProviderState.ERROR;
break;
case OpenPgpApi.RESULT_CODE_ERROR:
default:
recipientMvpView.showErrorOpenPgpConnection();
cryptoProviderState = CryptoProviderState.ERROR;
break;
}
updateCryptoStatus();
}
public void onActivityDestroy() {
if (openPgpServiceConnection != null && openPgpServiceConnection.isBound()) {
openPgpServiceConnection.unbindFromService();
}
openPgpServiceConnection = null;
}
private OpenPgpApi getOpenPgpApi() {
if (openPgpServiceConnection == null || !openPgpServiceConnection.isBound()) {
Timber.e("obtained openpgpapi object, but service is not bound! inconsistent state?");
}
return new OpenPgpApi(context, openPgpServiceConnection.getService());
}
public void builderSetProperties(PgpMessageBuilder pgpBuilder) {
pgpBuilder.setOpenPgpApi(getOpenPgpApi());
pgpBuilder.setCryptoStatus(getCurrentCryptoStatus());
}
public void onMenuSetPgpInline(boolean enablePgpInline) {
onCryptoPgpInlineChanged(enablePgpInline);
if (enablePgpInline) {
boolean shouldShowPgpInlineDialog = checkAndIncrementPgpInlineDialogCounter();
if (shouldShowPgpInlineDialog) {
recipientMvpView.showOpenPgpInlineDialog(true);
}
}
}
public void onMenuSetSignOnly(boolean enableSignOnly) {
if (enableSignOnly) {
onCryptoModeChanged(CryptoMode.SIGN_ONLY);
boolean shouldShowPgpSignOnlyDialog = checkAndIncrementPgpSignOnlyDialogCounter();
if (shouldShowPgpSignOnlyDialog) {
recipientMvpView.showOpenPgpSignOnlyDialog(true);
}
} else {
onCryptoModeChanged(CryptoMode.OPPORTUNISTIC);
}
}
public void onCryptoPgpSignOnlyDisabled() {
onCryptoPgpInlineChanged(false);
onCryptoModeChanged(CryptoMode.OPPORTUNISTIC);
}
private boolean checkAndIncrementPgpInlineDialogCounter() {
int pgpInlineDialogCounter = K9.getPgpInlineDialogCounter();
if (pgpInlineDialogCounter < PGP_DIALOG_DISPLAY_THRESHOLD) {
K9.setPgpInlineDialogCounter(pgpInlineDialogCounter + 1);
K9.saveSettingsAsync();
return true;
}
return false;
}
private boolean checkAndIncrementPgpSignOnlyDialogCounter() {
int pgpSignOnlyDialogCounter = K9.getPgpSignOnlyDialogCounter();
if (pgpSignOnlyDialogCounter < PGP_DIALOG_DISPLAY_THRESHOLD) {
K9.setPgpSignOnlyDialogCounter(pgpSignOnlyDialogCounter + 1);
K9.saveSettingsAsync();
return true;
}
return false;
}
void onClickCryptoSpecialModeIndicator() {
ComposeCryptoStatus currentCryptoStatus = getCurrentCryptoStatus();
if (currentCryptoStatus.isSignOnly()) {
recipientMvpView.showOpenPgpSignOnlyDialog(false);
} else if (currentCryptoStatus.isPgpInlineModeEnabled()) {
recipientMvpView.showOpenPgpInlineDialog(false);
} else {
throw new IllegalStateException("This icon should not be clickable while no special mode is active!");
}
}
@VisibleForTesting
void setOpenPgpServiceConnection(OpenPgpServiceConnection openPgpServiceConnection, String cryptoProvider) {
this.openPgpServiceConnection = openPgpServiceConnection;
this.openPgpProvider = cryptoProvider;
}
public enum CryptoProviderState {
UNCONFIGURED,
UNINITIALIZED,
LOST_CONNECTION,
ERROR,
OK
}
public enum CryptoMode {
DISABLE,
SIGN_ONLY,
OPPORTUNISTIC,
PRIVATE,
}
public static interface RecipientsChangedListener {
public void onRecipientsChanged();
}
}