Convert RecipientPresenter to Kotlin

This commit is contained in:
cketti 2021-08-31 03:13:15 +02:00
parent 9a0c6843a7
commit 5793d2e68f
4 changed files with 992 additions and 1230 deletions

View file

@ -58,6 +58,7 @@ dependencies {
testImplementation "org.robolectric:robolectric:${versions.robolectric}"
testImplementation "androidx.test:core:${versions.androidxTestCore}"
testImplementation "junit:junit:${versions.junit}"
testImplementation "org.jetbrains.kotlin:kotlin-test:${versions.kotlin}"
testImplementation "com.google.truth:truth:${versions.truth}"
testImplementation "org.mockito:mockito-core:${versions.mockito}"
testImplementation "org.mockito.kotlin:mockito-kotlin:${versions.mockitoKotlin}"

View file

@ -1,514 +1,387 @@
package com.fsck.k9.activity.compose;
package com.fsck.k9.activity.compose
import android.app.PendingIntent
import android.text.TextWatcher
import android.view.View
import android.widget.TextView
import android.widget.Toast
import android.widget.ViewAnimator
import androidx.core.view.isGone
import androidx.core.view.isVisible
import androidx.interpolator.view.animation.FastOutLinearInInterpolator
import androidx.interpolator.view.animation.LinearOutSlowInInterpolator
import androidx.loader.app.LoaderManager
import com.fsck.k9.FontSizes
import com.fsck.k9.activity.MessageCompose
import com.fsck.k9.mail.Address
import com.fsck.k9.mail.Message.RecipientType
import com.fsck.k9.ui.R
import com.fsck.k9.view.RecipientSelectView
import com.fsck.k9.view.RecipientSelectView.Recipient
import com.fsck.k9.view.ToolableViewAnimator
import java.lang.AssertionError
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
class RecipientMvpView(private val activity: MessageCompose) : View.OnFocusChangeListener, View.OnClickListener {
private val toView: RecipientSelectView = activity.findViewById(R.id.to)
private val ccView: RecipientSelectView = activity.findViewById(R.id.cc)
private val bccView: RecipientSelectView = activity.findViewById(R.id.bcc)
private val ccWrapper: View = activity.findViewById(R.id.cc_wrapper)
private val ccDivider: View = activity.findViewById(R.id.cc_divider)
private val bccWrapper: View = activity.findViewById(R.id.bcc_wrapper)
private val bccDivider: View = activity.findViewById(R.id.bcc_divider)
private val recipientExpanderContainer: ViewAnimator = activity.findViewById(R.id.recipient_expander_container)
private val cryptoStatusView: ToolableViewAnimator = activity.findViewById(R.id.crypto_status)
private val cryptoSpecialModeIndicator: ToolableViewAnimator = activity.findViewById(R.id.crypto_special_mode)
private val textWatchers: MutableSet<TextWatcher> = HashSet()
private lateinit var presenter: RecipientPresenter
import android.app.PendingIntent;
import androidx.loader.app.LoaderManager;
import androidx.interpolator.view.animation.FastOutLinearInInterpolator;
import androidx.interpolator.view.animation.LinearOutSlowInInterpolator;
import android.text.TextWatcher;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnFocusChangeListener;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ViewAnimator;
init {
cryptoStatusView.setOnClickListener(this)
cryptoSpecialModeIndicator.setOnClickListener(this)
toView.onFocusChangeListener = this
ccView.onFocusChangeListener = this
bccView.onFocusChangeListener = this
import com.fsck.k9.FontSizes;
import com.fsck.k9.ui.R;
import com.fsck.k9.activity.MessageCompose;
import com.fsck.k9.mail.Address;
import com.fsck.k9.mail.Message.RecipientType;
import com.fsck.k9.view.RecipientSelectView;
import com.fsck.k9.view.RecipientSelectView.Recipient;
import com.fsck.k9.view.RecipientSelectView.TokenListener;
import com.fsck.k9.view.ToolableViewAnimator;
import static com.fsck.k9.FontSizes.FONT_10SP;
import static com.fsck.k9.FontSizes.FONT_12SP;
import static com.fsck.k9.FontSizes.FONT_16SP;
import static com.fsck.k9.FontSizes.FONT_20SP;
import static com.fsck.k9.FontSizes.FONT_DEFAULT;
import static com.fsck.k9.FontSizes.LARGE;
import static com.fsck.k9.FontSizes.MEDIUM;
import static com.fsck.k9.FontSizes.SMALL;
public class RecipientMvpView implements OnFocusChangeListener, OnClickListener {
private static final int VIEW_INDEX_HIDDEN = -1;
private static final int VIEW_INDEX_BCC_EXPANDER_VISIBLE = 0;
private static final int VIEW_INDEX_BCC_EXPANDER_HIDDEN = 1;
private static final FastOutLinearInInterpolator CRYPTO_ICON_OUT_ANIMATOR = new FastOutLinearInInterpolator();
private static final int CRYPTO_ICON_OUT_DURATION = 195;
private static final LinearOutSlowInInterpolator CRYPTO_ICON_IN_ANIMATOR = new LinearOutSlowInInterpolator();
private static final int CRYPTO_ICON_IN_DURATION = 225;
private final MessageCompose activity;
private final View ccWrapper;
private final View ccDivider;
private final View bccWrapper;
private final View bccDivider;
private final RecipientSelectView toView;
private final RecipientSelectView ccView;
private final RecipientSelectView bccView;
private final ToolableViewAnimator cryptoStatusView;
private final ViewAnimator recipientExpanderContainer;
private final ToolableViewAnimator cryptoSpecialModeIndicator;
private final Set<TextWatcher> textWatchers = new HashSet<>();
private RecipientPresenter presenter;
public RecipientMvpView(MessageCompose activity) {
this.activity = activity;
toView = activity.findViewById(R.id.to);
ccView = activity.findViewById(R.id.cc);
bccView = activity.findViewById(R.id.bcc);
ccWrapper = activity.findViewById(R.id.cc_wrapper);
ccDivider = activity.findViewById(R.id.cc_divider);
bccWrapper = activity.findViewById(R.id.bcc_wrapper);
bccDivider = activity.findViewById(R.id.bcc_divider);
recipientExpanderContainer = activity.findViewById(R.id.recipient_expander_container);
cryptoStatusView = activity.findViewById(R.id.crypto_status);
cryptoStatusView.setOnClickListener(this);
cryptoSpecialModeIndicator = activity.findViewById(R.id.crypto_special_mode);
cryptoSpecialModeIndicator.setOnClickListener(this);
toView.setOnFocusChangeListener(this);
ccView.setOnFocusChangeListener(this);
bccView.setOnFocusChangeListener(this);
View recipientExpander = activity.findViewById(R.id.recipient_expander);
recipientExpander.setOnClickListener(this);
View toLabel = activity.findViewById(R.id.to_label);
View ccLabel = activity.findViewById(R.id.cc_label);
View bccLabel = activity.findViewById(R.id.bcc_label);
toLabel.setOnClickListener(this);
ccLabel.setOnClickListener(this);
bccLabel.setOnClickListener(this);
activity.findViewById<View>(R.id.recipient_expander).setOnClickListener(this)
activity.findViewById<View>(R.id.to_label).setOnClickListener(this)
activity.findViewById<View>(R.id.cc_label).setOnClickListener(this)
activity.findViewById<View>(R.id.bcc_label).setOnClickListener(this)
}
public void setPresenter(final RecipientPresenter presenter) {
this.presenter = presenter;
val isCcVisible: Boolean
get() = ccWrapper.isVisible
if (presenter == null) {
toView.setTokenListener(null);
ccView.setTokenListener(null);
bccView.setTokenListener(null);
return;
}
val isBccVisible: Boolean
get() = bccWrapper.isVisible
toView.setTokenListener(new TokenListener<Recipient>() {
@Override
public void onTokenAdded(Recipient recipient) {
presenter.onToTokenAdded();
}
val toAddresses: List<Address>
get() = toView.addresses.toList()
@Override
public void onTokenRemoved(Recipient recipient) {
presenter.onToTokenRemoved();
}
val ccAddresses: List<Address>
get() = ccView.addresses.toList()
@Override
public void onTokenChanged(Recipient recipient) {
presenter.onToTokenChanged();
}
val bccAddresses: List<Address>
get() = bccView.addresses.toList()
@Override
public void onTokenIgnored(Recipient token) {
// Do nothing
}
});
val toRecipients: List<Recipient>
get() = toView.objects
ccView.setTokenListener(new TokenListener<Recipient>() {
@Override
public void onTokenAdded(Recipient recipient) {
presenter.onCcTokenAdded();
}
val ccRecipients: List<Recipient>
get() = ccView.objects
@Override
public void onTokenRemoved(Recipient recipient) {
presenter.onCcTokenRemoved();
}
val bccRecipients: List<Recipient>
get() = bccView.objects
@Override
public void onTokenChanged(Recipient recipient) {
presenter.onCcTokenChanged();
}
fun setPresenter(presenter: RecipientPresenter) {
this.presenter = presenter
toView.setTokenListener(object : RecipientSelectView.TokenListener<Recipient> {
override fun onTokenAdded(recipient: Recipient) = presenter.onToTokenAdded()
@Override
public void onTokenIgnored(Recipient token) {
// Do nothing
}
});
override fun onTokenRemoved(recipient: Recipient) = presenter.onToTokenRemoved()
bccView.setTokenListener(new TokenListener<Recipient>() {
@Override
public void onTokenAdded(Recipient recipient) {
presenter.onBccTokenAdded();
}
override fun onTokenChanged(recipient: Recipient) = presenter.onToTokenChanged()
@Override
public void onTokenRemoved(Recipient recipient) {
presenter.onBccTokenRemoved();
}
override fun onTokenIgnored(token: Recipient) = Unit
})
@Override
public void onTokenChanged(Recipient recipient) {
presenter.onBccTokenChanged();
}
ccView.setTokenListener(object : RecipientSelectView.TokenListener<Recipient> {
override fun onTokenAdded(recipient: Recipient) = presenter.onCcTokenAdded()
@Override
public void onTokenIgnored(Recipient token) {
// Do nothing
}
});
override fun onTokenRemoved(recipient: Recipient) = presenter.onCcTokenRemoved()
override fun onTokenChanged(recipient: Recipient) = presenter.onCcTokenChanged()
override fun onTokenIgnored(token: Recipient) = Unit
})
bccView.setTokenListener(object : RecipientSelectView.TokenListener<Recipient> {
override fun onTokenAdded(recipient: Recipient) = presenter.onBccTokenAdded()
override fun onTokenRemoved(recipient: Recipient) = presenter.onBccTokenRemoved()
override fun onTokenChanged(recipient: Recipient) = presenter.onBccTokenChanged()
override fun onTokenIgnored(token: Recipient) = Unit
})
}
public void addTextChangedListener(TextWatcher textWatcher) {
textWatchers.add(textWatcher);
toView.addTextChangedListener(textWatcher);
ccView.addTextChangedListener(textWatcher);
bccView.addTextChangedListener(textWatcher);
fun addTextChangedListener(textWatcher: TextWatcher) {
textWatchers.add(textWatcher)
toView.addTextChangedListener(textWatcher)
ccView.addTextChangedListener(textWatcher)
bccView.addTextChangedListener(textWatcher)
}
private void removeAllTextChangedListeners(TextView view) {
for (TextWatcher textWatcher : textWatchers) {
view.removeTextChangedListener(textWatcher);
private fun removeAllTextChangedListeners(view: TextView) {
for (textWatcher in textWatchers) {
view.removeTextChangedListener(textWatcher)
}
}
private void addAllTextChangedListeners(TextView view) {
for (TextWatcher textWatcher : textWatchers) {
view.addTextChangedListener(textWatcher);
private fun addAllTextChangedListeners(view: TextView) {
for (textWatcher in textWatchers) {
view.addTextChangedListener(textWatcher)
}
}
public void setRecipientTokensShowCryptoEnabled(boolean isEnabled) {
toView.setShowCryptoEnabled(isEnabled);
ccView.setShowCryptoEnabled(isEnabled);
bccView.setShowCryptoEnabled(isEnabled);
fun setRecipientTokensShowCryptoEnabled(isEnabled: Boolean) {
toView.setShowCryptoEnabled(isEnabled)
ccView.setShowCryptoEnabled(isEnabled)
bccView.setShowCryptoEnabled(isEnabled)
}
public void setCryptoProvider(String openPgpProvider) {
fun setCryptoProvider(openPgpProvider: String?) {
// TODO move "show advanced" into settings, or somewhere?
toView.setCryptoProvider(openPgpProvider, false);
ccView.setCryptoProvider(openPgpProvider, false);
bccView.setCryptoProvider(openPgpProvider, false);
toView.setCryptoProvider(openPgpProvider, false)
ccView.setCryptoProvider(openPgpProvider, false)
bccView.setCryptoProvider(openPgpProvider, false)
}
public void requestFocusOnToField() {
toView.requestFocus();
fun requestFocusOnToField() {
toView.requestFocus()
}
public void requestFocusOnCcField() {
ccView.requestFocus();
fun requestFocusOnCcField() {
ccView.requestFocus()
}
public void requestFocusOnBccField() {
bccView.requestFocus();
fun requestFocusOnBccField() {
bccView.requestFocus()
}
public void setFontSizes(FontSizes fontSizes, int fontSize) {
int tokenTextSize = getTokenTextSize(fontSize);
toView.setTokenTextSize(tokenTextSize);
ccView.setTokenTextSize(tokenTextSize);
bccView.setTokenTextSize(tokenTextSize);
fontSizes.setViewTextSize(toView, fontSize);
fontSizes.setViewTextSize(ccView, fontSize);
fontSizes.setViewTextSize(bccView, fontSize);
fun setFontSizes(fontSizes: FontSizes, fontSize: Int) {
val tokenTextSize = getTokenTextSize(fontSize)
toView.setTokenTextSize(tokenTextSize)
ccView.setTokenTextSize(tokenTextSize)
bccView.setTokenTextSize(tokenTextSize)
fontSizes.setViewTextSize(toView, fontSize)
fontSizes.setViewTextSize(ccView, fontSize)
fontSizes.setViewTextSize(bccView, fontSize)
}
private int getTokenTextSize(int fontSize) {
switch (fontSize) {
case FONT_10SP: return FONT_10SP;
case FONT_12SP: return FONT_12SP;
case SMALL: return SMALL;
case FONT_16SP: return 15;
case MEDIUM: return FONT_16SP;
case FONT_20SP: return MEDIUM;
case LARGE: return FONT_20SP;
default: return FONT_DEFAULT;
private fun getTokenTextSize(fontSize: Int): Int {
return when (fontSize) {
FontSizes.FONT_10SP -> FontSizes.FONT_10SP
FontSizes.FONT_12SP -> FontSizes.FONT_12SP
FontSizes.SMALL -> FontSizes.SMALL
FontSizes.FONT_16SP -> 15
FontSizes.MEDIUM -> FontSizes.FONT_16SP
FontSizes.FONT_20SP -> FontSizes.MEDIUM
FontSizes.LARGE -> FontSizes.FONT_20SP
else -> FontSizes.FONT_DEFAULT
}
}
public void addRecipients(RecipientType recipientType, Recipient... recipients) {
switch (recipientType) {
case TO: {
toView.addRecipients(recipients);
break;
}
case CC: {
ccView.addRecipients(recipients);
break;
}
case BCC: {
bccView.addRecipients(recipients);
break;
}
fun addRecipients(recipientType: RecipientType, vararg recipients: Recipient) {
when (recipientType) {
RecipientType.TO -> toView.addRecipients(*recipients)
RecipientType.CC -> ccView.addRecipients(*recipients)
RecipientType.BCC -> bccView.addRecipients(*recipients)
else -> throw AssertionError("Unsupported type: $recipientType")
}
}
public void silentlyAddBccAddresses(Recipient... recipients) {
removeAllTextChangedListeners(bccView);
fun silentlyAddBccAddresses(vararg recipients: Recipient) {
removeAllTextChangedListeners(bccView)
bccView.addRecipients(recipients);
bccView.addRecipients(*recipients)
addAllTextChangedListeners(bccView);
addAllTextChangedListeners(bccView)
}
public void silentlyRemoveBccAddresses(Address[] addressesToRemove) {
if (addressesToRemove.length == 0) {
return;
}
fun silentlyRemoveBccAddresses(addresses: Array<Address>) {
if (addresses.isEmpty()) return
List<Recipient> bccRecipients = new ArrayList<>(getBccRecipients());
for (Recipient recipient : bccRecipients) {
removeAllTextChangedListeners(bccView);
val addressesToRemove = addresses.toSet()
for (recipient in bccRecipients.toList()) {
removeAllTextChangedListeners(bccView)
for (Address address : addressesToRemove) {
if (recipient.address.equals(address)) {
bccView.removeObjectSync(recipient);
}
if (recipient.address in addressesToRemove) {
bccView.removeObjectSync(recipient)
}
addAllTextChangedListeners(bccView);
addAllTextChangedListeners(bccView)
}
}
public void setCcVisibility(boolean visible) {
ccWrapper.setVisibility(visible ? View.VISIBLE : View.GONE);
ccDivider.setVisibility(visible ? View.VISIBLE : View.GONE);
fun setCcVisibility(visible: Boolean) {
ccWrapper.isVisible = visible
ccDivider.isVisible = visible
}
public void setBccVisibility(boolean visible) {
bccWrapper.setVisibility(visible ? View.VISIBLE : View.GONE);
bccDivider.setVisibility(visible ? View.VISIBLE : View.GONE);
fun setBccVisibility(visible: Boolean) {
bccWrapper.isVisible = visible
bccDivider.isVisible = visible
}
public void setRecipientExpanderVisibility(boolean visible) {
int childToDisplay = visible ? VIEW_INDEX_BCC_EXPANDER_VISIBLE : VIEW_INDEX_BCC_EXPANDER_HIDDEN;
if (recipientExpanderContainer.getDisplayedChild() != childToDisplay) {
recipientExpanderContainer.setDisplayedChild(childToDisplay);
fun setRecipientExpanderVisibility(visible: Boolean) {
val childToDisplay = if (visible) VIEW_INDEX_BCC_EXPANDER_VISIBLE else VIEW_INDEX_BCC_EXPANDER_HIDDEN
if (recipientExpanderContainer.displayedChild != childToDisplay) {
recipientExpanderContainer.displayedChild = childToDisplay
}
}
public boolean isCcVisible() {
return ccWrapper.getVisibility() == View.VISIBLE;
fun showNoRecipientsError() {
toView.error = toView.context.getString(R.string.message_compose_error_no_recipients)
}
public boolean isBccVisible() {
return bccWrapper.getVisibility() == View.VISIBLE;
fun recipientToHasUncompletedText(): Boolean {
return toView.hasUncompletedText()
}
public void showNoRecipientsError() {
toView.setError(toView.getContext().getString(R.string.message_compose_error_no_recipients));
fun recipientCcHasUncompletedText(): Boolean {
return ccView.hasUncompletedText()
}
public List<Address> getToAddresses() {
return Arrays.asList(toView.getAddresses());
fun recipientBccHasUncompletedText(): Boolean {
return bccView.hasUncompletedText()
}
public List<Address> getCcAddresses() {
return Arrays.asList(ccView.getAddresses());
fun recipientToTryPerformCompletion(): Boolean {
return toView.tryPerformCompletion()
}
public List<Address> getBccAddresses() {
return Arrays.asList(bccView.getAddresses());
fun recipientCcTryPerformCompletion(): Boolean {
return ccView.tryPerformCompletion()
}
public List<Recipient> getToRecipients() {
return toView.getObjects();
fun recipientBccTryPerformCompletion(): Boolean {
return bccView.tryPerformCompletion()
}
public List<Recipient> getCcRecipients() {
return ccView.getObjects();
fun showToUncompletedError() {
toView.error = toView.context.getString(R.string.compose_error_incomplete_recipient)
}
public List<Recipient> getBccRecipients() {
return bccView.getObjects();
fun showCcUncompletedError() {
ccView.error = ccView.context.getString(R.string.compose_error_incomplete_recipient)
}
public boolean recipientToHasUncompletedText() {
return toView.hasUncompletedText();
fun showBccUncompletedError() {
bccView.error = bccView.context.getString(R.string.compose_error_incomplete_recipient)
}
public boolean recipientCcHasUncompletedText() {
return ccView.hasUncompletedText();
}
public boolean recipientBccHasUncompletedText() {
return bccView.hasUncompletedText();
}
public boolean recipientToTryPerformCompletion() {
return toView.tryPerformCompletion();
}
public boolean recipientCcTryPerformCompletion() {
return ccView.tryPerformCompletion();
}
public boolean recipientBccTryPerformCompletion() {
return bccView.tryPerformCompletion();
}
public void showToUncompletedError() {
toView.setError(toView.getContext().getString(R.string.compose_error_incomplete_recipient));
}
public void showCcUncompletedError() {
ccView.setError(ccView.getContext().getString(R.string.compose_error_incomplete_recipient));
}
public void showBccUncompletedError() {
bccView.setError(bccView.getContext().getString(R.string.compose_error_incomplete_recipient));
}
public void showCryptoSpecialMode(CryptoSpecialModeDisplayType cryptoSpecialModeDisplayType) {
boolean shouldBeHidden = cryptoSpecialModeDisplayType.childIdToDisplay == VIEW_INDEX_HIDDEN;
fun showCryptoSpecialMode(cryptoSpecialModeDisplayType: CryptoSpecialModeDisplayType) {
val shouldBeHidden = cryptoSpecialModeDisplayType.childIdToDisplay == VIEW_INDEX_HIDDEN
if (shouldBeHidden) {
cryptoSpecialModeIndicator.setVisibility(View.GONE);
return;
cryptoSpecialModeIndicator.isGone = true
return
}
cryptoSpecialModeIndicator.setVisibility(View.VISIBLE);
cryptoSpecialModeIndicator.setDisplayedChildId(cryptoSpecialModeDisplayType.childIdToDisplay);
activity.invalidateOptionsMenu();
cryptoSpecialModeIndicator.isVisible = true
cryptoSpecialModeIndicator.displayedChildId = cryptoSpecialModeDisplayType.childIdToDisplay
activity.invalidateOptionsMenu()
}
public void showCryptoStatus(CryptoStatusDisplayType cryptoStatusDisplayType) {
boolean shouldBeHidden = cryptoStatusDisplayType.childIdToDisplay == VIEW_INDEX_HIDDEN;
fun showCryptoStatus(cryptoStatusDisplayType: CryptoStatusDisplayType) {
val shouldBeHidden = cryptoStatusDisplayType.childIdToDisplay == VIEW_INDEX_HIDDEN
if (shouldBeHidden) {
cryptoStatusView.animate()
.translationXBy(100.0f)
.alpha(0.0f)
.setDuration(CRYPTO_ICON_OUT_DURATION)
.setInterpolator(CRYPTO_ICON_OUT_ANIMATOR)
.start();
return;
.translationXBy(100.0f)
.alpha(0.0f)
.setDuration(CRYPTO_ICON_OUT_DURATION.toLong())
.setInterpolator(CRYPTO_ICON_OUT_ANIMATOR)
.start()
return
}
cryptoStatusView.setVisibility(View.VISIBLE);
cryptoStatusView.setDisplayedChildId(cryptoStatusDisplayType.childIdToDisplay);
cryptoStatusView.isVisible = true
cryptoStatusView.displayedChildId = cryptoStatusDisplayType.childIdToDisplay
cryptoStatusView.animate()
.translationX(0.0f)
.alpha(1.0f)
.setDuration(CRYPTO_ICON_IN_DURATION)
.setInterpolator(CRYPTO_ICON_IN_ANIMATOR)
.start();
.translationX(0.0f)
.alpha(1.0f)
.setDuration(CRYPTO_ICON_IN_DURATION.toLong())
.setInterpolator(CRYPTO_ICON_IN_ANIMATOR)
.start()
}
public void showContactPicker(int requestCode) {
activity.showContactPicker(requestCode);
fun showContactPicker(requestCode: Int) {
activity.showContactPicker(requestCode)
}
public void showErrorIsSignOnly() {
Toast.makeText(activity, R.string.error_sign_only_no_encryption, Toast.LENGTH_LONG).show();
fun showErrorIsSignOnly() {
Toast.makeText(activity, R.string.error_sign_only_no_encryption, Toast.LENGTH_LONG).show()
}
public void showErrorContactNoAddress() {
Toast.makeText(activity, R.string.error_contact_address_not_found, Toast.LENGTH_LONG).show();
fun showErrorContactNoAddress() {
Toast.makeText(activity, R.string.error_contact_address_not_found, Toast.LENGTH_LONG).show()
}
public void showErrorOpenPgpRetrieveStatus() {
Toast.makeText(activity, R.string.error_recipient_crypto_retrieve, Toast.LENGTH_LONG).show();
fun showErrorOpenPgpIncompatible() {
Toast.makeText(activity, R.string.error_crypto_provider_incompatible, Toast.LENGTH_LONG).show()
}
public void showErrorOpenPgpIncompatible() {
Toast.makeText(activity, R.string.error_crypto_provider_incompatible, Toast.LENGTH_LONG).show();
fun showErrorOpenPgpConnection() {
Toast.makeText(activity, R.string.error_crypto_provider_connect, Toast.LENGTH_LONG).show()
}
public void showErrorOpenPgpConnection() {
Toast.makeText(activity, R.string.error_crypto_provider_connect, Toast.LENGTH_LONG).show();
fun showErrorOpenPgpUserInteractionRequired() {
Toast.makeText(activity, R.string.error_crypto_provider_ui_required, Toast.LENGTH_LONG).show()
}
public void showErrorOpenPgpUserInteractionRequired() {
Toast.makeText(activity, R.string.error_crypto_provider_ui_required, Toast.LENGTH_LONG).show();
fun showErrorNoKeyConfigured() {
Toast.makeText(activity, R.string.compose_error_no_key_configured, Toast.LENGTH_LONG).show()
}
public void showErrorNoKeyConfigured() {
Toast.makeText(activity, R.string.compose_error_no_key_configured, Toast.LENGTH_LONG).show();
fun showErrorInlineAttach() {
Toast.makeText(activity, R.string.error_crypto_inline_attach, Toast.LENGTH_LONG).show()
}
public void showErrorInlineAttach() {
Toast.makeText(activity, R.string.error_crypto_inline_attach, Toast.LENGTH_LONG).show();
}
override fun onFocusChange(view: View, hasFocus: Boolean) {
if (!hasFocus) return
@Override
public void onFocusChange(View view, boolean hasFocus) {
if (!hasFocus) {
return;
}
int id = view.getId();
if (id == R.id.to) {
presenter.onToFocused();
} else if (id == R.id.cc) {
presenter.onCcFocused();
} else if (id == R.id.bcc) {
presenter.onBccFocused();
when (view.id) {
R.id.to -> presenter.onToFocused()
R.id.cc -> presenter.onCcFocused()
R.id.bcc -> presenter.onBccFocused()
}
}
@Override
public void onClick(View view) {
int id = view.getId();
if (id == R.id.to_label) {
presenter.onClickToLabel();
} else if (id == R.id.cc_label) {
presenter.onClickCcLabel();
} else if (id == R.id.bcc_label) {
presenter.onClickBccLabel();
} else if (id == R.id.recipient_expander) {
presenter.onClickRecipientExpander();
} else if (id == R.id.crypto_status) {
presenter.onClickCryptoStatus();
} else if (id == R.id.crypto_special_mode) {
presenter.onClickCryptoSpecialModeIndicator();
override fun onClick(view: View) {
when (view.id) {
R.id.to_label -> presenter.onClickToLabel()
R.id.cc_label -> presenter.onClickCcLabel()
R.id.bcc_label -> presenter.onClickBccLabel()
R.id.recipient_expander -> presenter.onClickRecipientExpander()
R.id.crypto_status -> presenter.onClickCryptoStatus()
R.id.crypto_special_mode -> presenter.onClickCryptoSpecialModeIndicator()
}
}
public void showOpenPgpInlineDialog(boolean firstTime) {
PgpInlineDialog dialog = PgpInlineDialog.newInstance(firstTime, R.id.crypto_special_mode);
dialog.show(activity.getSupportFragmentManager(), "openpgp_inline");
fun showOpenPgpInlineDialog(firstTime: Boolean) {
val dialog = PgpInlineDialog.newInstance(firstTime, R.id.crypto_special_mode)
dialog.show(activity.supportFragmentManager, "openpgp_inline")
}
public void showOpenPgpSignOnlyDialog(boolean firstTime) {
PgpSignOnlyDialog dialog = PgpSignOnlyDialog.newInstance(firstTime, R.id.crypto_special_mode);
dialog.show(activity.getSupportFragmentManager(), "openpgp_signonly");
fun showOpenPgpSignOnlyDialog(firstTime: Boolean) {
val dialog = PgpSignOnlyDialog.newInstance(firstTime, R.id.crypto_special_mode)
dialog.show(activity.supportFragmentManager, "openpgp_signonly")
}
public void showOpenPgpEnabledErrorDialog(final boolean isGotItDialog) {
PgpEnabledErrorDialog dialog = PgpEnabledErrorDialog.newInstance(isGotItDialog, R.id.crypto_status_anchor);
dialog.show(activity.getSupportFragmentManager(), "openpgp_error");
fun showOpenPgpEnabledErrorDialog(isGotItDialog: Boolean) {
val dialog = PgpEnabledErrorDialog.newInstance(isGotItDialog, R.id.crypto_status_anchor)
dialog.show(activity.supportFragmentManager, "openpgp_error")
}
public void showOpenPgpEncryptExplanationDialog() {
PgpEncryptDescriptionDialog dialog = PgpEncryptDescriptionDialog.newInstance(R.id.crypto_status_anchor);
dialog.show(activity.getSupportFragmentManager(), "openpgp_description");
fun showOpenPgpEncryptExplanationDialog() {
val dialog = PgpEncryptDescriptionDialog.newInstance(R.id.crypto_status_anchor)
dialog.show(activity.supportFragmentManager, "openpgp_description")
}
public void launchUserInteractionPendingIntent(PendingIntent pendingIntent, int requestCode) {
activity.launchUserInteractionPendingIntent(pendingIntent, requestCode);
fun launchUserInteractionPendingIntent(pendingIntent: PendingIntent?, requestCode: Int) {
activity.launchUserInteractionPendingIntent(pendingIntent, requestCode)
}
public void setLoaderManager(LoaderManager loaderManager) {
toView.setLoaderManager(loaderManager);
ccView.setLoaderManager(loaderManager);
bccView.setLoaderManager(loaderManager);
fun setLoaderManager(loaderManager: LoaderManager?) {
toView.setLoaderManager(loaderManager)
ccView.setLoaderManager(loaderManager)
bccView.setLoaderManager(loaderManager)
}
public enum CryptoStatusDisplayType {
enum class CryptoStatusDisplayType(val childIdToDisplay: Int) {
UNCONFIGURED(VIEW_INDEX_HIDDEN),
UNINITIALIZED(VIEW_INDEX_HIDDEN),
SIGN_ONLY(R.id.crypto_status_disabled),
@ -518,26 +391,24 @@ public class RecipientMvpView implements OnFocusChangeListener, OnClickListener
ENABLED_TRUSTED(R.id.crypto_status_trusted),
AVAILABLE(R.id.crypto_status_disabled),
ERROR(R.id.crypto_status_error);
final int childIdToDisplay;
CryptoStatusDisplayType(int childIdToDisplay) {
this.childIdToDisplay = childIdToDisplay;
}
}
public enum CryptoSpecialModeDisplayType {
enum class CryptoSpecialModeDisplayType(val childIdToDisplay: Int) {
NONE(VIEW_INDEX_HIDDEN),
PGP_INLINE(R.id.crypto_special_inline),
SIGN_ONLY(R.id.crypto_special_sign_only),
SIGN_ONLY_PGP_INLINE(R.id.crypto_special_sign_only_inline);
}
companion object {
private const val VIEW_INDEX_HIDDEN = -1
private const val VIEW_INDEX_BCC_EXPANDER_VISIBLE = 0
private const val VIEW_INDEX_BCC_EXPANDER_HIDDEN = 1
final int childIdToDisplay;
private val CRYPTO_ICON_OUT_ANIMATOR = FastOutLinearInInterpolator()
private const val CRYPTO_ICON_OUT_DURATION = 195
CryptoSpecialModeDisplayType(int childIdToDisplay) {
this.childIdToDisplay = childIdToDisplay;
}
private val CRYPTO_ICON_IN_ANIMATOR = LinearOutSlowInInterpolator()
private const val CRYPTO_ICON_IN_DURATION = 225
}
}

View file

@ -1,301 +1,307 @@
package com.fsck.k9.activity.compose;
package com.fsck.k9.activity.compose
import androidx.test.core.app.ApplicationProvider
import com.fsck.k9.Account
import com.fsck.k9.K9RobolectricTest
import com.fsck.k9.activity.compose.RecipientMvpView.CryptoSpecialModeDisplayType
import com.fsck.k9.activity.compose.RecipientMvpView.CryptoStatusDisplayType
import com.fsck.k9.activity.compose.RecipientPresenter.CryptoMode
import com.fsck.k9.autocrypt.AutocryptDraftStateHeaderParser
import com.fsck.k9.helper.ReplyToParser
import com.fsck.k9.helper.ReplyToParser.ReplyToAddresses
import com.fsck.k9.mail.Address
import com.fsck.k9.mail.Message
import com.fsck.k9.mail.Message.RecipientType
import com.fsck.k9.message.AutocryptStatusInteractor
import com.fsck.k9.message.AutocryptStatusInteractor.RecipientAutocryptStatus
import com.fsck.k9.message.AutocryptStatusInteractor.RecipientAutocryptStatusType
import com.fsck.k9.message.ComposePgpEnableByDefaultDecider
import com.fsck.k9.message.ComposePgpInlineDecider
import com.fsck.k9.view.RecipientSelectView.Recipient
import com.google.common.truth.Truth.assertThat
import kotlin.test.assertNotNull
import org.junit.Before
import org.junit.Ignore
import org.junit.Test
import org.koin.test.inject
import org.mockito.ArgumentMatchers.eq
import org.mockito.Mockito.verify
import org.mockito.kotlin.any
import org.mockito.kotlin.doAnswer
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock
import org.mockito.kotlin.stubbing
import org.openintents.openpgp.OpenPgpApiManager
import org.openintents.openpgp.OpenPgpApiManager.OpenPgpApiManagerCallback
import org.openintents.openpgp.OpenPgpApiManager.OpenPgpProviderState
import org.openintents.openpgp.util.OpenPgpApi
import org.robolectric.Robolectric
import org.robolectric.annotation.LooperMode
import java.util.Arrays;
import java.util.List;
private val TO_ADDRESS = Address("to@domain.example")
private val CC_ADDRESS = Address("cc@domain.example")
private const val CRYPTO_PROVIDER = "crypto_provider"
private const val CRYPTO_KEY_ID = 123L
import android.content.Context;
import androidx.loader.app.LoaderManager;
import com.fsck.k9.Account;
import com.fsck.k9.DI;
import com.fsck.k9.K9RobolectricTest;
import com.fsck.k9.activity.compose.RecipientMvpView.CryptoSpecialModeDisplayType;
import com.fsck.k9.activity.compose.RecipientMvpView.CryptoStatusDisplayType;
import com.fsck.k9.activity.compose.RecipientPresenter.CryptoMode;
import com.fsck.k9.autocrypt.AutocryptDraftStateHeaderParser;
import com.fsck.k9.helper.ReplyToParser;
import com.fsck.k9.helper.ReplyToParser.ReplyToAddresses;
import com.fsck.k9.mail.Address;
import com.fsck.k9.mail.Message;
import com.fsck.k9.mail.Message.RecipientType;
import com.fsck.k9.message.AutocryptStatusInteractor;
import com.fsck.k9.message.AutocryptStatusInteractor.RecipientAutocryptStatus;
import com.fsck.k9.message.AutocryptStatusInteractor.RecipientAutocryptStatusType;
import com.fsck.k9.message.ComposePgpEnableByDefaultDecider;
import com.fsck.k9.message.ComposePgpInlineDecider;
import com.fsck.k9.view.RecipientSelectView.Recipient;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.openintents.openpgp.OpenPgpApiManager;
import org.openintents.openpgp.OpenPgpApiManager.OpenPgpApiManagerCallback;
import org.openintents.openpgp.OpenPgpApiManager.OpenPgpProviderState;
import org.openintents.openpgp.util.OpenPgpApi;
import org.robolectric.Robolectric;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.LooperMode;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Matchers.isNull;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@SuppressWarnings("ConstantConditions")
@LooperMode(LooperMode.Mode.LEGACY)
public class RecipientPresenterTest extends K9RobolectricTest {
private static final ReplyToAddresses TO_ADDRESSES = new ReplyToAddresses(Address.parse("to@example.org"));
private static final List<Address> ALL_TO_ADDRESSES = Arrays.asList(Address.parse("allTo@example.org"));
private static final List<Address> ALL_CC_ADDRESSES = Arrays.asList(Address.parse("allCc@example.org"));
private static final String CRYPTO_PROVIDER = "crypto_provider";
private static final long CRYPTO_KEY_ID = 123L;
private RecipientPresenter recipientPresenter;
private ReplyToParser replyToParser;
private ComposePgpInlineDecider composePgpInlineDecider;
private ComposePgpEnableByDefaultDecider composePgpEnableByDefaultDecider;
private Account account;
private RecipientMvpView recipientMvpView;
private AutocryptStatusInteractor autocryptStatusInteractor;
private RecipientAutocryptStatus noRecipientsAutocryptResult;
private OpenPgpApiManager openPgpApiManager;
private OpenPgpApiManagerCallback openPgpApiManagerCallback;
class RecipientPresenterTest : K9RobolectricTest() {
private val openPgpApiManager = mock<OpenPgpApiManager> {
on { openPgpProviderState } doReturn OpenPgpProviderState.UNCONFIGURED
on { setOpenPgpProvider(any(), any()) } doAnswer { invocation ->
openPgpApiManagerCallback = invocation.getArgument(1)
}
}
private val recipientMvpView = mock<RecipientMvpView>()
private val account = mock<Account>()
private val composePgpInlineDecider = mock<ComposePgpInlineDecider>()
private val composePgpEnableByDefaultDecider = mock<ComposePgpEnableByDefaultDecider>()
private val autocryptStatusInteractor = mock<AutocryptStatusInteractor>()
private val replyToParser = mock<ReplyToParser>()
private val autocryptDraftStateHeaderParser: AutocryptDraftStateHeaderParser by inject()
private lateinit var recipientPresenter: RecipientPresenter
private val noRecipientsAutocryptResult = RecipientAutocryptStatus(RecipientAutocryptStatusType.NO_RECIPIENTS, null)
private var openPgpApiManagerCallback: OpenPgpApiManagerCallback? = null
@Before
public void setUp() throws Exception {
Context context = RuntimeEnvironment.application;
Robolectric.getBackgroundThreadScheduler().pause();
fun setUp() {
Robolectric.getBackgroundThreadScheduler().pause()
recipientMvpView = mock(RecipientMvpView.class);
openPgpApiManager = mock(OpenPgpApiManager.class);
account = mock(Account.class);
composePgpInlineDecider = mock(ComposePgpInlineDecider.class);
composePgpEnableByDefaultDecider = mock(ComposePgpEnableByDefaultDecider.class);
autocryptStatusInteractor = mock(AutocryptStatusInteractor.class);
replyToParser = mock(ReplyToParser.class);
LoaderManager loaderManager = mock(LoaderManager.class);
when(openPgpApiManager.getOpenPgpProviderState()).thenReturn(OpenPgpProviderState.UNCONFIGURED);
recipientPresenter = new RecipientPresenter(
context, loaderManager, openPgpApiManager, recipientMvpView, account, composePgpInlineDecider,
composePgpEnableByDefaultDecider, autocryptStatusInteractor, replyToParser,
DI.get(AutocryptDraftStateHeaderParser.class)
);
ArgumentCaptor<OpenPgpApiManagerCallback> callbackCaptor = ArgumentCaptor.forClass(OpenPgpApiManagerCallback.class);
verify(openPgpApiManager).setOpenPgpProvider(isNull(String.class), callbackCaptor.capture());
openPgpApiManagerCallback = callbackCaptor.getValue();
noRecipientsAutocryptResult = new RecipientAutocryptStatus(RecipientAutocryptStatusType.NO_RECIPIENTS, null);
recipientPresenter = RecipientPresenter(
ApplicationProvider.getApplicationContext(),
mock(),
openPgpApiManager,
recipientMvpView,
account,
composePgpInlineDecider,
composePgpEnableByDefaultDecider,
autocryptStatusInteractor,
replyToParser,
autocryptDraftStateHeaderParser
)
}
@Test
@Ignore("It looks like the support version of AsyncTaskLoader handles background tasks differently")
public void testInitFromReplyToMessage() throws Exception {
Message message = mock(Message.class);
when(replyToParser.getRecipientsToReplyTo(message, account)).thenReturn(TO_ADDRESSES);
fun testInitFromReplyToMessage() {
val message = mock<Message>()
stubbing(replyToParser) {
on { getRecipientsToReplyTo(message, account) } doReturn ReplyToAddresses(arrayOf(TO_ADDRESS))
}
recipientPresenter.initFromReplyToMessage(message, false);
runBackgroundTask();
recipientPresenter.initFromReplyToMessage(message, false)
runBackgroundTask()
Recipient toRecipient = new Recipient(TO_ADDRESSES.to[0]);
verify(recipientMvpView).addRecipients(eq(RecipientType.TO), eq(toRecipient));
verify(recipientMvpView).addRecipients(eq(RecipientType.TO), eq(Recipient(TO_ADDRESS)))
}
@Test
@Ignore("It looks like the support version of AsyncTaskLoader handles background tasks differently")
public void testInitFromReplyToAllMessage() throws Exception {
Message message = mock(Message.class);
when(replyToParser.getRecipientsToReplyTo(message, account)).thenReturn(TO_ADDRESSES);
ReplyToAddresses replyToAddresses = new ReplyToAddresses(ALL_TO_ADDRESSES, ALL_CC_ADDRESSES);
when(replyToParser.getRecipientsToReplyAllTo(message, account)).thenReturn(replyToAddresses);
fun testInitFromReplyToAllMessage() {
val message = mock<Message>()
val replyToAddresses = ReplyToAddresses(listOf(TO_ADDRESS), listOf(CC_ADDRESS))
stubbing(replyToParser) {
on { getRecipientsToReplyAllTo(message, account) } doReturn replyToAddresses
}
recipientPresenter.initFromReplyToMessage(message, true);
// one for To, one for Cc
runBackgroundTask();
runBackgroundTask();
recipientPresenter.initFromReplyToMessage(message, true)
runBackgroundTask()
runBackgroundTask()
verify(recipientMvpView).addRecipients(eq(RecipientType.TO), any(Recipient.class));
verify(recipientMvpView).addRecipients(eq(RecipientType.CC), any(Recipient.class));
verify(recipientMvpView).addRecipients(eq(RecipientType.TO), eq(Recipient(TO_ADDRESS)))
verify(recipientMvpView).addRecipients(eq(RecipientType.CC), eq(Recipient(CC_ADDRESS)))
}
@Test
public void initFromReplyToMessage_shouldCallComposePgpInlineDecider() throws Exception {
Message message = mock(Message.class);
when(replyToParser.getRecipientsToReplyTo(message, account)).thenReturn(TO_ADDRESSES);
fun initFromReplyToMessage_shouldCallComposePgpInlineDecider() {
val message = mock<Message>()
stubbing(replyToParser) {
on { getRecipientsToReplyTo(message, account) } doReturn ReplyToAddresses(arrayOf(TO_ADDRESS))
}
recipientPresenter.initFromReplyToMessage(message, false);
recipientPresenter.initFromReplyToMessage(message, false)
verify(composePgpInlineDecider).shouldReplyInline(message);
verify(composePgpInlineDecider).shouldReplyInline(message)
}
@Test
public void getCurrentCryptoStatus_withoutCryptoProvider() throws Exception {
when(openPgpApiManager.getOpenPgpProviderState()).thenReturn(OpenPgpProviderState.UNCONFIGURED);
recipientPresenter.asyncUpdateCryptoStatus();
fun getCurrentCryptoStatus_withoutCryptoProvider() {
stubbing(openPgpApiManager) {
on { openPgpProviderState } doReturn OpenPgpProviderState.UNCONFIGURED
}
ComposeCryptoStatus status = recipientPresenter.getCurrentCachedCryptoStatus();
recipientPresenter.asyncUpdateCryptoStatus()
assertEquals(CryptoStatusDisplayType.UNCONFIGURED, status.getDisplayType());
assertEquals(CryptoSpecialModeDisplayType.NONE, status.getSpecialModeDisplayType());
assertNull(status.getAttachErrorStateOrNull());
assertFalse(status.isProviderStateOk());
assertFalse(status.isOpenPgpConfigured());
assertNotNull(recipientPresenter.currentCachedCryptoStatus) { status ->
assertThat(status.displayType).isEqualTo(CryptoStatusDisplayType.UNCONFIGURED)
assertThat(status.specialModeDisplayType).isEqualTo(CryptoSpecialModeDisplayType.NONE)
assertThat(status.attachErrorStateOrNull).isNull()
assertThat(status.isProviderStateOk()).isFalse()
assertThat(status.isOpenPgpConfigured).isFalse()
}
}
@Test
public void getCurrentCryptoStatus_withCryptoProvider() throws Exception {
setupCryptoProvider(noRecipientsAutocryptResult);
fun getCurrentCryptoStatus_withCryptoProvider() {
setupCryptoProvider(noRecipientsAutocryptResult)
ComposeCryptoStatus status = recipientPresenter.getCurrentCachedCryptoStatus();
assertEquals(CryptoStatusDisplayType.UNAVAILABLE, status.getDisplayType());
assertTrue(status.isProviderStateOk());
assertTrue(status.isOpenPgpConfigured());
assertNotNull(recipientPresenter.currentCachedCryptoStatus) { status ->
assertThat(status.displayType).isEqualTo(CryptoStatusDisplayType.UNAVAILABLE)
assertThat(status.isProviderStateOk()).isTrue()
assertThat(status.isOpenPgpConfigured).isTrue()
}
}
@Test
public void getCurrentCryptoStatus_withOpportunistic() throws Exception {
RecipientAutocryptStatus recipientAutocryptStatus = new RecipientAutocryptStatus(
RecipientAutocryptStatusType.AVAILABLE_UNCONFIRMED, null);
setupCryptoProvider(recipientAutocryptStatus);
fun getCurrentCryptoStatus_withOpportunistic() {
val recipientAutocryptStatus = RecipientAutocryptStatus(
RecipientAutocryptStatusType.AVAILABLE_UNCONFIRMED, null
)
ComposeCryptoStatus status = recipientPresenter.getCurrentCachedCryptoStatus();
setupCryptoProvider(recipientAutocryptStatus)
assertEquals(CryptoStatusDisplayType.AVAILABLE, status.getDisplayType());
assertTrue(status.isProviderStateOk());
assertTrue(status.isOpenPgpConfigured());
assertNotNull(recipientPresenter.currentCachedCryptoStatus) { status ->
assertThat(status.displayType).isEqualTo(CryptoStatusDisplayType.AVAILABLE)
assertThat(status.isProviderStateOk()).isTrue()
assertThat(status.isOpenPgpConfigured).isTrue()
}
}
@Test
public void getCurrentCryptoStatus_withOpportunistic__confirmed() throws Exception {
RecipientAutocryptStatus recipientAutocryptStatus = new RecipientAutocryptStatus(
RecipientAutocryptStatusType.AVAILABLE_CONFIRMED, null);
setupCryptoProvider(recipientAutocryptStatus);
fun getCurrentCryptoStatus_withOpportunistic__confirmed() {
val recipientAutocryptStatus = RecipientAutocryptStatus(
RecipientAutocryptStatusType.AVAILABLE_CONFIRMED, null
)
ComposeCryptoStatus status = recipientPresenter.getCurrentCachedCryptoStatus();
setupCryptoProvider(recipientAutocryptStatus)
assertEquals(CryptoStatusDisplayType.AVAILABLE, status.getDisplayType());
assertTrue(status.isProviderStateOk());
assertTrue(status.isOpenPgpConfigured());
assertNotNull(recipientPresenter.currentCachedCryptoStatus) { status ->
assertThat(status.displayType).isEqualTo(CryptoStatusDisplayType.AVAILABLE)
assertThat(status.isProviderStateOk()).isTrue()
assertThat(status.isOpenPgpConfigured).isTrue()
}
}
@Test
public void getCurrentCryptoStatus_withOpportunistic__missingKeys() throws Exception {
RecipientAutocryptStatus recipientAutocryptStatus = new RecipientAutocryptStatus(
RecipientAutocryptStatusType.UNAVAILABLE, null);
setupCryptoProvider(recipientAutocryptStatus);
fun getCurrentCryptoStatus_withOpportunistic__missingKeys() {
val recipientAutocryptStatus = RecipientAutocryptStatus(
RecipientAutocryptStatusType.UNAVAILABLE, null
)
ComposeCryptoStatus status = recipientPresenter.getCurrentCachedCryptoStatus();
setupCryptoProvider(recipientAutocryptStatus)
assertEquals(CryptoStatusDisplayType.UNAVAILABLE, status.getDisplayType());
assertTrue(status.isProviderStateOk());
assertTrue(status.isOpenPgpConfigured());
assertNotNull(recipientPresenter.currentCachedCryptoStatus) { status ->
assertThat(status.displayType).isEqualTo(CryptoStatusDisplayType.UNAVAILABLE)
assertThat(status.isProviderStateOk()).isTrue()
assertThat(status.isOpenPgpConfigured).isTrue()
}
}
@Test
public void getCurrentCryptoStatus_withOpportunistic__privateMissingKeys() throws Exception {
RecipientAutocryptStatus recipientAutocryptStatus = new RecipientAutocryptStatus(
RecipientAutocryptStatusType.UNAVAILABLE, null);
setupCryptoProvider(recipientAutocryptStatus);
fun getCurrentCryptoStatus_withOpportunistic__privateMissingKeys() {
val recipientAutocryptStatus = RecipientAutocryptStatus(
RecipientAutocryptStatusType.UNAVAILABLE, null
)
recipientPresenter.onCryptoModeChanged(CryptoMode.CHOICE_ENABLED);
runBackgroundTask();
ComposeCryptoStatus status = recipientPresenter.getCurrentCachedCryptoStatus();
setupCryptoProvider(recipientAutocryptStatus)
recipientPresenter.onCryptoModeChanged(CryptoMode.CHOICE_ENABLED)
runBackgroundTask()
assertEquals(CryptoStatusDisplayType.ENABLED_ERROR, status.getDisplayType());
assertTrue(status.isProviderStateOk());
assertTrue(status.isOpenPgpConfigured());
assertNotNull(recipientPresenter.currentCachedCryptoStatus) { status ->
assertThat(status.displayType).isEqualTo(CryptoStatusDisplayType.ENABLED_ERROR)
assertThat(status.isProviderStateOk()).isTrue()
assertThat(status.isOpenPgpConfigured).isTrue()
}
}
@Test
public void getCurrentCryptoStatus_withModeDisabled() throws Exception {
RecipientAutocryptStatus recipientAutocryptStatus = new RecipientAutocryptStatus(
RecipientAutocryptStatusType.AVAILABLE_UNCONFIRMED, null);
setupCryptoProvider(recipientAutocryptStatus);
fun getCurrentCryptoStatus_withModeDisabled() {
val recipientAutocryptStatus = RecipientAutocryptStatus(
RecipientAutocryptStatusType.AVAILABLE_UNCONFIRMED, null
)
recipientPresenter.onCryptoModeChanged(CryptoMode.CHOICE_DISABLED);
runBackgroundTask();
ComposeCryptoStatus status = recipientPresenter.getCurrentCachedCryptoStatus();
setupCryptoProvider(recipientAutocryptStatus)
recipientPresenter.onCryptoModeChanged(CryptoMode.CHOICE_DISABLED)
runBackgroundTask()
assertEquals(CryptoStatusDisplayType.AVAILABLE, status.getDisplayType());
assertTrue(status.isProviderStateOk());
assertTrue(status.isOpenPgpConfigured());
assertNotNull(recipientPresenter.currentCachedCryptoStatus) { status ->
assertThat(status.displayType).isEqualTo(CryptoStatusDisplayType.AVAILABLE)
assertThat(status.isProviderStateOk()).isTrue()
assertThat(status.isOpenPgpConfigured).isTrue()
}
}
@Test
public void getCurrentCryptoStatus_withModePrivate() throws Exception {
RecipientAutocryptStatus recipientAutocryptStatus = new RecipientAutocryptStatus(
RecipientAutocryptStatusType.AVAILABLE_UNCONFIRMED, null);
setupCryptoProvider(recipientAutocryptStatus);
fun getCurrentCryptoStatus_withModePrivate() {
val recipientAutocryptStatus = RecipientAutocryptStatus(
RecipientAutocryptStatusType.AVAILABLE_UNCONFIRMED, null
)
recipientPresenter.onCryptoModeChanged(CryptoMode.CHOICE_ENABLED);
runBackgroundTask();
ComposeCryptoStatus status = recipientPresenter.getCurrentCachedCryptoStatus();
setupCryptoProvider(recipientAutocryptStatus)
recipientPresenter.onCryptoModeChanged(CryptoMode.CHOICE_ENABLED)
runBackgroundTask()
assertEquals(CryptoStatusDisplayType.ENABLED, status.getDisplayType());
assertTrue(status.isProviderStateOk());
assertTrue(status.isOpenPgpConfigured());
assertNotNull(recipientPresenter.currentCachedCryptoStatus) { status ->
assertThat(status.displayType).isEqualTo(CryptoStatusDisplayType.ENABLED)
assertThat(status.isProviderStateOk()).isTrue()
assertThat(status.isOpenPgpConfigured).isTrue()
}
}
@Test
public void getCurrentCryptoStatus_withModeSignOnly() throws Exception {
setupCryptoProvider(noRecipientsAutocryptResult);
fun getCurrentCryptoStatus_withModeSignOnly() {
setupCryptoProvider(noRecipientsAutocryptResult)
recipientPresenter.onMenuSetSignOnly(true);
runBackgroundTask();
ComposeCryptoStatus status = recipientPresenter.getCurrentCachedCryptoStatus();
recipientPresenter.onMenuSetSignOnly(true)
runBackgroundTask()
assertEquals(CryptoStatusDisplayType.SIGN_ONLY, status.getDisplayType());
assertTrue(status.isProviderStateOk());
assertTrue(status.isSigningEnabled());
assertTrue(status.isSignOnly());
assertNotNull(recipientPresenter.currentCachedCryptoStatus) { status ->
assertThat(status.displayType).isEqualTo(CryptoStatusDisplayType.SIGN_ONLY)
assertThat(status.isProviderStateOk()).isTrue()
assertThat(status.isOpenPgpConfigured).isTrue()
assertThat(status.isSignOnly).isTrue()
}
}
@Test
public void getCurrentCryptoStatus_withModeInline() throws Exception {
setupCryptoProvider(noRecipientsAutocryptResult);
fun getCurrentCryptoStatus_withModeInline() {
setupCryptoProvider(noRecipientsAutocryptResult)
recipientPresenter.onMenuSetPgpInline(true);
runBackgroundTask();
ComposeCryptoStatus status = recipientPresenter.getCurrentCachedCryptoStatus();
recipientPresenter.onMenuSetPgpInline(true)
runBackgroundTask()
assertEquals(CryptoStatusDisplayType.UNAVAILABLE, status.getDisplayType());
assertTrue(status.isProviderStateOk());
assertTrue(status.isPgpInlineModeEnabled());
assertNotNull(recipientPresenter.currentCachedCryptoStatus) { status ->
assertThat(status.displayType).isEqualTo(CryptoStatusDisplayType.UNAVAILABLE)
assertThat(status.isProviderStateOk()).isTrue()
assertThat(status.isPgpInlineModeEnabled).isTrue()
}
}
private void runBackgroundTask() {
boolean taskRun = Robolectric.getBackgroundThreadScheduler().runOneTask();
assertTrue(taskRun);
private fun runBackgroundTask() {
assertThat(Robolectric.getBackgroundThreadScheduler().runOneTask()).isTrue()
}
private void setupCryptoProvider(RecipientAutocryptStatus autocryptStatusResult) throws Exception {
Account account = mock(Account.class);
OpenPgpApi openPgpApi = mock(OpenPgpApi.class);
private fun setupCryptoProvider(autocryptStatusResult: RecipientAutocryptStatus) {
stubbing(account) {
on { openPgpProvider } doReturn CRYPTO_PROVIDER
on { isOpenPgpProviderConfigured } doReturn true
on { openPgpKey } doReturn CRYPTO_KEY_ID
}
when(account.getOpenPgpProvider()).thenReturn(CRYPTO_PROVIDER);
when(account.isOpenPgpProviderConfigured()).thenReturn(true);
when(account.getOpenPgpKey()).thenReturn(CRYPTO_KEY_ID);
recipientPresenter.onSwitchAccount(account);
recipientPresenter.onSwitchAccount(account)
when(openPgpApiManager.getOpenPgpProviderState()).thenReturn(OpenPgpProviderState.OK);
when(openPgpApiManager.getOpenPgpApi()).thenReturn(openPgpApi);
when(autocryptStatusInteractor.retrieveCryptoProviderRecipientStatus(
any(OpenPgpApi.class), any(String[].class))).thenReturn(autocryptStatusResult);
val openPgpApiMock = mock<OpenPgpApi>()
openPgpApiManagerCallback.onOpenPgpProviderStatusChanged();
runBackgroundTask();
stubbing(autocryptStatusInteractor) {
on { retrieveCryptoProviderRecipientStatus(eq(openPgpApiMock), any()) } doReturn autocryptStatusResult
}
stubbing(openPgpApiManager) {
on { openPgpApi } doReturn openPgpApiMock
on { openPgpProviderState } doReturn OpenPgpProviderState.OK
}
openPgpApiManagerCallback!!.onOpenPgpProviderStatusChanged()
runBackgroundTask()
}
}