Different approach to auto signin.

On startup, attempt to log the user into google sites.  Show a progress dialog
that the user can cancel if login takes too long.

Add a new preference for toggling auto signin.  This preference shows the
current account and allows the user to choose the account to use.  If there are
no accounts, the option is disabled.  The saved account is validated each time
it is accessed in case the account was removed.

Bug: 3278072
Change-Id: I10ce1dc57a683b2820b17ef6955577037c82f332
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 4464370..00a2a46 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -376,6 +376,15 @@
     <!-- Summary for the AutoFill Settings preference [CHAR-LIMIT=none] -->
     <string name="pref_autofill_profile_editor_summary">Set up &amp; manage data for AutoFilled forms</string>
 
+    <!-- Auto login preference title [CHAR-LIMIT=32] -->
+    <string name="pref_autologin_title">Automatic Google sign-in</string>
+    <!-- Summary when no accounts are found [CHAR-LIMIT=32] -->
+    <string name="pref_autologin_no_account">No accounts found</string>
+    <!-- Summary when there is an account available [CHAR-LIMIT=none] -->
+    <string name="pref_autologin_summary">Sign into Google sites automatically using <xliff:g>%s</xliff:g></string>
+    <!-- Message shown during auto login [CHAR-LIMIT=none] -->
+    <string name="pref_autologin_progress">Signing into Google sites using <xliff:g>%s</xliff:g></string>
+
     <!-- Heading for the AutoFill profile editor to tell the user what AutoFill does and why they should fill out the profile. [CHAR-LIMIT=None] -->
     <string name="autofill_profile_editor_heading">AutoFill will use your profile to help you complete web forms in a single click.</string>
     <!-- String for the user's full name in the AutoFill profile editor. [CHAR-LIMIT=32] -->
@@ -909,8 +918,4 @@
          reached. [CHAR LIMIT=50] -->
     <string name="max_tabs_warning">No more tabs available</string>
 
-    <!-- Title of the picker dialog to choose an account. [CHAR-LIMIT=none]-->
-    <string name="account_picker_title">Choose an account or cancel to login
-      manually</string>
-
 </resources>
diff --git a/res/xml/browser_preferences.xml b/res/xml/browser_preferences.xml
deleted file mode 100644
index 1c04528..0000000
--- a/res/xml/browser_preferences.xml
+++ /dev/null
@@ -1,216 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<PreferenceScreen
-        xmlns:android="http://schemas.android.com/apk/res/android">
-
-    <PreferenceCategory
-            android:title="@string/pref_content_title">  
-
-        <ListPreference
-                android:key="text_size"
-                android:title="@string/pref_text_size"
-                android:defaultValue="NORMAL"
-                android:entries="@array/pref_text_size_choices"
-                android:entryValues="@array/pref_text_size_values"
-                android:dialogTitle="@string/pref_text_size_dialogtitle" />
-
-        <ListPreference
-                android:key="default_zoom"
-                android:title="@string/pref_default_zoom"
-                android:defaultValue="MEDIUM"
-                android:entries="@array/pref_default_zoom_choices"
-                android:entryValues="@array/pref_default_zoom_values"
-                android:dialogTitle="@string/pref_default_zoom_dialogtitle" />
-
-        <CheckBoxPreference
-                android:key="load_page"
-                android:defaultValue="true"
-                android:title="@string/pref_content_load_page"
-                android:summary="@string/pref_content_load_page_summary" />
-
-        <ListPreference
-                android:key="default_text_encoding"
-                android:title="@string/pref_default_text_encoding"
-                android:defaultValue="@string/pref_default_text_encoding_default"
-                android:entries="@array/pref_default_text_encoding_choices"
-                android:entryValues="@array/pref_default_text_encoding_values"
-                android:dialogTitle="@string/pref_default_text_encoding_dialogtitle" />
-
-        <CheckBoxPreference
-                android:key="block_popup_windows"
-                android:defaultValue="true"
-                android:title="@string/pref_content_block_popups" /> 
-
-        <CheckBoxPreference
-                android:key="load_images"
-                android:defaultValue="true"
-                android:title="@string/pref_content_load_images"
-                android:summary="@string/pref_content_load_images_summary" />   
-
-        <CheckBoxPreference
-                android:key="autofit_pages"
-                android:defaultValue="true"
-                android:title="@string/pref_content_autofit"
-                android:summary="@string/pref_content_autofit_summary" />  
-
-        <CheckBoxPreference
-                android:key="enable_javascript"
-                android:defaultValue="true"
-                android:title="@string/pref_content_javascript" />     
-
-        <ListPreference
-                android:key="plugin_state"
-                android:title="@string/pref_content_plugins"
-                android:defaultValue="ON"
-                android:entries="@array/pref_content_plugins_choices"
-                android:entryValues="@array/pref_content_plugins_values"
-                android:dialogTitle="@string/pref_content_plugins" />
-
-        <CheckBoxPreference
-                android:key="open_in_background"
-                android:defaultValue="false"
-                android:title="@string/pref_content_open_in_background"
-                android:summary="@string/pref_content_open_in_background_summary" />
-
-        <com.android.browser.BrowserHomepagePreference
-                android:key="homepage" 
-                android:title="@string/pref_content_homepage"
-                android:hint="@string/http"
-                android:inputType="textUri|textMultiLine" />
-
-    </PreferenceCategory>
-
-    <PreferenceCategory
-            android:title="@string/pref_privacy_security_title">
-            
-        <com.android.browser.BrowserYesNoPreference
-                android:key="privacy_clear_cache"
-                android:title="@string/pref_privacy_clear_cache"
-                android:summary="@string/pref_privacy_clear_cache_summary"
-                android:dialogMessage="@string/pref_privacy_clear_cache_dlg" 
-                android:dialogTitle="@string/clear" 
-                android:dialogIcon="@android:drawable/ic_dialog_alert" />
-                
-        <com.android.browser.BrowserYesNoPreference
-                android:key="privacy_clear_history"
-                android:title="@string/pref_privacy_clear_history"
-                android:summary="@string/pref_privacy_clear_history_summary"
-                android:dialogMessage="@string/pref_privacy_clear_history_dlg" 
-                android:dialogTitle="@string/clear" 
-                android:dialogIcon="@android:drawable/ic_dialog_alert"/>
-
-        <CheckBoxPreference
-                android:key="accept_cookies"
-                android:defaultValue="true"
-                android:title="@string/pref_security_accept_cookies"
-                android:summary="@string/pref_security_accept_cookies_summary" />
-                
-        <com.android.browser.BrowserYesNoPreference
-                android:key="privacy_clear_cookies"
-                android:title="@string/pref_privacy_clear_cookies"
-                android:summary="@string/pref_privacy_clear_cookies_summary"
-                android:dialogMessage="@string/pref_privacy_clear_cookies_dlg" 
-                android:dialogTitle="@string/clear" 
-                android:dialogIcon="@android:drawable/ic_dialog_alert"/>
-
-        <CheckBoxPreference
-                android:key="save_formdata"
-                android:defaultValue="true"
-                android:title="@string/pref_security_save_form_data"
-                android:summary="@string/pref_security_save_form_data_summary" />
-
-        <CheckBoxPreference
-                android:key="autofill_enabled"
-                android:defaultValue="true"
-                android:title="@string/pref_autofill_enabled"
-                android:summary="@string/pref_autofill_enabled_summary" />
-
-        <com.android.browser.BrowserYesNoPreference
-                android:key="privacy_clear_form_data"
-                android:title="@string/pref_privacy_clear_form_data"
-                android:summary="@string/pref_privacy_clear_form_data_summary"
-                android:dialogMessage="@string/pref_privacy_clear_form_data_dlg" 
-                android:dialogTitle="@string/clear" 
-                android:dialogIcon="@android:drawable/ic_dialog_alert"/>
-
-        <CheckBoxPreference
-                android:key="enable_geolocation"
-                android:defaultValue="true"
-                android:title="@string/pref_privacy_enable_geolocation"
-                android:summary="@string/pref_privacy_enable_geolocation_summary" />
-
-        <com.android.browser.BrowserYesNoPreference
-                android:key="privacy_clear_geolocation_access"
-                android:dependency="enable_geolocation"
-                android:title="@string/pref_privacy_clear_geolocation_access"
-                android:summary="@string/pref_privacy_clear_geolocation_access_summary"
-                android:dialogMessage="@string/pref_privacy_clear_geolocation_access_dlg"
-                android:dialogTitle="@string/clear"
-                android:dialogIcon="@android:drawable/ic_dialog_alert"/>
-
-    </PreferenceCategory>
-    
-        <PreferenceCategory
-            android:title="@string/pref_privacy_security_title">
-            
-        <CheckBoxPreference
-                android:key="remember_passwords"
-                android:defaultValue="true"
-                android:title="@string/pref_security_remember_passwords"
-                android:summary="@string/pref_security_remember_passwords_summary" />
-
-        <com.android.browser.BrowserYesNoPreference
-                android:key="privacy_clear_passwords"
-                android:title="@string/pref_privacy_clear_passwords"
-                android:summary="@string/pref_privacy_clear_passwords_summary"
-                android:dialogMessage="@string/pref_privacy_clear_passwords_dlg" 
-                android:dialogTitle="@string/clear" 
-                android:dialogIcon="@android:drawable/ic_dialog_alert"/>
-                
-        <CheckBoxPreference
-                android:key="show_security_warnings"
-                android:defaultValue="true"
-                android:title="@string/pref_security_show_security_warning"
-                android:summary="@string/pref_security_show_security_warning_summary" />
-
-            
-    </PreferenceCategory>
-    <PreferenceCategory
-            android:title="@string/pref_extras_title">
-
-            <!-- Entries and values in this list are set dynamically. -->
-            <com.android.browser.search.SearchEnginePreference
-                    android:key="search_engine"
-                    android:title="@string/pref_content_search_engine"
-                    android:defaultValue="google"
-                    android:summary="@string/pref_content_search_engine_summary"
-                    android:dialogTitle="@string/pref_content_search_engine" />
-
-            <PreferenceScreen
-                  android:key="website_settings"
-                  android:title="@string/pref_extras_website_settings"
-                  android:summary="@string/pref_extras_website_settings_summary" />
-
-            <com.android.browser.BrowserYesNoPreference
-                    android:key="reset_default_preferences"
-                    android:title="@string/pref_extras_reset_default"
-                    android:summary="@string/pref_extras_reset_default_summary"
-                    android:dialogMessage="@string/pref_extras_reset_default_dlg" 
-                    android:dialogTitle="@string/pref_extras_reset_default_dlg_title" 
-                    android:dialogIcon="@android:drawable/ic_dialog_alert" />
-    </PreferenceCategory>
-</PreferenceScreen>
diff --git a/res/xml/privacy_security_preferences.xml b/res/xml/privacy_security_preferences.xml
index 50802ca..54f3ff0 100644
--- a/res/xml/privacy_security_preferences.xml
+++ b/res/xml/privacy_security_preferences.xml
@@ -39,6 +39,11 @@
             android:title="@string/pref_security_show_security_warning"
             android:summary="@string/pref_security_show_security_warning_summary" />
 
+    <CheckBoxPreference
+            android:key="enable_autologin"
+            android:title="@string/pref_autologin_title"
+            android:defaultValue="true" />
+
     <PreferenceCategory android:title="@string/pref_privacy_cookies_title">
         <CheckBoxPreference
                 android:key="accept_cookies"
diff --git a/src/com/android/browser/BrowserActivity.java b/src/com/android/browser/BrowserActivity.java
index ba5ba29..0fce014 100644
--- a/src/com/android/browser/BrowserActivity.java
+++ b/src/com/android/browser/BrowserActivity.java
@@ -19,6 +19,7 @@
 import com.google.common.annotations.VisibleForTesting;
 
 import android.app.Activity;
+import android.app.ProgressDialog;
 import android.content.Intent;
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
@@ -59,13 +60,15 @@
         }
         super.onCreate(icicle);
 
+        BrowserSettings settings = BrowserSettings.getInstance();
+
         // We load the first set of BrowserSettings from the db asynchronously
         // but if it has not completed at this point, we have no choice but
         // to block waiting for them to finish loading. :(
-        BrowserSettings.getInstance().waitForLoadFromDbToComplete();
+        settings.waitForLoadFromDbToComplete();
 
         // render the browser in OpenGL
-        if (BrowserSettings.getInstance().isHardwareAccelerated()) {
+        if (settings.isHardwareAccelerated()) {
             // Set the flag in the activity's window
             this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
                     WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
@@ -110,7 +113,28 @@
         if (state != null && icicle == null) {
             icicle = state;
         }
-        mController.start(icicle, getIntent());
+
+        String account = settings.getAutoLoginAccount(this);
+        if (settings.isAutoLoginEnabled() && account != null) {
+            GoogleAccountLogin login =
+                    new GoogleAccountLogin(this, account);
+            final ProgressDialog dialog = ProgressDialog.show(this,
+                    getString(R.string.pref_autologin_title),
+                    getString(R.string.pref_autologin_progress, account),
+                    true /* indeterminate */,
+                    true /* cancelable */,
+                    login);
+            final Bundle b = icicle;
+            final Runnable start = new Runnable() {
+                @Override public void run() {
+                    dialog.dismiss();
+                    mController.start(b, getIntent());
+                }
+            };
+            login.startLogin(start);
+        } else {
+            mController.start(icicle, getIntent());
+        }
     }
 
     @VisibleForTesting
diff --git a/src/com/android/browser/BrowserSettings.java b/src/com/android/browser/BrowserSettings.java
index 88bd78a..3393c4f 100644
--- a/src/com/android/browser/BrowserSettings.java
+++ b/src/com/android/browser/BrowserSettings.java
@@ -103,6 +103,9 @@
     private String databasePath; // default value set in loadFromDb()
     private String geolocationDatabasePath; // default value set in loadFromDb()
     private WebStorageSizeManager webStorageSizeManager;
+    // Autologin settings
+    private boolean autoLoginEnabled;
+    private String autoLoginAccount;
 
     private String jsFlags = "";
 
@@ -174,6 +177,8 @@
 
     public final static String PREF_QUICK_CONTROLS = "enable_quick_controls";
     public final static String PREF_MOST_VISITED_HOMEPAGE = "use_most_visited_homepage";
+    public final static String PREF_AUTOLOGIN = "enable_autologin";
+    public final static String PREF_AUTOLOGIN_ACCOUNT = "autologin_account";
 
     private static final String DESKTOP_USERAGENT = "Mozilla/5.0 (Macintosh; " +
             "U; Intel Mac OS X 10_6_3; en-us) AppleWebKit/533.16 (KHTML, " +
@@ -527,6 +532,11 @@
         geolocationEnabled = p.getBoolean("enable_geolocation", geolocationEnabled);
         workersEnabled = p.getBoolean("enable_workers", workersEnabled);
 
+        // Autologin account settings.  The account preference may be null until
+        // the user explicitly changes the account in the settings.
+        autoLoginEnabled = p.getBoolean(PREF_AUTOLOGIN, autoLoginEnabled);
+        autoLoginAccount = p.getString(PREF_AUTOLOGIN_ACCOUNT, autoLoginAccount);
+
         update();
     }
 
@@ -607,6 +617,24 @@
         update();
     }
 
+    public boolean isAutoLoginEnabled() {
+        return autoLoginEnabled;
+    }
+
+    public String getAutoLoginAccount(Context context) {
+        // Each time we attempt to get the account, we need to verify that the
+        // account is still valid.
+        return GoogleAccountLogin.validateAccount(context, autoLoginAccount);
+    }
+
+    public void setAutoLoginAccount(Context context, String name) {
+        Editor ed = PreferenceManager.
+                getDefaultSharedPreferences(context).edit();
+        ed.putString(PREF_AUTOLOGIN_ACCOUNT, name);
+        ed.apply();
+        autoLoginAccount = name;
+    }
+
     public void setAutoFillProfile(Context ctx, AutoFillProfile profile, Message msg) {
         if (profile != null) {
             setActiveAutoFillProfileId(ctx, profile.getUniqueId());
@@ -799,6 +827,9 @@
         domStorageEnabled = true;
         geolocationEnabled = true;
         workersEnabled = true;  // only affects V8. JSC does not have a similar setting
+        // Autologin default is true.  The account will be populated when
+        // reading from the DB as that is when a context is available.
+        autoLoginEnabled = true;
     }
 
     private abstract class AutoFillProfileDbTask<T> extends AsyncTask<T, Void, Void> {
diff --git a/src/com/android/browser/GoogleAccountLogin.java b/src/com/android/browser/GoogleAccountLogin.java
new file mode 100644
index 0000000..8ff0972
--- /dev/null
+++ b/src/com/android/browser/GoogleAccountLogin.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.browser;
+
+import org.apache.http.Header;
+import org.apache.http.HeaderIterator;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.util.EntityUtils;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.accounts.AccountManagerCallback;
+import android.accounts.AccountManagerFuture;
+import android.app.Activity;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnCancelListener;
+import android.net.http.AndroidHttpClient;
+import android.net.Uri;
+import android.os.Bundle;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+
+import java.util.ArrayList;
+
+public class GoogleAccountLogin extends Thread implements
+        AccountManagerCallback<Bundle>, OnCancelListener {
+
+    // Url for issuing the uber token.
+    private Uri ISSUE_AUTH_TOKEN_URL = Uri.parse(
+            "https://www.google.com/accounts/IssueAuthToken?service=gaia&Session=false");
+    // Url for signing into a particular service.
+    private final static Uri TOKEN_AUTH_URL = Uri.parse(
+            "https://www.google.com/accounts/TokenAuth");
+    // Google account type
+    private final static String GOOGLE = "com.google";
+
+    private final Activity mActivity;
+    private final Account mAccount;
+    private final WebView mWebView;
+    private Runnable mRunnable;
+
+    // SID and LSID retrieval process.
+    private String mSid;
+    private String mLsid;
+    private int mState;  // {NONE(0), SID(1), LSID(2)}
+
+    GoogleAccountLogin(Activity activity, String name) {
+        mActivity = activity;
+        mAccount = new Account(name, GOOGLE);
+        mWebView = new WebView(mActivity);
+        mWebView.setWebViewClient(new WebViewClient() {
+            @Override
+            public boolean shouldOverrideUrlLoading(WebView view, String url) {
+                return false;
+            }
+            @Override
+            public void onPageFinished(WebView view, String url) {
+                done();
+            }
+        });
+    }
+
+    // Thread
+    @Override
+    public void run() {
+        String url = ISSUE_AUTH_TOKEN_URL.buildUpon()
+                .appendQueryParameter("SID", mSid)
+                .appendQueryParameter("LSID", mLsid)
+                .build().toString();
+        // Intentionally not using Proxy.
+        AndroidHttpClient client = AndroidHttpClient.newInstance(
+                mWebView.getSettings().getUserAgentString());
+        HttpPost request = new HttpPost(url);
+
+        String result = null;
+        try {
+            HttpResponse response = client.execute(request);
+            if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
+                done();
+                return;
+            }
+            HttpEntity entity = response.getEntity();
+            if (entity == null) {
+                done();
+                return;
+            }
+            result = EntityUtils.toString(entity, "UTF-8");
+        } catch (Exception e) {
+            request.abort();
+            done();
+            return;
+        } finally {
+            client.close();
+        }
+        final String newUrl = TOKEN_AUTH_URL.buildUpon()
+                .appendQueryParameter("source", "android-browser")
+                .appendQueryParameter("auth", result)
+                .appendQueryParameter("continue",
+                        BrowserSettings.getFactoryResetHomeUrl(mActivity))
+                .build().toString();
+        mActivity.runOnUiThread(new Runnable() {
+            @Override public void run() {
+                mWebView.loadUrl(newUrl);
+            }
+        });
+    }
+
+    // AccountManager callbacks.
+    @Override
+    public void run(AccountManagerFuture<Bundle> value) {
+        try {
+            String id = value.getResult().getString(
+                    AccountManager.KEY_AUTHTOKEN);
+            switch (mState) {
+                default:
+                case 0:
+                    throw new IllegalStateException(
+                            "Impossible to get into this state");
+                case 1:
+                    mSid = id;
+                    mState = 2;  // LSID
+                    AccountManager.get(mActivity).getAuthToken(
+                            mAccount, "LSID", null, mActivity, this, null);
+                    break;
+                case 2:
+                    mLsid = id;
+                    this.start();
+                    break;
+            }
+        } catch (Exception e) {
+            // For all exceptions load the original signin page.
+            // TODO: toast login failed?
+            done();
+        }
+    }
+
+    public void startLogin(Runnable runnable) {
+        mRunnable = runnable;
+        mState = 1;  // SID
+        AccountManager.get(mActivity).getAuthToken(
+                mAccount, "SID", null, mActivity, this, null);
+    }
+
+    // Returns the account name passed in if the account exists, otherwise
+    // returns the default account.
+    public static String validateAccount(Context ctx, String name) {
+        Account[] accounts = getAccounts(ctx);
+        if (accounts.length == 0) {
+            return null;
+        }
+        if (name != null) {
+            // Make sure the account still exists.
+            for (Account a : accounts) {
+                if (a.name.equals(name)) {
+                    return name;
+                }
+            }
+        }
+        // Return the first entry.
+        return accounts[0].name;
+    }
+
+    public static Account[] getAccounts(Context ctx) {
+        return AccountManager.get(ctx).getAccountsByType(GOOGLE);
+    }
+
+    // Used to indicate that the Browser should continue loading the main page.
+    // This can happen on success, error, or timeout.
+    private synchronized void done() {
+        if (mRunnable != null) {
+            mActivity.runOnUiThread(mRunnable);
+            mRunnable = null;
+            mWebView.destroy();
+        }
+    }
+
+    // Called by the progress dialog on startup.
+    public void onCancel(DialogInterface unused) {
+        done();
+    }
+}
diff --git a/src/com/android/browser/UrlHandler.java b/src/com/android/browser/UrlHandler.java
index f39ac4b..9e41990 100644
--- a/src/com/android/browser/UrlHandler.java
+++ b/src/com/android/browser/UrlHandler.java
@@ -16,29 +16,12 @@
 
 package com.android.browser;
 
-import org.apache.http.Header;
-import org.apache.http.HeaderIterator;
-import org.apache.http.HttpEntity;
-import org.apache.http.HttpResponse;
-import org.apache.http.HttpStatus;
-import org.apache.http.client.methods.HttpPost;
-import org.apache.http.util.EntityUtils;
-
-import android.accounts.Account;
-import android.accounts.AccountManager;
-import android.accounts.AccountManagerCallback;
-import android.accounts.AccountManagerFuture;
 import android.app.Activity;
-import android.app.AlertDialog;
 import android.content.ActivityNotFoundException;
-import android.content.DialogInterface;
-import android.content.DialogInterface.OnCancelListener;
-import android.content.DialogInterface.OnClickListener;
 import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.database.Cursor;
 import android.net.Uri;
-import android.net.http.AndroidHttpClient;
 import android.os.AsyncTask;
 import android.os.Bundle;
 import android.util.Log;
@@ -125,14 +108,6 @@
             }
         }
 
-        // Check for service login and prompt the user for an account to use.
-        if (url.startsWith("https://www.google.com/accounts/ServiceLogin?") ||
-                url.startsWith("https://www.google.com/accounts/Login?")) {
-            if (loginWithDeviceAccount(view, url)) {
-                return true;
-            }
-        }
-
         if (startActivityForUrl(url)) {
             return true;
         }
@@ -209,162 +184,6 @@
         return false;
     }
 
-    // Url for issuing the uber token.
-    private final static Uri ISSUE_AUTH_TOKEN_URL = Uri.parse(
-            "https://www.google.com/accounts/IssueAuthToken?service=gaia&Session=false");
-    // Url for signing into a particular service.
-    private final static Uri TOKEN_AUTH_URL = Uri.parse(
-            "https://www.google.com/accounts/TokenAuth");
-
-    private class GoogleServiceLogin extends Thread implements
-            AccountManagerCallback<Bundle>, OnClickListener, OnCancelListener {
-        // For choosing the account.
-        private final Account[] mAccounts;
-        private int mCurrentAccount;  // initially 0 for the first account
-
-        // For loading the auth token urls or the original url on error.
-        private final WebView mWebView;
-        private final String mUrl;
-
-        // SID and LSID retrieval process.
-        private String mSid;
-        private String mLsid;
-        private int mState;  // {NONE(0), SID(1), LSID(2)}
-
-        GoogleServiceLogin(Account[] accounts, WebView view, String url) {
-            mAccounts = accounts;
-            mWebView = view;
-            mUrl = url;
-        }
-
-        // Thread
-        public void run() {
-            String url = ISSUE_AUTH_TOKEN_URL.buildUpon()
-                    .appendQueryParameter("SID", mSid)
-                    .appendQueryParameter("LSID", mLsid)
-                    .build().toString();
-            // Intentionally not using Proxy.
-            AndroidHttpClient client = AndroidHttpClient.newInstance(
-                    mWebView.getSettings().getUserAgentString());
-            HttpPost request = new HttpPost(url);
-
-            String result = null;
-            try {
-                HttpResponse response = client.execute(request);
-                if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
-                    onCancel(null);
-                    return;
-                }
-                HttpEntity entity = response.getEntity();
-                if (entity == null) {
-                    onCancel(null);
-                    return;
-                }
-                result = EntityUtils.toString(entity, "UTF-8");
-            } catch (Exception e) {
-                request.abort();
-                onCancel(null);
-            } finally {
-                client.close();
-            }
-            Uri parsedUri = Uri.parse(mUrl);
-            String service = parsedUri.getQueryParameter("service");
-            String redirect = parsedUri.getQueryParameter("continue");
-            final String newUrl = TOKEN_AUTH_URL.buildUpon()
-                    .appendQueryParameter("service", service)
-                    .appendQueryParameter("source", "android-browser")
-                    .appendQueryParameter("auth", result)
-                    .appendQueryParameter("continue", redirect)
-                    .build().toString();
-            mActivity.runOnUiThread(new Runnable() {
-                @Override public void run() {
-                    mController.loadUrl(mWebView, newUrl);
-                }
-            });
-        }
-
-        // AccountManager callbacks.
-        public void run(AccountManagerFuture<Bundle> value) {
-            try {
-                String id = value.getResult().getString(
-                        AccountManager.KEY_AUTHTOKEN);
-                switch (mState) {
-                    default:
-                    case 0:
-                        throw new IllegalStateException(
-                                "Impossible to get into this state");
-                    case 1:
-                        mSid = id;
-                        mState = 2;  // LSID
-                        AccountManager.get(mActivity).getAuthToken(
-                                mAccounts[mCurrentAccount], "LSID", null,
-                                mActivity, this, null);
-                        break;
-                    case 2:
-                        mLsid = id;
-                        this.start();
-                        break;
-                }
-            } catch (Exception e) {
-                // For all exceptions load the original signin page.
-                // TODO: toast login failed?
-                onCancel(null);
-            }
-        }
-
-        // Handle picking an account and "OK."
-        public void onClick(DialogInterface unused, int which) {
-            if (which == DialogInterface.BUTTON_POSITIVE) {
-                // TODO: toast loading...?
-                Account current = mAccounts[mCurrentAccount];
-                mState = 1;  // SID
-                AccountManager.get(mActivity).getAuthToken(
-                        mAccounts[mCurrentAccount], "SID", null,
-                        mActivity, this, null);
-            } else if (which == DialogInterface.BUTTON_NEGATIVE) {
-                onCancel(null);
-            } else {
-                mCurrentAccount = which;
-            }
-        }
-
-        // Handle "cancel."
-        public void onCancel(DialogInterface unusued) {
-            // load the original url to login manually.
-            mController.loadUrl(mWebView, mUrl);
-        }
-    }
-
-    private boolean loginWithDeviceAccount(WebView view, String url) {
-        Uri parsedUri = Uri.parse(url);
-        if ("true".equals(parsedUri.getQueryParameter("go"))) {
-            return false;
-        }
-        Account[] accounts =
-                AccountManager.get(mActivity).getAccountsByType("com.google");
-        if (accounts.length == 0) {
-            return false;
-        }
-
-        // Populate the account list.
-        CharSequence[] names = new CharSequence[accounts.length];
-        int i = 0;
-        for (Account a : accounts) {
-            names[i++] = a.name;
-        }
-
-        GoogleServiceLogin login = new GoogleServiceLogin(accounts, view, url);
-        new AlertDialog.Builder(mActivity)
-                .setTitle(R.string.account_picker_title)
-                .setSingleChoiceItems(names, 0 /* first choice */, login)
-                .setPositiveButton(R.string.ok, login)
-                .setNegativeButton(R.string.cancel, login)
-                .setCancelable(true)
-                .setOnCancelListener(login)
-                .show();
-        return true;
-    }
-
     private class RLZTask extends AsyncTask<Void, Void, String> {
         private Tab mTab;
         private Uri mSiteUri;
diff --git a/src/com/android/browser/preferences/PrivacySecurityPreferencesFragment.java b/src/com/android/browser/preferences/PrivacySecurityPreferencesFragment.java
index 8a5178c..20d4f42 100644
--- a/src/com/android/browser/preferences/PrivacySecurityPreferencesFragment.java
+++ b/src/com/android/browser/preferences/PrivacySecurityPreferencesFragment.java
@@ -17,26 +17,50 @@
 package com.android.browser.preferences;
 
 import com.android.browser.BrowserSettings;
+import com.android.browser.GoogleAccountLogin;
 import com.android.browser.R;
 
+import android.accounts.Account;
 import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnClickListener;
 import android.content.Intent;
 import android.os.Bundle;
+import android.preference.CheckBoxPreference;
 import android.preference.Preference;
 import android.preference.PreferenceFragment;
 
 public class PrivacySecurityPreferencesFragment extends PreferenceFragment
         implements Preference.OnPreferenceChangeListener {
 
+    private BrowserSettings mSettings;
+
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
+        mSettings = BrowserSettings.getInstance();
+
         // Load the preferences from an XML resource
         addPreferencesFromResource(R.xml.privacy_security_preferences);
 
         Preference e = findPreference(BrowserSettings.PREF_CLEAR_HISTORY);
         e.setOnPreferenceChangeListener(this);
+        e = findPreference(BrowserSettings.PREF_AUTOLOGIN);
+        e.setOnPreferenceChangeListener(this);
+        updateAutoLoginSummary((CheckBoxPreference) e);
+    }
+
+    private void updateAutoLoginSummary(CheckBoxPreference pref) {
+        String account = mSettings.getAutoLoginAccount(getActivity());
+        if (account == null) {
+            pref.setChecked(false);
+            pref.setEnabled(false);
+            pref.setSummary(R.string.pref_autologin_no_account);
+        } else {
+            pref.setSummary(getString(R.string.pref_autologin_summary, account));
+        }
     }
 
     @Override
@@ -48,8 +72,68 @@
             getActivity().setResult(Activity.RESULT_OK, (new Intent()).putExtra(Intent.EXTRA_TEXT,
                     pref.getKey()));
             return true;
+        } else if (pref.getKey().equals(BrowserSettings.PREF_AUTOLOGIN)) {
+            boolean val = ((Boolean) objValue).booleanValue();
+            if (val) {
+                selectAccount((CheckBoxPreference) pref);
+                return false;
+            }
+            return true;
         }
 
         return false;
     }
+
+    class AccountCallback implements OnClickListener {
+        private final Account[] mAccounts;
+        private final CheckBoxPreference mPref;
+
+        public AccountCallback(Account[] accounts, CheckBoxPreference pref) {
+            mAccounts = accounts;
+            mPref = pref;
+        }
+
+        public void onClick(DialogInterface d, int which) {
+            saveAutoLoginAccount(mPref, mAccounts[which].name);
+            d.dismiss();
+        }
+    }
+
+    private void saveAutoLoginAccount(CheckBoxPreference pref, String name) {
+        mSettings.setAutoLoginAccount(getActivity(), name);
+        pref.setChecked(true);
+        updateAutoLoginSummary(pref);
+    }
+
+    private void selectAccount(CheckBoxPreference pref) {
+        Account[] accounts = GoogleAccountLogin.getAccounts(getActivity());
+        if (accounts.length == 0) {
+            mSettings.setAutoLoginAccount(getActivity(), null);
+            updateAutoLoginSummary(pref);
+            return;
+        } else if (accounts.length == 1) {
+            // No need for a dialog with one account.
+            saveAutoLoginAccount(pref, accounts[0].name);
+            return;
+        }
+
+        String account = mSettings.getAutoLoginAccount(getActivity());
+        CharSequence[] names = new CharSequence[accounts.length];
+        int i = 0;
+        int defaultAccount = 0;
+        for (Account a : accounts) {
+            if (a.name.equals(account)) {
+                defaultAccount = i;
+            }
+            names[i++] = a.name;
+        }
+
+        AccountCallback callback =
+                new AccountCallback(accounts, pref);
+        new AlertDialog.Builder(getActivity())
+                .setTitle(R.string.pref_autologin_title)
+                .setSingleChoiceItems(names, defaultAccount, callback)
+                .setCancelable(true)
+                .show();
+    }
 }