Merge "Swapping in updated Browser icons, in place" into honeycomb
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 5b844e0..9ceaf82 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -223,6 +223,13 @@
                 <action android:name="android.intent.action.DOWNLOAD_NOTIFICATION_CLICKED"/>
             </intent-filter>
         </receiver>
+
+        <!-- For custom home pages (like most visited) -->
+        <provider
+            android:name=".homepages.HomeProvider"
+            android:authorities="com.android.browser.home"
+            android:readPermission="com.android.browser.permission.READ_HISTORY_BOOKMARKS"
+            android:exported="false" />
     </application>
 
 </manifest>
diff --git a/res/drawable-mdpi/ic_pie_web.png b/res/drawable-mdpi/ic_pie_web.png
new file mode 100644
index 0000000..86e41ff
--- /dev/null
+++ b/res/drawable-mdpi/ic_pie_web.png
Binary files differ
diff --git a/res/layout/new_folder_layout.xml b/res/layout/new_folder_layout.xml
index 4ce0ade..ecc730f 100644
--- a/res/layout/new_folder_layout.xml
+++ b/res/layout/new_folder_layout.xml
@@ -27,12 +27,29 @@
         android:gravity="center_vertical"
         android:minHeight="?android:attr/listPreferredItemHeight"
         android:src="@drawable/ic_folder_bookmark_widget_holo_dark" />
+  <LinearLayout
+      android:layout_width="match_parent"
+      android:layout_height="wrap_content"
+      android:background="@*android:drawable/edit_text_holo_dark"
+      android:gravity="center_vertical"
+      android:paddingBottom="5dip"
+      android:orientation="horizontal">
     <EditText
         android:id="@+id/folder_namer"
-        android:layout_width="match_parent"
+        android:layout_width="0dip"
         android:layout_height="wrap_content"
+        android:layout_weight="1"
         android:textAppearance="?android:attr/textAppearanceMedium"
+        android:background="@null"
         android:gravity="center_vertical"
         android:paddingLeft="6dip"
-        android:minHeight="?android:attr/listPreferredItemHeight" />
+        />
+    <ImageView
+        android:id="@+id/close"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:gravity="center_vertical"
+        android:src="@drawable/ic_tab_close"
+        />
+  </LinearLayout>
 </LinearLayout>
diff --git a/res/menu/bookmarkscontext.xml b/res/menu/bookmarkscontext.xml
index 4d7ec7a..3a13b9a 100644
--- a/res/menu/bookmarkscontext.xml
+++ b/res/menu/bookmarkscontext.xml
@@ -36,6 +36,8 @@
   </group>
   <group android:id="@+id/FOLDER_CONTEXT_MENU"
     android:visible="false">
+    <item android:id="@+id/new_window_context_menu_id"
+      android:title="@string/open_all_in_new_window"/>
     <item android:id="@+id/edit_context_menu_id"
       android:title="@string/edit_folder"/>
     <item android:id="@+id/delete_context_menu_id"
diff --git a/res/raw/most_visited.ktpl b/res/raw/most_visited.ktpl
new file mode 100644
index 0000000..04b9eee
--- /dev/null
+++ b/res/raw/most_visited.ktpl
@@ -0,0 +1,85 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

+

+<html>

+<head>

+<title><%@ string/new_tab %></title>

+<meta name="viewport" content="width=device-width; initial-scale=1.0;" />

+

+<style type="text/css">

+

+* {

+    padding: 0;

+    margin: 0;

+}

+

+body {

+    text-align: center;

+    margin: 16px auto;

+    padding: 0 8px 0 8px;

+    max-width: <%@ dimen/mv_max_width %>px;

+}

+

+#most_visited h3 {

+    text-align: center;

+    padding: 0;

+    margin: 5px 0 5px 0px;

+}

+

+.thumbwrap li {

+    display: inline-block;

+    margin: 0 7px 15px 7px;

+    padding: 0;

+}

+

+@media all and (orientation:portrait) {

+.thumbwrap li {

+    width: <%@ dimen/mv_item_width_portrait %>px;

+}

+}

+

+@media all and (orientation:landscape) {

+.thumbwrap li {

+    width: <%@ dimen/mv_item_width %>px;

+}

+}

+

+.thumbwrap a {

+    display: block;

+    text-decoration: none;

+    color: #000;

+}

+

+.thumbwrap img {

+    border: <%@ dimen/mv_border_width %>px solid #e0e0e0;

+    border-radius: 5px;

+    width: 100%;

+}

+

+.thumbwrap .caption {

+    margin-top: 2px;

+    margin-left: 4px;

+    white-space: nowrap;

+    overflow: hidden;

+    text-overflow: ellipsis;

+    display: block;

+    font-size: .8em;

+    text-align: left;

+}

+

+</style>

+

+</head>

+<body>

+    <h3><%@ string/tab_most_visited %></h3>

+    <ul class="thumbwrap">

+        <%{ most_visited %>

+            <li>

+                <a href="<%= url %>">

+                    <img class="wrimg" src="<%= thumbnail %>" />

+                    <span class="caption"><%= title %></span>

+                </a>

+            </li>

+        <%} most_visited %>

+    </ul>

+</body>

+</html>

diff --git a/res/values-es-rUS-xlarge/strings.xml b/res/values-es-rUS-xlarge/strings.xml
index 508f3fe..ed820a1 100644
--- a/res/values-es-rUS-xlarge/strings.xml
+++ b/res/values-es-rUS-xlarge/strings.xml
@@ -50,7 +50,7 @@
     <!-- XL -->
     <string name="pref_content_autofit" msgid="152292940099720429">"Ajuste automático de páginas"</string>
     <!-- XL -->
-    <string name="pref_autofill_profile_editor_summary" msgid="6606678927956330022">"Configurar &amp; administrar datos para los formularios de autollenado"</string>
+    <string name="pref_autofill_profile_editor_summary" msgid="6606678927956330022">"Configurar &amp; administrar datos para los formularios de autocompletado"</string>
     <!-- XL -->
     <string name="autofill_profile_editor_heading" msgid="376355900106687672">"La función Autocompletar utilizará tu perfil para ayudarte a completar los formularios web con solo un clic."</string>
     <!-- XL -->
@@ -82,7 +82,7 @@
     <!-- XL -->
     <string name="pref_content_load_page" msgid="7460666469137362825">"Abrir las páginas en visión general"</string>
     <!-- XL -->
-    <!-- outdated translation 3239395481036882698 -->     <string name="pref_extras_title" msgid="7223601187104530963">"Configuración avanzada"</string>
+    <string name="pref_extras_title" msgid="7223601187104530963">"Avanzado"</string>
     <!-- XL -->
     <string name="pref_extras_reset_default" msgid="113675796607112935">"Restablecer a la forma predeterminada"</string>
     <!-- XL -->
@@ -96,7 +96,23 @@
     <!-- XL -->
     <string name="max_tabs_warning" msgid="1283136201153746764">"No hay más etiquetas disponibles"</string>
     <!-- XL -->
-    <string name="pref_lab_title" msgid="209824994106188072">"Lab"</string>
+    <string name="pref_general_title" msgid="1229916674669616147">"General"</string>
+    <!-- XL -->
+    <string name="pref_general_sync_title" msgid="1799321350681060075">"Sincronización"</string>
+    <!-- XL -->
+    <string name="pref_general_autofill_title" msgid="3214478293686374847">"Autocompletar"</string>
+    <!-- XL -->
+    <string name="pref_privacy_security_title" msgid="1547485785692120937">"Privacidad &amp; Seguridad"</string>
+    <!-- XL -->
+    <string name="pref_privacy_cookies_title" msgid="2009543275661191347">"Cookies"</string>
+    <!-- XL -->
+    <string name="pref_privacy_formdata_title" msgid="808174611258405509">"Datos del formulario"</string>
+    <!-- XL -->
+    <string name="pref_privacy_location_title" msgid="4128439505504300548">"Ubicación"</string>
+    <!-- XL -->
+    <string name="pref_security_passwords_title" msgid="6502262261189522404">"Contraseñas"</string>
+    <!-- XL -->
+    <string name="pref_extras_reset_default_title" msgid="8689952816215143856">"Restablecer configuraciones predeterminadas"</string>
     <!-- XL -->
     <string name="pref_lab_quick_controls" msgid="1617774508416113544">"Controles rápidos"</string>
     <!-- XL -->
diff --git a/res/values-xlarge/dimensions.xml b/res/values-xlarge/dimensions.xml
index 5b86c86..9f5a602 100644
--- a/res/values-xlarge/dimensions.xml
+++ b/res/values-xlarge/dimensions.xml
@@ -14,4 +14,9 @@
     <dimen name="bookmarkThumbnailWidth">180dip</dimen>
     <dimen name="bookmarkThumbnailHeight">120dip</dimen>
     <dimen name="favicon_padded_size">24dip</dimen>
+    <!-- For the most visited page -->
+    <dimen name="mv_max_width">1010dp</dimen>
+    <dimen name="mv_item_width">231dp</dimen>
+    <dimen name="mv_item_width_portrait">213dp</dimen>
+    <dimen name="mv_border_width">3dp</dimen>
 </resources>
diff --git a/res/values-xlarge/strings.xml b/res/values-xlarge/strings.xml
index 856b2b9..8dcabe2 100644
--- a/res/values-xlarge/strings.xml
+++ b/res/values-xlarge/strings.xml
@@ -25,4 +25,6 @@
     <!-- Context Menu item to open the currently selected link in a new
          window. [CHAR LIMIT=30] -->
     <string name="contextmenu_openlink_newwindow">Open in new tab</string>
+    <!-- Context menu item to open every bookmark in a folder in new tabs [CHAR LIMIT=50] -->
+    <string name="open_all_in_new_window">Open all in new tabs</string>
 </resources>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index cb1b754..834bead 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -29,7 +29,7 @@
     <color name="bookmarkWidgetDivider">#383847</color>
     <color name="bookmarkWidgetItemBackground">#2b2b3c</color>
     <color name="bookmarkWidgetFolderBackground">#A0383847</color>
-    <color name="qc_slice_normal">#C0A0A0A0</color>
-    <color name="qc_slice_active">#C02090FF</color>
+    <color name="qc_slice_normal">#E0A0A0A0</color>
+    <color name="qc_slice_active">#E02090FF</color>
     <color name="bookmarkWidgetFaviconBackground">#23ffffff</color>
 </resources>
diff --git a/res/values/dimensions.xml b/res/values/dimensions.xml
index 03127dd..d50ce13 100644
--- a/res/values/dimensions.xml
+++ b/res/values/dimensions.xml
@@ -33,4 +33,9 @@
     <dimen name="qc_slop">15dip</dimen>
     <dimen name="bookmark_widget_thumb_size">32dip</dimen>
     <dimen name="bookmark_widget_favicon_size">26dip</dimen>
+    <!-- For the most visited page -->
+    <dimen name="mv_max_width">830dp</dimen>
+    <dimen name="mv_item_width">96dp</dimen>
+    <dimen name="mv_item_width_portrait">96dp</dimen>
+    <dimen name="mv_border_width">3dp</dimen>
 </resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index b8a45bf..4464370 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -204,6 +204,8 @@
     <string name="delete_bookmark_warning">Bookmark \"<xliff:g id="bookmark">%s</xliff:g>\" will be deleted.</string>
     <!-- Context Menu item to open the selected link in a new window -->
     <string name="open_in_new_window">Open in new window</string>
+    <!-- Context menu item to open every bookmark in a folder in new windows [CHAR LIMIT=50] -->
+    <string name="open_all_in_new_window">Open all in new windows</string>
     <!-- Menu item to open a dialog which allows the user to enter a url or do search-->
     <string name="goto_dot">Go</string>
     <!-- Menu item that opens up a new incognito tab. [CHAR LIMIT=30] -->
@@ -603,12 +605,17 @@
     </string-array>
     <string name="pref_default_text_encoding_default" translatable="false">Latin-1</string>
     <!-- Title for lab settings [CHAR LIMIT=25] -->
-    <string name="pref_lab_title">Lab</string>
+    <string name="pref_lab_title">Labs</string>
     <!-- Title for lab quick controls feature [CHAR LIMIT=40] -->
     <string name="pref_lab_quick_controls">Quick Controls</string>
     <!-- Summary for lab quick controls feature [CHAR LIMIT=80] -->
     <string name="pref_lab_quick_controls_summary">
         Swipe thumb from left or right edge to access quick controls</string>
+    <!-- Title for lab "Most Visited" homepage feature [CHAR LIMIT=40] -->
+    <string name="pref_lab_most_visited_homepage">Most Visited Homepage</string>
+    <!-- Summary for lab "Most Visited" homepage feature [CHAR LIMIT=80] -->
+    <string name="pref_lab_most_visited_homepage_summary">
+        Sets your homepage to show the most visited pages.</string>
     <!-- Title for a dialog displayed when the browser has a data connectivity
             problem -->
     <string name="browserFrameNetworkErrorLabel">Data connectivity problem</string>
diff --git a/res/xml/lab_preferences.xml b/res/xml/lab_preferences.xml
index 2168471..16a5169 100644
--- a/res/xml/lab_preferences.xml
+++ b/res/xml/lab_preferences.xml
@@ -23,4 +23,10 @@
         android:title="@string/pref_lab_quick_controls"
         android:summary="@string/pref_lab_quick_controls_summary" />
 
+    <CheckBoxPreference
+        android:key="use_most_visited_homepage"
+        android:defaultValue="false"
+        android:title="@string/pref_lab_most_visited_homepage"
+        android:summary="@string/pref_lab_most_visited_homepage_summary" />
+
 </PreferenceScreen>
diff --git a/src/com/android/browser/AddBookmarkPage.java b/src/com/android/browser/AddBookmarkPage.java
index 9d8c73c..5e389ea 100644
--- a/src/com/android/browser/AddBookmarkPage.java
+++ b/src/com/android/browser/AddBookmarkPage.java
@@ -98,6 +98,7 @@
     private View mDefaultView;
     private View mFolderSelector;
     private EditText mFolderNamer;
+    private View mFolderCancel;
     private boolean mIsFolderNamerShowing;
     private View mFolderNamerHolder;
     private View mAddNewFolder;
@@ -243,6 +244,8 @@
             } else {
                 finish();
             }
+        } else if (v == mFolderCancel) {
+            completeOrCancelFolderNaming(true);
         } else if (v == mAddNewFolder) {
             setShowFolderNamer(true);
             mFolderNamer.setText(R.string.new_folder);
@@ -286,6 +289,11 @@
     public void onNothingSelected(AdapterView<?> parent) {
     }
 
+    /**
+     * Finish naming a folder, and close the IME
+     * @param cancel If true, the new folder is not created.  If false, the new
+     *      folder is created and the user is taken inside it.
+     */
     private void completeOrCancelFolderNaming(boolean cancel) {
         if (!cancel && !TextUtils.isEmpty(mFolderNamer.getText())) {
             String name = mFolderNamer.getText().toString();
@@ -588,6 +596,8 @@
         mFolderNamerHolder = getLayoutInflater().inflate(R.layout.new_folder_layout, null);
         mFolderNamer = (EditText) mFolderNamerHolder.findViewById(R.id.folder_namer);
         mFolderNamer.setOnEditorActionListener(this);
+        mFolderCancel = mFolderNamerHolder.findViewById(R.id.close);
+        mFolderCancel.setOnClickListener(this);
 
         mAddNewFolder = findViewById(R.id.add_new_folder);
         mAddNewFolder.setOnClickListener(this);
diff --git a/src/com/android/browser/BrowserBookmarksPage.java b/src/com/android/browser/BrowserBookmarksPage.java
index 825da33..ea97c29 100644
--- a/src/com/android/browser/BrowserBookmarksPage.java
+++ b/src/com/android/browser/BrowserBookmarksPage.java
@@ -566,10 +566,43 @@
 
     private void openInNewWindow(int position) {
         if (mCallbacks != null) {
-            mCallbacks.onOpenInNewWindow(mAdapter.getItem(position));
+            Cursor c = mAdapter.getItem(position);
+            boolean isFolder = c.getInt(BookmarksLoader.COLUMN_INDEX_IS_FOLDER) == 1;
+            if (isFolder) {
+                long id = c.getLong(BookmarksLoader.COLUMN_INDEX_ID);
+                new OpenAllInTabsTask(id).execute();
+            } else {
+                mCallbacks.onOpenInNewWindow(c);
+            }
         }
     }
 
+    class OpenAllInTabsTask extends AsyncTask<Void, Void, Cursor> {
+        long mFolderId;
+        public OpenAllInTabsTask(long id) {
+            mFolderId = id;
+        }
+
+        @Override
+        protected Cursor doInBackground(Void... params) {
+            Context c = getActivity();
+            if (c == null) return null;
+            return c.getContentResolver().query(BookmarkUtils.getBookmarksUri(c),
+                    BookmarksLoader.PROJECTION, BrowserContract.Bookmarks.PARENT + "=?",
+                    new String[] { Long.toString(mFolderId) }, null);
+        }
+
+        @Override
+        protected void onPostExecute(Cursor result) {
+            if (mCallbacks != null) {
+                while (result.moveToNext()) {
+                    mCallbacks.onOpenInNewWindow(result);
+                }
+            }
+        }
+
+    }
+
     private void editBookmark(int position) {
         Intent intent = new Intent(getActivity(), AddBookmarkPage.class);
         Cursor cursor = mAdapter.getItem(position);
diff --git a/src/com/android/browser/BrowserSettings.java b/src/com/android/browser/BrowserSettings.java
index 267056e..88bd78a 100644
--- a/src/com/android/browser/BrowserSettings.java
+++ b/src/com/android/browser/BrowserSettings.java
@@ -17,6 +17,7 @@
 
 package com.android.browser;
 
+import com.android.browser.homepages.HomeProvider;
 import com.android.browser.search.SearchEngine;
 import com.android.browser.search.SearchEngines;
 
@@ -119,6 +120,7 @@
 
     // Lab settings
     private boolean quickControls = false;
+    private boolean useMostVisitedHomepage = false;
 
     // By default the error console is shown once the user navigates to about:debug.
     // The setting can be then toggled from the settings menu.
@@ -171,6 +173,7 @@
     public final static String PREF_USER_AGENT = "user_agent";
 
     public final static String PREF_QUICK_CONTROLS = "enable_quick_controls";
+    public final static String PREF_MOST_VISITED_HOMEPAGE = "use_most_visited_homepage";
 
     private static final String DESKTOP_USERAGENT = "Mozilla/5.0 (Macintosh; " +
             "U; Intel Mac OS X 10_6_3; en-us) AppleWebKit/533.16 (KHTML, " +
@@ -197,7 +200,7 @@
     public static final Uri RLZ_PROVIDER_URI = Uri.parse("content://" + RLZ_PROVIDER + "/");
 
     // Set to true to enable some of the about:debug options
-    public static final boolean DEV_BUILD = true;
+    public static final boolean DEV_BUILD = false;
 
     private Controller mController;
 
@@ -278,6 +281,8 @@
             // enable smooth transition for better performance during panning or
             // zooming
             s.setEnableSmoothTransition(true);
+            // disable content url access
+            s.setAllowContentAccess(false);
 
             // HTML5 API flags
             s.setAppCacheEnabled(b.appCacheEnabled);
@@ -496,6 +501,7 @@
         }
 
         quickControls = p.getBoolean(PREF_QUICK_CONTROLS, quickControls);
+        useMostVisitedHomepage = p.getBoolean(PREF_MOST_VISITED_HOMEPAGE, useMostVisitedHomepage);
 
         // Only set these on startup if it is a dev build
         if (DEV_BUILD) {
@@ -525,6 +531,9 @@
     }
 
     public String getHomePage() {
+        if (useMostVisitedHomepage) {
+            return HomeProvider.MOST_VISITED;
+        }
         return homeUrl;
     }
 
@@ -584,6 +593,10 @@
         return quickControls;
     }
 
+    public boolean useMostVisitedHomepage() {
+        return useMostVisitedHomepage;
+    }
+
     public boolean showDebugSettings() {
         return showDebugSettings;
     }
@@ -847,6 +860,8 @@
             update();
         } else if (PREF_QUICK_CONTROLS.equals(key)) {
             quickControls = p.getBoolean(PREF_QUICK_CONTROLS, quickControls);
+        } else if (PREF_MOST_VISITED_HOMEPAGE.equals(key)) {
+            useMostVisitedHomepage = p.getBoolean(PREF_MOST_VISITED_HOMEPAGE, useMostVisitedHomepage);
         }
     }
 }
diff --git a/src/com/android/browser/Controller.java b/src/com/android/browser/Controller.java
index a5a6090..23594f2 100644
--- a/src/com/android/browser/Controller.java
+++ b/src/com/android/browser/Controller.java
@@ -733,7 +733,7 @@
     // WebViewController
 
     @Override
-    public void onPageStarted(Tab tab, WebView view, String url, Bitmap favicon) {
+    public void onPageStarted(Tab tab, WebView view, Bitmap favicon) {
 
         // We've started to load a new page. If there was a pending message
         // to save a screenshot then we will now take the new page and save
@@ -764,6 +764,7 @@
 
         mUi.onTabDataChanged(tab);
 
+        String url = tab.getUrl();
         // update the bookmark database for favicon
         maybeUpdateFavicon(tab, null, url, favicon);
 
@@ -777,9 +778,10 @@
     }
 
     @Override
-    public void onPageFinished(Tab tab, String url) {
+    public void onPageFinished(Tab tab) {
         mUi.onTabDataChanged(tab);
-        if (!tab.isPrivateBrowsingEnabled()) {
+        if (!tab.isPrivateBrowsingEnabled()
+                && !TextUtils.isEmpty(tab.getUrl())) {
             if (tab.inForeground() && !didUserStopLoading()
                     || !tab.inForeground()) {
                 // Only update the bookmark screenshot if the user did not
@@ -799,7 +801,7 @@
         }
         // Performance probe
         if (false) {
-            Performance.onPageFinished(url);
+            Performance.onPageFinished(tab.getUrl());
          }
 
         Performance.tracePageFinished();
@@ -843,7 +845,7 @@
     public void onReceivedTitle(Tab tab, final String title) {
         mUi.onTabDataChanged(tab);
         final String pageUrl = tab.getUrl();
-        if (pageUrl == null || pageUrl.length()
+        if (TextUtils.isEmpty(pageUrl) || pageUrl.length()
                 >= SQLiteDatabase.SQLITE_MAX_LIKE_PATTERN_LENGTH) {
             return;
         }
@@ -887,12 +889,13 @@
     }
 
     @Override
-    public void doUpdateVisitedHistory(Tab tab, String url,
-            boolean isReload) {
+    public void doUpdateVisitedHistory(Tab tab, boolean isReload) {
         // Don't save anything in private browsing mode
         if (tab.isPrivateBrowsingEnabled()) return;
+        String url = tab.getUrl();
 
-        if (url.regionMatches(true, 0, "about:", 0, 6)) {
+        if (TextUtils.isEmpty(url)
+                || url.regionMatches(true, 0, "about:", 0, 6)) {
             return;
         }
         mDataController.updateVisitedHistory(url);
@@ -1026,6 +1029,7 @@
         intent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE,
                 mActivity.getComponentName().flattenToString());
         intent.putExtra(SEND_APP_ID_EXTRA, false);
+        intent.putExtra(RecognizerIntent.EXTRA_WEB_SEARCH_ONLY, true);
         mActivity.startActivity(intent);
     }
 
@@ -2352,9 +2356,11 @@
      * @return true if handled, false to pass to super
      */
     boolean onKeyDown(int keyCode, KeyEvent event) {
+        boolean noModifiers = event.hasNoModifiers();
+
         // Even if MENU is already held down, we need to call to super to open
         // the IME on long press.
-        if (KeyEvent.KEYCODE_MENU == keyCode) {
+        if (!noModifiers && KeyEvent.KEYCODE_MENU == keyCode) {
             mMenuIsDown = true;
             return false;
         }
@@ -2366,23 +2372,26 @@
         WebView webView = getCurrentTopWebView();
         if (webView == null) return false;
 
-        boolean ctrl = event.isCtrlPressed();
+        boolean ctrl = event.hasModifiers(KeyEvent.META_CTRL_ON);
+        boolean shift = event.hasModifiers(KeyEvent.META_SHIFT_ON);
 
         switch(keyCode) {
             case KeyEvent.KEYCODE_ESCAPE:
+                if (!noModifiers) break;
                 stopLoading();
                 return true;
             case KeyEvent.KEYCODE_SPACE:
                 // WebView/WebTextView handle the keys in the KeyDown. As
                 // the Activity's shortcut keys are only handled when WebView
                 // doesn't, have to do it in onKeyDown instead of onKeyUp.
-                if (event.isShiftPressed()) {
+                if (shift) {
                     pageUp();
-                } else {
+                } else if (noModifiers) {
                     pageDown();
                 }
                 return true;
             case KeyEvent.KEYCODE_BACK:
+                if (!noModifiers) break;
                 if (event.getRepeatCount() == 0) {
                     event.startTracking();
                     return true;
@@ -2498,6 +2507,7 @@
     }
 
     boolean onKeyUp(int keyCode, KeyEvent event) {
+        if (!event.hasNoModifiers()) return false;
         switch(keyCode) {
             case KeyEvent.KEYCODE_MENU:
                 mMenuIsDown = false;
diff --git a/src/com/android/browser/IntentHandler.java b/src/com/android/browser/IntentHandler.java
index 06a9f6f..e4b3201 100644
--- a/src/com/android/browser/IntentHandler.java
+++ b/src/com/android/browser/IntentHandler.java
@@ -202,13 +202,6 @@
             final String action = intent.getAction();
             if (Intent.ACTION_VIEW.equals(action)) {
                 url = UrlUtils.smartUrlFilter(intent.getData());
-                if (url != null && url.startsWith("content:")) {
-                    /* Append mimetype so webview knows how to display */
-                    String mimeType = intent.resolveType(mActivity.getContentResolver());
-                    if (mimeType != null) {
-                        url += "?" + mimeType;
-                    }
-                }
                 if (url != null && url.startsWith("http")) {
                     final Bundle pairs = intent
                             .getBundleExtra(Browser.EXTRA_HEADERS);
diff --git a/src/com/android/browser/PieControl.java b/src/com/android/browser/PieControl.java
index 210e9ea..6326f2e 100644
--- a/src/com/android/browser/PieControl.java
+++ b/src/com/android/browser/PieControl.java
@@ -70,7 +70,7 @@
             mPie.addItem(mRefresh);
             mBack = makeMenuView(R.drawable.ic_pie_back);
             mPie.addItem(mBack);
-            mUrl = makeMenuView(R.drawable.ic_pie_search);
+            mUrl = makeMenuView(R.drawable.ic_pie_web);
             mPie.addItem(mUrl);
             mBookmarks = makeMenuView(R.drawable.ic_pie_bookmarks);
             mPie.addItem(mBookmarks);
@@ -133,6 +133,7 @@
             mUiController.bookmarksOrHistoryPicker(false);
         } else if (mNewTab == v) {
             mUiController.openTabToHomePage();
+            mUi.showFakeTitleBarAndEdit();
         } else if (mClose == v) {
             mUiController.closeCurrentTab();
         } else {
diff --git a/src/com/android/browser/ScrollWebView.java b/src/com/android/browser/ScrollWebView.java
index 51df958..e2ef902 100644
--- a/src/com/android/browser/ScrollWebView.java
+++ b/src/com/android/browser/ScrollWebView.java
@@ -30,6 +30,7 @@
 
     private ScrollListener mScrollListener;
     private boolean mIsCancelled;
+    private boolean mBackgroundRemoved = false;
 
     /**
      * @param context
@@ -113,4 +114,16 @@
         public void onScroll(int visibleTitleHeight);
     }
 
+    @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);
+                }
+            });
+        }
+    }
 }
diff --git a/src/com/android/browser/SuggestionsAdapter.java b/src/com/android/browser/SuggestionsAdapter.java
index 7ee5c2a..e2d9386 100644
--- a/src/com/android/browser/SuggestionsAdapter.java
+++ b/src/com/android/browser/SuggestionsAdapter.java
@@ -67,6 +67,7 @@
     int mLinesLandscape;
     Object mResultsLock = new Object();
     List<String> mVoiceResults;
+    boolean mReverseResults;
 
     interface CompletionListener {
 
@@ -133,6 +134,9 @@
 
     @Override
     public SuggestItem getItem(int position) {
+        if (mReverseResults) {
+            position = (getCount() - 1) - position;
+        }
         if (mVoiceResults != null) {
             return new SuggestItem(mVoiceResults.get(position), null,
                     TYPE_SEARCH);
@@ -143,9 +147,13 @@
         return mMixedResults.items.get(position);
     }
 
+    public void setReverseResults(boolean reverse) {
+        mReverseResults = reverse;
+    }
+
     @Override
     public long getItemId(int position) {
-        return 0;
+        return position;
     }
 
     @Override
diff --git a/src/com/android/browser/Tab.java b/src/com/android/browser/Tab.java
index 320d3b3..d70b0ef 100644
--- a/src/com/android/browser/Tab.java
+++ b/src/com/android/browser/Tab.java
@@ -532,7 +532,7 @@
             }
 
             // finally update the UI in the activity if it is in the foreground
-            mWebViewController.onPageStarted(Tab.this, view, url, favicon);
+            mWebViewController.onPageStarted(Tab.this, view, favicon);
 
             updateBookmarkedStatus();
         }
@@ -556,7 +556,7 @@
                 // but before a provisional load occurred
                 mCurrentState.mLockIcon = LockIcon.LOCK_ICON_UNSECURE;
             }
-            mWebViewController.onPageFinished(Tab.this, url);
+            mWebViewController.onPageFinished(Tab.this);
         }
 
         // return true if want to hijack the url to let another app to handle it
@@ -687,7 +687,7 @@
         @Override
         public void doUpdateVisitedHistory(WebView view, String url,
                 boolean isReload) {
-            mWebViewController.doUpdateVisitedHistory(Tab.this, url, isReload);
+            mWebViewController.doUpdateVisitedHistory(Tab.this, isReload);
         }
 
         /**
@@ -1568,7 +1568,7 @@
     }
 
     String getUrl() {
-        return mCurrentState.mUrl;
+        return UrlUtils.filteredUrl(mCurrentState.mUrl);
     }
 
     /**
diff --git a/src/com/android/browser/TabBar.java b/src/com/android/browser/TabBar.java
index e36c204..ba123d0 100644
--- a/src/com/android/browser/TabBar.java
+++ b/src/com/android/browser/TabBar.java
@@ -16,7 +16,6 @@
 
 package com.android.browser;
 
-import android.graphics.Matrix;
 import com.android.browser.ScrollWebView.ScrollListener;
 
 import android.app.Activity;
@@ -26,6 +25,7 @@
 import android.graphics.BitmapShader;
 import android.graphics.Canvas;
 import android.graphics.Color;
+import android.graphics.Matrix;
 import android.graphics.Paint;
 import android.graphics.Path;
 import android.graphics.Shader;
@@ -33,6 +33,7 @@
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.LayerDrawable;
 import android.graphics.drawable.PaintDrawable;
+import android.util.Log;
 import android.view.ContextMenu;
 import android.view.Gravity;
 import android.view.LayoutInflater;
@@ -70,9 +71,8 @@
     private ImageButton mNewTab;
     private int mButtonWidth;
 
-    private Map<Tab, TabViewData> mTabMap;
+    private Map<Tab, TabView> mTabMap;
 
-    private boolean mUserRequestedUrlbar;
     private int mVisibleTitleHeight;
 
     private Drawable mGenericFavicon;
@@ -108,7 +108,8 @@
         mActiveDrawable = res.getDrawable(R.drawable.bg_urlbar);
         mInactiveDrawable = res.getDrawable(R.drawable.browsertab_inactive);
 
-        mTabMap = new HashMap<Tab, TabViewData>();
+        mTabMap = new HashMap<Tab, TabView>();
+        Resources resources = activity.getResources();
         LayoutInflater factory = LayoutInflater.from(activity);
         factory.inflate(R.layout.tab_bar, this);
         setPadding(12, 12, 0, 0);
@@ -123,7 +124,6 @@
 
         updateTabs(mUiController.getTabs());
 
-        mUserRequestedUrlbar = false;
         mVisibleTitleHeight = 1;
         mButtonWidth = -1;
         // tab dimensions
@@ -141,6 +141,8 @@
 
     void setUseQuickControls(boolean useQuickControls) {
         mUseQuickControls = useQuickControls;
+        mNewTab.setVisibility(mUseQuickControls ? View.GONE
+                : View.VISIBLE);
     }
 
     int getTabCount() {
@@ -151,8 +153,7 @@
         mTabs.clearTabs();
         mTabMap.clear();
         for (Tab tab : tabs) {
-            TabViewData data = buildTab(tab);
-            TabView tv = buildView(data);
+            TabView tv = buildTabView(tab);
         }
         mTabs.setSelectedTab(mTabControl.getCurrentIndex());
     }
@@ -162,7 +163,9 @@
         super.onMeasure(hspec, vspec);
         int w = getMeasuredWidth();
         // adjust for new tab overlap
-        w -= mTabOverlap;
+        if (!mUseQuickControls) {
+            w -= mTabOverlap;
+        }
         setMeasuredDimension(w, getMeasuredHeight());
     }
 
@@ -190,8 +193,14 @@
         if (mNewTab == view) {
             mUiController.openTabToHomePage();
         } else if (mTabs.getSelectedTab() == view) {
-            if (mUseQuickControls) return;
-            if (mUi.isFakeTitleBarShowing() && !isLoading()) {
+            if (mUseQuickControls) {
+                if (mUi.isFakeTitleBarShowing() && !isLoading()) {
+                    mUi.hideFakeTitleBar();
+                } else {
+                    mUi.stopWebViewScrolling();
+                    mUi.showFakeTitleBarAndEdit();
+                }
+            } else if (mUi.isFakeTitleBarShowing() && !isLoading()) {
                 mUi.hideFakeTitleBar();
             } else {
                 showUrlBar();
@@ -208,15 +217,14 @@
     private void showUrlBar() {
         mUi.stopWebViewScrolling();
         mUi.showFakeTitleBar();
-        mUserRequestedUrlbar = true;
     }
 
     void showTitleBarIndicator(boolean show) {
         Tab tab = mTabControl.getCurrentTab();
         if (tab != null) {
-            TabViewData tvd = mTabMap.get(tab);
-            if (tvd != null) {
-                tvd.mTabView.showIndicator(show);
+            TabView tv = mTabMap.get(tab);
+            if (tv != null) {
+                tv.showIndicator(show);
             }
         }
     }
@@ -231,7 +239,6 @@
         showTitleBarIndicator(mVisibleTitleHeight == 0);
         Tab tab = mTabControl.getCurrentTab();
         tab.getWebView().requestFocus();
-        mUserRequestedUrlbar = false;
     }
 
     // webview scroll listener
@@ -259,18 +266,12 @@
         mActivity.onCreateContextMenu(menu, this, null);
     }
 
-    private TabViewData buildTab(Tab tab) {
-        TabViewData data = new TabViewData(tab);
-        mTabMap.put(tab, data);
-        return data;
-    }
-
-    private TabView buildView(final TabViewData data) {
-        TabView tv = new TabView(mActivity, data);
-        tv.setTag(data);
-        tv.setOnClickListener(this);
-        mTabs.addTab(tv);
-        return tv;
+    private TabView buildTabView(Tab tab) {
+        TabView tabview = new TabView(mActivity, tab);
+        mTabMap.put(tab, tabview);
+        tabview.setOnClickListener(this);
+        mTabs.addTab(tabview);
+        return tabview;
     }
 
     @Override
@@ -292,7 +293,7 @@
      */
     class TabView extends LinearLayout implements OnClickListener {
 
-        TabViewData mTabData;
+        Tab mTab;
         View mTabContent;
         TextView mTitle;
         View mIndicator;
@@ -308,12 +309,12 @@
         /**
          * @param context
          */
-        public TabView(Context context, TabViewData tab) {
+        public TabView(Context context, Tab tab) {
             super(context);
             setWillNotDraw(false);
             mPath = new Path();
             mWindowPos = new int[2];
-            mTabData = tab;
+            mTab = tab;
             setGravity(Gravity.CENTER_VERTICAL);
             setOrientation(LinearLayout.HORIZONTAL);
             setPadding(mTabPadding, 0, 0, 0);
@@ -329,7 +330,7 @@
             mSelected = false;
             mInLoad = false;
             // update the status
-            updateFromData();
+            updateFromTab();
         }
 
         void showIndicator(boolean show) {
@@ -347,21 +348,19 @@
             }
         }
 
-        private void updateFromData() {
-            mTabData.mTabView = this;
-            Tab tab = mTabData.mTab;
-            String displayTitle = tab.getTitle();
+        private void updateFromTab() {
+            String displayTitle = mTab.getTitle();
             if (displayTitle == null) {
-                displayTitle = tab.getUrl();
+                displayTitle = mTab.getUrl();
             }
             setDisplayTitle(displayTitle);
-            setProgress(mTabData.mProgress);
-            if (mTabData.mIcon != null) {
-                setFavicon(mTabData.mIcon);
+            setProgress(mTab.getLoadProgress());
+            if (mTab.getFavicon() != null) {
+                setFavicon(renderFavicon(mTab.getFavicon()));
             }
-            if (mTabData.mTab != null) {
+            if (mTab != null) {
                 mIncognito.setVisibility(
-                        mTabData.mTab.isPrivateBrowsingEnabled() ?
+                        mTab.isPrivateBrowsingEnabled() ?
                         View.VISIBLE : View.GONE);
             }
         }
@@ -409,10 +408,10 @@
         }
 
         private void closeTab() {
-            if (mTabData.mTab == mTabControl.getCurrentTab()) {
+            if (mTab == mTabControl.getCurrentTab()) {
                 mUiController.closeCurrentTab();
             } else {
-                mUiController.closeTab(mTabData.mTab);
+                mUiController.closeTab(mTab);
             }
         }
 
@@ -472,65 +471,28 @@
 
     }
 
-    /**
-     * Store tab state within the title bar
-     */
-    class TabViewData {
-
-        Tab mTab;
-        TabView mTabView;
-        int mProgress;
-        Drawable mIcon;
-
-        TabViewData(Tab tab) {
-            mTab = tab;
-            setUrlAndTitle(mTab.getUrl(), mTab.getTitle());
+    private Drawable renderFavicon(Bitmap icon) {
+        Drawable[] array = new Drawable[3];
+        array[0] = new PaintDrawable(Color.BLACK);
+        array[1] = new PaintDrawable(Color.WHITE);
+        if (icon == null) {
+            array[2] = mGenericFavicon;
+        } else {
+            array[2] = new BitmapDrawable(icon);
         }
-
-        void setUrlAndTitle(String url, String title) {
-            if (mTabView != null) {
-                if (title != null) {
-                    mTabView.setDisplayTitle(title);
-                } else if (url != null) {
-                    mTabView.setDisplayTitle(UrlUtils.stripUrl(url));
-                }
-            }
-        }
-
-        void setProgress(int newProgress) {
-            mProgress = newProgress;
-            if (mTabView != null) {
-                mTabView.setProgress(mProgress);
-            }
-        }
-
-        void setFavicon(Bitmap icon) {
-            Drawable[] array = new Drawable[3];
-            array[0] = new PaintDrawable(Color.BLACK);
-            array[1] = new PaintDrawable(Color.WHITE);
-            if (icon == null) {
-                array[2] = mGenericFavicon;
-            } else {
-                array[2] = new BitmapDrawable(icon);
-            }
-            LayerDrawable d = new LayerDrawable(array);
-            d.setLayerInset(1, 1, 1, 1, 1);
-            d.setLayerInset(2, 2, 2, 2, 2);
-            mIcon = d;
-            if (mTabView != null) {
-                mTabView.setFavicon(mIcon);
-            }
-        }
-
+        LayerDrawable d = new LayerDrawable(array);
+        d.setLayerInset(1, 1, 1, 1, 1);
+        d.setLayerInset(2, 2, 2, 2, 2);
+        return d;
     }
 
     // TabChangeListener implementation
 
     public void onSetActiveTab(Tab tab) {
         mTabs.setSelectedTab(mTabControl.getTabIndex(tab));
-        TabViewData tvd = mTabMap.get(tab);
-        if (tvd != null) {
-            tvd.setProgress(tvd.mProgress);
+        TabView tv = mTabMap.get(tab);
+        if (tv != null) {
+            tv.setProgress(tv.mTab.getLoadProgress());
             // update the scroll state
             WebView webview = tab.getWebView();
             if (webview != null) {
@@ -542,46 +504,46 @@
     }
 
     public void onFavicon(Tab tab, Bitmap favicon) {
-        TabViewData tvd = mTabMap.get(tab);
-        if (tvd != null) {
-            tvd.setFavicon(favicon);
+        TabView tv = mTabMap.get(tab);
+        if (tv != null) {
+            tv.setFavicon(renderFavicon(favicon));
         }
     }
 
     public void onNewTab(Tab tab) {
-        TabViewData tvd = buildTab(tab);
-        buildView(tvd);
+        TabView tv = buildTabView(tab);
     }
 
     public void onProgress(Tab tab, int progress) {
-        TabViewData tvd = mTabMap.get(tab);
-        if (tvd != null) {
-            tvd.setProgress(progress);
+        TabView tv = mTabMap.get(tab);
+        if (tv != null) {
+            tv.setProgress(progress);
         }
     }
 
     public void onRemoveTab(Tab tab) {
-        TabViewData tvd = mTabMap.get(tab);
-        if (tvd != null) {
-            TabView tv = tvd.mTabView;
-            if (tv != null) {
-                mTabs.removeTab(tv);
-            }
+        TabView tv = mTabMap.get(tab);
+        if (tv != null) {
+            mTabs.removeTab(tv);
         }
         mTabMap.remove(tab);
     }
 
     public void onUrlAndTitle(Tab tab, String url, String title) {
-        TabViewData tvd = mTabMap.get(tab);
-        if (tvd != null) {
-            tvd.setUrlAndTitle(url, title);
+        TabView tv = mTabMap.get(tab);
+        if (tv != null) {
+            if (title != null) {
+                tv.setDisplayTitle(title);
+            } else if (url != null) {
+                tv.setDisplayTitle(UrlUtils.stripUrl(url));
+            }
         }
     }
 
     private boolean isLoading() {
-        TabViewData tvd = mTabMap.get(mTabControl.getCurrentTab());
-        if ((tvd != null) && (tvd.mTabView != null)) {
-            return tvd.mTabView.mInLoad;
+        TabView tv = mTabMap.get(mTabControl.getCurrentTab());
+        if (tv != null) {
+            return tv.mInLoad;
         } else {
             return false;
         }
diff --git a/src/com/android/browser/TitleBarXLarge.java b/src/com/android/browser/TitleBarXLarge.java
index b479139..8be4df5 100644
--- a/src/com/android/browser/TitleBarXLarge.java
+++ b/src/com/android/browser/TitleBarXLarge.java
@@ -17,6 +17,7 @@
 package com.android.browser;
 
 import com.android.browser.UrlInputView.UrlInputListener;
+import com.android.browser.search.SearchEngine;
 
 import android.app.Activity;
 import android.app.SearchManager;
@@ -87,11 +88,11 @@
                 R.drawable.textfield_active_holo_dark);
         mUnfocusDrawable = resources.getDrawable(
                 R.drawable.textfield_default_holo_dark);
-        rebuildLayout(activity, true);
+        initLayout(activity);
         mInVoiceMode = false;
     }
 
-    private void rebuildLayout(Context context, boolean rebuildData) {
+    private void initLayout(Context context) {
         LayoutInflater factory = LayoutInflater.from(context);
         factory.inflate(R.layout.url_bar, this);
 
@@ -143,6 +144,7 @@
 
     void setUseQuickControls(boolean useQuickControls) {
         mUseQuickControls = useQuickControls;
+        mUrlInput.setReverseResults(mUseQuickControls);
         if (mUseQuickControls) {
             mBackButton.setVisibility(View.GONE);
             mForwardButton.setVisibility(View.GONE);
@@ -372,7 +374,11 @@
     }
 
     private void setSearchMode(boolean voiceSearchEnabled) {
-        mVoiceSearch.setVisibility(voiceSearchEnabled ? View.VISIBLE :
+        SearchEngine searchEngine = BrowserSettings.getInstance()
+                .getSearchEngine();
+        boolean showvoicebutton = voiceSearchEnabled &&
+                (searchEngine != null && searchEngine.supportsVoiceSearch());
+        mVoiceSearch.setVisibility(showvoicebutton ? View.VISIBLE :
                 View.GONE);
         mGoButton.setVisibility(voiceSearchEnabled ? View.GONE :
                 View.VISIBLE);
diff --git a/src/com/android/browser/UrlInputView.java b/src/com/android/browser/UrlInputView.java
index 8aeef31..428a0f2 100644
--- a/src/com/android/browser/UrlInputView.java
+++ b/src/com/android/browser/UrlInputView.java
@@ -29,7 +29,6 @@
 import android.view.inputmethod.InputMethodManager;
 import android.widget.AdapterView;
 import android.widget.AdapterView.OnItemClickListener;
-import android.widget.AdapterView.OnItemSelectedListener;
 import android.widget.AutoCompleteTextView;
 import android.widget.TextView;
 import android.widget.TextView.OnEditorActionListener;
@@ -218,4 +217,8 @@
                 item.extra);
     }
 
+    public void setReverseResults(boolean reverse) {
+        mAdapter.setReverseResults(reverse);
+    }
+
 }
diff --git a/src/com/android/browser/UrlUtils.java b/src/com/android/browser/UrlUtils.java
index 2df0a61..0a7e90c 100644
--- a/src/com/android/browser/UrlUtils.java
+++ b/src/com/android/browser/UrlUtils.java
@@ -16,6 +16,8 @@
 
 package com.android.browser;
 
+import com.android.browser.homepages.HomeProvider;
+
 import android.net.Uri;
 import android.util.Patterns;
 import android.webkit.URLUtil;
@@ -32,7 +34,7 @@
             "(?i)" + // switch on case insensitive matching
             "(" +    // begin group for schema
             "(?:http|https|file):\\/\\/" +
-            "|(?:inline|data|about|content|javascript):" +
+            "|(?:inline|data|about|javascript):" +
             ")" +
             "(.*)" );
 
@@ -145,4 +147,15 @@
         return inUrl;
     }
 
+    // Returns the filtered URL. Cannot return null, but can return an empty string
+    /* package */ static String filteredUrl(String inUrl) {
+        if (inUrl == null) {
+            return "";
+        }
+        if (inUrl.startsWith(HomeProvider.MOST_VISITED)) {
+            return "";
+        }
+        return inUrl;
+    }
+
 }
diff --git a/src/com/android/browser/WebViewController.java b/src/com/android/browser/WebViewController.java
index a187af0..813b63b 100644
--- a/src/com/android/browser/WebViewController.java
+++ b/src/com/android/browser/WebViewController.java
@@ -46,9 +46,9 @@
 
     void createSubWindow(Tab tab);
 
-    void onPageStarted(Tab tab, WebView view, String url, Bitmap favicon);
+    void onPageStarted(Tab tab, WebView view, Bitmap favicon);
 
-    void onPageFinished(Tab tab, String url);
+    void onPageFinished(Tab tab);
 
     void onProgressChanged(Tab tab);
 
@@ -62,7 +62,7 @@
 
     void onUnhandledKeyEvent(KeyEvent event);
 
-    void doUpdateVisitedHistory(Tab tab, String url, boolean isReload);
+    void doUpdateVisitedHistory(Tab tab, boolean isReload);
 
     void getVisitedHistory(final ValueCallback<String[]> callback);
 
diff --git a/src/com/android/browser/XLargeUi.java b/src/com/android/browser/XLargeUi.java
index f45b0a1..1e607a7 100644
--- a/src/com/android/browser/XLargeUi.java
+++ b/src/com/android/browser/XLargeUi.java
@@ -242,6 +242,9 @@
     }
 
     void editUrl(boolean clearInput) {
+        if (mUiController.isInCustomActionMode()) {
+            mUiController.endActionMode();
+        }
         showFakeTitleBar();
         mFakeTitleBar.onEditUrl(clearInput);
     }
@@ -273,6 +276,7 @@
     @Override
     protected void hideFakeTitleBar() {
         if (isFakeTitleBarShowing()) {
+            mFakeTitleBar.setUrlMode(false);
             mContentView.removeView(mFakeTitleBar);
             mTabBar.onHideTitleBar();
         }
diff --git a/src/com/android/browser/homepages/HomeProvider.java b/src/com/android/browser/homepages/HomeProvider.java
new file mode 100644
index 0000000..5c368eb
--- /dev/null
+++ b/src/com/android/browser/homepages/HomeProvider.java
@@ -0,0 +1,81 @@
+

+/*

+ * 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.homepages;

+

+import android.content.ContentProvider;

+import android.content.ContentValues;

+import android.content.res.AssetFileDescriptor;

+import android.database.Cursor;

+import android.net.Uri;

+import android.os.ParcelFileDescriptor;

+import android.util.Log;

+

+import java.io.IOException;

+

+public class HomeProvider extends ContentProvider {

+

+    private static final String TAG = "HomeProvider";

+    public static final String AUTHORITY = "com.android.browser.home";

+    public static final String MOST_VISITED = "content://" + AUTHORITY + "/";

+

+    @Override

+    public int delete(Uri uri, String selection, String[] selectionArgs) {

+        return 0;

+    }

+

+    @Override

+    public String getType(Uri uri) {

+        return null;

+    }

+

+    @Override

+    public Uri insert(Uri uri, ContentValues values) {

+        return null;

+    }

+

+    @Override

+    public boolean onCreate() {

+        return false;

+    }

+

+    @Override

+    public Cursor query(Uri uri, String[] projection, String selection,

+            String[] selectionArgs, String sortOrder) {

+        return null;

+    }

+

+    @Override

+    public int update(Uri uri, ContentValues values, String selection,

+            String[] selectionArgs) {

+        return 0;

+    }

+

+    @Override

+    public ParcelFileDescriptor openFile(Uri uri, String mode) {

+        try {

+            ParcelFileDescriptor[] pipes = ParcelFileDescriptor.createPipe();

+            final ParcelFileDescriptor write = pipes[1];

+            AssetFileDescriptor afd = new AssetFileDescriptor(write, 0, -1);

+            new RequestHandler(getContext(), uri, afd.createOutputStream()).start();

+            return pipes[0];

+        } catch (IOException e) {

+            Log.e(TAG, "Failed to handle request: " + uri, e);

+            return null;

+        }

+    }

+

+}

diff --git a/src/com/android/browser/homepages/RequestHandler.java b/src/com/android/browser/homepages/RequestHandler.java
new file mode 100644
index 0000000..a53fb52
--- /dev/null
+++ b/src/com/android/browser/homepages/RequestHandler.java
@@ -0,0 +1,145 @@
+

+/*

+ * 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.homepages;

+

+import com.android.browser.R;

+

+import java.io.IOException;

+import java.io.InputStream;

+import java.io.OutputStream;

+import java.util.regex.Matcher;

+import java.util.regex.Pattern;

+

+import android.content.Context;

+import android.content.UriMatcher;

+import android.content.res.Resources;

+import android.database.Cursor;

+import android.net.Uri;

+import android.provider.Browser;

+import android.util.Base64;

+import android.util.Log;

+

+public class RequestHandler extends Thread {

+

+    private static final String TAG = "RequestHandler";

+    private static final int INDEX = 1;

+    private static final int RESOURCE = 2;

+    private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);

+

+    Uri mUri;

+    Context mContext;

+    OutputStream mOutput;

+

+    static {

+        sUriMatcher.addURI(HomeProvider.AUTHORITY, "/", INDEX);

+        sUriMatcher.addURI(HomeProvider.AUTHORITY, "res/*/*", RESOURCE);

+    }

+

+    public RequestHandler(Context context, Uri uri, OutputStream out) {

+        mUri = uri;

+        mContext = context;

+        mOutput = out;

+    }

+

+    @Override

+    public void run() {

+        super.run();

+        try {

+            doHandleRequest();

+        } catch (Exception e) {

+            Log.e(TAG, "Failed to handle request: " + mUri, e);

+        } finally {

+            cleanup();

+        }

+    }

+

+    void doHandleRequest() throws IOException {

+        int match = sUriMatcher.match(mUri);

+        switch (match) {

+        case INDEX:

+            writeTemplatedIndex();

+            break;

+        case RESOURCE:

+            writeResource(getUriResourcePath());

+            break;

+        }

+    }

+

+    void writeTemplatedIndex() throws IOException {

+        Template t = Template.getCachedTemplate(mContext, R.raw.most_visited);

+        Cursor cursor = mContext.getContentResolver().query(Browser.BOOKMARKS_URI,

+                new String[] { "DISTINCT url", "title", "thumbnail" },

+                "(visits > 0 OR bookmark = 1) AND url NOT LIKE 'content:%' AND thumbnail IS NOT NULL", null, "visits DESC LIMIT 12");

+

+        t.assignLoop("most_visited", new Template.CursorListEntityWrapper(cursor) {

+            @Override

+            public void writeValue(OutputStream stream, String key) throws IOException {

+                Cursor cursor = getCursor();

+                if (key.equals("url")) {

+                    stream.write(cursor.getString(0).getBytes());

+                } else if (key.equals("title")) {

+                    stream.write(cursor.getString(1).getBytes());

+                } else if (key.equals("thumbnail")) {

+                    stream.write("data:image/png;base64,".getBytes());

+                    byte[] thumb = cursor.getBlob(2);

+                    stream.write(Base64.encode(thumb, Base64.DEFAULT));

+                }

+            }

+        });

+        t.write(mOutput);

+    }

+

+    String getUriResourcePath() {

+        final Pattern pattern = Pattern.compile("/?res/([\\w/]+)");

+        Matcher m = pattern.matcher(mUri.getPath());

+        if (m.matches()) {

+            return m.group(1);

+        } else {

+            return mUri.getPath();

+        }

+    }

+

+    void writeResource(String fileName) throws IOException {

+        Resources res = mContext.getResources();

+        int id = res.getIdentifier(fileName, null, mContext.getPackageName());

+        if (id != 0) {

+            InputStream in = res.openRawResource(id);

+            byte[] buf = new byte[4096];

+            int read;

+            while ((read = in.read(buf)) > 0) {

+                mOutput.write(buf, 0, read);

+            }

+        }

+    }

+

+    void writeString(String str) throws IOException {

+        mOutput.write(str.getBytes());

+    }

+

+    void writeString(String str, int offset, int count) throws IOException {

+        mOutput.write(str.getBytes(), offset, count);

+    }

+

+    void cleanup() {

+        try {

+            mOutput.close();

+        } catch (Exception e) {

+            Log.e(TAG, "Failed to close pipe!", e);

+        }

+    }

+

+}

diff --git a/src/com/android/browser/homepages/Template.java b/src/com/android/browser/homepages/Template.java
new file mode 100644
index 0000000..c1a6b0e
--- /dev/null
+++ b/src/com/android/browser/homepages/Template.java
@@ -0,0 +1,279 @@
+

+/*

+ * 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.homepages;

+

+import java.io.IOException;

+import java.io.InputStream;

+import java.io.OutputStream;

+import java.util.ArrayList;

+import java.util.HashMap;

+import java.util.List;

+import java.util.regex.Matcher;

+import java.util.regex.Pattern;

+

+import android.content.Context;

+import android.content.res.Resources;

+import android.database.Cursor;

+import android.util.TypedValue;

+

+public class Template {

+

+    private static HashMap<Integer, Template> sCachedTemplates = new HashMap<Integer, Template>();

+

+    public static Template getCachedTemplate(Context context, int id) {

+        synchronized (sCachedTemplates) {

+            Template template = sCachedTemplates.get(id);

+            if (template == null) {

+                template = new Template(context, id);

+                sCachedTemplates.put(id, template);

+            }

+            // Return a copy so that we don't share data

+            return template.copy();

+        }

+    }

+

+    interface Entity {

+        void write(OutputStream stream, EntityData params) throws IOException;

+    }

+

+    interface EntityData {

+        void writeValue(OutputStream stream, String key) throws IOException;

+        ListEntityIterator getListIterator(String key);

+    }

+

+    interface ListEntityIterator extends EntityData {

+        void reset();

+        boolean moveToNext();

+    }

+

+    static class StringEntity implements Entity {

+

+        byte[] mValue;

+

+        public StringEntity(String value) {

+            mValue = value.getBytes();

+        }

+

+        @Override

+        public void write(OutputStream stream, EntityData params) throws IOException {

+            stream.write(mValue);

+        }

+

+    }

+

+    static class SimpleEntity implements Entity {

+

+        String mKey;

+

+        public SimpleEntity(String key) {

+            mKey = key;

+        }

+

+        @Override

+        public void write(OutputStream stream, EntityData params) throws IOException {

+            params.writeValue(stream, mKey);

+        }

+

+    }

+

+    static class ListEntity implements Entity {

+

+        String mKey;

+        Template mSubTemplate;

+

+        public ListEntity(Context context, String key, String subTemplate) {

+            mKey = key;

+            mSubTemplate = new Template(context, subTemplate);

+        }

+

+        @Override

+        public void write(OutputStream stream, EntityData params) throws IOException {

+            ListEntityIterator iter = params.getListIterator(mKey);

+            iter.reset();

+            while (iter.moveToNext()) {

+                mSubTemplate.write(stream, iter);

+            }

+        }

+

+    }

+

+    public abstract static class CursorListEntityWrapper implements ListEntityIterator {

+

+        private Cursor mCursor;

+

+        public CursorListEntityWrapper(Cursor cursor) {

+            mCursor = cursor;

+        }

+

+        @Override

+        public boolean moveToNext() {

+            return mCursor.moveToNext();

+        }

+

+        @Override

+        public void reset() {

+            mCursor.moveToPosition(-1);

+        }

+

+        @Override

+        public ListEntityIterator getListIterator(String key) {

+            return null;

+        }

+

+        public Cursor getCursor() {

+            return mCursor;

+        }

+

+    }

+

+    static class HashMapEntityData implements EntityData {

+

+        HashMap<String, Object> mData;

+

+        public HashMapEntityData(HashMap<String, Object> map) {

+            mData = map;

+        }

+

+        @Override

+        public ListEntityIterator getListIterator(String key) {

+            return (ListEntityIterator) mData.get(key);

+        }

+

+        @Override

+        public void writeValue(OutputStream stream, String key) throws IOException {

+            stream.write((byte[]) mData.get(key));

+        }

+

+    }

+

+    private List<Entity> mTemplate;

+    private HashMap<String, Object> mData = new HashMap<String, Object>();

+    private Template(Context context, int tid) {

+        this(context, readRaw(context, tid));

+    }

+

+    private Template(Context context, String template) {

+        mTemplate = new ArrayList<Entity>();

+        template = replaceConsts(context, template);

+        parseTemplate(context, template);

+    }

+

+    private Template(Template copy) {

+        mTemplate = copy.mTemplate;

+    }

+

+    Template copy() {

+        return new Template(this);

+    }

+

+    void parseTemplate(Context context, String template) {

+        final Pattern pattern = Pattern.compile("<%([=\\{])\\s*(\\w+)\\s*%>");

+        Matcher m = pattern.matcher(template);

+        int start = 0;

+        while (m.find()) {

+            String static_part = template.substring(start, m.start());

+            if (static_part.length() > 0) {

+                mTemplate.add(new StringEntity(static_part));

+            }

+            String type = m.group(1);

+            String name = m.group(2);

+            if (type.equals("=")) {

+                mTemplate.add(new SimpleEntity(name));

+            } else if (type.equals("{")) {

+                Pattern p = Pattern.compile("<%\\}\\s*" + Pattern.quote(name) + "\\s*%>");

+                Matcher end_m = p.matcher(template);

+                if (end_m.find(m.end())) {

+                    start = m.end();

+                    m.region(end_m.end(), template.length());

+                    String subTemplate = template.substring(start, end_m.start());

+                    mTemplate.add(new ListEntity(context, name, subTemplate));

+                    start = end_m.end();

+                    continue;

+                }

+            }

+            start = m.end();

+        }

+        String static_part = template.substring(start, template.length());

+        if (static_part.length() > 0) {

+            mTemplate.add(new StringEntity(static_part));

+        }

+    }

+

+    public void assign(String name, String value) {

+        mData.put(name, value.getBytes());

+    }

+

+    public void assignLoop(String name, ListEntityIterator iter) {

+        mData.put(name, iter);

+    }

+

+    public void write(OutputStream stream) throws IOException {

+        write(stream, new HashMapEntityData(mData));

+    }

+

+    public void write(OutputStream stream, EntityData data) throws IOException {

+        for (Entity ent : mTemplate) {

+            ent.write(stream, data);

+        }

+    }

+

+    private static String replaceConsts(Context context, String template) {

+        final Pattern pattern = Pattern.compile("<%@\\s*(\\w+/\\w+)\\s*%>");

+        final Resources res = context.getResources();

+        final String packageName = context.getPackageName();

+        Matcher m = pattern.matcher(template);

+        StringBuffer sb = new StringBuffer();

+        while (m.find()) {

+            String name = m.group(1);

+            if (name.startsWith("drawable/")) {

+                m.appendReplacement(sb, "res/" + name);

+            } else {

+                int id = res.getIdentifier(name, null, packageName);

+                if (id != 0) {

+                    TypedValue value = new TypedValue();

+                    res.getValue(id, value, true);

+                    String replacement;

+                    if (value.type == TypedValue.TYPE_DIMENSION) {

+                        float dimen = res.getDimension(id);

+                        int dimeni = (int) dimen;

+                        if (dimeni == dimen)

+                            replacement = Integer.toString(dimeni);

+                        else

+                            replacement = Float.toString(dimen);

+                    } else {

+                        replacement = value.coerceToString().toString();

+                    }

+                    m.appendReplacement(sb, replacement);

+                }

+            }

+        }

+        m.appendTail(sb);

+        return sb.toString();

+    }

+

+    private static String readRaw(Context context, int id) {

+        InputStream ins = context.getResources().openRawResource(id);

+        try {

+            byte[] buf = new byte[ins.available()];

+            ins.read(buf);

+            return new String(buf, "utf-8");

+        } catch (IOException ex) {

+            return "<html><body>Error</body></html>";

+        }

+    }

+

+}

diff --git a/src/com/android/browser/provider/BrowserProvider2.java b/src/com/android/browser/provider/BrowserProvider2.java
index 919a135..ff00c56 100644
--- a/src/com/android/browser/provider/BrowserProvider2.java
+++ b/src/com/android/browser/provider/BrowserProvider2.java
@@ -402,6 +402,7 @@
 
         @Override
         public void onOpen(SQLiteDatabase db) {
+            db.enableWriteAheadLogging();
             mSyncHelper.onDatabaseOpened(db);
         }
 
@@ -478,6 +479,9 @@
         }
 
         private byte[] readRaw(Resources res, int id) throws IOException {
+            if (id == 0) {
+                return null;
+            }
             InputStream is = res.openRawResource(id);
             try {
                 ByteArrayOutputStream bos = new ByteArrayOutputStream();