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 android.accounts.Account;
20539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scottimport android.accounts.AccountManager;
21539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scottimport android.accounts.AccountManagerCallback;
22539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scottimport android.accounts.AccountManagerFuture;
23539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scottimport android.app.Activity;
24cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scottimport android.app.ProgressDialog;
25539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scottimport android.content.Context;
26539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scottimport android.content.DialogInterface;
27539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scottimport android.content.DialogInterface.OnCancelListener;
28cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scottimport android.content.SharedPreferences.Editor;
29539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scottimport android.net.Uri;
300fba5d9470f3b98d5aa61ae7392164450baf73deMichael Kolbimport android.net.http.AndroidHttpClient;
31539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scottimport android.os.Bundle;
32a4af6dce2ebe6c4979524461047fcc0eb76fce84Patrick Scottimport android.util.Log;
33ef18de60e02b4b2a7227d9e9751487cc74baec36Patrick Scottimport android.webkit.CookieSyncManager;
34539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scottimport android.webkit.WebView;
35539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scottimport android.webkit.WebViewClient;
36539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott
37ba287c2673922ac51c4e4258224574411c0117e1John Reckimport org.apache.http.HttpEntity;
38ba287c2673922ac51c4e4258224574411c0117e1John Reckimport org.apache.http.HttpResponse;
39ba287c2673922ac51c4e4258224574411c0117e1John Reckimport org.apache.http.HttpStatus;
40ba287c2673922ac51c4e4258224574411c0117e1John Reckimport org.apache.http.client.methods.HttpPost;
41ba287c2673922ac51c4e4258224574411c0117e1John Reckimport org.apache.http.util.EntityUtils;
42ba287c2673922ac51c4e4258224574411c0117e1John Reck
437d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scottpublic class GoogleAccountLogin implements Runnable,
44539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott        AccountManagerCallback<Bundle>, OnCancelListener {
45539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott
46a4af6dce2ebe6c4979524461047fcc0eb76fce84Patrick Scott    private static final String LOGTAG = "BrowserLogin";
47a4af6dce2ebe6c4979524461047fcc0eb76fce84Patrick Scott
48539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott    // Url for issuing the uber token.
49539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott    private Uri ISSUE_AUTH_TOKEN_URL = Uri.parse(
50539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott            "https://www.google.com/accounts/IssueAuthToken?service=gaia&Session=false");
51539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott    // Url for signing into a particular service.
52a4af6dce2ebe6c4979524461047fcc0eb76fce84Patrick Scott    private static final Uri TOKEN_AUTH_URL = Uri.parse(
53539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott            "https://www.google.com/accounts/TokenAuth");
54539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott    // Google account type
55a4af6dce2ebe6c4979524461047fcc0eb76fce84Patrick Scott    private static final String GOOGLE = "com.google";
56cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott    // Last auto login time
57ba287c2673922ac51c4e4258224574411c0117e1John Reck    public static final String PREF_AUTOLOGIN_TIME = "last_autologin_time";
58539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott
59539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott    private final Activity mActivity;
60539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott    private final Account mAccount;
61539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott    private final WebView mWebView;
62539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott    private Runnable mRunnable;
63cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott    private ProgressDialog mProgressDialog;
64539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott
65539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott    // SID and LSID retrieval process.
66539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott    private String mSid;
67539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott    private String mLsid;
68539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott    private int mState;  // {NONE(0), SID(1), LSID(2)}
697d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott    private boolean mTokensInvalidated;
709bbd9314fee5f284ff254d7063c30d147fe47454Ben Murdoch    private String mUserAgent;
71539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott
72d43e75adea6f394730828cbf830438e2bddaed4bPatrick Scott    private GoogleAccountLogin(Activity activity, Account account,
73cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott            Runnable runnable) {
74539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott        mActivity = activity;
75d43e75adea6f394730828cbf830438e2bddaed4bPatrick Scott        mAccount = account;
76539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott        mWebView = new WebView(mActivity);
77cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott        mRunnable = runnable;
789bbd9314fee5f284ff254d7063c30d147fe47454Ben Murdoch        mUserAgent = mWebView.getSettings().getUserAgentString();
79cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott
80ef18de60e02b4b2a7227d9e9751487cc74baec36Patrick Scott        // XXX: Doing pre-login causes onResume to skip calling
81ef18de60e02b4b2a7227d9e9751487cc74baec36Patrick Scott        // resumeWebViewTimers. So to avoid problems with timers not running, we
82ef18de60e02b4b2a7227d9e9751487cc74baec36Patrick Scott        // duplicate the work here using the off-screen WebView.
83ef18de60e02b4b2a7227d9e9751487cc74baec36Patrick Scott        CookieSyncManager.getInstance().startSync();
84e1dbb956d762c3f07033f247c05270a9882a79a7Mathew Inwood        WebViewTimersControl.getInstance().onBrowserActivityResume(mWebView);
85ef18de60e02b4b2a7227d9e9751487cc74baec36Patrick Scott
86539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott        mWebView.setWebViewClient(new WebViewClient() {
87539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott            @Override
88539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott            public boolean shouldOverrideUrlLoading(WebView view, String url) {
89539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott                return false;
90539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott            }
91539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott            @Override
92539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott            public void onPageFinished(WebView view, String url) {
93539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott                done();
94539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott            }
95539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott        });
96539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott    }
97539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott
98cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott    private void saveLoginTime() {
99ba287c2673922ac51c4e4258224574411c0117e1John Reck        Editor ed = BrowserSettings.getInstance().getPreferences().edit();
100cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott        ed.putLong(PREF_AUTOLOGIN_TIME, System.currentTimeMillis());
101cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott        ed.apply();
102cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott    }
103cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott
1047d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott    // Runnable
105539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott    @Override
106539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott    public void run() {
107539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott        String url = ISSUE_AUTH_TOKEN_URL.buildUpon()
108539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott                .appendQueryParameter("SID", mSid)
109539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott                .appendQueryParameter("LSID", mLsid)
110539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott                .build().toString();
111539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott        // Intentionally not using Proxy.
1129bbd9314fee5f284ff254d7063c30d147fe47454Ben Murdoch        AndroidHttpClient client = AndroidHttpClient.newInstance(mUserAgent);
113539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott        HttpPost request = new HttpPost(url);
114539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott
115539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott        String result = null;
116539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott        try {
117539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott            HttpResponse response = client.execute(request);
1187d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott            int status = response.getStatusLine().getStatusCode();
1197d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott            if (status != HttpStatus.SC_OK) {
120a4af6dce2ebe6c4979524461047fcc0eb76fce84Patrick Scott                Log.d(LOGTAG, "LOGIN_FAIL: Bad status from auth url "
1217d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott                      + status + ": "
122a4af6dce2ebe6c4979524461047fcc0eb76fce84Patrick Scott                      + response.getStatusLine().getReasonPhrase());
1237d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott                // Invalidate the tokens once just in case the 403 was for other
1247d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott                // reasons.
1257d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott                if (status == HttpStatus.SC_FORBIDDEN && !mTokensInvalidated) {
1267d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott                    Log.d(LOGTAG, "LOGIN_FAIL: Invalidating tokens...");
1277d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott                    // Need to regenerate the auth tokens and try again.
1287d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott                    invalidateTokens();
1297d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott                    // XXX: Do not touch any more member variables from this
1307d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott                    // thread as a second thread will handle the next login
1317d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott                    // attempt.
1327d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott                    return;
1337d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott                }
134539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott                done();
135539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott                return;
136539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott            }
137539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott            HttpEntity entity = response.getEntity();
138539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott            if (entity == null) {
139a4af6dce2ebe6c4979524461047fcc0eb76fce84Patrick Scott                Log.d(LOGTAG, "LOGIN_FAIL: Null entity in response");
140539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott                done();
141539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott                return;
142539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott            }
143539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott            result = EntityUtils.toString(entity, "UTF-8");
144539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott        } catch (Exception e) {
145a4af6dce2ebe6c4979524461047fcc0eb76fce84Patrick Scott            Log.d(LOGTAG, "LOGIN_FAIL: Exception acquiring uber token " + e);
146539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott            request.abort();
147539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott            done();
148539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott            return;
149539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott        } finally {
150539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott            client.close();
151539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott        }
152539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott        final String newUrl = TOKEN_AUTH_URL.buildUpon()
153539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott                .appendQueryParameter("source", "android-browser")
154539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott                .appendQueryParameter("auth", result)
155539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott                .appendQueryParameter("continue",
156539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott                        BrowserSettings.getFactoryResetHomeUrl(mActivity))
157539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott                .build().toString();
158539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott        mActivity.runOnUiThread(new Runnable() {
159539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott            @Override public void run() {
160081caaa34ab5af0694087c3203e39be25797455aPatrick Scott                // Check mRunnable in case the request has been canceled.  This
161081caaa34ab5af0694087c3203e39be25797455aPatrick Scott                // is most likely not necessary as run() is the only non-UI
162081caaa34ab5af0694087c3203e39be25797455aPatrick Scott                // thread that calls done() but I am paranoid.
163081caaa34ab5af0694087c3203e39be25797455aPatrick Scott                synchronized (GoogleAccountLogin.this) {
164081caaa34ab5af0694087c3203e39be25797455aPatrick Scott                    if (mRunnable == null) {
165081caaa34ab5af0694087c3203e39be25797455aPatrick Scott                        return;
166081caaa34ab5af0694087c3203e39be25797455aPatrick Scott                    }
167081caaa34ab5af0694087c3203e39be25797455aPatrick Scott                    mWebView.loadUrl(newUrl);
168081caaa34ab5af0694087c3203e39be25797455aPatrick Scott                }
169539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott            }
170539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott        });
171539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott    }
172539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott
1737d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott    private void invalidateTokens() {
1747d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott        AccountManager am = AccountManager.get(mActivity);
1757d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott        am.invalidateAuthToken(GOOGLE, mSid);
1767d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott        am.invalidateAuthToken(GOOGLE, mLsid);
1777d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott        mTokensInvalidated = true;
1787d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott        mState = 1;  // SID
1797d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott        am.getAuthToken(mAccount, "SID", null, mActivity, this, null);
1807d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott    }
1817d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott
182539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott    // AccountManager callbacks.
183539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott    @Override
184539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott    public void run(AccountManagerFuture<Bundle> value) {
185539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott        try {
186539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott            String id = value.getResult().getString(
187539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott                    AccountManager.KEY_AUTHTOKEN);
188539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott            switch (mState) {
189539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott                default:
190539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott                case 0:
191539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott                    throw new IllegalStateException(
192539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott                            "Impossible to get into this state");
193539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott                case 1:
194539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott                    mSid = id;
195539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott                    mState = 2;  // LSID
196539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott                    AccountManager.get(mActivity).getAuthToken(
197539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott                            mAccount, "LSID", null, mActivity, this, null);
198539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott                    break;
199539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott                case 2:
200539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott                    mLsid = id;
2017d50a9364107c21e3358e1dbc51a06359a5287fbPatrick Scott                    new Thread(this).start();
202539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott                    break;
203539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott            }
204539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott        } catch (Exception e) {
205a4af6dce2ebe6c4979524461047fcc0eb76fce84Patrick Scott            Log.d(LOGTAG, "LOGIN_FAIL: Exception in state " + mState + " " + e);
206539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott            // For all exceptions load the original signin page.
207539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott            // TODO: toast login failed?
208539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott            done();
209539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott        }
210539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott    }
211539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott
212cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott    // Start the login process if auto-login is enabled and the user is not
213cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott    // already logged in.
214cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott    public static void startLoginIfNeeded(Activity activity,
215d43e75adea6f394730828cbf830438e2bddaed4bPatrick Scott            Runnable runnable) {
216d43e75adea6f394730828cbf830438e2bddaed4bPatrick Scott        // Already logged in?
217ba287c2673922ac51c4e4258224574411c0117e1John Reck        if (isLoggedIn()) {
218cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott            runnable.run();
219cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott            return;
220cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott        }
221cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott
222cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott        // No account found?
223d43e75adea6f394730828cbf830438e2bddaed4bPatrick Scott        Account[] accounts = getAccounts(activity);
224d43e75adea6f394730828cbf830438e2bddaed4bPatrick Scott        if (accounts == null || accounts.length == 0) {
225cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott            runnable.run();
226cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott            return;
227cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott        }
228cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott
229cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott        GoogleAccountLogin login =
230d43e75adea6f394730828cbf830438e2bddaed4bPatrick Scott                new GoogleAccountLogin(activity, accounts[0], runnable);
231cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott        login.startLogin();
232cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott    }
233cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott
234cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott    private void startLogin() {
235ba287c2673922ac51c4e4258224574411c0117e1John Reck        saveLoginTime();
236cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott        mProgressDialog = ProgressDialog.show(mActivity,
237cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott                mActivity.getString(R.string.pref_autologin_title),
238cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott                mActivity.getString(R.string.pref_autologin_progress,
239cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott                                    mAccount.name),
240cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott                true /* indeterminate */,
241cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott                true /* cancelable */,
242cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott                this);
243539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott        mState = 1;  // SID
244539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott        AccountManager.get(mActivity).getAuthToken(
245539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott                mAccount, "SID", null, mActivity, this, null);
246539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott    }
247539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott
248d43e75adea6f394730828cbf830438e2bddaed4bPatrick Scott    private static Account[] getAccounts(Context ctx) {
249539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott        return AccountManager.get(ctx).getAccountsByType(GOOGLE);
250539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott    }
251539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott
252d43e75adea6f394730828cbf830438e2bddaed4bPatrick Scott    // Checks if we already did pre-login.
253ba287c2673922ac51c4e4258224574411c0117e1John Reck    private static boolean isLoggedIn() {
254cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott        // See if we last logged in less than a week ago.
255ba287c2673922ac51c4e4258224574411c0117e1John Reck        long lastLogin = BrowserSettings.getInstance().getPreferences()
256ba287c2673922ac51c4e4258224574411c0117e1John Reck                .getLong(PREF_AUTOLOGIN_TIME, -1);
257cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott        if (lastLogin == -1) {
258cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott            return false;
259cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott        }
260d43e75adea6f394730828cbf830438e2bddaed4bPatrick Scott        return true;
26197efb1e650b356d3fc81ff531544383362759d77Patrick Scott    }
26297efb1e650b356d3fc81ff531544383362759d77Patrick Scott
263539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott    // Used to indicate that the Browser should continue loading the main page.
264539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott    // This can happen on success, error, or timeout.
265539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott    private synchronized void done() {
266539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott        if (mRunnable != null) {
267a4af6dce2ebe6c4979524461047fcc0eb76fce84Patrick Scott            Log.d(LOGTAG, "Finished login attempt for " + mAccount.name);
268539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott            mActivity.runOnUiThread(mRunnable);
269cd135089d54a8c003f7b0a35d88b3230f0a206b5Patrick Scott
270cf1df73719e171915eed887a5f06916158e42f04John Reck            try {
271cf1df73719e171915eed887a5f06916158e42f04John Reck                mProgressDialog.dismiss();
272cf1df73719e171915eed887a5f06916158e42f04John Reck            } catch (Exception e) {
273cf1df73719e171915eed887a5f06916158e42f04John Reck                // TODO: Switch to a managed dialog solution (DialogFragment?)
274cf1df73719e171915eed887a5f06916158e42f04John Reck                // Also refactor this class, it doesn't
275cf1df73719e171915eed887a5f06916158e42f04John Reck                // play nice with the activity lifecycle, leading to issues
276cf1df73719e171915eed887a5f06916158e42f04John Reck                // with the dialog it manages
277cf1df73719e171915eed887a5f06916158e42f04John Reck                Log.w(LOGTAG, "Failed to dismiss mProgressDialog: " + e.getMessage());
278cf1df73719e171915eed887a5f06916158e42f04John Reck            }
279539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott            mRunnable = null;
280474c927a76d4a6b12e942ba4bde3a7db18a1a332John Reck            mActivity.runOnUiThread(new Runnable() {
281474c927a76d4a6b12e942ba4bde3a7db18a1a332John Reck                @Override
282474c927a76d4a6b12e942ba4bde3a7db18a1a332John Reck                public void run() {
283474c927a76d4a6b12e942ba4bde3a7db18a1a332John Reck                    mWebView.destroy();
284474c927a76d4a6b12e942ba4bde3a7db18a1a332John Reck                }
285474c927a76d4a6b12e942ba4bde3a7db18a1a332John Reck            });
286539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott        }
287539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott    }
288539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott
289539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott    // Called by the progress dialog on startup.
290539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott    public void onCancel(DialogInterface unused) {
291539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott        done();
292539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott    }
2930fba5d9470f3b98d5aa61ae7392164450baf73deMichael Kolb
294539e2eced0f35144d7841477e5cdc2d8c521e82aPatrick Scott}
295