Merge "Implement the psychic search engine."
diff --git a/res/drawable-mdpi/qc_background_normal.png b/res/drawable-mdpi/qc_background_normal.png
new file mode 100644
index 0000000..539b45d
--- /dev/null
+++ b/res/drawable-mdpi/qc_background_normal.png
Binary files differ
diff --git a/res/drawable-mdpi/qc_background_selected.png b/res/drawable-mdpi/qc_background_selected.png
new file mode 100644
index 0000000..c0a6efc
--- /dev/null
+++ b/res/drawable-mdpi/qc_background_selected.png
Binary files differ
diff --git a/res/layout-land/http_authentication.xml b/res/layout-land/http_authentication.xml
deleted file mode 100644
index 3fa7e4f..0000000
--- a/res/layout-land/http_authentication.xml
+++ /dev/null
@@ -1,65 +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.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:gravity="center_horizontal"
-    android:orientation="vertical" >
-
-    <TableLayout
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_marginTop="12dip"
-        android:gravity="center_horizontal" >
-    
-        <TableRow>
-            <TextView android:id="@+id/username_view"
-                android:text="@string/username"
-                android:gravity="right"
-                android:layout_marginLeft="20dip" />
-
-            <EditText android:id="@+id/username_edit"
-                android:scrollHorizontally="true"
-                android:autoText="false"
-                android:capitalize="none"
-                android:gravity="fill_horizontal"
-                android:layout_weight="1"
-                android:layout_marginLeft="10dip"
-                android:layout_marginRight="20dip"
-                android:layout_marginBottom="12dip" />
-        </TableRow>
-
-        <TableRow>
-            <TextView android:id="@+id/password_view"
-                android:text="@string/password"
-                android:gravity="right"
-                android:layout_marginLeft="20dip" />
-    
-            <EditText android:id="@+id/password_edit"
-                android:scrollHorizontally="true"
-                android:autoText="false"
-                android:capitalize="none"
-                android:gravity="fill_horizontal"
-                android:layout_weight="1"
-                android:layout_marginLeft="10dip"
-                android:layout_marginRight="20dip"
-                android:layout_marginBottom="12dip"
-                android:password="true" />
-        </TableRow>
-    </TableLayout>
-
-</LinearLayout>
diff --git a/res/layout/http_authentication.xml b/res/layout/http_authentication.xml
index cee3a42..856c45c 100644
--- a/res/layout/http_authentication.xml
+++ b/res/layout/http_authentication.xml
@@ -14,49 +14,48 @@
      limitations under the License.
 -->
 
-<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:gravity="center_horizontal"
     android:orientation="vertical"
     >
 
     <TextView 
-        android:id="@+id/username_view"
         android:layout_height="wrap_content"
         android:layout_width="wrap_content"
         android:text="@string/username"
-        android:gravity="left"
         android:layout_marginTop="12dip"
         android:layout_marginLeft="20dip"
         android:layout_marginRight="20dip" />
             
     <EditText
         android:id="@+id/username_edit"
+        android:layout_height="wrap_content"
+        android:layout_width="match_parent"
         android:scrollHorizontally="true"
         android:inputType="text"
-        android:gravity="fill_horizontal"
-        android:layout_weight="1"
         android:layout_marginLeft="20dip"
         android:layout_marginRight="20dip"
-        android:layout_marginBottom="12dip" />
+        android:layout_marginBottom="12dip"
+        android:singleLine="true"
+        android:imeOptions="actionNext" />
 
     <TextView
-        android:id="@+id/password_view"
         android:layout_height="wrap_content"
         android:layout_width="wrap_content"
         android:text="@string/password"
-        android:gravity="left"
         android:layout_marginLeft="20dip"
         android:layout_marginRight="20dip" />
             
     <EditText
         android:id="@+id/password_edit"
+        android:layout_height="wrap_content"
+        android:layout_width="match_parent"
         android:scrollHorizontally="true"
         android:inputType="textPassword"
-        android:gravity="fill_horizontal"
-        android:layout_weight="1"
         android:layout_marginLeft="20dip"
         android:layout_marginRight="20dip"
-        android:layout_marginBottom="12dip" />
-</TableLayout>
+        android:layout_marginBottom="12dip"
+        android:singleLine="true"
+        android:imeOptions="actionDone" />
+</LinearLayout>
diff --git a/res/layout/url_bar.xml b/res/layout/url_bar.xml
index 4d8efdd..f2b32c4 100644
--- a/res/layout/url_bar.xml
+++ b/res/layout/url_bar.xml
@@ -51,19 +51,12 @@
             android:orientation="horizontal"
             android:background="@drawable/url_background">
             <ImageView
-                android:id="@+id/web_icon"
+                android:id="@+id/url_icon"
                 android:layout_width="wrap_content"
                 android:layout_height="match_parent"
                 android:src="@drawable/ic_web_holo_dark"
                 style="@style/HoloIcon" />
             <ImageView
-                android:id="@+id/voice_icon"
-                android:layout_width="wrap_content"
-                android:layout_height="match_parent"
-                android:src="@drawable/ic_voice_search_holo_dark"
-                style="@style/HoloIcon"
-                android:visibility="gone" />
-            <ImageView
                 android:id="@+id/lock"
                 android:layout_width="wrap_content"
                 android:layout_height="match_parent"
diff --git a/res/menu-xlarge/browser.xml b/res/menu-xlarge/browser.xml
index a791cdd..be4a521 100644
--- a/res/menu-xlarge/browser.xml
+++ b/res/menu-xlarge/browser.xml
@@ -32,6 +32,8 @@
             android:title="@string/share_page"
             android:icon="@drawable/ic_share_holo_dark"
             android:alphabeticShortcut="s" />
+        <item android:id="@+id/save_webarchive_menu_id"
+            android:title="@string/menu_save_webarchive" />
         <item android:id="@+id/page_info_menu_id"
             android:title="@string/page_info"
             android:icon="@drawable/ic_pageinfo_holo_dark"
@@ -44,8 +46,6 @@
             android:title="@string/menu_preferences"
             android:icon="@drawable/ic_settings_holo_dark"
             android:alphabeticShortcut="p" />
-        <item android:id="@+id/save_webarchive_menu_id"
-            android:title="@string/menu_save_webarchive" />
         <!-- followings are debug only -->
         <item android:id="@+id/dump_nav_menu_id"
             android:title="@string/dump_nav"
diff --git a/res/menu/browser.xml b/res/menu/browser.xml
index 7a59ffd..abe3716 100644
--- a/res/menu/browser.xml
+++ b/res/menu/browser.xml
@@ -45,6 +45,8 @@
             android:title="@string/share_page"
             android:icon="@drawable/ic_share_holo_dark"
             android:alphabeticShortcut="s" />
+        <item android:id="@+id/save_webarchive_menu_id"
+            android:title="@string/menu_save_webarchive" />
         <item android:id="@+id/page_info_menu_id"
             android:title="@string/page_info"
             android:icon="@drawable/ic_pageinfo_holo_dark"
@@ -57,8 +59,6 @@
             android:title="@string/menu_preferences"
             android:icon="@drawable/ic_settings_holo_dark"
             android:alphabeticShortcut="p" />
-        <item android:id="@+id/save_webarchive_menu_id"
-            android:title="@string/menu_save_webarchive" />
         <!-- followings are debug only -->
         <item android:id="@+id/dump_nav_menu_id"
             android:title="@string/dump_nav"
diff --git a/res/values/dimensions.xml b/res/values/dimensions.xml
index f0230bd..5054254 100644
--- a/res/values/dimensions.xml
+++ b/res/values/dimensions.xml
@@ -45,7 +45,6 @@
     <dimen name="list_favicon_padding">5dip</dimen>
     <dimen name="list_favicon_corner_radius">3dip</dimen>
     <dimen name="tab_favicon_corner_radius">2dip</dimen>
-    <dimen name="dropdown_offset">8dip</dimen>
     <dimen name="widgetThumbnailHeight">104dip</dimen>
     <dimen name="widgetHorizontalSpacing">14dip</dimen>
     <dimen name="widgetVerticalSpacing">12dip</dimen>
diff --git a/res/values/integers.xml b/res/values/integers.xml
index a899a14..ad0ed90 100644
--- a/res/values/integers.xml
+++ b/res/values/integers.xml
@@ -25,4 +25,6 @@
     <integer name="most_visits_limit">10</integer>
     <!-- Animation durations -->
     <integer name="comboViewFadeInDuration">400</integer>
+    <!--  fade between tabs duration -->
+    <integer name="tabFadeDuration">300</integer>
 </resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 321da95..893f02e 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -235,12 +235,12 @@
     <string name="copy_page_url">Copy page url</string>
     <!-- Menu item -->
     <string name="share_page">Share page</string>
-    <!-- Menu item for saving a page as a web archive. -->
-    <string name="menu_save_webarchive">Save as Web Archive</string>
-    <!-- Toast informing the user that the page has been saved. -->
-    <string name="webarchive_saved">Web archive saved.</string>
-    <!-- Toast informing the user that saving the page has failed. -->
-    <string name="webarchive_failed">Failed to save web archive.</string>
+    <!-- Menu item for saving a page. [CHAR LIMIT=30] -->
+    <string name="menu_save_webarchive">Save page</string>
+    <!-- Toast informing the user that the page has been saved. [CHAR LIMIT=50] -->
+    <string name="webarchive_saved">Page saved.</string>
+    <!-- Toast informing the user that saving the page has failed. [CHAR LIMIT=50] -->
+    <string name="webarchive_failed">Failed to save page.</string>
     <!-- The number of bookmarks in a folder [CHAR LIMT=50] -->
     <string name="contextheader_folder_bookmarkcount"><xliff:g id="bookmark_count">%d</xliff:g> bookmarks</string>
     <!-- No bookmarks in the folder [CHAR LIMIT=50] -->
diff --git a/src/com/android/browser/BaseUi.java b/src/com/android/browser/BaseUi.java
index 15f07c6..c01ec06 100644
--- a/src/com/android/browser/BaseUi.java
+++ b/src/com/android/browser/BaseUi.java
@@ -19,6 +19,8 @@
 import com.android.browser.Tab.LockIcon;
 import com.android.browser.UI.DropdownChangeListener;
 
+import android.animation.Animator;
+import android.animation.Animator.AnimatorListener;
 import android.animation.ObjectAnimator;
 import android.app.Activity;
 import android.content.res.Configuration;
@@ -68,7 +70,7 @@
     Activity mActivity;
     UiController mUiController;
     TabControl mTabControl;
-    private Tab mActiveTab;
+    protected Tab mActiveTab;
     private InputMethodManager mInputManager;
 
     private Drawable mSecLockIcon;
@@ -221,12 +223,18 @@
     }
 
     @Override
-    public void setActiveTab(Tab tab) {
+    public void setActiveTab(final Tab tab) {
+        setActiveTab(tab, true);
+    }
+
+    void setActiveTab(Tab tab, boolean needsAttaching) {
         if ((tab != mActiveTab) && (mActiveTab != null)) {
             removeTabFromContentView(mActiveTab);
         }
         mActiveTab = tab;
-        attachTabToContentView(tab);
+        if (needsAttaching) {
+            attachTabToContentView(tab);
+        }
         setShouldShowErrorConsole(tab, mUiController.shouldShowErrorConsole());
         onTabDataChanged(tab);
         onProgressChanged(tab);
@@ -260,7 +268,7 @@
         attachTabToContentView(tab);
     }
 
-    private void attachTabToContentView(Tab tab) {
+    protected void attachTabToContentView(Tab tab) {
         if ((tab == null) || (tab.getWebView() == null)) {
             return;
         }
diff --git a/src/com/android/browser/Controller.java b/src/com/android/browser/Controller.java
index 5b655c4..e4b0a0c 100644
--- a/src/com/android/browser/Controller.java
+++ b/src/com/android/browser/Controller.java
@@ -489,7 +489,8 @@
                             case R.id.save_link_context_menu_id:
                             case R.id.download_context_menu_id:
                                 DownloadHandler.onDownloadStartNoStream(
-                                        mActivity, url, null, null, null);
+                                        mActivity, url, null, null, null,
+                                        view.isPrivateBrowsingEnabled());
                                 break;
                         }
                         break;
@@ -963,9 +964,10 @@
     @Override
     public void onDownloadStart(Tab tab, String url, String userAgent,
             String contentDisposition, String mimetype, long contentLength) {
+        WebView w = tab.getWebView();
         DownloadHandler.onDownloadStart(mActivity, url, userAgent,
-                contentDisposition, mimetype);
-        if (tab.getWebView().copyBackForwardList().getSize() == 0) {
+                contentDisposition, mimetype, w.isPrivateBrowsingEnabled());
+        if (w.copyBackForwardList().getSize() == 0) {
             // This Tab was opened for the sole purpose of downloading a
             // file. Remove it.
             if (tab == mTabControl.getCurrentTab()) {
@@ -1372,7 +1374,8 @@
                 menu.findItem(R.id.view_image_context_menu_id).setIntent(
                         new Intent(Intent.ACTION_VIEW, Uri.parse(extra)));
                 menu.findItem(R.id.download_context_menu_id).
-                        setOnMenuItemClickListener(new Download(mActivity, extra));
+                        setOnMenuItemClickListener(
+                                new Download(mActivity, extra, webview.isPrivateBrowsingEnabled()));
                 menu.findItem(R.id.set_wallpaper_context_menu_id).
                         setOnMenuItemClickListener(new WallpaperHandler(mActivity,
                                 extra));
@@ -1469,8 +1472,10 @@
                 newtab.setEnabled(getTabControl().canCreateNewTab());
 
                 MenuItem archive = menu.findItem(R.id.save_webarchive_menu_id);
-                String url = w != null ? w.getUrl() : null;
-                archive.setVisible(url != null && !url.endsWith(".webarchivexml"));
+                Tab tab = getTabControl().getCurrentTab();
+                String url = tab != null ? tab.getUrl() : null;
+                archive.setVisible(!TextUtils.isEmpty(url)
+                        && !url.endsWith(".webarchivexml"));
                 break;
         }
         mCurrentMenuState = mMenuState;
@@ -1590,8 +1595,9 @@
                             Toast.LENGTH_SHORT).show();
                     break;
                 }
-                WebView topWebView = getCurrentTopWebView();
+                final WebView topWebView = getCurrentTopWebView();
                 final String title = topWebView.getTitle();
+                final String url = topWebView.getUrl();
                 topWebView.saveWebArchive(directory, true,
                         new ValueCallback<String>() {
                     @Override
@@ -1615,8 +1621,8 @@
                                 return;
                             }
                         }
-                        Toast.makeText(mActivity,
-                                R.string.webarchive_failed, Toast.LENGTH_SHORT).show();
+                        DownloadHandler.onDownloadStartNoStream(mActivity,
+                                url, null, null, null, topWebView.isPrivateBrowsingEnabled());
                     }
                 });
                 break;
@@ -2044,16 +2050,18 @@
     private static class Download implements OnMenuItemClickListener {
         private Activity mActivity;
         private String mText;
+        private boolean mPrivateBrowsing;
 
         public boolean onMenuItemClick(MenuItem item) {
             DownloadHandler.onDownloadStartNoStream(mActivity, mText, null,
-                    null, null);
+                    null, null, mPrivateBrowsing);
             return true;
         }
 
-        public Download(Activity activity, String toDownload) {
+        public Download(Activity activity, String toDownload, boolean privateBrowsing) {
             mActivity = activity;
             mText = toDownload;
+            mPrivateBrowsing = privateBrowsing;
         }
     }
 
diff --git a/src/com/android/browser/DownloadHandler.java b/src/com/android/browser/DownloadHandler.java
index 4903a41..17ad320 100644
--- a/src/com/android/browser/DownloadHandler.java
+++ b/src/com/android/browser/DownloadHandler.java
@@ -53,9 +53,11 @@
      * @param userAgent User agent of the downloading application.
      * @param contentDisposition Content-disposition http header, if present.
      * @param mimetype The mimetype of the content reported by the server
+     * @param privateBrowsing If the request is coming from a private browsing tab.
      */
     public static void onDownloadStart(Activity activity, String url,
-            String userAgent, String contentDisposition, String mimetype) {
+            String userAgent, String contentDisposition, String mimetype,
+            boolean privateBrowsing) {
         // if we're dealing wih A/V content that's not explicitly marked
         //     for download, check if it's streamable.
         if (contentDisposition == null
@@ -93,7 +95,7 @@
             }
         }
         onDownloadStartNoStream(activity, url, userAgent, contentDisposition,
-                mimetype);
+                mimetype, privateBrowsing);
     }
 
     // This is to work around the fact that java.net.URI throws Exceptions
@@ -134,10 +136,11 @@
      * @param userAgent User agent of the downloading application.
      * @param contentDisposition Content-disposition http header, if present.
      * @param mimetype The mimetype of the content reported by the server
+     * @param privateBrowsing If the request is coming from a private browsing tab.
      */
     /*package */ static void onDownloadStartNoStream(Activity activity,
             String url, String userAgent, String contentDisposition,
-            String mimetype) {
+            String mimetype, boolean privateBrowsing) {
 
         String filename = URLUtil.guessFileName(url,
                 contentDisposition, mimetype);
@@ -198,7 +201,7 @@
         request.setDescription(webAddress.getHost());
         // XXX: Have to use the old url since the cookies were stored using the
         // old percent-encoded url.
-        String cookies = CookieManager.getInstance().getCookie(url);
+        String cookies = CookieManager.getInstance().getCookie(url, privateBrowsing);
         request.addRequestHeader("cookie", cookies);
         request.setNotificationVisibility(
                 DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
diff --git a/src/com/android/browser/HttpAuthenticationDialog.java b/src/com/android/browser/HttpAuthenticationDialog.java
index a9ba332..ac4119c 100644
--- a/src/com/android/browser/HttpAuthenticationDialog.java
+++ b/src/com/android/browser/HttpAuthenticationDialog.java
@@ -18,10 +18,13 @@
 import android.app.AlertDialog;
 import android.content.Context;
 import android.content.DialogInterface;
+import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.WindowManager;
+import android.view.inputmethod.EditorInfo;
 import android.widget.TextView;
+import android.widget.TextView.OnEditorActionListener;
 
 /**
  * HTTP authentication dialog.
@@ -109,6 +112,16 @@
         View v = factory.inflate(R.layout.http_authentication, null);
         mUsernameView = (TextView) v.findViewById(R.id.username_edit);
         mPasswordView = (TextView) v.findViewById(R.id.password_edit);
+        mPasswordView.setOnEditorActionListener(new OnEditorActionListener() {
+            @Override
+            public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+                if (actionId == EditorInfo.IME_ACTION_DONE) {
+                    mDialog.getButton(AlertDialog.BUTTON_POSITIVE).performClick();
+                    return true;
+                }
+                return false;
+            }
+        });
 
         String title = mContext.getText(R.string.sign_in_to).toString().replace(
                 "%s1", mHost).replace("%s2", mRealm);
diff --git a/src/com/android/browser/PieControl.java b/src/com/android/browser/PieControl.java
index 23dcced..2e2eba4 100644
--- a/src/com/android/browser/PieControl.java
+++ b/src/com/android/browser/PieControl.java
@@ -64,22 +64,22 @@
             LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT,
                     LayoutParams.MATCH_PARENT);
             mPie.setLayoutParams(lp);
-            mForward = makeMenuView(R.drawable.ic_pie_forward);
-            mPie.addItem(mForward);
-            mRefresh = makeMenuView(R.drawable.ic_pie_refresh);
-            mPie.addItem(mRefresh);
+            mNewTab = makeMenuView(R.drawable.ic_pie_new_tab);
+            mPie.addItem(mNewTab);
             mBack = makeMenuView(R.drawable.ic_pie_back);
             mPie.addItem(mBack);
             mUrl = makeMenuView(R.drawable.ic_pie_web);
             mPie.addItem(mUrl);
             mBookmarks = makeMenuView(R.drawable.ic_pie_bookmarks);
             mPie.addItem(mBookmarks);
-            mNewTab = makeMenuView(R.drawable.ic_pie_new_tab);
-            mPie.addItem(mNewTab);
             mOptions = makeMenuView(R.drawable.ic_pie_more);
             mPie.addItem(mOptions);
-            setClickListener(mBack, mForward, mRefresh, mUrl, mOptions,
-                    mBookmarks, mNewTab);
+            setClickListener(mBack,
+                    mUrl,
+                    mOptions,
+                    mBookmarks,
+                    mNewTab
+                    );
             mPie.setController(this);
         }
         container.addView(mPie);
diff --git a/src/com/android/browser/ScrollWebView.java b/src/com/android/browser/ScrollWebView.java
index 2bf07e1..d1dc25b 100644
--- a/src/com/android/browser/ScrollWebView.java
+++ b/src/com/android/browser/ScrollWebView.java
@@ -1,22 +1,24 @@
 /*
  * 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
+ * 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
+ * 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.
+ * 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.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Paint;
 import android.util.AttributeSet;
 import android.view.MotionEvent;
 import android.view.View;
@@ -25,7 +27,7 @@
 import java.util.Map;
 
 /**
- *  Manage WebView scroll events
+ * Manage WebView scroll events
  */
 public class ScrollWebView extends WebView implements Runnable {
 
@@ -34,6 +36,9 @@
     private boolean mBackgroundRemoved = false;
     private boolean mUserInitiated = false;
     private TitleBarBase mTitleBar;
+    private boolean mDrawCached = false;
+    private Bitmap mBitmap;
+    private Paint mCachePaint = new Paint();
 
     /**
      * @param context
@@ -51,8 +56,8 @@
      * @param attrs
      * @param defStyle
      */
-    public ScrollWebView(Context context, AttributeSet attrs, int defStyle,
-            boolean privateBrowsing) {
+    public ScrollWebView(
+            Context context, AttributeSet attrs, int defStyle, boolean privateBrowsing) {
         super(context, attrs, defStyle, privateBrowsing);
     }
 
@@ -97,6 +102,10 @@
         }
     }
 
+    public boolean hasTitleBar() {
+        return (mTitleBar != null);
+    }
+
     @Override
     public boolean onTouchEvent(MotionEvent evt) {
         if (MotionEvent.ACTION_DOWN == evt.getActionMasked()) {
@@ -128,22 +137,46 @@
         mScrollListener = l;
     }
 
+    @Override
+    public void invalidate() {
+        if (!mDrawCached) {
+            super.invalidate();
+        }
+    }
+
     // callback for scroll events
 
     interface ScrollListener {
         public void onScroll(int visibleTitleHeight, boolean userInitiated);
     }
 
-    @Override
-    protected void onDraw(android.graphics.Canvas c) {
-        super.onDraw(c);
-        if (!mBackgroundRemoved && getRootView().getBackground() != null) {
-            mBackgroundRemoved = true;
-            post(new Runnable() {
-                public void run() {
-                    getRootView().setBackgroundDrawable(null);
-                }
-            });
+    void setDrawCached(boolean cached) {
+        if (cached) {
+            buildDrawingCache();
+            mBitmap = getDrawingCache(false);
+            mDrawCached = (mBitmap != null);
+        } else {
+            mBitmap = null;
+            destroyDrawingCache();
+            mDrawCached = false;
         }
     }
+
+    @Override
+    protected void onDraw(android.graphics.Canvas c) {
+        if (mDrawCached) {
+            c.drawBitmap(mBitmap, getScrollX(), getScrollY(), mCachePaint);
+        } else {
+            super.onDraw(c);
+            if (!mBackgroundRemoved && getRootView().getBackground() != null) {
+                mBackgroundRemoved = true;
+                post(new Runnable() {
+                    public void run() {
+                        getRootView().setBackgroundDrawable(null);
+                    }
+                });
+            }
+        }
+    }
+
 }
diff --git a/src/com/android/browser/TitleBarXLarge.java b/src/com/android/browser/TitleBarXLarge.java
index f4ba9db..8a715b1 100644
--- a/src/com/android/browser/TitleBarXLarge.java
+++ b/src/com/android/browser/TitleBarXLarge.java
@@ -58,15 +58,14 @@
     private ImageButton mBackButton;
     private ImageButton mForwardButton;
     private ImageView mStar;
-    private ImageView mWebIcon;
-    private View mSearchButton;
+    private ImageView mUrlIcon;
+    private ImageView mSearchButton;
     private View mUrlContainer;
     private View mGoButton;
     private ImageView mStopButton;
     private View mAllButton;
     private View mClearButton;
-    private View mVoiceSearch;
-    private View mVoiceSearchIndicator;
+    private ImageView mVoiceSearch;
     private PageProgressView mProgressView;
     private Drawable mFocusDrawable;
     private Drawable mUnfocusDrawable;
@@ -112,17 +111,16 @@
         // back/forward.  Probably should be done inside onPageStarted.
         mBackButton = (ImageButton) findViewById(R.id.back);
         mForwardButton = (ImageButton) findViewById(R.id.forward);
-        mWebIcon = (ImageView) findViewById(R.id.web_icon);
+        mUrlIcon = (ImageView) findViewById(R.id.url_icon);
         mStar = (ImageView) findViewById(R.id.star);
         mStopButton = (ImageView) findViewById(R.id.stop);
-        mSearchButton = findViewById(R.id.search);
+        mSearchButton = (ImageView) findViewById(R.id.search);
         mLockIcon = (ImageView) findViewById(R.id.lock);
         mGoButton = findViewById(R.id.go);
         mClearButton = findViewById(R.id.clear);
-        mVoiceSearch = findViewById(R.id.voicesearch);
+        mVoiceSearch = (ImageView) findViewById(R.id.voicesearch);
         mProgressView = (PageProgressView) findViewById(R.id.progress);
         mUrlContainer = findViewById(R.id.urlbar_focused);
-        mVoiceSearchIndicator = findViewById(R.id.voice_icon);
         mBackButton.setOnClickListener(this);
         mForwardButton.setOnClickListener(this);
         mStar.setOnClickListener(this);
@@ -173,17 +171,6 @@
         mUseQuickControls = useQuickControls;
         mUrlInput.setUseQuickControls(mUseQuickControls);
         setLayoutParams(makeLayoutParams());
-        if (mUseQuickControls) {
-            mBackButton.setVisibility(View.GONE);
-            mForwardButton.setVisibility(View.GONE);
-            mStopButton.setVisibility(View.GONE);
-            mAllButton.setVisibility(View.GONE);
-        } else {
-            mBackButton.setVisibility(View.VISIBLE);
-            mForwardButton.setVisibility(View.VISIBLE);
-            mStopButton.setVisibility(View.VISIBLE);
-            mAllButton.setVisibility(View.VISIBLE);
-        }
     }
 
     void setShowProgressOnly(boolean progress) {
@@ -210,6 +197,9 @@
         } else if (!mUrlInput.needsUpdate()) {
             mUrlInput.dismissDropDown();
             mUrlInput.hideIME();
+            if (mUseQuickControls) {
+                mUi.hideTitleBar();
+            }
         }
         mUrlInput.clearNeedsUpdate();
     }
@@ -294,23 +284,21 @@
             mSearchButton.setVisibility(View.GONE);
             mStar.setVisibility(View.GONE);
             mClearButton.setVisibility(View.VISIBLE);
-            if (mInVoiceMode) {
-                mVoiceSearchIndicator.setVisibility(View.VISIBLE);
-            }
-            mWebIcon.setImageResource(R.drawable.ic_search_holo_dark);
+            mUrlIcon.setImageResource(R.drawable.ic_search_holo_dark);
             updateSearchMode(false);
         } else {
             mGoButton.setVisibility(View.GONE);
             mVoiceSearch.setVisibility(View.GONE);
             mStar.setVisibility(View.VISIBLE);
             mClearButton.setVisibility(View.GONE);
-            mVoiceSearchIndicator.setVisibility(View.GONE);
             if (mUseQuickControls) {
                 mSearchButton.setVisibility(View.GONE);
             } else {
                 mSearchButton.setVisibility(View.VISIBLE);
             }
-            mWebIcon.setImageResource(R.drawable.ic_web_holo_dark);
+            mUrlIcon.setImageResource(mInVoiceMode ?
+                    R.drawable.ic_search_holo_dark
+                    : R.drawable.ic_web_holo_dark);
         }
     }
 
@@ -392,9 +380,7 @@
     public void setInVoiceMode(boolean voicemode, List<String> voiceResults) {
         mInVoiceMode = voicemode;
         mUrlInput.setVoiceResults(voiceResults);
-        mVoiceSearchIndicator.setVisibility(mInVoiceMode
-                ? View.VISIBLE : View.GONE);
-        mWebIcon.setVisibility(mInVoiceMode ? View.GONE : View.VISIBLE);
+        mUrlIcon.setImageDrawable(mSearchButton.getDrawable());
     }
 
     @Override
diff --git a/src/com/android/browser/UrlInputView.java b/src/com/android/browser/UrlInputView.java
index 5e6684d..b7f2bff 100644
--- a/src/com/android/browser/UrlInputView.java
+++ b/src/com/android/browser/UrlInputView.java
@@ -61,7 +61,6 @@
     private View mContainer;
     private boolean mLandscape;
     private boolean mIncognitoMode;
-    private int mVOffset;
     private boolean mNeedsUpdate;
     private DropdownChangeListener mDropdownListener;
 
@@ -89,7 +88,6 @@
         onConfigurationChanged(ctx.getResources().getConfiguration());
         setThreshold(1);
         setOnItemClickListener(this);
-        mVOffset = 0;
         mNeedsUpdate = false;
         mDropdownListener = null;
 
@@ -130,9 +128,6 @@
     }
 
     void setUseQuickControls(boolean useQuickControls) {
-        mVOffset = (useQuickControls
-                ? (int) getResources().getDimension(R.dimen.dropdown_offset)
-                : 0);
         mAdapter.setReverseResults(useQuickControls);
     }
 
@@ -180,7 +175,6 @@
         if (getLeft() != -getDropDownHorizontalOffset()) {
             setDropDownHorizontalOffset(-getLeft());
         }
-        setDropDownVerticalOffset(mVOffset);
     }
 
     @Override
diff --git a/src/com/android/browser/XLargeUi.java b/src/com/android/browser/XLargeUi.java
index 5127ff3..33151f7 100644
--- a/src/com/android/browser/XLargeUi.java
+++ b/src/com/android/browser/XLargeUi.java
@@ -19,6 +19,9 @@
 import com.android.browser.ScrollWebView.ScrollListener;
 import com.android.browser.UI.DropdownChangeListener;
 
+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;
@@ -30,6 +33,7 @@
 import android.view.View;
 import android.webkit.WebChromeClient.CustomViewCallback;
 import android.webkit.WebView;
+import android.widget.FrameLayout;
 
 import java.util.List;
 
@@ -205,11 +209,57 @@
     }
 
     @Override
-    public void setActiveTab(Tab tab) {
-        if (mTitleBar.isEditingUrl()) {
-            mTitleBar.stopEditingUrl();
+    public void setActiveTab(final Tab tab) {
+        if ((tab != mActiveTab) && (mActiveTab != null)) {
+            // animate between the two
+            final ScrollWebView fromWV = (ScrollWebView) mActiveTab.getWebView();
+            fromWV.setDrawCached(true);
+            fromWV.setEmbeddedTitleBar(null);
+            final ScrollWebView toWV = (ScrollWebView) tab.getWebView();
+            if (!mUseQuickControls) {
+                if (mTitleBar.getParent() == null) {
+                    toWV.setEmbeddedTitleBar(mTitleBar);
+                }
+            }
+            toWV.setDrawCached(true);
+            attachTabToContentView(tab);
+            super.setActiveTab(tab, false);
+            ObjectAnimator transition = ObjectAnimator.ofFloat(
+                    toWV, "alpha", 0f, 1f);
+            transition.setDuration(mActivity.getResources()
+                    .getInteger(R.integer.tabFadeDuration));
+            transition.addListener(new AnimatorListener() {
+                @Override
+                public void onAnimationCancel(Animator animation) {
+                    fromWV.setDrawCached(false);
+                    toWV.setDrawCached(false);
+                    setActiveTab(tab, false);
+                }
+
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    fromWV.setDrawCached(false);
+                    toWV.setDrawCached(false);
+                    setActiveTab(tab, false);
+                }
+
+                @Override
+                public void onAnimationRepeat(Animator animation) {
+                }
+
+                @Override
+                public void onAnimationStart(Animator animation) {
+                }
+            });
+            transition.start();
+        } else {
+            super.setActiveTab(tab, true);
+            setActiveTab(tab, true);
         }
-        super.setActiveTab(tab);
+    }
+
+    @Override
+    void setActiveTab(Tab tab, boolean needsAttaching) {
         ScrollWebView view = (ScrollWebView) tab.getWebView();
         // TabControl.setCurrentTab has been called before this,
         // so the tab is guaranteed to have a webview
@@ -223,7 +273,10 @@
             view.setScrollListener(null);
             mTabBar.showTitleBarIndicator(false);
         } else {
-            view.setEmbeddedTitleBar(mTitleBar);
+            // check if title bar is already attached by animation
+            if (mTitleBar.getParent() == null) {
+                view.setEmbeddedTitleBar(mTitleBar);
+            }
             view.setScrollListener(this);
         }
         mTabBar.onSetActiveTab(tab);
@@ -282,7 +335,6 @@
     protected void showTitleBar() {
         if (canShowTitleBar()) {
             if (mUseQuickControls) {
-                setTitleGravity(Gravity.BOTTOM);
                 mContentView.addView(mTitleBar);
             } else {
                 setTitleGravity(Gravity.TOP);
@@ -296,9 +348,10 @@
     protected void hideTitleBar() {
         if (isTitleBarShowing()) {
             mTabBar.onHideTitleBar();
-            setTitleGravity(Gravity.NO_GRAVITY);
             if (mUseQuickControls) {
                 mContentView.removeView(mTitleBar);
+            } else {
+                setTitleGravity(Gravity.NO_GRAVITY);
             }
             super.hideTitleBar();
         }
@@ -313,6 +366,18 @@
         return mTitleBar;
     }
 
+    @Override
+    protected void setTitleGravity(int gravity) {
+        if (mUseQuickControls) {
+            FrameLayout.LayoutParams lp =
+                (FrameLayout.LayoutParams) mTitleBar.getLayoutParams();
+            lp.gravity = gravity;
+            mTitleBar.setLayoutParams(lp);
+        } else {
+            super.setTitleGravity(gravity);
+        }
+    }
+
     // action mode callbacks
 
     @Override
diff --git a/src/com/android/browser/preferences/GeneralPreferencesFragment.java b/src/com/android/browser/preferences/GeneralPreferencesFragment.java
index 1c82e1c..9c763e9 100644
--- a/src/com/android/browser/preferences/GeneralPreferencesFragment.java
+++ b/src/com/android/browser/preferences/GeneralPreferencesFragment.java
@@ -426,7 +426,8 @@
                     // Re-parent the existing bookmarks to the newly create bookmarks bar folder
                     ops.add(ContentProviderOperation.newUpdate(Bookmarks.CONTENT_URI)
                             .withValueBackReference(Bookmarks.PARENT, 2)
-                            .withSelection(Bookmarks.PARENT + "=?",
+                            .withSelection(Bookmarks.ACCOUNT_NAME + " IS NULL AND " +
+                                    Bookmarks.PARENT + "=?",
                                         new String[] { Integer.toString(1) })
                             .build());
 
diff --git a/src/com/android/browser/view/PieMenu.java b/src/com/android/browser/view/PieMenu.java
index 5185adb..080c257 100644
--- a/src/com/android/browser/view/PieMenu.java
+++ b/src/com/android/browser/view/PieMenu.java
@@ -20,15 +20,21 @@
 
 import android.content.Context;
 import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapShader;
 import android.graphics.Canvas;
+import android.graphics.Matrix;
 import android.graphics.Paint;
 import android.graphics.Path;
 import android.graphics.Point;
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.graphics.RectF;
+import android.graphics.Shader;
+import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.view.MotionEvent;
+import android.view.SoundEffectConstants;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.FrameLayout;
@@ -64,6 +70,17 @@
 
     private boolean mDirty;
 
+    private Drawable mActiveDrawable;
+    private Drawable mInactiveDrawable;
+    private final Paint mActiveShaderPaint = new Paint();
+    private final Paint mInactiveShaderPaint = new Paint();
+    private final Matrix mActiveMatrix = new Matrix();
+    private final Matrix mInactiveMatrix = new Matrix();
+
+    private BitmapShader mActiveShader;
+    private BitmapShader mInactiveShader;
+
+
     /**
      * @param context
      * @param attrs
@@ -111,6 +128,37 @@
         setDrawingCacheEnabled(false);
         mCenter = new Point(0,0);
         mDirty = true;
+        mActiveShaderPaint.setStyle(Paint.Style.FILL);
+        mActiveShaderPaint.setAntiAlias(true);
+
+        mInactiveShaderPaint.setStyle(Paint.Style.FILL);
+        mInactiveShaderPaint.setAntiAlias(true);
+        mActiveDrawable = res.getDrawable(R.drawable.qc_background_selected);
+        mInactiveDrawable = res.getDrawable(R.drawable.qc_background_normal);
+
+        Bitmap activeTexture = getDrawableAsBitmap(mActiveDrawable,
+                mActiveDrawable.getIntrinsicWidth(),
+                mActiveDrawable.getIntrinsicHeight());
+        Bitmap inactiveTexture = getDrawableAsBitmap(mInactiveDrawable,
+                mInactiveDrawable.getIntrinsicWidth(),
+                mInactiveDrawable.getIntrinsicHeight());
+
+        mActiveShader = new BitmapShader(activeTexture,
+                Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
+        mActiveShaderPaint.setShader(mActiveShader);
+
+        mInactiveShader = new BitmapShader(inactiveTexture,
+                Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
+        mInactiveShaderPaint.setShader(mInactiveShader);
+
+    }
+
+    private static Bitmap getDrawableAsBitmap(Drawable drawable, int width, int height) {
+        Bitmap b = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+        Canvas c = new Canvas(b);
+        drawable.setBounds(0, 0, width, height);
+        drawable.draw(c);
+        return b;
     }
 
     public void setController(PieController ctl) {
@@ -268,10 +316,15 @@
             tag.sweep = sweep;
             tag.inner = inner;
             tag.outer = outer;
-
-            Paint p = item.isPressed() ? mSelectedPaint : mPaint;
-            canvas.drawPath(slice, p);
             int state = canvas.save();
+            int[] topLeft = new int[2];
+            getLocationInWindow(topLeft);
+            topLeft[0] = mCenter.x - outer;
+            topLeft[1] = mCenter.y - outer;
+            Paint paint = item.isPressed() ? mActiveShaderPaint : mInactiveShaderPaint;
+            drawClipped(canvas, paint, slice, topLeft, item.isPressed());
+            canvas.restoreToCount(state);
+            state = canvas.save();
             if (onTheLeft()) {
                 canvas.scale(-1, 1);
             }
@@ -287,6 +340,16 @@
         return newanchor;
     }
 
+    private void drawClipped(Canvas canvas, Paint paint, Path clipPath, int[] pos,
+            boolean selected) {
+        // TODO: We should change the matrix/shader only when needed
+        final Matrix matrix = selected ? mActiveMatrix : mInactiveMatrix;
+        matrix.setTranslate(pos[0], pos[1]);
+        (selected ? mActiveShader : mInactiveShader).setLocalMatrix(matrix);
+        canvas.drawPath(clipPath, paint);
+    }
+
+
     /**
      * converts a
      * @param angle from 0..PI to Android degrees (clockwise starting at 3 o'clock)
@@ -391,6 +454,7 @@
         }
         if (view != null) {
             // clear up stack
+            playSoundEffect(SoundEffectConstants.CLICK);
             MenuTag tag = (MenuTag) view.getTag();
             int i = mStack.size() - 1;
             while (i > 0) {