GoogleAccountLogin.java revision d43e75adea6f394730828cbf830438e2bddaed4b
1539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott/*
2539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott * Copyright (C) 2010 The Android Open Source Project
3539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott *
4539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott * Licensed under the Apache License, Version 2.0 (the "License");
5539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott * you may not use this file except in compliance with the License.
6539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott * You may obtain a copy of the License at
7539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott *
8539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott *      http://www.apache.org/licenses/LICENSE-2.0
9539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott *
10539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott * Unless required by applicable law or agreed to in writing, software
11539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott * distributed under the License is distributed on an "AS IS" BASIS,
12539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott * See the License for the specific language governing permissions and
14539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott * limitations under the License.
15539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott */
16539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott
17539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scottpackage com.android.browser;
18539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott
19539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scottimport org.apache.http.Header;
20539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scottimport org.apache.http.HeaderIterator;
21539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scottimport org.apache.http.HttpEntity;
22539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scottimport org.apache.http.HttpResponse;
23539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scottimport org.apache.http.HttpStatus;
24539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scottimport org.apache.http.client.methods.HttpPost;
25539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scottimport org.apache.http.util.EntityUtils;
26539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott
27539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scottimport android.accounts.Account;
28539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scottimport android.accounts.AccountManager;
29539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scottimport android.accounts.AccountManagerCallback;
30539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scottimport android.accounts.AccountManagerFuture;
31539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scottimport android.app.Activity;
32cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scottimport android.app.ProgressDialog;
33539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scottimport android.content.Context;
34539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scottimport android.content.DialogInterface;
35539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scottimport android.content.DialogInterface.OnCancelListener;
36cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scottimport android.content.SharedPreferences.Editor;
37539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scottimport android.net.http.AndroidHttpClient;
38539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scottimport android.net.Uri;
39539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scottimport android.os.Bundle;
40cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scottimport android.os.Handler;
41cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scottimport android.preference.PreferenceManager;
42a4af6dce2ebe6c4979524461047fcc0eb76fce84Patrick Scottimport android.util.Log;
43ef18de60e02b4b2a7227d9e9751487cc74baec36Patrick Scottimport android.webkit.CookieSyncManager;
44539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scottimport android.webkit.WebView;
45539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scottimport android.webkit.WebViewClient;
46539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott
4797efb1e650b356d3fc81ff531544383362759d77Patrick Scottimport java.util.StringTokenizer;
48539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott
497d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scottpublic class GoogleAccountLogin implements Runnable,
50539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott        AccountManagerCallback<Bundle>, OnCancelListener {
51539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott
52a4af6dce2ebe6c4979524461047fcc0eb76fce84Patrick Scott    private static final String LOGTAG = "BrowserLogin";
53a4af6dce2ebe6c4979524461047fcc0eb76fce84Patrick Scott
54539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott    // Url for issuing the uber token.
55539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott    private Uri ISSUE_AUTH_TOKEN_URL = Uri.parse(
56539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott            "https://www.google.com/accounts/IssueAuthToken?service=gaia&Session=false");
57539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott    // Url for signing into a particular service.
58a4af6dce2ebe6c4979524461047fcc0eb76fce84Patrick Scott    private static final Uri TOKEN_AUTH_URL = Uri.parse(
59539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott            "https://www.google.com/accounts/TokenAuth");
60539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott    // Google account type
61a4af6dce2ebe6c4979524461047fcc0eb76fce84Patrick Scott    private static final String GOOGLE = "com.google";
62cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott    // Last auto login time
63cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott    private static final String PREF_AUTOLOGIN_TIME = "last_autologin_time";
64cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott    // A week in milliseconds (7*24*60*60*1000)
65cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott    private static final long WEEK_IN_MILLIS = 604800000L;
66539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott
67539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott    private final Activity mActivity;
68539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott    private final Account mAccount;
69539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott    private final WebView mWebView;
70cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott    // Does not matter if this is initialized in a non-ui thread.
71cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott    // Dialog.dismiss() will post to the right handler.
72cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott    private final Handler mHandler = new Handler();
73539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott    private Runnable mRunnable;
74cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott    private ProgressDialog mProgressDialog;
75539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott
76539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott    // SID and LSID retrieval process.
77539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott    private String mSid;
78539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott    private String mLsid;
79539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott    private int mState;  // {NONE(0), SID(1), LSID(2)}
807d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott    private boolean mTokensInvalidated;
81539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott
82d43e75adea6f394730828cbf830438e2bddaed4bPatrick Scott    private GoogleAccountLogin(Activity activity, Account account,
83cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott            Runnable runnable) {
84539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott        mActivity = activity;
85d43e75adea6f394730828cbf830438e2bddaed4bPatrick Scott        mAccount = account;
86539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott        mWebView = new WebView(mActivity);
87cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott        mRunnable = runnable;
88cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott
89ef18de60e02b4b2a7227d9e9751487cc74baec36Patrick Scott        // XXX: Doing pre-login causes onResume to skip calling
90ef18de60e02b4b2a7227d9e9751487cc74baec36Patrick Scott        // resumeWebViewTimers. So to avoid problems with timers not running, we
91ef18de60e02b4b2a7227d9e9751487cc74baec36Patrick Scott        // duplicate the work here using the off-screen WebView.
92ef18de60e02b4b2a7227d9e9751487cc74baec36Patrick Scott        CookieSyncManager.getInstance().startSync();
93ef18de60e02b4b2a7227d9e9751487cc74baec36Patrick Scott        mWebView.resumeTimers();
94ef18de60e02b4b2a7227d9e9751487cc74baec36Patrick Scott
95539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott        mWebView.setWebViewClient(new WebViewClient() {
96539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott            @Override
97539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott            public boolean shouldOverrideUrlLoading(WebView view, String url) {
98539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott                return false;
99539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott            }
100539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott            @Override
101539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott            public void onPageFinished(WebView view, String url) {
102cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott                saveLoginTime();
103539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott                done();
104539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott            }
105539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott        });
106539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott    }
107539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott
108cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott    private void saveLoginTime() {
109cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott        Editor ed = PreferenceManager.
110cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott                getDefaultSharedPreferences(mActivity).edit();
111cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott        ed.putLong(PREF_AUTOLOGIN_TIME, System.currentTimeMillis());
112cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott        ed.apply();
113cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott    }
114cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott
1157d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott    // Runnable
116539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott    @Override
117539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott    public void run() {
118539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott        String url = ISSUE_AUTH_TOKEN_URL.buildUpon()
119539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott                .appendQueryParameter("SID", mSid)
120539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott                .appendQueryParameter("LSID", mLsid)
121539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott                .build().toString();
122081caaa34ab5af0694087c3203e39be25797455aPatrick Scott        // Check mRunnable to see if the request has been canceled.  Otherwise
123081caaa34ab5af0694087c3203e39be25797455aPatrick Scott        // we might access a destroyed WebView.
124081caaa34ab5af0694087c3203e39be25797455aPatrick Scott        String ua = null;
125081caaa34ab5af0694087c3203e39be25797455aPatrick Scott        synchronized (this) {
126081caaa34ab5af0694087c3203e39be25797455aPatrick Scott            if (mRunnable == null) {
127081caaa34ab5af0694087c3203e39be25797455aPatrick Scott                return;
128081caaa34ab5af0694087c3203e39be25797455aPatrick Scott            }
129081caaa34ab5af0694087c3203e39be25797455aPatrick Scott            ua = mWebView.getSettings().getUserAgentString();
130081caaa34ab5af0694087c3203e39be25797455aPatrick Scott        }
131539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott        // Intentionally not using Proxy.
132081caaa34ab5af0694087c3203e39be25797455aPatrick Scott        AndroidHttpClient client = AndroidHttpClient.newInstance(ua);
133539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott        HttpPost request = new HttpPost(url);
134539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott
135539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott        String result = null;
136539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott        try {
137539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott            HttpResponse response = client.execute(request);
1387d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott            int status = response.getStatusLine().getStatusCode();
1397d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott            if (status != HttpStatus.SC_OK) {
140a4af6dce2ebe6c4979524461047fcc0eb76fce84Patrick Scott                Log.d(LOGTAG, "LOGIN_FAIL: Bad status from auth url "
1417d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott                      + status + ": "
142a4af6dce2ebe6c4979524461047fcc0eb76fce84Patrick Scott                      + response.getStatusLine().getReasonPhrase());
1437d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott                // Invalidate the tokens once just in case the 403 was for other
1447d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott                // reasons.
1457d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott                if (status == HttpStatus.SC_FORBIDDEN && !mTokensInvalidated) {
1467d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott                    Log.d(LOGTAG, "LOGIN_FAIL: Invalidating tokens...");
1477d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott                    // Need to regenerate the auth tokens and try again.
1487d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott                    invalidateTokens();
1497d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott                    // XXX: Do not touch any more member variables from this
1507d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott                    // thread as a second thread will handle the next login
1517d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott                    // attempt.
1527d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott                    return;
1537d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott                }
154539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott                done();
155539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott                return;
156539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott            }
157539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott            HttpEntity entity = response.getEntity();
158539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott            if (entity == null) {
159a4af6dce2ebe6c4979524461047fcc0eb76fce84Patrick Scott                Log.d(LOGTAG, "LOGIN_FAIL: Null entity in response");
160539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott                done();
161539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott                return;
162539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott            }
163539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott            result = EntityUtils.toString(entity, "UTF-8");
164539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott        } catch (Exception e) {
165a4af6dce2ebe6c4979524461047fcc0eb76fce84Patrick Scott            Log.d(LOGTAG, "LOGIN_FAIL: Exception acquiring uber token " + e);
166539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott            request.abort();
167539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott            done();
168539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott            return;
169539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott        } finally {
170539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott            client.close();
171539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott        }
172539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott        final String newUrl = TOKEN_AUTH_URL.buildUpon()
173539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott                .appendQueryParameter("source", "android-browser")
174539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott                .appendQueryParameter("auth", result)
175539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott                .appendQueryParameter("continue",
176539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott                        BrowserSettings.getFactoryResetHomeUrl(mActivity))
177539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott                .build().toString();
178539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott        mActivity.runOnUiThread(new Runnable() {
179539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott            @Override public void run() {
180081caaa34ab5af0694087c3203e39be25797455aPatrick Scott                // Check mRunnable in case the request has been canceled.  This
181081caaa34ab5af0694087c3203e39be25797455aPatrick Scott                // is most likely not necessary as run() is the only non-UI
182081caaa34ab5af0694087c3203e39be25797455aPatrick Scott                // thread that calls done() but I am paranoid.
183081caaa34ab5af0694087c3203e39be25797455aPatrick Scott                synchronized (GoogleAccountLogin.this) {
184081caaa34ab5af0694087c3203e39be25797455aPatrick Scott                    if (mRunnable == null) {
185081caaa34ab5af0694087c3203e39be25797455aPatrick Scott                        return;
186081caaa34ab5af0694087c3203e39be25797455aPatrick Scott                    }
187081caaa34ab5af0694087c3203e39be25797455aPatrick Scott                    mWebView.loadUrl(newUrl);
188081caaa34ab5af0694087c3203e39be25797455aPatrick Scott                }
189539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott            }
190539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott        });
191539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott    }
192539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott
1937d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott    private void invalidateTokens() {
1947d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott        AccountManager am = AccountManager.get(mActivity);
1957d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott        am.invalidateAuthToken(GOOGLE, mSid);
1967d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott        am.invalidateAuthToken(GOOGLE, mLsid);
1977d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott        mTokensInvalidated = true;
1987d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott        mState = 1;  // SID
1997d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott        am.getAuthToken(mAccount, "SID", null, mActivity, this, null);
2007d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott    }
2017d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott
202539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott    // AccountManager callbacks.
203539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott    @Override
204539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott    public void run(AccountManagerFuture<Bundle> value) {
205539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott        try {
206539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott            String id = value.getResult().getString(
207539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott                    AccountManager.KEY_AUTHTOKEN);
208539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott            switch (mState) {
209539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott                default:
210539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott                case 0:
211539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott                    throw new IllegalStateException(
212539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott                            "Impossible to get into this state");
213539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott                case 1:
214539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott                    mSid = id;
215539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott                    mState = 2;  // LSID
216539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott                    AccountManager.get(mActivity).getAuthToken(
217539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott                            mAccount, "LSID", null, mActivity, this, null);
218539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott                    break;
219539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott                case 2:
220539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott                    mLsid = id;
2217d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott                    new Thread(this).start();
222539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott                    break;
223539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott            }
224539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott        } catch (Exception e) {
225a4af6dce2ebe6c4979524461047fcc0eb76fce84Patrick Scott            Log.d(LOGTAG, "LOGIN_FAIL: Exception in state " + mState + " " + e);
226539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott            // For all exceptions load the original signin page.
227539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott            // TODO: toast login failed?
228539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott            done();
229539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott        }
230539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott    }
231539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott
232cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott    // Start the login process if auto-login is enabled and the user is not
233cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott    // already logged in.
234cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott    public static void startLoginIfNeeded(Activity activity,
235d43e75adea6f394730828cbf830438e2bddaed4bPatrick Scott            Runnable runnable) {
236d43e75adea6f394730828cbf830438e2bddaed4bPatrick Scott        // Already logged in?
237d43e75adea6f394730828cbf830438e2bddaed4bPatrick Scott        if (isLoggedIn(activity)) {
238cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott            runnable.run();
239cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott            return;
240cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott        }
241cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott
242cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott        // No account found?
243d43e75adea6f394730828cbf830438e2bddaed4bPatrick Scott        Account[] accounts = getAccounts(activity);
244d43e75adea6f394730828cbf830438e2bddaed4bPatrick Scott        if (accounts == null || accounts.length == 0) {
245cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott            runnable.run();
246cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott            return;
247cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott        }
248cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott
249cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott        GoogleAccountLogin login =
250d43e75adea6f394730828cbf830438e2bddaed4bPatrick Scott                new GoogleAccountLogin(activity, accounts[0], runnable);
251cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott        login.startLogin();
252cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott    }
253cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott
254cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott    private void startLogin() {
255cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott        mProgressDialog = ProgressDialog.show(mActivity,
256cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott                mActivity.getString(R.string.pref_autologin_title),
257cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott                mActivity.getString(R.string.pref_autologin_progress,
258cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott                                    mAccount.name),
259cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott                true /* indeterminate */,
260cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott                true /* cancelable */,
261cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott                this);
262539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott        mState = 1;  // SID
263539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott        AccountManager.get(mActivity).getAuthToken(
264539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott                mAccount, "SID", null, mActivity, this, null);
265539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott    }
266539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott
267d43e75adea6f394730828cbf830438e2bddaed4bPatrick Scott    private static Account[] getAccounts(Context ctx) {
268539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott        return AccountManager.get(ctx).getAccountsByType(GOOGLE);
269539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott    }
270539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott
271d43e75adea6f394730828cbf830438e2bddaed4bPatrick Scott    // Checks if we already did pre-login.
272d43e75adea6f394730828cbf830438e2bddaed4bPatrick Scott    private static boolean isLoggedIn(Context ctx) {
273cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott        // See if we last logged in less than a week ago.
274cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott        long lastLogin = PreferenceManager.
275cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott                getDefaultSharedPreferences(ctx).
276cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott                getLong(PREF_AUTOLOGIN_TIME, -1);
277cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott        if (lastLogin == -1) {
278cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott            return false;
279cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott        }
280d43e75adea6f394730828cbf830438e2bddaed4bPatrick Scott        return true;
28197efb1e650b356d3fc81ff531544383362759d77Patrick Scott    }
28297efb1e650b356d3fc81ff531544383362759d77Patrick Scott
283539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott    // Used to indicate that the Browser should continue loading the main page.
284539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott    // This can happen on success, error, or timeout.
285539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott    private synchronized void done() {
286539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott        if (mRunnable != null) {
287a4af6dce2ebe6c4979524461047fcc0eb76fce84Patrick Scott            Log.d(LOGTAG, "Finished login attempt for " + mAccount.name);
288539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott            mActivity.runOnUiThread(mRunnable);
289cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott
290cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott            // Post a delayed message to dismiss the dialog in order to avoid a
291cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott            // flash of the progress dialog.
292cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott            mHandler.postDelayed(new Runnable() {
293cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott                @Override public void run() {
294cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott                    mProgressDialog.dismiss();
295cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott                }
296065a7ee11d226f755d217bee100c585f803a2e0aPatrick Scott            }, 2000);
297cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott
298539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott            mRunnable = null;
299539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott            mWebView.destroy();
300539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott        }
301539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott    }
302539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott
303539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott    // Called by the progress dialog on startup.
304539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott    public void onCancel(DialogInterface unused) {
305539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott        done();
306539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott    }
307539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott}
308