Convert AccountSetupBasics to Kotlin

This commit is contained in:
cketti 2022-05-18 17:46:21 +02:00
parent bf5924d288
commit fa803526d2

View file

@ -1,359 +1,301 @@
package com.fsck.k9.activity.setup;
package com.fsck.k9.activity.setup
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import com.fsck.k9.Account;
import com.fsck.k9.Core;
import com.fsck.k9.DI;
import com.fsck.k9.EmailAddressValidator;
import com.fsck.k9.Preferences;
import com.fsck.k9.account.AccountCreator;
import com.fsck.k9.ui.base.K9Activity;
import com.fsck.k9.activity.setup.AccountSetupCheckSettings.CheckDirection;
import com.fsck.k9.autodiscovery.api.DiscoveredServerSettings;
import com.fsck.k9.autodiscovery.api.DiscoveryResults;
import com.fsck.k9.autodiscovery.api.DiscoveryTarget;
import com.fsck.k9.autodiscovery.providersxml.ProvidersXmlDiscovery;
import com.fsck.k9.helper.Utility;
import com.fsck.k9.mail.AuthType;
import com.fsck.k9.mail.ServerSettings;
import com.fsck.k9.mailstore.SpecialLocalFoldersCreator;
import com.fsck.k9.ui.R;
import com.fsck.k9.ui.ConnectionSettings;
import com.fsck.k9.ui.settings.ExtraAccountDiscovery;
import com.fsck.k9.view.ClientCertificateSpinner;
import com.fsck.k9.view.ClientCertificateSpinner.OnClientCertificateChangedListener;
import com.google.android.material.textfield.TextInputEditText;
import timber.log.Timber;
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.text.Editable
import android.view.ViewGroup
import android.widget.Button
import android.widget.CheckBox
import androidx.core.view.isVisible
import com.fsck.k9.Account
import com.fsck.k9.Core
import com.fsck.k9.EmailAddressValidator
import com.fsck.k9.Preferences
import com.fsck.k9.account.AccountCreator
import com.fsck.k9.activity.setup.AccountSetupCheckSettings.CheckDirection
import com.fsck.k9.autodiscovery.api.DiscoveredServerSettings
import com.fsck.k9.autodiscovery.api.DiscoveryTarget
import com.fsck.k9.autodiscovery.providersxml.ProvidersXmlDiscovery
import com.fsck.k9.helper.SimpleTextWatcher
import com.fsck.k9.helper.Utility.requiredFieldValid
import com.fsck.k9.mail.AuthType
import com.fsck.k9.mail.ServerSettings
import com.fsck.k9.mailstore.SpecialLocalFoldersCreator
import com.fsck.k9.ui.ConnectionSettings
import com.fsck.k9.ui.R
import com.fsck.k9.ui.base.K9Activity
import com.fsck.k9.ui.settings.ExtraAccountDiscovery
import com.fsck.k9.view.ClientCertificateSpinner
import com.google.android.material.textfield.TextInputEditText
import org.koin.android.ext.android.inject
/**
* Prompts the user for the email address and password.
* Attempts to lookup default settings for the domain the user specified. If the
* domain is known the settings are handed off to the AccountSetupCheckSettings
* activity. If no settings are found the settings are handed off to the
* AccountSetupAccountType activity.
*
* Attempts to lookup default settings for the domain the user specified. If the domain is known, the settings are
* handed off to the [AccountSetupCheckSettings] activity. If no settings are found, the settings are handed off to the
* [AccountSetupAccountType] activity.
*/
public class AccountSetupBasics extends K9Activity
implements OnClickListener, TextWatcher, OnCheckedChangeListener, OnClientCertificateChangedListener {
private final static String EXTRA_ACCOUNT = "com.fsck.k9.AccountSetupBasics.account";
private final static String STATE_KEY_CHECKED_INCOMING = "com.fsck.k9.AccountSetupBasics.checkedIncoming";
class AccountSetupBasics : K9Activity() {
private val providersXmlDiscovery: ProvidersXmlDiscovery by inject()
private val accountCreator: AccountCreator by inject()
private val localFoldersCreator: SpecialLocalFoldersCreator by inject()
private val preferences: Preferences by inject()
private val emailValidator: EmailAddressValidator by inject()
private lateinit var emailView: TextInputEditText
private lateinit var passwordView: TextInputEditText
private lateinit var clientCertificateCheckBox: CheckBox
private lateinit var clientCertificateSpinner: ClientCertificateSpinner
private lateinit var nextButton: Button
private lateinit var manualSetupButton: Button
private lateinit var allowClientCertificateView: ViewGroup
private final ProvidersXmlDiscovery providersXmlDiscovery = DI.get(ProvidersXmlDiscovery.class);
private final AccountCreator accountCreator = DI.get(AccountCreator.class);
private final SpecialLocalFoldersCreator localFoldersCreator = DI.get(SpecialLocalFoldersCreator.class);
private var account: Account? = null
private var checkedIncoming = false
private TextInputEditText mEmailView;
private TextInputEditText mPasswordView;
private CheckBox mClientCertificateCheckBox;
private ClientCertificateSpinner mClientCertificateSpinner;
private Button mNextButton;
private Button mManualSetupButton;
private Account mAccount;
private ViewGroup mAllowClientCertificateView;
public override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setLayout(R.layout.account_setup_basics)
setTitle(R.string.account_setup_basics_title)
private EmailAddressValidator mEmailValidator = new EmailAddressValidator();
private boolean mCheckedIncoming = false;
emailView = findViewById(R.id.account_email)
passwordView = findViewById(R.id.account_password)
clientCertificateCheckBox = findViewById(R.id.account_client_certificate)
clientCertificateSpinner = findViewById(R.id.account_client_certificate_spinner)
allowClientCertificateView = findViewById(R.id.account_allow_client_certificate)
nextButton = findViewById(R.id.next)
manualSetupButton = findViewById(R.id.manual_setup)
public static void actionNewAccount(Context context) {
Intent i = new Intent(context, AccountSetupBasics.class);
context.startActivity(i);
manualSetupButton.setOnClickListener { onManualSetup() }
nextButton.setOnClickListener { onNext() }
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setLayout(R.layout.account_setup_basics);
setTitle(R.string.account_setup_basics_title);
mEmailView = findViewById(R.id.account_email);
mPasswordView = findViewById(R.id.account_password);
mClientCertificateCheckBox = findViewById(R.id.account_client_certificate);
mClientCertificateSpinner = findViewById(R.id.account_client_certificate_spinner);
mAllowClientCertificateView = findViewById(R.id.account_allow_client_certificate);
mNextButton = findViewById(R.id.next);
mManualSetupButton = findViewById(R.id.manual_setup);
mNextButton.setOnClickListener(this);
mManualSetupButton.setOnClickListener(this);
}
private void initializeViewListeners() {
mEmailView.addTextChangedListener(this);
mPasswordView.addTextChangedListener(this);
mClientCertificateCheckBox.setOnCheckedChangeListener(this);
mClientCertificateSpinner.setOnClientCertificateChangedListener(this);
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if (mAccount != null) {
outState.putString(EXTRA_ACCOUNT, mAccount.getUuid());
}
outState.putBoolean(STATE_KEY_CHECKED_INCOMING, mCheckedIncoming);
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
if (savedInstanceState.containsKey(EXTRA_ACCOUNT)) {
String accountUuid = savedInstanceState.getString(EXTRA_ACCOUNT);
mAccount = Preferences.getPreferences(this).getAccount(accountUuid);
}
mCheckedIncoming = savedInstanceState.getBoolean(STATE_KEY_CHECKED_INCOMING);
updateViewVisibility(mClientCertificateCheckBox.isChecked());
}
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
override fun onPostCreate(savedInstanceState: Bundle?) {
super.onPostCreate(savedInstanceState)
/*
* We wait until now to initialize the listeners because we didn't want
* the OnCheckedChangeListener active while the
* mClientCertificateCheckBox state was being restored because it could
* trigger the pop-up of a ClientCertificateSpinner.chooseCertificate()
* dialog.
* We wait until now to initialize the listeners because we didn't want the OnCheckedChangeListener active
* while the clientCertificateCheckBox state was being restored because it could trigger the pop-up of a
* ClientCertificateSpinner.chooseCertificate() dialog.
*/
initializeViewListeners();
validateFields();
initializeViewListeners()
validateFields()
}
public void afterTextChanged(Editable s) {
validateFields();
}
private fun initializeViewListeners() {
val textWatcher = object : SimpleTextWatcher() {
override fun afterTextChanged(s: Editable) {
validateFields()
}
}
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
emailView.addTextChangedListener(textWatcher)
passwordView.addTextChangedListener(textWatcher)
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
clientCertificateCheckBox.setOnCheckedChangeListener { _, isChecked ->
updateViewVisibility(isChecked)
validateFields()
@Override
public void onClientCertificateChanged(String alias) {
validateFields();
}
// Have the user select the client certificate if not already selected
if (isChecked && clientCertificateSpinner.alias == null) {
clientCertificateSpinner.chooseCertificate()
}
}
/**
* Called when checking the client certificate CheckBox
*/
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
updateViewVisibility(isChecked);
validateFields();
// Have the user select the client certificate if not already selected
if ((isChecked) && (mClientCertificateSpinner.getAlias() == null)) {
mClientCertificateSpinner.chooseCertificate();
clientCertificateSpinner.setOnClientCertificateChangedListener {
validateFields()
}
}
private void updateViewVisibility(boolean usingCertificates) {
if (usingCertificates) {
// show client certificate spinner
mAllowClientCertificateView.setVisibility(View.VISIBLE);
} else {
// hide client certificate spinner
mAllowClientCertificateView.setVisibility(View.GONE);
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putString(EXTRA_ACCOUNT, account?.uuid)
outState.putBoolean(STATE_KEY_CHECKED_INCOMING, checkedIncoming)
}
private void validateFields() {
boolean clientCertificateChecked = mClientCertificateCheckBox.isChecked();
String clientCertificateAlias = mClientCertificateSpinner.getAlias();
String email = mEmailView.getText().toString();
override fun onRestoreInstanceState(savedInstanceState: Bundle) {
super.onRestoreInstanceState(savedInstanceState)
boolean valid = Utility.requiredFieldValid(mEmailView)
&& ((!clientCertificateChecked && Utility.requiredFieldValid(mPasswordView))
|| (clientCertificateChecked && clientCertificateAlias != null))
&& mEmailValidator.isValidAddressOnly(email);
mNextButton.setEnabled(valid);
mNextButton.setFocusable(valid);
mManualSetupButton.setEnabled(valid);
/*
* Dim the next button's icon to 50% if the button is disabled.
* TODO this can probably be done with a stateful drawable. Check into it.
* android:state_enabled
*/
Utility.setCompoundDrawablesAlpha(mNextButton, mNextButton.isEnabled() ? 255 : 128);
}
private String getOwnerName() {
String name = null;
try {
name = getDefaultSenderName();
} catch (Exception e) {
Timber.e(e, "Could not get default account name");
val accountUuid = savedInstanceState.getString(EXTRA_ACCOUNT)
if (accountUuid != null) {
account = preferences.getAccount(accountUuid)
}
if (name == null) {
name = "";
}
return name;
checkedIncoming = savedInstanceState.getBoolean(STATE_KEY_CHECKED_INCOMING)
updateViewVisibility(clientCertificateCheckBox.isChecked)
}
private String getDefaultSenderName() {
String name = null;
Account account = Preferences.getPreferences(this).getDefaultAccount();
if (account != null) {
name = account.getSenderName();
}
return name;
private fun updateViewVisibility(usingCertificates: Boolean) {
allowClientCertificateView.isVisible = usingCertificates
}
private void finishAutoSetup(ConnectionSettings connectionSettings) {
String email = mEmailView.getText().toString();
String password = mPasswordView.getText().toString();
private fun validateFields() {
val email = emailView.text?.toString().orEmpty()
val valid = requiredFieldValid(emailView) && emailValidator.isValidAddressOnly(email) && isPasswordFieldValid()
if (mAccount == null) {
mAccount = Preferences.getPreferences(this).newAccount();
mAccount.setChipColor(accountCreator.pickColor());
}
mAccount.setSenderName(getOwnerName());
mAccount.setEmail(email);
ServerSettings incomingServerSettings = connectionSettings.getIncoming().newPassword(password);
mAccount.setIncomingServerSettings(incomingServerSettings);
ServerSettings outgoingServerSettings = connectionSettings.getOutgoing().newPassword(password);
mAccount.setOutgoingServerSettings(outgoingServerSettings);
mAccount.setDeletePolicy(accountCreator.getDefaultDeletePolicy(incomingServerSettings.type));
localFoldersCreator.createSpecialLocalFolders(mAccount);
// Check incoming here. Then check outgoing in onActivityResult()
AccountSetupCheckSettings.actionCheckSettings(this, mAccount, CheckDirection.INCOMING);
nextButton.isEnabled = valid
nextButton.isFocusable = valid
manualSetupButton.isEnabled = valid
}
private ConnectionSettings providersXmlDiscoveryDiscover(String email, DiscoveryTarget discoveryTarget) {
DiscoveryResults discoveryResults = providersXmlDiscovery.discover(email, DiscoveryTarget.INCOMING_AND_OUTGOING);
if (discoveryResults == null || (discoveryResults.getIncoming().size() < 1 || discoveryResults.getOutgoing().size() < 1)) {
return null;
}
DiscoveredServerSettings incoming = discoveryResults.getIncoming().get(0);
DiscoveredServerSettings outgoing = discoveryResults.getOutgoing().get(0);
return new ConnectionSettings(new ServerSettings(
incoming.getProtocol(),
incoming.getHost(),
incoming.getPort(),
incoming.getSecurity(),
incoming.getAuthType(),
incoming.getUsername(),
null,
null
), new ServerSettings(
outgoing.getProtocol(),
outgoing.getHost(),
outgoing.getPort(),
outgoing.getSecurity(),
outgoing.getAuthType(),
outgoing.getUsername(),
null,
null
));
private fun isPasswordFieldValid(): Boolean {
val clientCertificateChecked = clientCertificateCheckBox.isChecked
val clientCertificateAlias = clientCertificateSpinner.alias
return !clientCertificateChecked && requiredFieldValid(passwordView) ||
clientCertificateChecked && clientCertificateAlias != null
}
private void onNext() {
if (mClientCertificateCheckBox.isChecked()) {
private fun onNext() {
if (clientCertificateCheckBox.isChecked) {
// Auto-setup doesn't support client certificates.
onManualSetup();
return;
onManualSetup()
return
}
String email = mEmailView.getText().toString();
val email = emailView.text?.toString() ?: error("Email missing")
ConnectionSettings extraConnectionSettings = ExtraAccountDiscovery.discover(email);
val extraConnectionSettings = ExtraAccountDiscovery.discover(email)
if (extraConnectionSettings != null) {
finishAutoSetup(extraConnectionSettings);
return;
finishAutoSetup(extraConnectionSettings)
return
}
ConnectionSettings connectionSettings = providersXmlDiscoveryDiscover(email, DiscoveryTarget.INCOMING_AND_OUTGOING);
val connectionSettings = providersXmlDiscoveryDiscover(email)
if (connectionSettings != null) {
finishAutoSetup(connectionSettings);
finishAutoSetup(connectionSettings)
} else {
// We don't have default settings for this account, start the manual setup process.
onManualSetup();
onManualSetup()
}
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
private fun finishAutoSetup(connectionSettings: ConnectionSettings) {
val email = emailView.text?.toString() ?: error("Email missing")
val password = passwordView.text?.toString()
val account = initAccount(email)
val incomingServerSettings = connectionSettings.incoming.newPassword(password)
account.incomingServerSettings = incomingServerSettings
val outgoingServerSettings = connectionSettings.outgoing.newPassword(password)
account.outgoingServerSettings = outgoingServerSettings
account.deletePolicy = accountCreator.getDefaultDeletePolicy(incomingServerSettings.type)
localFoldersCreator.createSpecialLocalFolders(account)
// Check incoming here. Then check outgoing in onActivityResult()
AccountSetupCheckSettings.actionCheckSettings(this, account, CheckDirection.INCOMING)
}
private fun onManualSetup() {
val email = emailView.text?.toString() ?: error("Email missing")
var password: String? = passwordView.text?.toString()
var clientCertificateAlias: String? = null
var authenticationType: AuthType = AuthType.PLAIN
if (clientCertificateCheckBox.isChecked) {
clientCertificateAlias = clientCertificateSpinner.alias
if (password.isNullOrEmpty()) {
authenticationType = AuthType.EXTERNAL
password = null
}
}
val account = initAccount(email)
val initialAccountSettings = InitialAccountSettings(
authenticationType = authenticationType,
email = email,
password = password,
clientCertificateAlias = clientCertificateAlias
)
AccountSetupAccountType.actionSelectAccountType(this, account, makeDefault = false, initialAccountSettings)
}
private fun initAccount(email: String): Account {
val account = this.account ?: createAccount().also { this.account = it }
account.senderName = getOwnerName()
account.email = email
return account
}
private fun createAccount(): Account {
return preferences.newAccount().apply {
chipColor = accountCreator.pickColor()
}
}
private fun getOwnerName(): String {
return preferences.defaultAccount?.senderName ?: ""
}
private fun providersXmlDiscoveryDiscover(email: String): ConnectionSettings? {
val discoveryResults = providersXmlDiscovery.discover(email, DiscoveryTarget.INCOMING_AND_OUTGOING)
if (discoveryResults == null || discoveryResults.incoming.isEmpty() || discoveryResults.outgoing.isEmpty()) {
return null
}
val incomingServerSettings = discoveryResults.incoming.first().toServerSettings() ?: return null
val outgoingServerSettings = discoveryResults.outgoing.first().toServerSettings() ?: return null
return ConnectionSettings(incomingServerSettings, outgoingServerSettings)
}
public override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode != AccountSetupCheckSettings.ACTIVITY_REQUEST_CODE) {
super.onActivityResult(requestCode, resultCode, data);
return;
super.onActivityResult(requestCode, resultCode, data)
return
}
if (resultCode == RESULT_OK) {
if (!mCheckedIncoming) {
//We've successfully checked incoming. Now check outgoing.
mCheckedIncoming = true;
AccountSetupCheckSettings.actionCheckSettings(this, mAccount, CheckDirection.OUTGOING);
if (!checkedIncoming) {
// We've successfully checked incoming. Now check outgoing.
checkedIncoming = true
AccountSetupCheckSettings.actionCheckSettings(this, account, CheckDirection.OUTGOING)
} else {
//We've successfully checked outgoing as well.
mAccount.setName(mAccount.getEmail());
Preferences.getPreferences(this).saveAccount(mAccount);
Core.setServicesEnabled(this);
AccountSetupNames.actionSetNames(this, mAccount);
// We've successfully checked outgoing as well.
val account = this.account ?: error("Account instance missing")
preferences.saveAccount(account)
Core.setServicesEnabled(applicationContext)
AccountSetupNames.actionSetNames(this, account)
}
}
}
private void onManualSetup() {
String email = mEmailView.getText().toString();
companion object {
private const val EXTRA_ACCOUNT = "com.fsck.k9.AccountSetupBasics.account"
private const val STATE_KEY_CHECKED_INCOMING = "com.fsck.k9.AccountSetupBasics.checkedIncoming"
String password = null;
String clientCertificateAlias = null;
AuthType authenticationType;
authenticationType = AuthType.PLAIN;
password = mPasswordView.getText().toString();
if (mClientCertificateCheckBox.isChecked()) {
clientCertificateAlias = mClientCertificateSpinner.getAlias();
if (mPasswordView.getText().toString().equals("")) {
authenticationType = AuthType.EXTERNAL;
password = null;
}
}
if (mAccount == null) {
mAccount = Preferences.getPreferences(this).newAccount();
mAccount.setChipColor(accountCreator.pickColor());
}
mAccount.setSenderName(getOwnerName());
mAccount.setEmail(email);
InitialAccountSettings initialAccountSettings = new InitialAccountSettings(authenticationType, email, password,
clientCertificateAlias);
AccountSetupAccountType.actionSelectAccountType(this, mAccount, false, initialAccountSettings);
}
public void onClick(View v) {
int id = v.getId();
if (id == R.id.next) {
onNext();
} else if (id == R.id.manual_setup) {
onManualSetup();
@JvmStatic
fun actionNewAccount(context: Context) {
val intent = Intent(context, AccountSetupBasics::class.java)
context.startActivity(intent)
}
}
}
private fun DiscoveredServerSettings.toServerSettings(): ServerSettings? {
val authType = this.authType ?: return null
val username = this.username ?: return null
return ServerSettings(
type = protocol,
host = host,
port = port,
connectionSecurity = security,
authenticationType = authType,
username = username,
password = null,
clientCertificateAlias = null
)
}