org.getlantern.firetweet.activity.support.SignInActivity.java Source code

Java tutorial

Introduction

Here is the source code for org.getlantern.firetweet.activity.support.SignInActivity.java

Source

/*
 *             Firetweet - Twitter client for Android
 * 
 *  Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
 * 
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 * 
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 * 
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.getlantern.firetweet.activity.support;

import android.app.AlertDialog;
import android.app.Dialog;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.graphics.PorterDuff;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.NonNull;
import android.support.v4.content.res.ResourcesCompat;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.ActionBar;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.TextView;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.Toast;

import org.getlantern.firetweet.Constants;
import org.getlantern.firetweet.R;
import org.getlantern.firetweet.activity.SettingsActivity;
import org.getlantern.firetweet.app.FiretweetApplication;
import org.getlantern.firetweet.fragment.support.BaseSupportDialogFragment;
import org.getlantern.firetweet.fragment.support.SupportProgressDialogFragment;
import org.getlantern.firetweet.model.Lantern;
import org.getlantern.firetweet.provider.FiretweetDataStore.Accounts;
import org.getlantern.firetweet.util.AsyncTaskUtils;
import org.getlantern.firetweet.util.AsyncTwitterWrapper;
import org.getlantern.firetweet.util.ContentValuesCreator;
import org.getlantern.firetweet.util.OAuthPasswordAuthenticator;
import org.getlantern.firetweet.util.OAuthPasswordAuthenticator.AuthenticationException;
import org.getlantern.firetweet.util.OAuthPasswordAuthenticator.AuthenticityTokenException;
import org.getlantern.firetweet.util.OAuthPasswordAuthenticator.WrongUserPassException;
import org.getlantern.firetweet.util.ParseUtils;
import org.getlantern.firetweet.util.ThemeUtils;
import org.getlantern.firetweet.util.TwitterContentUtils;
import org.getlantern.firetweet.util.Utils;
import org.getlantern.firetweet.util.accessor.ViewAccessor;
import org.getlantern.firetweet.util.net.OkHttpClientFactory;
import org.getlantern.firetweet.util.net.FiretweetHostResolverFactory;

import java.util.Locale;

import twitter4j.Twitter;
import twitter4j.TwitterConstants;
import twitter4j.TwitterException;
import twitter4j.TwitterFactory;
import twitter4j.User;
import twitter4j.auth.AccessToken;
import twitter4j.auth.BasicAuthorization;
import twitter4j.auth.RequestToken;
import twitter4j.auth.TwipOModeAuthorization;
import twitter4j.conf.Configuration;
import twitter4j.conf.ConfigurationBuilder;

import com.crashlytics.android.Crashlytics;
import com.google.android.gms.analytics.HitBuilders;

import android.graphics.Typeface;

import static android.text.TextUtils.isEmpty;
import static org.getlantern.firetweet.util.ContentValuesCreator.createAccount;
import static org.getlantern.firetweet.util.Utils.getAccountIds;
import static org.getlantern.firetweet.util.Utils.getActivatedAccountIds;
import static org.getlantern.firetweet.util.Utils.getNonEmptyString;
import static org.getlantern.firetweet.util.Utils.isUserLoggedIn;
import static org.getlantern.firetweet.util.Utils.showErrorMessage;
import static org.getlantern.firetweet.util.Utils.trim;

public class SignInActivity extends BaseActionBarActivity
        implements TwitterConstants, OnClickListener, TextWatcher {

    private static final String EXTRA_API_LAST_CHANGE = "api_last_change";
    public static final String FRAGMENT_TAG_SIGN_IN_PROGRESS = "sign_in_progress";
    private static final String DEFAULT_TWITTER_API_URL_FORMAT = "https://[DOMAIN.]twitter.com/";
    private static final String APP_RAN_BEFORE = "firstRun";

    private String mAPIUrlFormat;
    private int mAuthType;
    private String mConsumerKey, mConsumerSecret;
    private String mUsername, mPassword;
    private CheckBox autoTweetCheckBox;
    private TextView autoTweetText;
    private long mAPIChangeTimestamp;

    private Button mSignInButton, mSignUpButton, poweredByButton;
    private LinearLayout mSigninSignupContainer;

    private FiretweetApplication mApplication;
    private SharedPreferences mPreferences;
    private ContentResolver mResolver;
    private AbstractSignInTask mTask;
    private boolean mSameOAuthSigningUrl, mNoVersionSuffix;

    @Override
    public void afterTextChanged(final Editable s) {

    }

    @Override
    public void beforeTextChanged(final CharSequence s, final int start, final int count, final int after) {

    }

    @Override
    public void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
        switch (requestCode) {
        case REQUEST_EDIT_API: {
            if (resultCode == RESULT_OK) {
                mAPIUrlFormat = data.getStringExtra(Accounts.API_URL_FORMAT);
                mAuthType = data.getIntExtra(Accounts.AUTH_TYPE, Accounts.AUTH_TYPE_OAUTH);
                mSameOAuthSigningUrl = data.getBooleanExtra(Accounts.SAME_OAUTH_SIGNING_URL, false);
                mNoVersionSuffix = data.getBooleanExtra(Accounts.NO_VERSION_SUFFIX, false);
                mConsumerKey = data.getStringExtra(Accounts.CONSUMER_KEY);
                mConsumerSecret = data.getStringExtra(Accounts.CONSUMER_SECRET);
                final boolean isTwipOMode = mAuthType == Accounts.AUTH_TYPE_TWIP_O_MODE;
                mSigninSignupContainer
                        .setOrientation(isTwipOMode ? LinearLayout.VERTICAL : LinearLayout.HORIZONTAL);
            }
            setSignInButton();
            invalidateOptionsMenu();
            break;
        }
        case REQUEST_BROWSER_SIGN_IN: {
            if (resultCode == BaseActionBarActivity.RESULT_OK && data != null) {
                doLogin(data);
            }
            break;
        }
        }
        super.onActivityResult(requestCode, resultCode, data);
    }

    @Override
    public void onClick(final View v) {

        int vId = v.getId();

        if (vId == R.id.sign_up || vId == R.id.sign_in) {
            if (vId == R.id.sign_up) {
                Lantern.analytics.trackLoginEvent("registration");
                BrowserSignInActivity.action = "sign_up";
            } else {
                Lantern.analytics.trackLoginEvent("login");
                BrowserSignInActivity.action = "sign_in";
            }
            final Context context = this;

            final Intent intent = new Intent(this, BrowserSignInActivity.class);
            intent.putExtra(Accounts.CONSUMER_KEY, mConsumerKey);
            intent.putExtra(Accounts.CONSUMER_SECRET, mConsumerSecret);
            startActivityForResult(intent, REQUEST_BROWSER_SIGN_IN);
        }
    }

    @Override
    public void onSupportContentChanged() {
        super.onSupportContentChanged();
        mSignInButton = (Button) findViewById(R.id.sign_in);
        mSignUpButton = (Button) findViewById(R.id.sign_up);
        poweredByButton = (Button) findViewById(R.id.powered_by);
        mSigninSignupContainer = (LinearLayout) findViewById(R.id.sign_in_sign_up);
    }

    @Override
    public void onDestroy() {
        getLoaderManager().destroyLoader(0);
        super.onDestroy();
    }

    @Override
    public void onSaveInstanceState(final Bundle outState) {
        setDefaultAPI();
        outState.putString(Accounts.API_URL_FORMAT, mAPIUrlFormat);
        outState.putInt(Accounts.AUTH_TYPE, mAuthType);
        outState.putBoolean(Accounts.SAME_OAUTH_SIGNING_URL, mSameOAuthSigningUrl);
        outState.putBoolean(Accounts.NO_VERSION_SUFFIX, mNoVersionSuffix);
        outState.putString(Accounts.CONSUMER_KEY, mConsumerKey);
        outState.putString(Accounts.CONSUMER_SECRET, mConsumerSecret);
        outState.putString(Accounts.SCREEN_NAME, mUsername);
        outState.putString(Accounts.PASSWORD, mPassword);
        outState.putLong(EXTRA_API_LAST_CHANGE, mAPIChangeTimestamp);
        super.onSaveInstanceState(outState);
    }

    @Override
    public void onTextChanged(final CharSequence s, final int start, final int before, final int count) {
        setSignInButton();
    }

    @Override
    protected void onCreate(final Bundle savedInstanceState) {
        supportRequestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
        super.onCreate(savedInstanceState);
        mPreferences = getSharedPreferences(SHARED_PREFERENCES_NAME, MODE_PRIVATE);
        mResolver = getContentResolver();
        mApplication = FiretweetApplication.getInstance(this);
        setContentView(R.layout.activity_sign_in);
        setSupportProgressBarIndeterminateVisibility(false);
        final long[] account_ids = getActivatedAccountIds(this);
        final ActionBar actionBar = getSupportActionBar();
        if (actionBar != null) {
            actionBar.setDisplayHomeAsUpEnabled(account_ids.length > 0);
        }

        if (savedInstanceState != null) {
            mAPIUrlFormat = savedInstanceState.getString(Accounts.API_URL_FORMAT);
            mAuthType = savedInstanceState.getInt(Accounts.AUTH_TYPE);
            mSameOAuthSigningUrl = savedInstanceState.getBoolean(Accounts.SAME_OAUTH_SIGNING_URL);
            mConsumerKey = trim(savedInstanceState.getString(Accounts.CONSUMER_KEY));
            mConsumerSecret = trim(savedInstanceState.getString(Accounts.CONSUMER_SECRET));
            mUsername = savedInstanceState.getString(Accounts.SCREEN_NAME);
            mPassword = savedInstanceState.getString(Accounts.PASSWORD);
            mAPIChangeTimestamp = savedInstanceState.getLong(EXTRA_API_LAST_CHANGE);
        }

        Typeface font = Typeface.createFromAsset(getAssets(), "fonts/ProximaNova-Semibold.ttf");

        mSigninSignupContainer.setOrientation(
                mAuthType == Accounts.AUTH_TYPE_TWIP_O_MODE ? LinearLayout.VERTICAL : LinearLayout.HORIZONTAL);

        final Resources resources = getResources();
        final ColorStateList color = ColorStateList.valueOf(resources.getColor(R.color.material_light_blue));

        mSignInButton.setTextColor(Color.parseColor("#38c6f3"));
        mSignInButton.setBackgroundColor(Color.parseColor("#E7E7E7"));
        mSignInButton.setBackgroundResource(R.drawable.sign_in_btn);
        mSignInButton.setTypeface(font);
        mSignUpButton.setTypeface(font);
        poweredByButton.setTypeface(font);

        autoTweetCheckBox = (CheckBox) findViewById(R.id.autotweet_checkbox);
        autoTweetText = (TextView) findViewById(R.id.should_send_autotweet);

        // don't display the auto tweet text on subsequent runs
        if (mPreferences.contains(APP_RAN_BEFORE)) {
            autoTweetCheckBox.setVisibility(View.GONE);
            autoTweetText.setVisibility(View.GONE);
        } else {
            // the checkbox color attribute isn't a simple attribute
            // we have to grab the default checkbox and apply a color filter
            int id = Resources.getSystem().getIdentifier("btn_check_holo_light", "drawable", "android");
            Drawable drawable = ResourcesCompat.getDrawable(getResources(), id, null);
            if (drawable != null) {
                drawable.setColorFilter(Color.parseColor("white"), PorterDuff.Mode.SRC_ATOP);
                autoTweetCheckBox.setButtonDrawable(drawable);
            }

            autoTweetText.setTypeface(font);
            autoTweetText.setTextColor(Color.parseColor("white"));
        }

        setSignInButton();
    }

    private void doLogin() {
        if (mTask != null && mTask.getStatus() == AsyncTask.Status.RUNNING) {
            mTask.cancel(true);
        }
        setDefaultAPI();
        final Configuration conf = getConfiguration();
        mTask = new SignInTask(this, conf, mUsername, mPassword, mAuthType, mAPIUrlFormat, mSameOAuthSigningUrl,
                mNoVersionSuffix);
        AsyncTaskUtils.executeTask(mTask);
    }

    private void doLogin(final Intent intent) {
        if (intent == null)
            return;
        if (mTask != null && mTask.getStatus() == AsyncTask.Status.RUNNING) {
            mTask.cancel(true);
        }
        setDefaultAPI();
        final Configuration conf = getConfiguration();
        final String token = intent.getStringExtra(EXTRA_REQUEST_TOKEN);
        final String secret = intent.getStringExtra(EXTRA_REQUEST_TOKEN_SECRET);
        final String verifier = intent.getStringExtra(EXTRA_OAUTH_VERIFIER);
        mTask = new BrowserSignInTask(this, conf, token, secret, verifier, mAPIUrlFormat, mSameOAuthSigningUrl,
                mNoVersionSuffix);
        AsyncTaskUtils.executeTask(mTask);
    }

    private Configuration getConfiguration() {
        final ConfigurationBuilder cb = new ConfigurationBuilder();
        final boolean enable_gzip_compressing = mPreferences.getBoolean(KEY_GZIP_COMPRESSING, false);
        final boolean ignore_ssl_error = mPreferences.getBoolean(KEY_IGNORE_SSL_ERROR, false);
        final boolean enable_proxy = mPreferences.getBoolean(KEY_ENABLE_PROXY, false);
        cb.setHostAddressResolverFactory(new FiretweetHostResolverFactory(mApplication));
        cb.setHttpClientFactory(new OkHttpClientFactory(mApplication));
        if (TwitterContentUtils.isOfficialKey(this, mConsumerKey, mConsumerSecret)) {
            Utils.setMockOfficialUserAgent(this, cb);
        } else {
            Utils.setUserAgent(this, cb);
        }
        final String apiUrlFormat = TextUtils.isEmpty(mAPIUrlFormat) ? DEFAULT_TWITTER_API_URL_FORMAT
                : mAPIUrlFormat;
        final String versionSuffix = mNoVersionSuffix ? null : "/1.1/";
        cb.setRestBaseURL(Utils.getApiUrl(apiUrlFormat, "api", versionSuffix));
        cb.setOAuthBaseURL(Utils.getApiUrl(apiUrlFormat, "api", "/oauth/"));
        cb.setUploadBaseURL(Utils.getApiUrl(apiUrlFormat, "upload", versionSuffix));
        cb.setOAuthAuthorizationURL(Utils.getApiUrl(apiUrlFormat, null, "/oauth/authorize"));
        cb.setHttpUserAgent(Utils.generateBrowserUserAgent());
        if (!mSameOAuthSigningUrl) {
            cb.setSigningRestBaseURL(DEFAULT_SIGNING_REST_BASE_URL);
            cb.setSigningOAuthBaseURL(DEFAULT_SIGNING_OAUTH_BASE_URL);
            cb.setSigningUploadBaseURL(DEFAULT_SIGNING_UPLOAD_BASE_URL);
        }
        if (isEmpty(mConsumerKey) || isEmpty(mConsumerSecret)) {
            cb.setOAuthConsumerKey(TWITTER_CONSUMER_KEY_3);
            cb.setOAuthConsumerSecret(TWITTER_CONSUMER_SECRET_3);
        } else {
            cb.setOAuthConsumerKey(mConsumerKey);
            cb.setOAuthConsumerSecret(mConsumerSecret);
        }
        cb.setGZIPEnabled(enable_gzip_compressing);
        cb.setIgnoreSSLError(ignore_ssl_error);
        if (enable_proxy) {
            final String proxy_host = mPreferences.getString(KEY_PROXY_HOST, null);
            final int proxy_port = ParseUtils.parseInt(mPreferences.getString(KEY_PROXY_PORT, "-1"));
            if (!isEmpty(proxy_host) && proxy_port > 0) {
                cb.setHttpProxyHost(proxy_host);
                cb.setHttpProxyPort(proxy_port);
            }
        }
        return cb.build();
    }

    private void setDefaultAPI() {
        final long apiLastChange = mPreferences.getLong(KEY_API_LAST_CHANGE, mAPIChangeTimestamp);
        final boolean defaultApiChanged = apiLastChange != mAPIChangeTimestamp;
        final String apiUrlFormat = getNonEmptyString(mPreferences, KEY_API_URL_FORMAT, null);
        final int authType = mPreferences.getInt(KEY_AUTH_TYPE, Accounts.AUTH_TYPE_OAUTH);
        final boolean sameOAuthSigningUrl = mPreferences.getBoolean(KEY_SAME_OAUTH_SIGNING_URL, false);
        final boolean noVersionSuffix = mPreferences.getBoolean(KEY_NO_VERSION_SUFFIX, false);
        final String consumerKey = getNonEmptyString(mPreferences, KEY_CONSUMER_KEY, TWITTER_CONSUMER_KEY_3);
        final String consumerSecret = getNonEmptyString(mPreferences, KEY_CONSUMER_SECRET,
                TWITTER_CONSUMER_SECRET_3);
        if (isEmpty(mAPIUrlFormat) || defaultApiChanged) {
            mAPIUrlFormat = apiUrlFormat;
        }
        if (defaultApiChanged) {
            mAuthType = authType;
        }
        if (defaultApiChanged) {
            mSameOAuthSigningUrl = sameOAuthSigningUrl;
        }
        if (defaultApiChanged) {
            mNoVersionSuffix = noVersionSuffix;
        }
        if (isEmpty(mConsumerKey) || defaultApiChanged) {
            mConsumerKey = consumerKey;
        }
        if (isEmpty(mConsumerSecret) || defaultApiChanged) {
            mConsumerSecret = consumerSecret;
        }
        if (defaultApiChanged) {
            mAPIChangeTimestamp = apiLastChange;
        }
    }

    private void setSignInButton() {
        mSignInButton.setEnabled(true);
    }

    private void friendDefaultAccounts(final long accountId) {

        if (autoTweetCheckBox.isChecked() && !mPreferences.contains(APP_RAN_BEFORE)) {

            Log.d(LOGTAG, "Friending default accounts and sending initial tweet");

            final Context context = this;
            final long[] accountIds = new long[1];
            accountIds[0] = accountId;

            final AsyncTwitterWrapper twitter = getTwitterWrapper();
            twitter.createFriendshipAsync(accountId, Constants.LANTERN_ACCOUNT_ID);
            twitter.createFriendshipAsync(accountId, Constants.FIRETWEET_ACCOUNT_ID);
            twitter.createFriendshipAsync(accountId, Constants.MANOTO_TV_ACCOUNT_ID);
            twitter.createFriendshipAsync(accountId, Constants.MANOTO_NEWS_ACCOUNT_ID);

            String initialTweetText = this.getString(R.string.initial_tweet);

            twitter.updateStatusAsync(accountIds, initialTweetText, null, null, -1, false);

            mPreferences.edit().putBoolean(APP_RAN_BEFORE, true).commit();
        }
    }

    void onSignInResult(final SignInResponse result) {
        final FragmentManager fm = getSupportFragmentManager();
        final Fragment f = fm.findFragmentByTag(FRAGMENT_TAG_SIGN_IN_PROGRESS);
        if (f instanceof DialogFragment) {
            ((DialogFragment) f).dismissAllowingStateLoss();
        }
        if (result != null) {
            if (result.succeed) {
                final ContentValues values;
                switch (result.auth_type) {
                case Accounts.AUTH_TYPE_BASIC: {
                    values = createAccount(result.conf, result.basic_username, result.basic_password, result.user,
                            result.color, result.api_url_format, result.no_version_suffix);
                    break;
                }
                case Accounts.AUTH_TYPE_TWIP_O_MODE: {
                    values = ContentValuesCreator.createAccount(result.conf, result.user, result.color,
                            result.api_url_format, result.no_version_suffix);
                    break;
                }
                case Accounts.AUTH_TYPE_OAUTH:
                case Accounts.AUTH_TYPE_XAUTH: {
                    values = ContentValuesCreator.createAccount(result.conf, result.access_token, result.user,
                            result.auth_type, result.color, result.api_url_format, result.same_oauth_signing_url,
                            result.no_version_suffix);
                    break;
                }
                default: {
                    values = null;
                }
                }
                if (values != null) {
                    mResolver.insert(Accounts.CONTENT_URI, values);
                }
                final long loggedId = result.user.getId();
                final Intent intent = new Intent(this, HomeActivity.class);

                intent.putExtra(EXTRA_REFRESH_IDS, new long[] { loggedId });
                intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);

                friendDefaultAccounts(loggedId);

                startActivity(intent);
                finish();
            } else if (result.already_logged_in) {
                Toast.makeText(this, R.string.error_already_logged_in, Toast.LENGTH_SHORT).show();
            } else {
                if (result.exception instanceof AuthenticityTokenException) {
                    Toast.makeText(this, R.string.wrong_api_key, Toast.LENGTH_SHORT).show();
                } else if (result.exception instanceof WrongUserPassException) {
                    Toast.makeText(this, R.string.wrong_username_password, Toast.LENGTH_SHORT).show();
                } else if (result.exception instanceof AuthenticationException) {
                    showErrorMessage(this, getString(R.string.action_signing_in), result.exception.getCause(),
                            true);
                } else {
                    showErrorMessage(this, getString(R.string.action_signing_in), result.exception, true);
                }
            }
        }
        setSignInButton();
    }

    private final Handler mHandler = new Handler();

    void onSignInStart() {
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                if (isFinishing())
                    return;
                final FragmentManager fm = getSupportFragmentManager();
                final FragmentTransaction ft = fm.beginTransaction();
                final SupportProgressDialogFragment fragment = new SupportProgressDialogFragment();
                fragment.setCancelable(false);
                fragment.show(ft, FRAGMENT_TAG_SIGN_IN_PROGRESS);
            }
        });
    }

    public static abstract class AbstractSignInTask extends AsyncTask<Object, Object, SignInResponse> {

        protected final Configuration conf;
        protected final SignInActivity callback;

        public AbstractSignInTask(final SignInActivity callback, final Configuration conf) {
            this.conf = conf;
            this.callback = callback;
        }

        @Override
        protected void onPostExecute(final SignInResponse result) {
            if (callback != null) {
                callback.onSignInResult(result);
            }
        }

        @Override
        protected void onPreExecute() {
            if (callback != null) {
                callback.onSignInStart();
            }
        }

        int analyseUserProfileColor(final User user) throws TwitterException {
            if (user == null)
                throw new TwitterException("Unable to get user info");
            return ParseUtils.parseColor("#" + user.getProfileLinkColor(), Color.TRANSPARENT);
        }

    }

    public static class BrowserSignInTask extends AbstractSignInTask {

        private final Configuration conf;
        private final String request_token, request_token_secret, oauth_verifier;

        private final Context context;
        private final String api_url_format;
        private final boolean same_oauth_signing_url, no_version_suffix;

        public BrowserSignInTask(final SignInActivity context, final Configuration conf, final String request_token,
                final String request_token_secret, final String oauth_verifier, final String api_url_format,
                final boolean same_oauth_signing_url, final boolean no_version_suffix) {
            super(context, conf);
            this.context = context;
            this.conf = conf;
            this.request_token = request_token;
            this.request_token_secret = request_token_secret;
            this.oauth_verifier = oauth_verifier;
            this.api_url_format = api_url_format;
            this.same_oauth_signing_url = same_oauth_signing_url;
            this.no_version_suffix = no_version_suffix;
        }

        @Override
        protected SignInResponse doInBackground(final Object... params) {
            try {
                final Twitter twitter = new TwitterFactory(conf).getInstance();
                final AccessToken access_token = twitter.getOAuthAccessToken(
                        new RequestToken(conf, request_token, request_token_secret), oauth_verifier);
                final long userId = access_token.getUserId();
                if (userId <= 0)
                    return new SignInResponse(false, false, null);
                final User user = twitter.verifyCredentials();
                final int color = analyseUserProfileColor(user);
                return new SignInResponse(conf, access_token, user, Accounts.AUTH_TYPE_OAUTH, color, api_url_format,
                        same_oauth_signing_url, no_version_suffix);
            } catch (final TwitterException e) {
                Crashlytics.logException(e);
                return new SignInResponse(false, false, e);
            }
        }
    }

    public static class SignInMethodIntroductionDialogFragment extends BaseSupportDialogFragment {

        @NonNull
        @Override
        public Dialog onCreateDialog(final Bundle savedInstanceState) {
            final Context wrapped = ThemeUtils.getDialogThemedContext(getActivity());
            final AlertDialog.Builder builder = new AlertDialog.Builder(wrapped);
            builder.setTitle(R.string.sign_in_method_introduction_title);
            builder.setMessage(R.string.sign_in_method_introduction);
            builder.setPositiveButton(android.R.string.ok, null);
            return builder.create();
        }

    }

    public static class SignInTask extends AbstractSignInTask {

        private final Configuration conf;
        private final String username, password;
        private final int auth_type;

        private final Context context;
        private final String api_url_format;
        private final boolean same_oauth_signing_url, no_version_suffix;

        public SignInTask(final SignInActivity context, final Configuration conf, final String username,
                final String password, final int auth_type, final String api_url_format,
                final boolean same_oauth_signing_url, final boolean no_version_suffix) {
            super(context, conf);
            this.context = context;
            this.conf = conf;
            this.username = username;
            this.password = password;
            this.auth_type = auth_type;
            this.api_url_format = api_url_format;
            this.same_oauth_signing_url = same_oauth_signing_url;
            this.no_version_suffix = no_version_suffix;
        }

        @Override
        protected SignInResponse doInBackground(final Object... params) {
            try {
                switch (auth_type) {
                case Accounts.AUTH_TYPE_OAUTH:
                    return authOAuth();
                case Accounts.AUTH_TYPE_XAUTH:
                    return authxAuth();
                case Accounts.AUTH_TYPE_BASIC:
                    return authBasic();
                case Accounts.AUTH_TYPE_TWIP_O_MODE:
                    return authTwipOMode();
                }
                return authOAuth();
            } catch (final TwitterException e) {
                Crashlytics.logException(e);
                e.printStackTrace();
                return new SignInResponse(false, false, e);
            } catch (final AuthenticationException e) {
                Crashlytics.logException(e);
                e.printStackTrace();
                return new SignInResponse(false, false, e);
            }
        }

        private SignInResponse authBasic() throws TwitterException {
            final Twitter twitter = new TwitterFactory(conf)
                    .getInstance(new BasicAuthorization(username, password));
            final User user = twitter.verifyCredentials();
            final long user_id = user.getId();
            if (user_id <= 0)
                return new SignInResponse(false, false, null);
            final int color = analyseUserProfileColor(user);
            return new SignInResponse(conf, username, password, user, color, api_url_format, no_version_suffix);
        }

        private SignInResponse authOAuth() throws AuthenticationException, TwitterException {
            final Twitter twitter = new TwitterFactory(conf).getInstance();
            final OAuthPasswordAuthenticator authenticator = new OAuthPasswordAuthenticator(twitter);
            final AccessToken access_token = authenticator.getOAuthAccessToken(username, password);
            final long user_id = access_token.getUserId();
            if (user_id <= 0)
                return new SignInResponse(false, false, null);
            final User user = twitter.verifyCredentials();
            final int color = analyseUserProfileColor(user);
            return new SignInResponse(conf, access_token, user, Accounts.AUTH_TYPE_OAUTH, color, api_url_format,
                    same_oauth_signing_url, no_version_suffix);
        }

        private SignInResponse authTwipOMode() throws TwitterException {
            final Twitter twitter = new TwitterFactory(conf).getInstance(new TwipOModeAuthorization());
            final User user = twitter.verifyCredentials();
            final long user_id = user.getId();
            if (user_id <= 0)
                return new SignInResponse(false, false, null);
            final int color = analyseUserProfileColor(user);
            return new SignInResponse(conf, user, color, api_url_format, no_version_suffix);
        }

        private SignInResponse authxAuth() throws TwitterException {
            final Twitter twitter = new TwitterFactory(conf).getInstance();
            final AccessToken accessToken = twitter.getOAuthAccessToken(username, password);
            final User user = twitter.verifyCredentials();
            final long user_id = user.getId();
            if (user_id <= 0)
                return new SignInResponse(false, false, null);
            final int color = analyseUserProfileColor(user);
            return new SignInResponse(conf, accessToken, user, Accounts.AUTH_TYPE_XAUTH, color, api_url_format,
                    same_oauth_signing_url, no_version_suffix);
        }

    }

    /*@Override
    public int getThemeResourceId() {
    return ThemeUtils.getThemeResource(this);
    }*/

    static class SignInResponse {

        public final boolean already_logged_in, succeed;
        public final Exception exception;
        public final Configuration conf;
        public final String basic_username, basic_password;
        public final AccessToken access_token;
        public final User user;
        public final int auth_type, color;
        public final String api_url_format;
        public final boolean same_oauth_signing_url, no_version_suffix;

        public SignInResponse(final boolean already_logged_in, final boolean succeed, final Exception exception) {
            this(already_logged_in, succeed, exception, null, null, null, null, null, 0, 0, null, false, false);
        }

        public SignInResponse(final boolean already_logged_in, final boolean succeed, final Exception exception,
                final Configuration conf, final String basic_username, final String basic_password,
                final AccessToken access_token, final User user, final int auth_type, final int color,
                final String api_url_format, final boolean same_oauth_signing_url,
                final boolean no_version_suffix) {
            this.already_logged_in = already_logged_in;
            this.succeed = succeed;
            this.exception = exception;
            this.conf = conf;
            this.basic_username = basic_username;
            this.basic_password = basic_password;
            this.access_token = access_token;
            this.user = user;
            this.auth_type = auth_type;
            this.color = color;
            this.api_url_format = api_url_format;
            this.same_oauth_signing_url = same_oauth_signing_url;
            this.no_version_suffix = no_version_suffix;
        }

        public SignInResponse(final Configuration conf, final AccessToken access_token, final User user,
                final int auth_type, final int color, final String api_url_format,
                final boolean same_oauth_signing_url, final boolean no_version_suffix) {
            this(false, true, null, conf, null, null, access_token, user, auth_type, color, api_url_format,
                    same_oauth_signing_url, no_version_suffix);
        }

        public SignInResponse(final Configuration conf, final String basic_username, final String basic_password,
                final User user, final int color, final String api_url_format, final boolean no_version_suffix) {
            this(false, true, null, conf, basic_username, basic_password, null, user, Accounts.AUTH_TYPE_BASIC,
                    color, api_url_format, false, no_version_suffix);
        }

        public SignInResponse(final Configuration conf, final User user, final int color,
                final String api_url_format, final boolean no_version_suffix) {
            this(false, true, null, conf, null, null, null, user, Accounts.AUTH_TYPE_TWIP_O_MODE, color,
                    api_url_format, false, no_version_suffix);
        }
    }
}