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

Commit 1e69cbcd authored by daquexian's avatar daquexian Committed by Vincent Breitmoser
Browse files

integrate xoauth2 and new UI, handle the dialog appearing when user's prompt is needed for xoauth2

parent 6ec83381
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -117,7 +117,7 @@ public class AndroidAccountOAuth2TokenStore implements OAuth2TokenProvider {
            if (bundle == null)
                throw new AuthenticationFailedException("No token provided");
            if (bundle.get(AccountManager.KEY_INTENT) != null) {
                promptRequestHandler.handleIntent((Intent) bundle.get(AccountManager.KEY_INTENT));
                promptRequestHandler.handleGMailXOAuth2Intent((Intent) bundle.get(AccountManager.KEY_INTENT));
                throw new OAuth2NeedUserPromptException();
            } else {
                if (bundle.get(AccountManager.KEY_ACCOUNT_NAME) == null)
+1 −1
Original line number Diff line number Diff line
@@ -3,5 +3,5 @@ package com.fsck.k9.account;
import android.content.Intent;

public interface GMailXOauth2PromptRequestHandler {
    void handleIntent(Intent intent);
    void handleGMailXOAuth2Intent(Intent intent);
}
+28 −2
Original line number Diff line number Diff line
@@ -4,7 +4,6 @@ import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Looper;
import android.support.annotation.LayoutRes;
import android.support.annotation.Nullable;
import android.support.design.widget.CoordinatorLayout;
@@ -12,6 +11,7 @@ import android.support.design.widget.Snackbar;
import android.support.design.widget.TextInputEditText;
import android.support.design.widget.TextInputLayout;
import android.view.View;
import android.view.View.OnFocusChangeListener;
import android.view.ViewGroup;

import com.fsck.k9.Preferences;
@@ -31,7 +31,6 @@ import android.app.AlertDialog;
import android.app.DialogFragment;
import android.app.FragmentTransaction;
import android.content.DialogInterface;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.text.Editable;
import android.text.TextWatcher;
@@ -233,7 +232,9 @@ public class AccountSetupActivity extends AppCompatActivity implements AccountSe
    }

    private void basicsStart() {
        coordinatorLayout = (CoordinatorLayout) findViewById(R.id.basics_coordinator_layout);
        emailView = (EditText) findViewById(R.id.account_email);
        passwordViewLayout = (TextInputLayout) findViewById(R.id.password_input_layout);
        passwordView = (EditText) findViewById(R.id.account_password);
        manualSetupButton = (Button) findViewById(R.id.manual_setup);
        nextButton = (Button) findViewById(R.id.basics_next);
@@ -272,6 +273,20 @@ public class AccountSetupActivity extends AppCompatActivity implements AccountSe
    private void initializeViewListenersInBasics() {
        emailView.addTextChangedListener(validationTextWatcherInBasics);
        passwordView.addTextChangedListener(validationTextWatcherInBasics);
        emailView.setOnFocusChangeListener(new OnFocusChangeListener() {
            @Override
            public void onFocusChange(View v, boolean hasFocus) {
                if (!hasFocus) {
                    presenter.onEmailEditTextLosesFocus(emailView.getText().toString());
                }
            }
        });
    }

    @Override
    public void setPasswordAndManualSetupButtonInBasicsVisibility(int visibility) {
        passwordViewLayout.setVisibility(visibility);
        manualSetupButton.setVisibility(visibility);
    }

    private void checkingStart() {
@@ -1239,6 +1254,17 @@ public class AccountSetupActivity extends AppCompatActivity implements AccountSe
        onBackPressed();
    }

    @Override
    public void startIntentForResult(Intent intent, int requestCode) {
        startActivityForResult(intent, requestCode);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        canceled = false;
        presenter.onActivityResult(requestCode, resultCode, data);
    }

    @Override
    protected void onResume() {
        super.onResume();
+6 −0
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@ import java.net.URISyntaxException;
import java.security.cert.X509Certificate;

import android.content.Context;
import android.content.Intent;
import android.support.annotation.StringRes;

import com.fsck.k9.Account;
@@ -22,6 +23,7 @@ interface AccountSetupContract {
        void goToIncomingSettings();

        // basics
        void setPasswordAndManualSetupButtonInBasicsVisibility(int visibility);
        void setNextButtonInBasicsEnabled(boolean enabled);
        void goToAccountType();
        void goToAutoConfiguration();
@@ -115,6 +117,7 @@ interface AccountSetupContract {
        // ---
        void goBack();
        void end();
        void startIntentForResult(Intent intent, int requestCode);
    }

    interface Presenter extends BasePresenter {
@@ -128,6 +131,7 @@ interface AccountSetupContract {
        void onManualSetupButtonClicked(String email, String password);
        void onNextButtonInBasicViewClicked(String email, String password);
        void setAccount(Account account);
        void onEmailEditTextLosesFocus(String email);
        Account getAccount();

        /* checking */
@@ -183,6 +187,8 @@ interface AccountSetupContract {
        void onRestoreStart();
        void onRestoreEnd();

        void onActivityResult(int requestCode, int resultCode, Intent data);

        AccountSetupPresenter.AccountSetupStatus getStatus();
        AccountConfig getAccountConfig();
    }
+78 −13
Original line number Diff line number Diff line
package com.fsck.k9.activity.setup;


import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.res.XmlResourceParser;
import android.os.AsyncTask;
import android.os.Handler;
@@ -17,6 +19,8 @@ import com.fsck.k9.K9;
import com.fsck.k9.Preferences;
import com.fsck.k9.R;
import com.fsck.k9.account.AccountCreator;
import com.fsck.k9.account.AndroidAccountOAuth2TokenStore;
import com.fsck.k9.account.GMailXOauth2PromptRequestHandler;
import com.fsck.k9.activity.AccountConfig;
import com.fsck.k9.activity.setup.AccountSetupContract.View;
import com.fsck.k9.controller.MessagingController;
@@ -28,6 +32,7 @@ import com.fsck.k9.mail.AuthenticationFailedException;
import com.fsck.k9.mail.CertificateValidationException;
import com.fsck.k9.mail.ConnectionSecurity;
import com.fsck.k9.mail.NetworkType;
import com.fsck.k9.mail.OAuth2NeedUserPromptException;
import com.fsck.k9.mail.ServerSettings;
import com.fsck.k9.mail.ServerSettings.Type;
import com.fsck.k9.mail.Store;
@@ -68,7 +73,8 @@ import static com.fsck.k9.mail.ServerSettings.Type.SMTP;
import static com.fsck.k9.mail.ServerSettings.Type.WebDAV;


public class AccountSetupPresenter implements AccountSetupContract.Presenter {
public class AccountSetupPresenter implements AccountSetupContract.Presenter,
        GMailXOauth2PromptRequestHandler {

    private Context context;
    private Preferences preferences;
@@ -78,6 +84,8 @@ public class AccountSetupPresenter implements AccountSetupContract.Presenter {
    private boolean makeDefault;
    private Provider provider;

    private static final int REQUEST_CODE_GMAIL = 1;

    enum Stage {
        BASICS,
        AUTOCONFIGURATION,
@@ -121,6 +129,8 @@ public class AccountSetupPresenter implements AccountSetupContract.Presenter {
        this.preferences = preferences;
        this.view = view;
        this.handler = new Handler(Looper.getMainLooper());
        ((AndroidAccountOAuth2TokenStore) Globals.getOAuth2TokenProvider()).
                setPromptRequestHandler(this);
    }

    // region basics
@@ -135,12 +145,32 @@ public class AccountSetupPresenter implements AccountSetupContract.Presenter {
        EmailAddressValidator emailValidator = new EmailAddressValidator();

        boolean valid = email != null && email.length() > 0
                && password != null && password.length() > 0
                && (onlyXOAuth2(email) || (password != null && password.length() > 0))
                && emailValidator.isValidAddressOnly(email);

        if (!onlyXOAuth2(email)) {
            view.setPasswordAndManualSetupButtonInBasicsVisibility(android.view.View.VISIBLE);
        }

        view.setNextButtonInBasicsEnabled(valid);
    }

    @Override
    public void onEmailEditTextLosesFocus(String email) {
        if (onlyXOAuth2(email)) {
            view.setPasswordAndManualSetupButtonInBasicsVisibility(android.view.View.GONE);
            view.setNextButtonInBasicsEnabled(true);
        } else {
            view.setPasswordAndManualSetupButtonInBasicsVisibility(android.view.View.VISIBLE);
        }
    }

    private boolean onlyXOAuth2(String email) {
        EmailHelper emailHelper = new EmailHelper();
        String domain = emailHelper.splitEmail(email)[1];
        return domain.equals("gmail.com");
    }

    @Override
    public void onManualSetupButtonClicked(String email, String password) {
        manualSetup(email, password);
@@ -198,7 +228,6 @@ public class AccountSetupPresenter implements AccountSetupContract.Presenter {
                EmailHelper emailHelper = new EmailHelper();
                String[] emailParts = emailHelper.splitEmail(email);
                final String domain = emailParts[1];

                ProviderInfo providerInfo;
                AutoconfigureMozilla autoconfigureMozilla = new AutoconfigureMozilla();
                AutoconfigureSrv autoconfigureSrv = new AutoconfigureSrv();
@@ -223,17 +252,24 @@ public class AccountSetupPresenter implements AccountSetupContract.Presenter {
            protected void onPostExecute(ProviderInfo providerInfo) {
                super.onPostExecute(providerInfo);

                if (providerInfo != null) {
                try {
                    if (providerInfo != null) {
                        provider = Provider.newInstanceFromProviderInfo(providerInfo);
                        modifyAccount(accountConfig.getEmail(), password, provider);
                    }

                    if (provider != null) {
                        boolean usingOAuth2 = false;
                        if (onlyXOAuth2(email)) {
                            usingOAuth2 = true;
                        }
                        modifyAccount(accountConfig.getEmail(), password, provider, usingOAuth2);

                        checkIncomingAndOutgoing();
                    }
                } catch (URISyntaxException e) {
                    Timber.e(e, "Error while converting providerInfo to provider");
                    provider = null;
                }
                }

                if (provider == null) {
                    manualSetup(accountConfig.getEmail(), password);
@@ -473,6 +509,8 @@ public class AccountSetupPresenter implements AccountSetupContract.Presenter {

                return true;

            } catch (OAuth2NeedUserPromptException ignored) {

            } catch (final AuthenticationFailedException afe) {
                Timber.e(afe, "Error while testing settings");
                handler.post(new Runnable() {
@@ -569,7 +607,9 @@ public class AccountSetupPresenter implements AccountSetupContract.Presenter {
        return null;
    }

    private void modifyAccount(String email, String password, @NonNull Provider provider) throws URISyntaxException {
    private void modifyAccount(String email, String password, @NonNull Provider provider,
                               boolean usingOAuth2) throws URISyntaxException {

        accountConfig.init(email, password);

        EmailHelper emailHelper = new EmailHelper();
@@ -585,7 +625,11 @@ public class AccountSetupPresenter implements AccountSetupContract.Presenter {
        incomingUsername = incomingUsername.replaceAll("\\$domain", domain);

        URI incomingUriTemplate = provider.incomingUriTemplate;
        URI incomingUri = new URI(incomingUriTemplate.getScheme(), incomingUsername + ":" + passwordEnc,
        String incomingUserInfo = incomingUsername + ":" + passwordEnc;
        if (usingOAuth2) {
            incomingUserInfo = AuthType.XOAUTH2 + ":" + incomingUserInfo;
        }
        URI incomingUri = new URI(incomingUriTemplate.getScheme(), incomingUserInfo,
                incomingUriTemplate.getHost(), incomingUriTemplate.getPort(), null, null, null);

        String outgoingUsername = provider.outgoingUsernameTemplate;
@@ -598,8 +642,13 @@ public class AccountSetupPresenter implements AccountSetupContract.Presenter {
            outgoingUsername = outgoingUsername.replaceAll("\\$email", email);
            outgoingUsername = outgoingUsername.replaceAll("\\$user", userEnc);
            outgoingUsername = outgoingUsername.replaceAll("\\$domain", domain);
            outgoingUri = new URI(outgoingUriTemplate.getScheme(), outgoingUsername + ":"
                    + passwordEnc, outgoingUriTemplate.getHost(), outgoingUriTemplate.getPort(), null,

            String outgoingUserInfo = outgoingUsername + ":" + passwordEnc;
            if (usingOAuth2) {
                outgoingUserInfo = outgoingUserInfo + ":" + AuthType.XOAUTH2;
            }
            outgoingUri = new URI(outgoingUriTemplate.getScheme(), outgoingUserInfo,
                    outgoingUriTemplate.getHost(), outgoingUriTemplate.getPort(), null,
                    null, null);

        } else {
@@ -1575,6 +1624,22 @@ public class AccountSetupPresenter implements AccountSetupContract.Presenter {
        view.goToAccountType();
    }

    @Override
    public void handleGMailXOAuth2Intent(Intent intent) {
        view.startIntentForResult(intent, REQUEST_CODE_GMAIL);
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == REQUEST_CODE_GMAIL) {
            if (resultCode == Activity.RESULT_OK) {
                checkIncomingAndOutgoing();
            } else {
                view.goBack();
            }
        }
    }

    static class AccountSetupStatus {
        private ConnectionSecurity incomingSecurityType;
        private AuthType incomingAuthType;
Loading