Merge "change app tab behavior" into honeycomb-mr1
diff --git a/res/anim/autologin_enter.xml b/res/anim/autologin_enter.xml
new file mode 100644
index 0000000..45e5204
--- /dev/null
+++ b/res/anim/autologin_enter.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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.
+-->
+
+<translate xmlns:android="http://schemas.android.com/apk/res/android"
+ android:fromYDelta="-100%" android:toYDelta="0"
+ android:duration="@android:integer/config_longAnimTime"/>
diff --git a/res/anim/autologin_exit.xml b/res/anim/autologin_exit.xml
new file mode 100644
index 0000000..6faa715
--- /dev/null
+++ b/res/anim/autologin_exit.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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.
+-->
+
+<translate xmlns:android="http://schemas.android.com/apk/res/android"
+ android:fromYDelta="0" android:toYDelta="-100%"
+ android:duration="@android:integer/config_longAnimTime"/>
diff --git a/res/layout/url_bar.xml b/res/layout/url_bar.xml
index f2b32c4..bf184a8 100644
--- a/res/layout/url_bar.xml
+++ b/res/layout/url_bar.xml
@@ -10,11 +10,68 @@
the specific language governing permissions and limitations under the
License.
-->
-<LinearLayout
+<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="vertical">
+ >
+ <LinearLayout
+ android:id="@+id/autologin"
+ android:background="#FBF0A0"
+ android:gravity="center_vertical"
+ android:paddingTop="3dip"
+ android:visibility="gone"
+ android:layout_below="@+id/taburlbar"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ <TextView
+ android:text="@string/autologin_bar_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textColor="@android:color/primary_text_light"
+ android:paddingLeft="15dip"
+ android:paddingRight="15dip"
+ android:textAppearance="?android:attr/textAppearanceMedium"/>
+ <Button
+ android:id="@+id/autologin_account"
+ android:background="@android:drawable/btn_dropdown"
+ android:textColor="@android:color/primary_text_light"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"/>
+ <Button
+ android:id="@+id/autologin_login"
+ android:text="@string/autologin_bar_login_text"
+ android:background="@android:drawable/btn_default"
+ android:textColor="@android:color/primary_text_light"
+ android:layout_marginRight="15dip"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content" />
+ <ProgressBar
+ android:id="@+id/autologin_progress"
+ android:indeterminateOnly="true"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:visibility="gone" />
+ <TextView
+ android:id="@+id/autologin_error"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textColor="#dd6826"
+ android:text="@string/autologin_bar_error"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:visibility="gone" />
+ <View
+ android:layout_width="2dip"
+ android:layout_height="match_parent"
+ android:layout_weight="1"/>
+ <ImageButton
+ android:id="@+id/autologin_close"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingRight="15dip"
+ android:background="@null"
+ android:src="@*android:drawable/btn_close"/>
+ </LinearLayout>
<LinearLayout
android:id="@+id/taburlbar"
android:layout_width="match_parent"
@@ -128,7 +185,8 @@
android:layout_width="match_parent"
android:layout_height="22dip"
android:background="@null"
+ android:layout_below="@+id/taburlbar"
android:src="@drawable/progress"
android:layout_marginTop="-11dip"
android:visibility="gone" />
-</LinearLayout>
+</RelativeLayout>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 5a8a110..9f339f5 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -381,14 +381,8 @@
<!-- 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>\nYour privacy & security settings control automatic Google sign-in</string>
- <!-- Option in account list to disable autologin [CHAR-LIMIT=50] -->
- <string name="pref_autologin_disable">Don\'t sign in automatically</string>
<!-- Auto-login bar description [CHAR-LIMIT=40] -->
<string name="autologin_bar_text">Automatic sign-in is available.</string>
<!-- Login button [CHAR-LIMIT=10] -->
diff --git a/res/xml/privacy_security_preferences.xml b/res/xml/privacy_security_preferences.xml
index 9bff4b8..50802ca 100644
--- a/res/xml/privacy_security_preferences.xml
+++ b/res/xml/privacy_security_preferences.xml
@@ -39,10 +39,6 @@
android:title="@string/pref_security_show_security_warning"
android:summary="@string/pref_security_show_security_warning_summary" />
- <ListPreference
- android:key="autologin_account"
- android:title="@string/pref_autologin_title" />
-
<PreferenceCategory android:title="@string/pref_privacy_cookies_title">
<CheckBoxPreference
android:key="accept_cookies"
diff --git a/src/com/android/browser/BaseUi.java b/src/com/android/browser/BaseUi.java
index 5084e31..71346ae 100644
--- a/src/com/android/browser/BaseUi.java
+++ b/src/com/android/browser/BaseUi.java
@@ -240,6 +240,7 @@
onProgressChanged(tab);
boolean incognito = mActiveTab.getWebView().isPrivateBrowsingEnabled();
getTitleBar().setIncognitoMode(incognito);
+ updateAutoLogin(tab, false);
}
Tab getActiveTab() {
@@ -546,11 +547,23 @@
&& mComboView == null;
}
+ @Override
+ public void showAutoLogin(Tab tab) {
+ updateAutoLogin(tab, true);
+ }
+
+ @Override
+ public void hideAutoLogin(Tab tab) {
+ updateAutoLogin(tab, true);
+ }
+
// -------------------------------------------------------------------------
protected void updateNavigationState(Tab tab) {
}
+ protected void updateAutoLogin(Tab tab, boolean animate) {}
+
/**
* Update the lock icon to correspond to our latest state.
*/
diff --git a/src/com/android/browser/BrowserSettings.java b/src/com/android/browser/BrowserSettings.java
index 75e0cfb..357d1e9 100644
--- a/src/com/android/browser/BrowserSettings.java
+++ b/src/com/android/browser/BrowserSettings.java
@@ -92,9 +92,6 @@
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 = "";
@@ -168,8 +165,6 @@
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";
public final static String PREF_PLUGIN_STATE = "plugin_state";
public final static String PREF_USE_INSTANT = "use_instant_search";
@@ -537,11 +532,6 @@
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();
}
@@ -632,32 +622,6 @@
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 setAutoLoginEnabled(Context context, boolean enable) {
- Editor ed = PreferenceManager.
- getDefaultSharedPreferences(context).edit();
- ed.putBoolean(PREF_AUTOLOGIN, enable);
- ed.apply();
- autoLoginEnabled = enable;
- }
-
public void setAutoFillProfile(Context ctx, AutoFillProfile profile, Message msg) {
if (profile != null) {
setActiveAutoFillProfileId(ctx, profile.getUniqueId());
@@ -854,9 +818,6 @@
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/Controller.java b/src/com/android/browser/Controller.java
index d02f05c..82aea47 100644
--- a/src/com/android/browser/Controller.java
+++ b/src/com/android/browser/Controller.java
@@ -279,7 +279,7 @@
CookieManager.getInstance().removeSessionCookie();
}
- GoogleAccountLogin.startLoginIfNeeded(mActivity, mSettings,
+ GoogleAccountLogin.startLoginIfNeeded(mActivity,
new Runnable() {
@Override public void run() {
start(icicle, intent, currentTab, restoreIncognitoTabs);
@@ -996,6 +996,19 @@
mPageDialogsHandler.showSSLCertificateOnError(view, handler, error);
}
+ @Override
+ public void showAutoLogin(Tab tab) {
+ assert tab.inForeground();
+ // Update the title bar to show the auto-login request.
+ mUi.showAutoLogin(tab);
+ }
+
+ @Override
+ public void hideAutoLogin(Tab tab) {
+ assert tab.inForeground();
+ mUi.hideAutoLogin(tab);
+ }
+
// helper method
/*
@@ -2216,17 +2229,9 @@
// animation behavior.
addTab(tab);
setActiveTab(tab);
-
- // Callback to load the url data.
- final Runnable load = new Runnable() {
- @Override public void run() {
- if (!urlData.isEmpty()) {
- loadUrlDataIn(tab, urlData);
- }
- }
- };
-
- GoogleAccountLogin.startLoginIfNeeded(mActivity, mSettings, load);
+ if (!urlData.isEmpty()) {
+ loadUrlDataIn(tab, urlData);
+ }
return tab;
} else {
// Get rid of the subwindow if it exists
diff --git a/src/com/android/browser/DeviceAccountLogin.java b/src/com/android/browser/DeviceAccountLogin.java
new file mode 100644
index 0000000..50b8c97
--- /dev/null
+++ b/src/com/android/browser/DeviceAccountLogin.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2011 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 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.DialogInterface;
+import android.os.Bundle;
+import android.webkit.WebView;
+import android.webkit.WebViewClient;
+
+public class DeviceAccountLogin implements
+ AccountManagerCallback<Bundle>, DialogInterface.OnClickListener {
+
+ private final Activity mActivity;
+ private final WebView mWebView;
+ private final Tab mTab;
+ private final WebViewController mWebViewController;
+ private final AccountManager mAccountManager;
+ private Account[] mAccounts;
+ private int mCurrentAccount;
+ private AutoLoginCallback mCallback;
+ private String mAuthToken;
+
+ // Current state of the login.
+ private int mState = INITIAL;
+
+ public static final int INITIAL = 0;
+ public static final int FAILED = 1;
+ public static final int PROCESSING = 2;
+
+ public interface AutoLoginCallback {
+ public void setAccount(String account);
+ public void loginFailed();
+ }
+
+ public DeviceAccountLogin(Activity activity, WebView view, Tab tab,
+ WebViewController controller) {
+ mActivity = activity;
+ mWebView = view;
+ mTab = tab;
+ mWebViewController = controller;
+ mAccountManager = AccountManager.get(activity);
+ }
+
+ public void handleLogin(String realm, String account, String args) {
+ mAccounts = mAccountManager.getAccountsByType(realm);
+ mAuthToken = "weblogin:" + args;
+
+ // No need to display UI if there are no accounts.
+ if (mAccounts.length == 0) {
+ return;
+ }
+
+ // Verify the account before using it.
+ for (Account a : mAccounts) {
+ if (a.name.equals(account)) {
+ // Handle the automatic login case where the service gave us an
+ // account to use.
+ mAccountManager.getAuthToken(a, mAuthToken, null,
+ mActivity, this, null);
+ return;
+ }
+ }
+
+ displayLoginUi();
+ }
+
+ @Override
+ public void run(AccountManagerFuture<Bundle> value) {
+ try {
+ String result = value.getResult().getString(
+ AccountManager.KEY_AUTHTOKEN);
+ if (result == null) {
+ loginFailed();
+ } else {
+ mWebView.loadUrl(result);
+ mTab.setDeviceAccountLogin(null);
+ if (mTab.inForeground()) {
+ mWebViewController.hideAutoLogin(mTab);
+ }
+ }
+ } catch (Exception e) {
+ loginFailed();
+ }
+ }
+
+ public int getState() {
+ return mState;
+ }
+
+ private void loginFailed() {
+ mState = FAILED;
+ if (mTab.getDeviceAccountLogin() == null) {
+ displayLoginUi();
+ } else {
+ assert mCallback != null;
+ mCallback.loginFailed();
+ }
+ }
+
+ private void displayLoginUi() {
+ // Display the account picker.
+ mTab.setDeviceAccountLogin(this);
+ if (mTab.inForeground()) {
+ mWebViewController.showAutoLogin(mTab);
+ }
+ }
+
+ public void cancel() {
+ mTab.setDeviceAccountLogin(null);
+ }
+
+ public void login(AutoLoginCallback cb) {
+ mState = PROCESSING;
+ mCallback = cb;
+ mAccountManager.getAuthToken(
+ mAccounts[mCurrentAccount], mAuthToken, null,
+ mActivity, this, null);
+ }
+
+ public void chooseAccount(AutoLoginCallback cb) {
+ mCallback = cb;
+ CharSequence[] names = new CharSequence[mAccounts.length];
+ int i = 0;
+ for (Account a : mAccounts) {
+ names[i++] = a.name;
+ }
+ new AlertDialog.Builder(mActivity)
+ .setTitle(R.string.pref_autologin_title)
+ .setSingleChoiceItems(names, mCurrentAccount, this)
+ .setCancelable(true)
+ .show();
+ }
+
+ public String getCurrentAccount() {
+ return mAccounts[mCurrentAccount].name;
+ }
+
+ @Override
+ public void onClick(DialogInterface d, int which) {
+ assert mCallback != null;
+ mCallback.setAccount(mAccounts[which].name);
+ mCurrentAccount = which;
+ d.dismiss();
+ }
+}
diff --git a/src/com/android/browser/GoogleAccountLogin.java b/src/com/android/browser/GoogleAccountLogin.java
index f4ccfd1..0bde010 100644
--- a/src/com/android/browser/GoogleAccountLogin.java
+++ b/src/com/android/browser/GoogleAccountLogin.java
@@ -40,7 +40,6 @@
import android.os.Handler;
import android.preference.PreferenceManager;
import android.util.Log;
-import android.webkit.CookieManager;
import android.webkit.CookieSyncManager;
import android.webkit.WebView;
import android.webkit.WebViewClient;
@@ -80,10 +79,10 @@
private int mState; // {NONE(0), SID(1), LSID(2)}
private boolean mTokensInvalidated;
- private GoogleAccountLogin(Activity activity, String name,
+ private GoogleAccountLogin(Activity activity, Account account,
Runnable runnable) {
mActivity = activity;
- mAccount = new Account(name, GOOGLE);
+ mAccount = account;
mWebView = new WebView(mActivity);
mRunnable = runnable;
@@ -233,28 +232,22 @@
// Start the login process if auto-login is enabled and the user is not
// already logged in.
public static void startLoginIfNeeded(Activity activity,
- BrowserSettings settings, Runnable runnable) {
- // Auto login not enabled?
- if (!settings.isAutoLoginEnabled()) {
- runnable.run();
- return;
- }
-
- // No account found?
- String account = settings.getAutoLoginAccount(activity);
- if (account == null) {
- runnable.run();
- return;
- }
-
+ Runnable runnable) {
// Already logged in?
if (isLoggedIn(activity)) {
runnable.run();
return;
}
+ // No account found?
+ Account[] accounts = getAccounts(activity);
+ if (accounts == null || accounts.length == 0) {
+ runnable.run();
+ return;
+ }
+
GoogleAccountLogin login =
- new GoogleAccountLogin(activity, account, runnable);
+ new GoogleAccountLogin(activity, accounts[0], runnable);
login.startLogin();
}
@@ -271,31 +264,12 @@
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) {
+ private static Account[] getAccounts(Context ctx) {
return AccountManager.get(ctx).getAccountsByType(GOOGLE);
}
- // Checks for the presence of the SID cookie on google.com.
- public static boolean isLoggedIn(Context ctx) {
+ // Checks if we already did pre-login.
+ private static boolean isLoggedIn(Context ctx) {
// See if we last logged in less than a week ago.
long lastLogin = PreferenceManager.
getDefaultSharedPreferences(ctx).
@@ -303,31 +277,7 @@
if (lastLogin == -1) {
return false;
}
- long diff = System.currentTimeMillis() - lastLogin;
- if (diff > WEEK_IN_MILLIS) {
- Log.d(LOGTAG, "Forcing login after " + diff + "ms");
- return false;
- }
-
- // This will potentially block the UI thread but we have to have the
- // most updated cookies.
- // FIXME: Figure out how to avoid waiting to clear session cookies.
- CookieManager.getInstance().waitForCookieOperationsToComplete();
-
- // Use /a/ to grab hosted cookies as well as the base set of google.com
- // cookies.
- String cookies = CookieManager.getInstance().getCookie(
- "http://www.google.com/a/");
- if (cookies != null) {
- StringTokenizer tokenizer = new StringTokenizer(cookies, ";");
- while (tokenizer.hasMoreTokens()) {
- String cookie = tokenizer.nextToken().trim();
- if (cookie.startsWith("SID=") || cookie.startsWith("ASIDAP=")) {
- return true;
- }
- }
- }
- return false;
+ return true;
}
// Used to indicate that the Browser should continue loading the main page.
diff --git a/src/com/android/browser/Tab.java b/src/com/android/browser/Tab.java
index bab3458..863fc95 100644
--- a/src/com/android/browser/Tab.java
+++ b/src/com/android/browser/Tab.java
@@ -132,6 +132,8 @@
// Listener used to know when we move forward or back in the history list.
private final WebBackForwardListClient mWebBackForwardListClient;
private DataController mDataController;
+ // State of the auto-login request.
+ private DeviceAccountLogin mDeviceAccountLogin;
// AsyncTask for downloading touch icons
DownloadTouchIcon mTouchIconLoader;
@@ -530,6 +532,13 @@
}
}
+ // Cancel the auto-login process.
+ if (mDeviceAccountLogin != null) {
+ mDeviceAccountLogin.cancel();
+ mDeviceAccountLogin = null;
+ mWebViewController.hideAutoLogin(Tab.this);
+ }
+
// finally update the UI in the activity if it is in the foreground
mWebViewController.onPageStarted(Tab.this, view, favicon);
@@ -812,8 +821,27 @@
}
mWebViewController.onUnhandledKeyEvent(event);
}
+
+ @Override
+ public void onReceivedLoginRequest(WebView view, String realm,
+ String account, String args) {
+ new DeviceAccountLogin(mActivity, view, Tab.this, mWebViewController)
+ .handleLogin(realm, account, args);
+ }
+
};
+ // Called by DeviceAccountLogin when the Tab needs to have the auto-login UI
+ // displayed.
+ void setDeviceAccountLogin(DeviceAccountLogin login) {
+ mDeviceAccountLogin = login;
+ }
+
+ // Returns non-null if the title bar should display the auto-login UI.
+ DeviceAccountLogin getDeviceAccountLogin() {
+ return mDeviceAccountLogin;
+ }
+
// -------------------------------------------------------------------------
// WebChromeClient implementation for the main WebView
// -------------------------------------------------------------------------
diff --git a/src/com/android/browser/TitleBarXLarge.java b/src/com/android/browser/TitleBarXLarge.java
index 51cf0c3..a786fd7 100644
--- a/src/com/android/browser/TitleBarXLarge.java
+++ b/src/com/android/browser/TitleBarXLarge.java
@@ -26,6 +26,9 @@
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.text.TextUtils;
+import android.view.animation.Animation;
+import android.view.animation.Animation.AnimationListener;
+import android.view.animation.AnimationUtils;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
@@ -34,9 +37,12 @@
import android.view.ViewGroup;
import android.webkit.WebView;
import android.widget.AbsoluteLayout;
+import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.ImageView;
+import android.widget.ProgressBar;
+import android.widget.TextView;
import java.util.List;
@@ -44,7 +50,8 @@
* tabbed title bar for xlarge screen browser
*/
public class TitleBarXLarge extends TitleBarBase
- implements OnClickListener, OnFocusChangeListener, TextChangeWatcher {
+ implements OnClickListener, OnFocusChangeListener, TextChangeWatcher,
+ DeviceAccountLogin.AutoLoginCallback {
private XLargeUi mUi;
@@ -66,6 +73,14 @@
private PageProgressView mProgressView;
private Drawable mFocusDrawable;
private Drawable mUnfocusDrawable;
+ // Auto-login UI
+ private View mAutoLogin;
+ private Button mAutoLoginAccount;
+ private Button mAutoLoginLogin;
+ private ProgressBar mAutoLoginProgress;
+ private TextView mAutoLoginError;
+ private ImageButton mAutoLoginCancel;
+ private DeviceAccountLogin mAutoLoginHandler;
private boolean mInLoad;
private boolean mUseQuickControls;
@@ -133,6 +148,18 @@
mUrlInput.setOnFocusChangeListener(this);
mUrlInput.setSelectAllOnFocus(true);
mUrlInput.addQueryTextWatcher(this);
+ mAutoLogin = findViewById(R.id.autologin);
+ mAutoLoginAccount = (Button) findViewById(R.id.autologin_account);
+ mAutoLoginAccount.setOnClickListener(this);
+ mAutoLoginLogin = (Button) findViewById(R.id.autologin_login);
+ mAutoLoginLogin.setOnClickListener(this);
+ mAutoLoginProgress =
+ (ProgressBar) findViewById(R.id.autologin_progress);
+ mAutoLoginError = (TextView) findViewById(R.id.autologin_error);
+ mAutoLoginCancel =
+ (ImageButton) mAutoLogin.findViewById(R.id.autologin_close);
+ mAutoLoginCancel.setOnClickListener(this);
+
setFocusState(false);
}
@@ -148,6 +175,45 @@
}
}
+ void updateAutoLogin(Tab tab, boolean animate) {
+ DeviceAccountLogin login = tab.getDeviceAccountLogin();
+ if (login != null) {
+ mAutoLoginHandler = login;
+ mAutoLogin.setVisibility(View.VISIBLE);
+ mAutoLoginAccount.setText(login.getCurrentAccount());
+ mAutoLoginAccount.setEnabled(true);
+ mAutoLoginLogin.setEnabled(true);
+ mAutoLoginProgress.setVisibility(View.GONE);
+ mAutoLoginError.setVisibility(View.GONE);
+ switch (login.getState()) {
+ case DeviceAccountLogin.PROCESSING:
+ mAutoLoginAccount.setEnabled(false);
+ mAutoLoginLogin.setEnabled(false);
+ mAutoLoginProgress.setVisibility(View.VISIBLE);
+ break;
+ case DeviceAccountLogin.FAILED:
+ mAutoLoginProgress.setVisibility(View.GONE);
+ mAutoLoginError.setVisibility(View.VISIBLE);
+ break;
+ case DeviceAccountLogin.INITIAL:
+ break;
+ default:
+ throw new IllegalStateException();
+ }
+ if (animate) {
+ mAutoLogin.startAnimation(AnimationUtils.loadAnimation(
+ getContext(), R.anim.autologin_enter));
+ }
+ } else {
+ mAutoLoginHandler = null;
+ if (animate) {
+ hideAutoLogin();
+ } else if (mAutoLogin.getAnimation() == null) {
+ mAutoLogin.setVisibility(View.GONE);
+ }
+ }
+ }
+
private ViewGroup.LayoutParams makeLayoutParams() {
if (mUseQuickControls) {
return new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT,
@@ -161,7 +227,11 @@
@Override
public int getEmbeddedHeight() {
- return mContainer.getHeight();
+ int height = mContainer.getHeight();
+ if (mAutoLogin.getVisibility() == View.VISIBLE) {
+ height += mAutoLogin.getHeight();
+ }
+ return height;
}
void setUseQuickControls(boolean useQuickControls) {
@@ -234,6 +304,19 @@
mUrlInput.clearFocus();
}
+ private void hideAutoLogin() {
+ Animation anim = AnimationUtils.loadAnimation(
+ getContext(), R.anim.autologin_exit);
+ anim.setAnimationListener(new AnimationListener() {
+ @Override public void onAnimationEnd(Animation a) {
+ mAutoLogin.setVisibility(View.GONE);
+ }
+ @Override public void onAnimationStart(Animation a) {}
+ @Override public void onAnimationRepeat(Animation a) {}
+ });
+ mAutoLogin.startAnimation(anim);
+ }
+
@Override
public void onClick(View v) {
if (mBackButton == v) {
@@ -258,10 +341,41 @@
clearOrClose();
} else if (mVoiceSearch == v) {
mUiController.startVoiceSearch();
+ } else if (mAutoLoginCancel == v) {
+ if (mAutoLoginHandler != null) {
+ mAutoLoginHandler.cancel();
+ mAutoLoginHandler = null;
+ }
+ hideAutoLogin();
+ } else if (mAutoLoginLogin == v) {
+ if (mAutoLoginHandler != null) {
+ mAutoLoginAccount.setEnabled(false);
+ mAutoLoginLogin.setEnabled(false);
+ mAutoLoginProgress.setVisibility(View.VISIBLE);
+ mAutoLoginError.setVisibility(View.GONE);
+ mAutoLoginHandler.login(this);
+ }
+ } else if (mAutoLoginAccount == v) {
+ if (mAutoLoginHandler != null) {
+ mAutoLoginHandler.chooseAccount(this);
+ }
}
}
@Override
+ public void setAccount(String account) {
+ mAutoLoginAccount.setText(account);
+ }
+
+ @Override
+ public void loginFailed() {
+ mAutoLoginAccount.setEnabled(true);
+ mAutoLoginLogin.setEnabled(true);
+ mAutoLoginProgress.setVisibility(View.GONE);
+ mAutoLoginError.setVisibility(View.VISIBLE);
+ }
+
+ @Override
void setFavicon(Bitmap icon) { }
private void clearOrClose() {
diff --git a/src/com/android/browser/UI.java b/src/com/android/browser/UI.java
index 13f8af2..368c829 100644
--- a/src/com/android/browser/UI.java
+++ b/src/com/android/browser/UI.java
@@ -124,9 +124,12 @@
boolean dispatchKey(int code, KeyEvent event);
-
public static interface DropdownChangeListener {
void onNewDropdownDimensions(int height);
}
void registerDropdownChangeListener(DropdownChangeListener d);
+
+ void showAutoLogin(Tab tab);
+
+ void hideAutoLogin(Tab tab);
}
diff --git a/src/com/android/browser/WebViewController.java b/src/com/android/browser/WebViewController.java
index 813b63b..6b44207 100644
--- a/src/com/android/browser/WebViewController.java
+++ b/src/com/android/browser/WebViewController.java
@@ -112,4 +112,7 @@
void bookmarkedStatusHasChanged(Tab tab);
+ void showAutoLogin(Tab tab);
+
+ void hideAutoLogin(Tab tab);
}
diff --git a/src/com/android/browser/XLargeUi.java b/src/com/android/browser/XLargeUi.java
index a9a55e8..02533b0 100644
--- a/src/com/android/browser/XLargeUi.java
+++ b/src/com/android/browser/XLargeUi.java
@@ -18,6 +18,9 @@
import com.android.browser.ScrollWebView.ScrollListener;
+import android.animation.Animator;
+import android.animation.Animator.AnimatorListener;
+import android.animation.ObjectAnimator;
import android.app.ActionBar;
import android.app.Activity;
import android.content.pm.PackageManager;
@@ -47,6 +50,8 @@
private TabBar mTabBar;
private TitleBarXLarge mTitleBar;
+ private Animator mTitleBarAnimator;
+ private boolean mSkipTitleBarAnimations;
private boolean mUseQuickControls;
private PieControl mPieControl;
@@ -220,6 +225,8 @@
@Override
public void setActiveTab(final Tab tab) {
+ cancelTitleBarAnimation(true);
+ mSkipTitleBarAnimations = true;
if (mUseQuickControls) {
if (mActiveTab != null) {
captureTab(mActiveTab);
@@ -227,6 +234,7 @@
}
super.setActiveTab(tab, true);
setActiveTab(tab, true);
+ mSkipTitleBarAnimations = false;
}
@Override
@@ -277,8 +285,11 @@
@Override
public void removeTab(Tab tab) {
+ cancelTitleBarAnimation(true);
+ mSkipTitleBarAnimations = true;
super.removeTab(tab);
mTabBar.onRemoveTab(tab);
+ mSkipTitleBarAnimations = false;
}
protected void onRemoveTabCompleted(Tab tab) {
@@ -317,6 +328,18 @@
if (mUseQuickControls) {
mContentView.addView(mTitleBar);
} else {
+ if (!mSkipTitleBarAnimations) {
+ cancelTitleBarAnimation(false);
+ int visibleHeight = getVisibleTitleHeight();
+ float startPos = (-mTitleBar.getEmbeddedHeight() + visibleHeight);
+ if (mTitleBar.getTranslationY() != 0) {
+ startPos = Math.max(startPos, mTitleBar.getTranslationY());
+ }
+ mTitleBarAnimator = ObjectAnimator.ofFloat(mTitleBar,
+ "translationY",
+ startPos, 0);
+ mTitleBarAnimator.start();
+ }
setTitleGravity(Gravity.TOP);
}
super.showTitleBar();
@@ -331,12 +354,63 @@
if (mUseQuickControls) {
mContentView.removeView(mTitleBar);
} else {
- setTitleGravity(Gravity.NO_GRAVITY);
+ if (!mSkipTitleBarAnimations) {
+ cancelTitleBarAnimation(false);
+ int visibleHeight = getVisibleTitleHeight();
+ mTitleBarAnimator = ObjectAnimator.ofFloat(mTitleBar,
+ "translationY", mTitleBar.getTranslationY(),
+ (-mTitleBar.getEmbeddedHeight() + visibleHeight));
+ mTitleBarAnimator.addListener(mHideTileBarAnimatorListener);
+ mTitleBarAnimator.start();
+ } else {
+ setTitleGravity(Gravity.NO_GRAVITY);
+ }
}
super.hideTitleBar();
}
}
+ private void cancelTitleBarAnimation(boolean reset) {
+ if (mTitleBarAnimator != null) {
+ mTitleBarAnimator.cancel();
+ mTitleBarAnimator = null;
+ }
+ if (reset) {
+ mTitleBar.setTranslationY(0);
+ }
+ }
+
+ private int getVisibleTitleHeight() {
+ WebView webview = mActiveTab != null ? mActiveTab.getWebView() : null;
+ return webview != null ? webview.getVisibleTitleHeight() : 0;
+ }
+
+ private AnimatorListener mHideTileBarAnimatorListener = new AnimatorListener() {
+
+ boolean mWasCanceled;
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mWasCanceled = false;
+ }
+
+ @Override
+ public void onAnimationRepeat(Animator animation) {
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (!mWasCanceled) {
+ mTitleBar.setTranslationY(0);
+ }
+ setTitleGravity(Gravity.NO_GRAVITY);
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mWasCanceled = true;
+ }
+ };
+
public boolean isEditingUrl() {
return mTitleBar.isEditingUrl();
}
@@ -390,6 +464,11 @@
}
@Override
+ protected void updateAutoLogin(Tab tab, boolean animate) {
+ mTitleBar.updateAutoLogin(tab, animate);
+ }
+
+ @Override
public void setUrlTitle(Tab tab) {
super.setUrlTitle(tab);
mTabBar.onUrlAndTitle(tab, tab.getUrl(), tab.getTitle());
diff --git a/src/com/android/browser/preferences/PrivacySecurityPreferencesFragment.java b/src/com/android/browser/preferences/PrivacySecurityPreferencesFragment.java
index 2b2ee3e..2266608 100644
--- a/src/com/android/browser/preferences/PrivacySecurityPreferencesFragment.java
+++ b/src/com/android/browser/preferences/PrivacySecurityPreferencesFragment.java
@@ -17,14 +17,11 @@
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.content.Intent;
import android.os.Bundle;
-import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceFragment;
@@ -44,53 +41,11 @@
Preference e = findPreference(BrowserSettings.PREF_CLEAR_HISTORY);
e.setOnPreferenceChangeListener(this);
- setupAutoLoginPreference();
}
@Override
public void onResume() {
super.onResume();
- setupAutoLoginPreference();
- }
-
- void setupAutoLoginPreference() {
- ListPreference autologinPref = (ListPreference) findPreference(
- BrowserSettings.PREF_AUTOLOGIN_ACCOUNT);
- autologinPref.setOnPreferenceChangeListener(this);
- updateAutoLoginSummary(autologinPref);
- Account[] accounts = GoogleAccountLogin.getAccounts(getActivity());
- // +1 for disable
- CharSequence[] names = new CharSequence[accounts.length + 1];
- CharSequence[] values = new CharSequence[names.length];
- int i = 0;
- int defaultAccount = 0;
- for (Account a : accounts) {
- values[i] = names[i] = a.name;
- i++;
- }
- names[i] = getResources().getString(R.string.pref_autologin_disable);
- values[i] = "";
- autologinPref.setEntries(names);
- autologinPref.setEntryValues(values);
- BrowserSettings bs = BrowserSettings.getInstance();
- if (bs.isAutoLoginEnabled()) {
- autologinPref.setValue(bs.getAutoLoginAccount(getActivity()));
- } else {
- autologinPref.setValue("");
- }
- }
-
- private void updateAutoLoginSummary(Preference pref) {
- if (!mSettings.isAutoLoginEnabled()) {
- pref.setSummary(R.string.pref_autologin_disable);
- } else {
- String account = mSettings.getAutoLoginAccount(getActivity());
- if (account == null) {
- pref.setSummary(R.string.pref_autologin_no_account);
- } else {
- pref.setSummary(getString(R.string.pref_autologin_summary, account));
- }
- }
}
@Override
@@ -102,17 +57,6 @@
getActivity().setResult(Activity.RESULT_OK, (new Intent()).putExtra(Intent.EXTRA_TEXT,
pref.getKey()));
return true;
- } else if (pref.getKey().equals(BrowserSettings.PREF_AUTOLOGIN_ACCOUNT)) {
- String account = (String) objValue;
- if (account.length() == 0) {
- // Disable
- mSettings.setAutoLoginEnabled(getActivity(), false);
- } else {
- mSettings.setAutoLoginEnabled(getActivity(), true);
- }
- mSettings.setAutoLoginAccount(getActivity(), account);
- updateAutoLoginSummary(pref);
- return true;
}
return false;