diff options
Diffstat (limited to 'src/com/android')
| -rw-r--r-- | src/com/android/browser/BrowserActivity.java | 30 | ||||
| -rw-r--r-- | src/com/android/browser/BrowserSettings.java | 31 | ||||
| -rw-r--r-- | src/com/android/browser/GoogleAccountLogin.java | 199 | ||||
| -rw-r--r-- | src/com/android/browser/UrlHandler.java | 181 | ||||
| -rw-r--r-- | src/com/android/browser/preferences/PrivacySecurityPreferencesFragment.java | 84 |
5 files changed, 341 insertions, 184 deletions
diff --git a/src/com/android/browser/BrowserActivity.java b/src/com/android/browser/BrowserActivity.java index ba5ba29fe..0fce014ae 100644 --- a/src/com/android/browser/BrowserActivity.java +++ b/src/com/android/browser/BrowserActivity.java @@ -19,6 +19,7 @@ package com.android.browser; 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 @@ public class BrowserActivity extends Activity { } 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 @@ public class BrowserActivity extends Activity { 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 88bd78a8c..3393c4fc5 100644 --- a/src/com/android/browser/BrowserSettings.java +++ b/src/com/android/browser/BrowserSettings.java @@ -103,6 +103,9 @@ public class BrowserSettings extends Observable implements OnSharedPreferenceCha 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 class BrowserSettings extends Observable implements OnSharedPreferenceCha 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 @@ public class BrowserSettings extends Observable implements OnSharedPreferenceCha 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 @@ public class BrowserSettings extends Observable implements OnSharedPreferenceCha 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 @@ public class BrowserSettings extends Observable implements OnSharedPreferenceCha 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 000000000..8ff09727d --- /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 f39ac4b6b..9e41990be 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 @@ public class UrlHandler { } } - // 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 @@ public class UrlHandler { 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 8a5178c02..20d4f420c 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 @@ public class PrivacySecurityPreferencesFragment extends PreferenceFragment 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(); + } } |
