am 457ac4aa: Update Portuguese translations.

Merge commit '457ac4aa9e0a08f60641d88c170a1da47bcc23c6'

* commit '457ac4aa9e0a08f60641d88c170a1da47bcc23c6':
  Update Portuguese translations.
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 0cc9538..3000143 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -168,6 +168,11 @@
                   android:theme="@android:style/Theme.Dialog">
         </activity>
 
+        <activity android:name="PermissionDialog"
+                  android:configChanges="orientation|keyboardHidden"
+                  android:theme="@android:style/Theme.Dialog">
+        </activity>
+
         <activity android:name="GearsNativeDialog"
                   android:configChanges="orientation|keyboardHidden"
                   android:theme="@android:style/Theme.Dialog">
diff --git a/res/drawable/background_titlebar.png b/res/drawable/background_titlebar.png
new file mode 100644
index 0000000..1fdb078
--- /dev/null
+++ b/res/drawable/background_titlebar.png
Binary files differ
diff --git a/res/drawable/button_line.xml b/res/drawable/button_line.xml
new file mode 100644
index 0000000..67869d0
--- /dev/null
+++ b/res/drawable/button_line.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 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.
+-->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+    <item>
+        <shape android:width="2dip">
+            <solid android:color="#ff000000"/>
+        </shape>
+    </item>
+    <item android:left="1dip" android:width="1dip">
+        <shape>
+            <solid android:color="#ffffffff"/>
+        </shape>
+    </item>
+</layer-list>
diff --git a/res/drawable/ic_titlebar_zoom.png b/res/drawable/ic_titlebar_zoom.png
new file mode 100644
index 0000000..b497dab
--- /dev/null
+++ b/res/drawable/ic_titlebar_zoom.png
Binary files differ
diff --git a/res/drawable/ic_titlebar_zoom_out.png b/res/drawable/ic_titlebar_zoom_out.png
new file mode 100644
index 0000000..4b5a3dd
--- /dev/null
+++ b/res/drawable/ic_titlebar_zoom_out.png
Binary files differ
diff --git a/res/layout/browser_downloads_page.xml b/res/layout/browser_downloads_page.xml
index c83a727..1d4d4e6 100644
--- a/res/layout/browser_downloads_page.xml
+++ b/res/layout/browser_downloads_page.xml
@@ -18,8 +18,14 @@
 ** limitations under the License.
 */
 -->
-
-<ListView xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/list"
-    android:layout_width="fill_parent"
-    android:layout_height="fill_parent"/>
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+    <ListView 
+        android:id="@+id/list"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent"/>
+    <ViewStub 
+        android:id="@+id/empty"
+        android:layout="@layout/no_downloads"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent"/>
+</merge>
diff --git a/res/layout/custom_screen.xml b/res/layout/custom_screen.xml
new file mode 100644
index 0000000..95c8434
--- /dev/null
+++ b/res/layout/custom_screen.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 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:orientation="vertical"
+    >
+    <com.android.browser.TitleBar android:id="@+id/title_bar"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        />
+    <FrameLayout android:id="@+id/main_content"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent"
+        android:foreground="?android:attr/windowContentOverlay"
+        />
+</LinearLayout>
\ No newline at end of file
diff --git a/res/layout/permission_dialog.xml b/res/layout/permission_dialog.xml
new file mode 100644
index 0000000..ff24eaf
--- /dev/null
+++ b/res/layout/permission_dialog.xml
@@ -0,0 +1,158 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright 2009, 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:drawingCacheQuality="auto"
+  android:layout_width="fill_parent"
+  android:layout_height="wrap_content"
+  android:orientation="vertical"
+  android:padding="0dip">
+
+  <LinearLayout
+    android:layout_width="fill_parent"
+    android:layout_height="wrap_content"
+    android:orientation="horizontal"
+    android:padding="10dip">
+
+    <ImageView
+      android:id="@+id/icon"
+      android:paddingRight="10dip"
+      android:layout_width="wrap_content"
+      android:layout_height="wrap_content"
+      android:layout_centerHorizontal="true"/>
+
+    <TextView
+      android:id="@+id/dialog_title"
+      android:layout_width="wrap_content"
+      android:layout_height="wrap_content"
+      android:layout_centerVertical="true"
+      android:gravity="center_vertical"
+      android:visibility="gone"
+      android:textSize="16dip"
+      android:textStyle="bold"
+      android:textColor="@color/white"/>
+
+  </LinearLayout>
+
+  <LinearLayout
+    android:layout_width="fill_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical">
+
+    <ImageView android:id="@+id/titleDivider"
+        android:layout_width="fill_parent"
+        android:layout_height="1dip"
+        android:scaleType="fitXY"
+        android:gravity="fill_horizontal"
+        android:src="@drawable/dialog_divider_horizontal_light"
+        android:layout_marginLeft="10dip"
+        android:layout_marginRight="10dip"/>
+
+  </LinearLayout>
+
+  <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="wrap_content"
+    android:paddingBottom="10dip"
+    android:layout_weight="1">
+
+    <LinearLayout
+      android:orientation="vertical"
+      android:layout_width="fill_parent"
+      android:paddingTop="10dip"
+      android:paddingLeft="10dip"
+      android:paddingRight="10dip"
+      android:layout_height="wrap_content">
+
+      <TextView
+        android:id="@+id/origin"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:visibility="gone"
+        android:textStyle="bold"
+        android:gravity="left"
+        android:textSize="16dip"
+        android:textColor="@color/white"/>
+
+      <TextView
+        android:id="@+id/dialog_message"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:paddingLeft="4dip"
+        android:paddingTop="10dip"
+        android:gravity="left"
+        android:textSize="16dip"
+        android:textColor="@color/white"/>
+
+    </LinearLayout>
+
+  </ScrollView>
+
+  <LinearLayout
+    android:layout_width="fill_parent"
+    android:background="@color/gray"
+    android:layout_height="wrap_content"
+    android:paddingTop="4dip"
+    android:paddingLeft="0dip"
+    android:paddingRight="0dip">
+
+    <LinearLayout android:id="@+id/leftSpacer"
+       android:layout_weight="0.25"
+       android:layout_width="0dip"
+       android:layout_height="wrap_content"
+       android:orientation="horizontal"
+       android:visibility="gone"/>
+
+    <Button
+      android:id="@+id/button_allow"
+      android:layout_width="96dip"
+      android:layout_height="48dip"
+      android:layout_gravity="left"
+      android:layout_weight="1"
+      android:maxLines="2"
+      android:textSize="13dip"/>
+
+    <Button
+      android:id="@+id/button_alwaysdeny"
+      android:layout_width="96dip"
+      android:layout_height="48dip"
+      android:layout_gravity="left"
+      android:layout_weight="1"
+      android:maxLines="2"
+      android:textSize="13dip"/>
+
+    <Button
+      android:id="@+id/button_deny"
+      android:layout_width="96dip"
+      android:layout_height="48dip"
+      android:layout_gravity="right"
+      android:layout_weight="1"
+      android:maxLines="2"
+      android:textSize="13dip"/>
+
+    <LinearLayout android:id="@+id/rightSpacer"
+      android:layout_width="0dip"
+      android:layout_weight="0.25"
+      android:layout_height="wrap_content"
+      android:orientation="horizontal"
+      android:visibility="gone" />
+
+  </LinearLayout>
+
+</LinearLayout>
diff --git a/res/layout/title_bar.xml b/res/layout/title_bar.xml
new file mode 100644
index 0000000..0f70519
--- /dev/null
+++ b/res/layout/title_bar.xml
@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 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:fitsSystemWindows="true"
+    android:orientation="horizontal"
+    android:layout_width="fill_parent"
+    android:background="@drawable/background_titlebar"
+    android:layout_height="45dip">
+    <ImageView android:id="@+id/favicon"
+        android:layout_height="20dip"
+        android:layout_width="20dip"
+        android:layout_marginLeft="6dip"
+        android:layout_marginRight="6dip"
+        android:layout_gravity="center_vertical"
+        />
+    <!-- layout which contains the title, progress bar, and url -->
+    <LinearLayout
+        android:orientation="vertical"
+        android:layout_width="0dip"
+        android:layout_weight="1"
+        android:layout_height="wrap_content">
+        <!-- This part contains the favicon and the progress bar -->
+        <RelativeLayout
+            android:layout_marginTop="3dip"
+            android:layout_height="wrap_content"
+            android:layout_width="fill_parent"
+            >
+            <LinearLayout
+                android:orientation="horizontal"
+                android:layout_marginTop="3dip"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content">
+                <ProgressBar android:id="@+id/progress_horizontal"
+                    style="?android:attr/progressBarStyleHorizontal"
+                    android:layout_width="0dip"
+                    android:layout_weight="1"
+                    android:layout_height="wrap_content"
+                    android:max="100" />
+                <ProgressBar android:id="@+id/progress_circular"
+                    style="?android:attr/progressBarStyleSmallTitle"
+                    android:layout_marginLeft="3dip"
+                    android:layout_gravity="center_vertical"
+                    android:max="100"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content" />
+            </LinearLayout>
+            <!-- need to make this no wider than the horizontal progress bar -->
+            <TextView android:id="@+id/title"
+                android:layout_height="wrap_content"
+                android:layout_width="wrap_content"
+                android:layout_marginLeft="6dip"
+                android:layout_marginTop="4dip"
+                android:textSize="14dip"
+                android:textColor="@color/white"
+                android:textStyle="bold"
+                android:singleLine="true"
+                />
+            <TextView android:id="@+id/url"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="6dip"
+                android:layout_below="@id/title"
+                android:textSize="12dip"
+                android:textColor="@color/white"
+                android:singleLine="true"
+                />
+            <ImageView android:id="@+id/lock_icon"
+                android:layout_height="wrap_content"
+                android:layout_width="wrap_content"
+                android:layout_alignBottom="@id/title"
+                android:layout_alignParentRight="true"
+                android:visibility="gone"/>
+        </RelativeLayout>
+    </LinearLayout>
+    <!-- These buttons will change look/functionality -->
+    <ImageView android:id="@+id/lft_button"
+        android:layout_width="52dip"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical"
+        android:src="@android:drawable/btn_star"/>
+    <!-- divider -->
+    <View android:id="@+id/divider"
+        android:layout_height="fill_parent"
+        android:layout_width="2dip"
+        android:background="@drawable/button_line"/>
+    <ImageView android:id="@+id/rt_button"
+        android:layout_width="52dip"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical"
+        android:src="@*android:drawable/btn_browser_zoom_page_overview"/>
+</LinearLayout>
diff --git a/res/menu/bookmarkscontext.xml b/res/menu/bookmarkscontext.xml
index b43e242..ba5d1dc 100644
--- a/res/menu/bookmarkscontext.xml
+++ b/res/menu/bookmarkscontext.xml
@@ -34,5 +34,7 @@
       android:title="@string/contextmenu_copylink"/>
     <item android:id="@+id/delete_context_menu_id"
       android:title="@string/remove_bookmark"/>
+    <item android:id="@+id/homepage_context_menu_id"
+      android:title="@string/set_as_homepage"/>
   </group>
 </menu>
diff --git a/res/menu/historycontext.xml b/res/menu/historycontext.xml
index dfda010..5306396 100644
--- a/res/menu/historycontext.xml
+++ b/res/menu/historycontext.xml
@@ -26,5 +26,7 @@
     <item android:id="@+id/copy_context_menu_id"
         android:title="@string/contextmenu_copylink"/> 
     <item android:id="@+id/delete_context_menu_id"
-        android:title="@string/remove_history_item"/> 
+        android:title="@string/remove_history_item"/>
+    <item android:id="@+id/homepage_context_menu_id"
+        android:title="@string/set_as_homepage"/>
 </menu>
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
new file mode 100644
index 0000000..219cc6b
--- /dev/null
+++ b/res/values/arrays.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2009 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.
+  -->
+<resources>
+   <string-array name="webstorage_quota_entries">
+      <item>No quota allowed</item>
+      <item>5 MB</item>
+      <item>10 MB</item>
+      <item>30 MB</item>
+      <item>100 MB</item>
+   </string-array>
+   <string-array name="webstorage_quota_entries_values">
+      <item>0</item>
+      <item>5</item>
+      <item>10</item>
+      <item>30</item>
+      <item>100</item>
+   </string-array>
+</resources>
+
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 253efc1..8440314 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -58,7 +58,10 @@
         <!-- Case of several matches -->
         <item quantity="other"><xliff:g id="number" example="137">%d</xliff:g> matches</item>
     </plurals>
-    
+
+    <!-- Displayed on the title bar while the page is loading -->
+    <string name="title_bar_loading">Loading\u2026</string>
+
     <!-- Menu item -->
     <string name="page_info">Page info</string>
     <!-- Label for a button on an SSL error dialog that allows the user to see
@@ -143,8 +146,12 @@
     <string name="remove_bookmark">Delete bookmark</string>
     <!-- Menu item to remove the currently highlighted history entry from the list of previously visited sites -->
     <string name="remove_history_item">Remove from history</string>
+    <!-- Context menu item for setting the bookmark/history item as the homepage -->
+    <string name="set_as_homepage">Set as homepage</string>
     <!-- Toast informing the user that their action to save a bookmark has succeeded -->
     <string name="bookmark_saved">Saved to bookmarks.</string>
+    <!-- Toast confirming that the homepage has been set -->
+    <string name="homepage_set">Homepage set</string>
     <!-- Error that appears in the title of Bookmark dialog when user selects OK with empty Name field -->
     <string name="bookmark_needs_title">"Bookmark must have a name."</string>
         <!-- Error that appears in the title of Bookmark dialog when user selects OK with empty Location field -->
@@ -284,6 +291,10 @@
     <string name="pref_content_autofit">Auto-fit pages</string>
     <!-- Settings summary -->
     <string name="pref_content_autofit_summary">Format Web pages to fit the screen</string>
+    <!-- Settings label for enabling a mode where the browser is always set to landscape mode -->
+    <string name="pref_content_landscape_only">Landscape only display</string>
+    <!-- Settings summary -->
+    <string name="pref_content_landscape_only_summary">Always read pages in the wider, landscape screen orientation</string>
     <!-- Settings screen, section title -->
     <string name="pref_privacy_title">Privacy settings</string>
     <!-- Settings label -->
@@ -361,6 +372,31 @@
     <!-- Settings summary -->
     <string name="pref_extras_gears_enable_summary">Applications that extend browser functionality</string>
     <!-- Settings label -->
+    <string name="pref_extras_webstorage_settings">Local Storage</string>
+    <!-- Settings summary -->
+    <string name="pref_extras_webstorage_settings_summary">Allow websites to store information on your phone</string>
+    <!-- Settings label -->
+    <string name="pref_extras_webstorage_enable">Enable Database Storage</string>
+    <!-- Settings summary -->
+    <string name="pref_extras_webstorage_enable_summary">Allow websites to store informatin in a local database</string>
+    <!-- Settings label -->
+    <string name="pref_extras_webstorage_set_location">Set Databases Location</string>
+    <!-- Settings summary -->
+    <string name="pref_extras_webstorage_set_location_summary">Define where the databases are stored</string>
+    <!-- Settings label -->
+    <string name="pref_extras_webstorage_set_quota">Set Default Quota</string>
+    <!-- Settings summary -->
+    <string name="pref_extras_webstorage_set_quota_summary">The amount of storage new websites can use without your permission</string>
+    <!-- Settings label -->
+    <string name="pref_extras_webstorage_manage_databases">Manage Databases</string>
+    <!-- Settings summary -->
+    <string name="pref_extras_webstorage_manage_databases_summary">Configure existing databases</string>
+    <!-- Settings label -->
+    <string name="pref_extras_webstorage_clear_databases">Clear All Existing Databases</string>
+    <!-- Settings summary -->
+    <string name="pref_extras_webstorage_clear_databases_summary">Clear all data stored in local databases</string>
+    <string name="pref_extras_webstorage_clear_databases_dlg">All existing databases will be cleared</string>
+    <!-- Settings label -->
     <string name="pref_extras_gears_settings">Gears settings</string>
     <!-- Settings summary -->
     <string name="pref_plugin_installed">Plugins list</string>
@@ -657,6 +693,9 @@
     <!-- Gears Dialogs -->
     <string name="query_data_prompt">Allow storage</string>
     <string name="query_data_message">This web site would like to store information on your phone.</string>
+    <string name="query_storage_quota_prompt">Increase storage quota</string>
+    <string name="query_storage_quota_message">This web site is over its current
+      storage limit. Would you like to increase its quota limit ?</string>
     <string name="location_prompt">Access your location</string>
     <string name="location_message">This web site would like to have access to your location.</string>
     <string name="shortcut_prompt">Create a shortcut</string>
@@ -713,6 +752,22 @@
     <string name="unrecognized_dialog_message">Unrecognized dialog type</string>
     <string name="default_button">OK</string>
 
+    <!-- HTML5 dialogs -->
+    <!-- Used as a toast notification after the user close the html5 webstorage permission dialog -->
+    <string name="webstorage_notification">The quota for this site can be changed in the Local Storage section of the Browser settings</string>
+    <!-- Used in the Browser Settings -->
+    <string name="webstorage_manage_quota_title">Manage Quota</string>
+    <string name="webstorage_manage_quota_summary">Set a new size quota</string>
+    <string name="webstorage_clear_data_title">Clear All Data</string>
+    <string name="webstorage_clear_data_summary">Remove all databases associated with this website</string>
+    <!-- Confirmation dialog when the user ask to clear all data for an origin -->
+    <string name="webstorage_clear_data_dialog_title">Clear All Data</string>
+    <string name="webstorage_clear_data_dialog_message">All stored data by this origin will be deleted</string>
+    <!-- Strings used in the summary of origins -->
+    <string name="webstorage_origin_summary_mb_used">MB used</string>
+    <string name="webstorage_origin_summary_no_quota_left">no allowed quota left</string>
+    <string name="webstorage_origin_summary_mb_left">MB left in the quota</string>
+
     <!-- Zoom-related strings --><skip />
     <!-- Caption for a button that is shown when the zoom widget is showing.  The button's action will switch to the zoom overview mode. -->
     <string name="zoom_overview_button_text">Overview</string>
diff --git a/res/xml/browser_preferences.xml b/res/xml/browser_preferences.xml
index fdfa839..c5b6b24 100644
--- a/res/xml/browser_preferences.xml
+++ b/res/xml/browser_preferences.xml
@@ -54,6 +54,12 @@
                 android:summary="@string/pref_content_autofit_summary" />  
 
         <CheckBoxPreference
+                android:key="landscape_only"
+                android:defaultValue="false"
+                android:title="@string/pref_content_landscape_only"
+                android:summary="@string/pref_content_landscape_only_summary" />
+
+        <CheckBoxPreference
                 android:key="enable_javascript"
                 android:defaultValue="true"
                 android:title="@string/pref_content_javascript" />     
@@ -165,6 +171,42 @@
                     android:title="@string/pref_extras_gears_settings"
                     android:summary="@string/pref_extras_gears_settings_summary" />
 
+            <PreferenceScreen
+                    android:key="webstorage_settings"
+                    android:title="@string/pref_extras_webstorage_settings"
+                    android:summary="@string/pref_extras_webstorage_settings_summary">
+
+                  <CheckBoxPreference
+                        android:key="enable_database"
+                        android:defaultValue="true"
+                        android:title="@string/pref_extras_webstorage_enable"
+                        android:summary="@string/pref_extras_webstorage_enable_summary" />
+
+                  <ListPreference
+                        android:key="webstorage_default_quota"
+                        android:dependency="enable_database"
+                        android:title="@string/pref_extras_webstorage_set_quota"
+                        android:summary="@string/pref_extras_webstorage_set_quota_summary"
+                        android:entries="@array/webstorage_quota_entries"
+                        android:entryValues="@array/webstorage_quota_entries_values" />
+
+                  <PreferenceScreen
+                        android:key="webstorage_manage_databases"
+                        android:dependency="enable_database"
+                        android:title="@string/pref_extras_webstorage_manage_databases"
+                        android:summary="@string/pref_extras_webstorage_manage_databases_summary" />
+
+                  <com.android.browser.BrowserYesNoPreference
+                        android:key="webstorage_clear_databases"
+                        android:dependency="enable_database"
+                        android:title="@string/pref_extras_webstorage_clear_databases"
+                        android:summary="@string/pref_extras_webstorage_clear_databases_summary"
+                        android:dialogMessage="@string/pref_extras_webstorage_clear_databases_dlg"
+                        android:dialogTitle="@string/clear"
+                        android:dialogIcon="@android:drawable/ic_dialog_alert" />
+
+            </PreferenceScreen>
+
             <com.android.browser.BrowserYesNoPreference
                     android:key="reset_default_preferences"
                     android:title="@string/pref_extras_reset_default"
diff --git a/src/com/android/browser/AddBookmarkPage.java b/src/com/android/browser/AddBookmarkPage.java
index cf3fe70..74efdb8 100644
--- a/src/com/android/browser/AddBookmarkPage.java
+++ b/src/com/android/browser/AddBookmarkPage.java
@@ -48,9 +48,11 @@
     private Bundle      mMap;
     
     private static final String[]   mProjection = 
-        { "_id", "url", "bookmark", "created", "title", "visits" };
-    private static final String     WHERE_CLAUSE = "url = ?";
-    private final String[]          SELECTION_ARGS = new String[1];
+            { "_id", "url", "bookmark", "created", "title", "visits" };
+    private static final String     WHERE_CLAUSE
+            = "url = ? OR url = ? OR url = ? OR url = ?";
+    private static final String     WHERE_CLAUSE_SECURE = "url = ? OR url = ?";
+    private String[]                SELECTION_ARGS;
 
     private View.OnClickListener mSaveBookmark = new View.OnClickListener() {
         public void onClick(View v) {
@@ -153,11 +155,36 @@
             } else {
                 // Want to append to the beginning of the list
                 long creationTime = new Date().getTime();
-                SELECTION_ARGS[0] = url;
+                // First we check to see if the user has already visited this
+                // site.  They may have bookmarked it in a different way from
+                // how it's stored in the database, so allow different combos
+                // to map to the same url.
+                boolean secure = false;
+                String compareString = url;
+                if (compareString.startsWith("http://")) {
+                    compareString = compareString.substring(7);
+                } else if (compareString.startsWith("https://")) {
+                    compareString = compareString.substring(8);
+                    secure = true;
+                }
+                if (compareString.startsWith("www.")) {
+                    compareString = compareString.substring(4);
+                }
+                if (secure) {
+                    SELECTION_ARGS = new String[2];
+                    SELECTION_ARGS[0] = "https://" + compareString;
+                    SELECTION_ARGS[1] = "https://www." + compareString;
+                } else {
+                    SELECTION_ARGS = new String[4];
+                    SELECTION_ARGS[0] = compareString;
+                    SELECTION_ARGS[1] = "www." + compareString;
+                    SELECTION_ARGS[2] = "http://" + compareString;
+                    SELECTION_ARGS[3] = "http://" + SELECTION_ARGS[1];
+                }
                 ContentResolver cr = getContentResolver();
                 Cursor c = cr.query(Browser.BOOKMARKS_URI,
                         mProjection,
-                        WHERE_CLAUSE,
+                        secure ? WHERE_CLAUSE_SECURE : WHERE_CLAUSE,
                         SELECTION_ARGS,
                         null);
                 ContentValues map = new ContentValues();
@@ -186,6 +213,7 @@
                             cr.update(Browser.BOOKMARKS_URI, map, 
                                     "_id = " + c.getInt(0), null);
                             matchedTitle = true;
+                            break;
                         }
                     }
                     if (!matchedTitle) {
diff --git a/src/com/android/browser/BrowserActivity.java b/src/com/android/browser/BrowserActivity.java
index 3252da3..1966b8b 100644
--- a/src/com/android/browser/BrowserActivity.java
+++ b/src/com/android/browser/BrowserActivity.java
@@ -36,6 +36,7 @@
 import android.content.IntentFilter;
 import android.content.ServiceConnection;
 import android.content.DialogInterface.OnCancelListener;
+import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.res.AssetManager;
@@ -57,6 +58,8 @@
 import android.graphics.drawable.PaintDrawable;
 import android.hardware.SensorListener;
 import android.hardware.SensorManager;
+import android.location.Location;
+import android.location.LocationManager;
 import android.net.ConnectivityManager;
 import android.net.Uri;
 import android.net.WebAddress;
@@ -81,6 +84,7 @@
 import android.provider.Contacts;
 import android.provider.Downloads;
 import android.provider.MediaStore;
+import android.provider.Settings;
 import android.provider.Contacts.Intents.Insert;
 import android.text.IClipboard;
 import android.text.TextUtils;
@@ -110,11 +114,13 @@
 import android.webkit.CookieSyncManager;
 import android.webkit.DownloadListener;
 import android.webkit.HttpAuthHandler;
+import android.webkit.PluginManager;
 import android.webkit.SslErrorHandler;
 import android.webkit.URLUtil;
 import android.webkit.WebChromeClient;
 import android.webkit.WebHistoryItem;
 import android.webkit.WebIconDatabase;
+import android.webkit.WebStorage;
 import android.webkit.WebView;
 import android.webkit.WebViewClient;
 import android.widget.EditText;
@@ -162,6 +168,8 @@
 
     private SensorManager mSensorManager = null;
 
+    private WebStorage.QuotaUpdater mWebStorageQuotaUpdater = null;
+
     // These are single-character shortcuts for searching popular sources.
     private static final int SHORTCUT_INVALID = 0;
     private static final int SHORTCUT_GOOGLE_SEARCH = 1;
@@ -586,11 +594,6 @@
                 }
 
                 copyBuildInfos();
-
-                // Refresh the plugin list.
-                if (mTabControl.getCurrentWebView() != null) {
-                    mTabControl.getCurrentWebView().refreshPlugins(false);
-                }
             } catch (IOException e) {
                 Log.e(TAG, "IO Exception: " + e);
             }
@@ -637,16 +640,22 @@
         }
     }
 
+    // Flag to enable the touchable browser bar with buttons
+    private final boolean CUSTOM_BROWSER_BAR = true;
+
     @Override public void onCreate(Bundle icicle) {
         if (LOGV_ENABLED) {
             Log.v(LOGTAG, this + " onStart");
         }
         super.onCreate(icicle);
-        this.requestWindowFeature(Window.FEATURE_LEFT_ICON);
-        this.requestWindowFeature(Window.FEATURE_RIGHT_ICON);
-        this.requestWindowFeature(Window.FEATURE_PROGRESS);
-        this.requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
-
+        if (CUSTOM_BROWSER_BAR) {
+            this.requestWindowFeature(Window.FEATURE_NO_TITLE);
+        } else {
+            this.requestWindowFeature(Window.FEATURE_LEFT_ICON);
+            this.requestWindowFeature(Window.FEATURE_RIGHT_ICON);
+            this.requestWindowFeature(Window.FEATURE_PROGRESS);
+            this.requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
+        }
         // test the browser in OpenGL
         // requestWindowFeature(Window.FEATURE_OPENGL);
 
@@ -674,8 +683,21 @@
         mGenericFavicon = getResources().getDrawable(
                 R.drawable.app_web_browser_sm);
 
-        mContentView = (FrameLayout) getWindow().getDecorView().findViewById(
-                com.android.internal.R.id.content);
+        FrameLayout frameLayout = (FrameLayout) getWindow().getDecorView()
+                .findViewById(com.android.internal.R.id.content);
+        if (CUSTOM_BROWSER_BAR) {
+            // This LinearLayout will hold the title bar and a FrameLayout, which
+            // holds everything else.
+            LinearLayout linearLayout = (LinearLayout) LayoutInflater.from(this)
+                    .inflate(R.layout.custom_screen, null);
+            mTitleBar = (TitleBar) linearLayout.findViewById(R.id.title_bar);
+            mTitleBar.setBrowserActivity(this);
+            mContentView = (FrameLayout) linearLayout.findViewById(
+                    R.id.main_content);
+            frameLayout.addView(linearLayout, COVER_SCREEN_PARAMS);
+        } else {
+            mContentView = frameLayout;
+        }
 
         // Create the tab control and our initial tab
         mTabControl = new TabControl(this);
@@ -741,7 +763,12 @@
                     waitForCredentials();
                 }
             } else {
-                webView.loadUrl(url);
+                byte[] postData = getLocationData(intent);
+                if (postData != null) {
+                    webView.postUrl(url, postData);
+                } else {
+                    webView.loadUrl(url);
+                }
             }
         } else {
             // TabControl.restoreState() will create a new tab even if
@@ -766,6 +793,52 @@
                     }
                 }
             };
+
+        IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
+        filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+        filter.addDataScheme("package");
+        mPackageInstallationReceiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                final String action = intent.getAction();
+                final String packageName = intent.getData()
+                        .getSchemeSpecificPart();
+                final boolean replacing = intent.getBooleanExtra(
+                        Intent.EXTRA_REPLACING, false);
+                if (Intent.ACTION_PACKAGE_REMOVED.equals(action) && replacing) {
+                    // if it is replacing, refreshPlugins() when adding
+                    return;
+                }
+                PackageManager pm = BrowserActivity.this.getPackageManager();
+                PackageInfo pkgInfo = null;
+                try {
+                    pkgInfo = pm.getPackageInfo(packageName,
+                            PackageManager.GET_PERMISSIONS);
+                } catch (PackageManager.NameNotFoundException e) {
+                    return;
+                }
+                if (pkgInfo != null) {
+                    String permissions[] = pkgInfo.requestedPermissions;
+                    if (permissions == null) {
+                        return;
+                    }
+                    boolean permissionOk = false;
+                    for (String permit : permissions) {
+                        if (PluginManager.PLUGIN_PERMISSION.equals(permit)) {
+                            permissionOk = true;
+                            break;
+                        }
+                    }
+                    if (permissionOk) {
+                        PluginManager.getInstance(BrowserActivity.this)
+                                .refreshPlugins(
+                                        Intent.ACTION_PACKAGE_ADDED
+                                                .equals(action));
+                    }
+                }
+            }
+        };
+        registerReceiver(mPackageInstallationReceiver, filter);
     }
 
     @Override
@@ -827,8 +900,8 @@
                     } else {
                         if (mTabOverview != null && mAnimationCount == 0) {
                             sendAnimateFromOverview(appTab, false,
-                                    needsLoad ? url : null, TAB_OVERVIEW_DELAY,
-                                    null);
+                                    needsLoad ? url : null, null,
+                                    TAB_OVERVIEW_DELAY, null);
                         } else {
                             // If the tab was the current tab, we have to attach
                             // it to the view system again.
@@ -850,15 +923,20 @@
                     mSettings.toggleDebugSettings();
                     return;
                 }
+                byte[] postData = getLocationData(intent);
                 // If the Window overview is up and we are not in the midst of
                 // an animation, animate away from the Window overview.
                 if (mTabOverview != null && mAnimationCount == 0) {
                     sendAnimateFromOverview(current, false, url,
-                            TAB_OVERVIEW_DELAY, null);
+                            postData, TAB_OVERVIEW_DELAY, null);
                 } else {
                     // Get rid of the subwindow if it exists
                     dismissSubWindow(current);
-                    current.getWebView().loadUrl(url);
+                    if (postData != null) {
+                        current.getWebView().postUrl(url, postData);
+                    } else {
+                        current.getWebView().loadUrl(url);
+                    }
                 }
             }
         }
@@ -976,6 +1054,31 @@
         return url;
     }
 
+    byte[] getLocationData(Intent intent) {
+        byte[] postData = null;
+        if (intent != null) {
+            final String action = intent.getAction();
+            if ((Intent.ACTION_SEARCH.equals(action)
+                    || Intent.ACTION_WEB_SEARCH.equals(action))
+                    && Settings.Secure.isLocationProviderEnabled(
+                            getContentResolver(),
+                            LocationManager.NETWORK_PROVIDER)) {
+                // Attempt to get location info
+                LocationManager locationManager = (LocationManager)
+                        getSystemService(Context.LOCATION_SERVICE);
+                Location location = locationManager
+                        .getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
+                if (location != null) {
+                    StringBuilder str = new StringBuilder("sll=");
+                    str.append(location.getLatitude()).append(",").append(
+                            location.getLongitude());
+                    postData = str.toString().getBytes();
+                }
+            }
+        }
+        return postData;
+    }
+
     /* package */ static String fixUrl(String inUrl) {
         if (inUrl.startsWith("http://") || inUrl.startsWith("https://"))
             return inUrl;
@@ -1092,8 +1195,9 @@
             return;
         }
 
+        mTabControl.resumeCurrentTab();
         mActivityInPause = false;
-        resumeWebView();
+        resumeWebViewTimers();
 
         if (mWakeLock.isHeld()) {
             mHandler.removeMessages(RELEASE_WAKELOCK);
@@ -1151,8 +1255,9 @@
             return;
         }
 
+        mTabControl.pauseCurrentTab();
         mActivityInPause = true;
-        if (mTabControl.getCurrentIndex() >= 0 && !pauseWebView()) {
+        if (mTabControl.getCurrentIndex() >= 0 && !pauseWebViewTimers()) {
             mWakeLock.acquire();
             mHandler.sendMessageDelayed(mHandler
                     .obtainMessage(RELEASE_WAKELOCK), WAKELOCK_TIMEOUT);
@@ -1182,8 +1287,10 @@
         super.onDestroy();
         // Remove the current tab and sub window
         TabControl.Tab t = mTabControl.getCurrentTab();
-        dismissSubWindow(t);
-        removeTabFromContentView(t);
+        if (t != null) {
+            dismissSubWindow(t);
+            removeTabFromContentView(t);
+        }
         // Destroy all the tabs
         mTabControl.destroy();
         WebIconDatabase.getInstance().close();
@@ -1201,6 +1308,8 @@
         //        "com.android.masfproxyservice",
         //        "com.android.masfproxyservice.MasfProxyService"));
         //stopService(proxyServiceIntent);
+
+        unregisterReceiver(mPackageInstallationReceiver);
     }
 
     @Override
@@ -1249,7 +1358,7 @@
         mTabControl.freeMemory();
     }
 
-    private boolean resumeWebView() {
+    private boolean resumeWebViewTimers() {
         if ((!mActivityInPause && !mPageStarted) ||
                 (mActivityInPause && mPageStarted)) {
             CookieSyncManager.getInstance().startSync();
@@ -1263,7 +1372,7 @@
         }
     }
 
-    private boolean pauseWebView() {
+    private boolean pauseWebViewTimers() {
         if (mActivityInPause && !mPageStarted) {
             CookieSyncManager.getInstance().stopSync();
             WebView w = mTabControl.getCurrentWebView();
@@ -1895,8 +2004,8 @@
 
     // Send the ANIMTE_FROM_OVERVIEW message after changing the current tab.
     private void sendAnimateFromOverview(final TabControl.Tab tab,
-            final boolean newTab, final String url, final int delay,
-            final Message msg) {
+            final boolean newTab, final String url, final byte[] postData,
+            final int delay, final Message msg) {
         // Set the current tab.
         mTabControl.setCurrentTab(tab);
         // Attach the WebView so it will layout.
@@ -1921,7 +2030,11 @@
         // animation.
         if (url != null) {
             dismissSubWindow(tab);
-            tab.getWebView().loadUrl(url);
+            if (postData != null) {
+                tab.getWebView().postUrl(url, postData);
+            } else {
+                tab.getWebView().loadUrl(url);
+            }
         }
         map.put("msg", msg);
         mHandler.sendMessageDelayed(mHandler.obtainMessage(
@@ -1957,7 +2070,7 @@
             delay = TAB_ANIMATION_DURATION + TAB_OVERVIEW_DELAY;
             tabPicker(false, mTabControl.getTabIndex(t), false);
         }
-        sendAnimateFromOverview(t, false, url, delay, null);
+        sendAnimateFromOverview(t, false, url, null, delay, null);
     }
 
     // This method does a ton of stuff. It will attempt to create a new tab
@@ -1968,7 +2081,7 @@
     // the given Message. If the tab overview is already showing (i.e. this
     // method is called from TabListener.onClick(), the method will animate
     // away from the tab overview.
-    private void openTabAndShow(String url, final Message msg,
+    private TabControl.Tab openTabAndShow(String url, final Message msg,
             boolean closeOnExit, String appId) {
         final boolean newTab = mTabControl.getTabCount() != TabControl.MAX_TABS;
         final TabControl.Tab currentTab = mTabControl.getCurrentTab();
@@ -1997,15 +2110,16 @@
                 }
                 // Animate from the Tab overview after any animations have
                 // finished.
-                sendAnimateFromOverview(
-                        mTabControl.createNewTab(closeOnExit, appId, url), true,
-                        url, delay, msg);
+                final TabControl.Tab tab = mTabControl.createNewTab(
+                        closeOnExit, appId, url);
+                sendAnimateFromOverview(tab, true, url, null, delay, msg);
+                return tab;
             }
         } else if (url != null) {
             // We should not have a msg here.
             assert msg == null;
             if (mTabOverview != null && mAnimationCount == 0) {
-                sendAnimateFromOverview(currentTab, false, url,
+                sendAnimateFromOverview(currentTab, false, url, null,
                         TAB_OVERVIEW_DELAY, null);
             } else {
                 // Get rid of the subwindow if it exists
@@ -2014,6 +2128,7 @@
                 currentTab.getWebView().loadUrl(url);
             }
         }
+        return currentTab;
     }
 
     private Animation createTabAnimation(final AnimatingView view,
@@ -2233,14 +2348,15 @@
         mTabListener = null;
     }
 
-    private void openTab(String url) {
+    private TabControl.Tab openTab(String url) {
         if (mSettings.openInBackground()) {
             TabControl.Tab t = mTabControl.createNewTab();
             if (t != null) {
                 t.getWebView().loadUrl(url);
             }
+            return t;
         } else {
-            openTabAndShow(url, null, false, null);
+            return openTabAndShow(url, null, false, null);
         }
     }
 
@@ -2340,7 +2456,11 @@
         // While the tab overview is animating or being shown, block changes
         // to the title.
         if (mAnimationCount == 0 && mTabOverview == null) {
-            setTitle(buildUrlTitle(url, title));
+            if (CUSTOM_BROWSER_BAR) {
+                mTitleBar.setTitleAndUrl(title, url);
+            } else {
+                setTitle(buildUrlTitle(url, title));
+            }
         }
     }
 
@@ -2417,18 +2537,34 @@
         if (mAnimationCount > 0 || mTabOverview != null) {
             return;
         }
-        Drawable[] array = new Drawable[2];
-        PaintDrawable p = new PaintDrawable(Color.WHITE);
-        p.setCornerRadius(3f);
-        array[0] = p;
-        if (icon == null) {
-            array[1] = mGenericFavicon;
+        if (CUSTOM_BROWSER_BAR) {
+            Drawable[] array = new Drawable[3];
+            array[0] = new PaintDrawable(Color.BLACK);
+            PaintDrawable p = new PaintDrawable(Color.WHITE);
+            array[1] = p;
+            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);
+            mTitleBar.setFavicon(d);
         } else {
-            array[1] = new BitmapDrawable(icon);
+            Drawable[] array = new Drawable[2];
+            PaintDrawable p = new PaintDrawable(Color.WHITE);
+            p.setCornerRadius(3f);
+            array[0] = p;
+            if (icon == null) {
+                array[1] = mGenericFavicon;
+            } else {
+                array[1] = new BitmapDrawable(icon);
+            }
+            LayerDrawable d = new LayerDrawable(array);
+            d.setLayerInset(1, 2, 2, 2, 2);
+            getWindow().setFeatureDrawable(Window.FEATURE_LEFT_ICON, d);
         }
-        LayerDrawable d = new LayerDrawable(array);
-        d.setLayerInset(1, 2, 2, 2, 2);
-        getWindow().setFeatureDrawable(Window.FEATURE_LEFT_ICON, d);
     }
 
     /**
@@ -2464,7 +2600,7 @@
         // Change to the parent tab
         final TabControl.Tab tab = mTabControl.getTab(indexToShow);
         if (tab != null) {
-            sendAnimateFromOverview(tab, false, null, delay, null);
+            sendAnimateFromOverview(tab, false, null, null, delay, null);
         } else {
             // Increment this here so that no other animations can happen in
             // between the end of the tab picker transition and the beginning
@@ -2506,9 +2642,9 @@
                         finish();
                         return;
                     }
-                    // call pauseWebView() now, we won't be able to call it in
-                    // onPause() as the WebView won't be valid.
-                    pauseWebView();
+                    // call pauseWebViewTimers() now, we won't be able to call
+                    // it in onPause() as the WebView won't be valid.
+                    pauseWebViewTimers();
                     removeTabFromContentView(current);
                     mTabControl.removeTab(current);
                 }
@@ -2674,7 +2810,12 @@
                             loadURL(getTopWindow(), url);
                             break;
                         case R.id.open_newtab_context_menu_id:
-                            openTab(url);
+                            final TabControl.Tab parent = mTabControl
+                                    .getCurrentTab();
+                            final TabControl.Tab newTab = openTab(url);
+                            if (newTab != parent) {
+                                parent.addChildTab(newTab);
+                            }
                             break;
                         case R.id.bookmark_context_menu_id:
                             Intent intent = new Intent(BrowserActivity.this,
@@ -2799,8 +2940,9 @@
 
             if (!mPageStarted) {
                 mPageStarted = true;
-                // if onResume() has been called, resumeWebView() does nothing.
-                resumeWebView();
+                // if onResume() has been called, resumeWebViewTimers() does
+                // nothing.
+                resumeWebViewTimers();
             }
 
             // reset sync timer to avoid sync starts during loading a page
@@ -2921,9 +3063,9 @@
 
             if (mPageStarted) {
                 mPageStarted = false;
-                // pauseWebView() will do nothing and return false if onPause()
-                // is not called yet.
-                if (pauseWebView()) {
+                // pauseWebViewTimers() will do nothing and return false if
+                // onPause() is not called yet.
+                if (pauseWebViewTimers()) {
                     if (mWakeLock.isHeld()) {
                         mHandler.removeMessages(RELEASE_WAKELOCK);
                         mWakeLock.release();
@@ -3334,8 +3476,11 @@
                 // openTabAndShow will dispatch the message after creating the
                 // new WebView. This will prevent another request from coming
                 // in during the animation.
-                openTabAndShow(null, msg, false, null);
-                parent.addChildTab(mTabControl.getCurrentTab());
+                final TabControl.Tab newTab = openTabAndShow(null, msg, false,
+                        null);
+                if (newTab != parent) {
+                    parent.addChildTab(newTab);
+                }
                 WebView.WebViewTransport transport =
                         (WebView.WebViewTransport) msg.obj;
                 transport.setWebView(mTabControl.getCurrentWebView());
@@ -3441,8 +3586,13 @@
             // Block progress updates to the title bar while the tab overview
             // is animating or being displayed.
             if (mAnimationCount == 0 && mTabOverview == null) {
-                getWindow().setFeatureInt(Window.FEATURE_PROGRESS,
-                        newProgress * 100);
+                if (CUSTOM_BROWSER_BAR) {
+                    mTitleBar.setProgress(newProgress);
+                } else {
+                    getWindow().setFeatureInt(Window.FEATURE_PROGRESS,
+                            newProgress * 100);
+
+                }
             }
 
             if (newProgress == 100) {
@@ -3476,6 +3626,8 @@
                 url.length() >= SQLiteDatabase.SQLITE_MAX_LIKE_PATTERN_LENGTH) {
                 return;
             }
+            // See if we can find the current url in our history database and
+            // add the new title to it.
             if (url.startsWith("http://www.")) {
                 url = url.substring(11);
             } else if (url.startsWith("http://")) {
@@ -3490,15 +3642,12 @@
                 Cursor c = mResolver.query(Browser.BOOKMARKS_URI,
                     Browser.HISTORY_PROJECTION, where, selArgs, null);
                 if (c.moveToFirst()) {
-                    if (LOGV_ENABLED) {
-                        Log.v(LOGTAG, "updating cursor");
-                    }
                     // Current implementation of database only has one entry per
                     // url.
-                    int titleIndex =
-                            c.getColumnIndex(Browser.BookmarkColumns.TITLE);
-                    c.updateString(titleIndex, title);
-                    c.commitUpdates();
+                    ContentValues map = new ContentValues();
+                    map.put(Browser.BookmarkColumns.TITLE, title);
+                    mResolver.update(Browser.BOOKMARKS_URI, map,
+                            "_id = " + c.getInt(0), null);
                 }
                 c.close();
             } catch (IllegalStateException e) {
@@ -3512,6 +3661,50 @@
         public void onReceivedIcon(WebView view, Bitmap icon) {
             updateIcon(view.getUrl(), icon);
         }
+
+        /**
+         * The origin has exceeded it's database quota.
+         * @param url the URL that exceeded the quota
+         * @param databaseIdentifier the identifier of the database on
+         *     which the transaction that caused the quota overflow was run
+         * @param currentQuota the current quota for the origin.
+         * @param quotaUpdater The callback to run when a decision to allow or
+         *     deny quota has been made. Don't forget to call this!
+         */
+        @Override
+        public void onExceededDatabaseQuota(String url,
+            String databaseIdentifier, long currentQuota,
+            WebStorage.QuotaUpdater quotaUpdater) {
+            if(LOGV_ENABLED) {
+                Log.v(LOGTAG,
+                      "BrowserActivity received onExceededDatabaseQuota for "
+                      + url +
+                      ":"
+                      + databaseIdentifier +
+                      "(current quota: "
+                      + currentQuota +
+                      ")");
+            }
+            mWebStorageQuotaUpdater = quotaUpdater;
+            String DIALOG_PACKAGE = "com.android.browser";
+            String DIALOG_CLASS = DIALOG_PACKAGE + ".PermissionDialog";
+            Intent intent = new Intent();
+            intent.setClassName(DIALOG_PACKAGE, DIALOG_CLASS);
+            intent.putExtra(PermissionDialog.PARAM_ORIGIN, url);
+            intent.putExtra(PermissionDialog.PARAM_QUOTA, currentQuota);
+            startActivityForResult(intent, WEBSTORAGE_QUOTA_DIALOG);
+        }
+
+        /* Adds a JavaScript error message to the system log.
+         * @param message The error message to report.
+         * @param lineNumber The line number of the error.
+         * @param sourceID The name of the source file that caused the error.
+         */
+        @Override
+        public void addMessageToConsole(String message, int lineNumber, String sourceID) {
+            Log.w(LOGTAG, "Console: " + message + " (" + sourceID + ":" + lineNumber + ")");
+        }
+
     };
 
     /**
@@ -3627,19 +3820,19 @@
         String cookies = CookieManager.getInstance().getCookie(url);
 
         ContentValues values = new ContentValues();
-        values.put(Downloads.URI, uri.toString());
-        values.put(Downloads.COOKIE_DATA, cookies);
-        values.put(Downloads.USER_AGENT, userAgent);
-        values.put(Downloads.NOTIFICATION_PACKAGE,
+        values.put(Downloads.COLUMN_URI, uri.toString());
+        values.put(Downloads.COLUMN_COOKIE_DATA, cookies);
+        values.put(Downloads.COLUMN_USER_AGENT, userAgent);
+        values.put(Downloads.COLUMN_NOTIFICATION_PACKAGE,
                 getPackageName());
-        values.put(Downloads.NOTIFICATION_CLASS,
+        values.put(Downloads.COLUMN_NOTIFICATION_CLASS,
                 BrowserDownloadPage.class.getCanonicalName());
-        values.put(Downloads.VISIBILITY, Downloads.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
-        values.put(Downloads.MIMETYPE, mimetype);
-        values.put(Downloads.FILENAME_HINT, filename);
-        values.put(Downloads.DESCRIPTION, uri.getHost());
+        values.put(Downloads.COLUMN_VISIBILITY, Downloads.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
+        values.put(Downloads.COLUMN_MIME_TYPE, mimetype);
+        values.put(Downloads.COLUMN_FILE_NAME_HINT, filename);
+        values.put(Downloads.COLUMN_DESCRIPTION, uri.getHost());
         if (contentLength > 0) {
-            values.put(Downloads.TOTAL_BYTES, contentLength);
+            values.put(Downloads.COLUMN_TOTAL_BYTES, contentLength);
         }
         if (mimetype == null) {
             // We must have long pressed on a link or image to download it. We
@@ -3705,7 +3898,11 @@
         // If the tab overview is animating or being shown, do not update the
         // lock icon.
         if (mAnimationCount == 0 && mTabOverview == null) {
-            getWindow().setFeatureDrawable(Window.FEATURE_RIGHT_ICON, d);
+            if (CUSTOM_BROWSER_BAR) {
+                mTitleBar.setLock(d);
+            } else {
+                getWindow().setFeatureDrawable(Window.FEATURE_RIGHT_ICON, d);
+            }
         }
     }
 
@@ -4207,7 +4404,7 @@
                         // current tab.
                         if (mTabOverview != null && mAnimationCount == 0) {
                             sendAnimateFromOverview(currentTab, false, data,
-                                    TAB_OVERVIEW_DELAY, null);
+                                    null, TAB_OVERVIEW_DELAY, null);
                         } else {
                             dismissSubWindow(currentTab);
                             if (data != null && data.length() != 0) {
@@ -4217,6 +4414,14 @@
                     }
                 }
                 break;
+            case WEBSTORAGE_QUOTA_DIALOG:
+                long currentQuota = 0;
+                if (resultCode == RESULT_OK && intent != null) {
+                    currentQuota = intent.getLongExtra(
+                        PermissionDialog.PARAM_QUOTA, currentQuota);
+                }
+                mWebStorageQuotaUpdater.updateQuota(currentQuota);
+                break;
             default:
                 break;
         }
@@ -4258,7 +4463,8 @@
                 if (mTabControl.getTabCount() == 0) {
                     current = mTabControl.createNewTab();
                     sendAnimateFromOverview(current, true,
-                            mSettings.getHomePage(), TAB_OVERVIEW_DELAY, null);
+                            mSettings.getHomePage(), null, TAB_OVERVIEW_DELAY,
+                            null);
                 } else {
                     final int index = position > 0 ? (position - 1) : 0;
                     current = mTabControl.getTab(index);
@@ -4295,7 +4501,7 @@
                 openTabAndShow(mSettings.getHomePage(), null, false, null);
             } else {
                 sendAnimateFromOverview(mTabControl.getTab(index),
-                        false, null, 0, null);
+                        false, null, null, 0, null);
             }
         }
     }
@@ -4317,13 +4523,19 @@
         AnimatingView(Context ctxt, TabControl.Tab t) {
             super(ctxt);
             mTab = t;
-            // Use the top window in the animation since the tab overview will
-            // display the top window in each cell.
-            final WebView w = t.getTopWindow();
-            mPicture = w.capturePicture();
-            mScale = w.getScale() / w.getWidth();
-            mScrollX = w.getScrollX();
-            mScrollY = w.getScrollY();
+            if (t != null && t.getTopWindow() != null) {
+                // Use the top window in the animation since the tab overview
+                // will display the top window in each cell.
+                final WebView w = t.getTopWindow();
+                mPicture = w.capturePicture();
+                mScale = w.getScale() / w.getWidth();
+                mScrollX = w.getScrollX();
+                mScrollY = w.getScrollY();
+            } else {
+                mPicture = null;
+                mScale = 1.0f;
+                mScrollX = mScrollY = 0;
+            }
         }
 
         @Override
@@ -4397,16 +4609,20 @@
         mAnimationCount++;
         // Always change the title bar to the window overview title while
         // animating.
-        getWindow().setFeatureDrawable(Window.FEATURE_LEFT_ICON, null);
-        getWindow().setFeatureDrawable(Window.FEATURE_RIGHT_ICON, null);
-        getWindow().setFeatureInt(Window.FEATURE_PROGRESS,
-                Window.PROGRESS_VISIBILITY_OFF);
-        setTitle(R.string.tab_picker_title);
+        if (CUSTOM_BROWSER_BAR) {
+            mTitleBar.setToTabPicker();
+        } else {
+            getWindow().setFeatureDrawable(Window.FEATURE_LEFT_ICON, null);
+            getWindow().setFeatureDrawable(Window.FEATURE_RIGHT_ICON, null);
+            getWindow().setFeatureInt(Window.FEATURE_PROGRESS,
+                    Window.PROGRESS_VISIBILITY_OFF);
+            setTitle(R.string.tab_picker_title);
+        }
         // Make the menu empty until the animation completes.
         mMenuState = EMPTY_MENU;
     }
 
-    private void bookmarksOrHistoryPicker(boolean startWithHistory) {
+    /* package */ void bookmarksOrHistoryPicker(boolean startWithHistory) {
         WebView current = mTabControl.getCurrentWebView();
         if (current == null) {
             return;
@@ -4482,7 +4698,7 @@
       return 0;
     }
 
-    static final Pattern ACCEPTED_URI_SCHEMA = Pattern.compile(
+    protected static final Pattern ACCEPTED_URI_SCHEMA = Pattern.compile(
             "(?i)" + // switch on case insensitive matching
             "(" +    // begin group for schema
             "(?:http|https|file):\\/\\/" +
@@ -4590,6 +4806,8 @@
                     country)
                     + "client=ms-"
                     + Partner.getString(this.getContentResolver(), Partner.CLIENT_ID)
+                    // FIXME, remove this when GEOLOCATION team make their move
+                    + "&action=devloc"
                     + "&source=android-" + GOOGLE_SEARCH_SOURCE_SUGGEST + "&q=%s";
         } else {
             QuickSearch_G = url;
@@ -4737,6 +4955,8 @@
 
     private Toast mStopToast;
 
+    private TitleBar mTitleBar;
+
     // Used during animations to prevent other animations from being triggered.
     // A count is used since the animation to and from the Window overview can
     // overlap. A count of 0 means no animation where a count of > 0 means
@@ -4754,10 +4974,13 @@
     private IntentFilter mNetworkStateChangedFilter;
     private BroadcastReceiver mNetworkStateIntentReceiver;
 
+    private BroadcastReceiver mPackageInstallationReceiver;
+
     // activity requestCode
-    final static int COMBO_PAGE             = 1;
-    final static int DOWNLOAD_PAGE          = 2;
-    final static int PREFERENCES_PAGE       = 3;
+    final static int COMBO_PAGE                 = 1;
+    final static int DOWNLOAD_PAGE              = 2;
+    final static int PREFERENCES_PAGE           = 3;
+    final static int WEBSTORAGE_QUOTA_DIALOG    = 4;
 
     // the frenquency of checking whether system memory is low
     final static int CHECK_MEMORY_INTERVAL = 30000;     // 30 seconds
diff --git a/src/com/android/browser/BrowserBookmarksAdapter.java b/src/com/android/browser/BrowserBookmarksAdapter.java
index 27782e0..09741ae 100644
--- a/src/com/android/browser/BrowserBookmarksAdapter.java
+++ b/src/com/android/browser/BrowserBookmarksAdapter.java
@@ -40,8 +40,6 @@
 
 class BrowserBookmarksAdapter extends BaseAdapter {
 
-    private final String            LOGTAG = "Bookmarks";
-
     private String                  mCurrentPage;
     private Cursor                  mCursor;
     private int                     mCount;
diff --git a/src/com/android/browser/BrowserBookmarksPage.java b/src/com/android/browser/BrowserBookmarksPage.java
index dd34c14..45fca87 100644
--- a/src/com/android/browser/BrowserBookmarksPage.java
+++ b/src/com/android/browser/BrowserBookmarksPage.java
@@ -44,6 +44,7 @@
 import android.view.ContextMenu.ContextMenuInfo;
 import android.widget.AdapterView;
 import android.widget.ListView;
+import android.widget.Toast;
 
 /**
  *  View showing the user's bookmarks in the browser.
@@ -107,7 +108,13 @@
             break;
         case R.id.copy_url_context_menu_id:
             copy(getUrl(i.position));
-            
+            break;
+        case R.id.homepage_context_menu_id:
+            BrowserSettings.getInstance().setHomePage(this,
+                    getUrl(i.position));
+            Toast.makeText(this, R.string.homepage_set,
+                    Toast.LENGTH_LONG).show();
+            break;
         default:
             return super.onContextItemSelected(item);
         }
diff --git a/src/com/android/browser/BrowserDownloadAdapter.java b/src/com/android/browser/BrowserDownloadAdapter.java
index 38b83fe..16cb982 100644
--- a/src/com/android/browser/BrowserDownloadAdapter.java
+++ b/src/com/android/browser/BrowserDownloadAdapter.java
@@ -60,14 +60,14 @@
     public BrowserDownloadAdapter(Context context, int layout, Cursor c) {
         super(context, layout, c);
         mFilenameColumnId = c.getColumnIndexOrThrow(Downloads._DATA);
-        mTitleColumnId = c.getColumnIndexOrThrow(Downloads.TITLE);
-        mDescColumnId = c.getColumnIndexOrThrow(Downloads.DESCRIPTION);
-        mStatusColumnId = c.getColumnIndexOrThrow(Downloads.STATUS);
-        mTotalBytesColumnId = c.getColumnIndexOrThrow(Downloads.TOTAL_BYTES);
+        mTitleColumnId = c.getColumnIndexOrThrow(Downloads.COLUMN_TITLE);
+        mDescColumnId = c.getColumnIndexOrThrow(Downloads.COLUMN_DESCRIPTION);
+        mStatusColumnId = c.getColumnIndexOrThrow(Downloads.COLUMN_STATUS);
+        mTotalBytesColumnId = c.getColumnIndexOrThrow(Downloads.COLUMN_TOTAL_BYTES);
         mCurrentBytesColumnId = 
-            c.getColumnIndexOrThrow(Downloads.CURRENT_BYTES);
-        mMimetypeColumnId = c.getColumnIndexOrThrow(Downloads.MIMETYPE);
-        mDateColumnId = c.getColumnIndexOrThrow(Downloads.LAST_MODIFICATION);
+            c.getColumnIndexOrThrow(Downloads.COLUMN_CURRENT_BYTES);
+        mMimetypeColumnId = c.getColumnIndexOrThrow(Downloads.COLUMN_MIME_TYPE);
+        mDateColumnId = c.getColumnIndexOrThrow(Downloads.COLUMN_LAST_MODIFICATION);
     }
 
     @Override
@@ -106,7 +106,7 @@
                 // We have a filename, so we can build a title from that
                 title = new File(fullFilename).getName();
                 ContentValues values = new ContentValues();
-                values.put(Downloads.TITLE, title);
+                values.put(Downloads.COLUMN_TITLE, title);
                 // assume "_id" is the first column for the cursor 
                 context.getContentResolver().update(
                         ContentUris.withAppendedId(Downloads.CONTENT_URI,
diff --git a/src/com/android/browser/BrowserDownloadPage.java b/src/com/android/browser/BrowserDownloadPage.java
index 4397337..22e0e65 100644
--- a/src/com/android/browser/BrowserDownloadPage.java
+++ b/src/com/android/browser/BrowserDownloadPage.java
@@ -66,34 +66,30 @@
         setTitle(getText(R.string.download_title));
 
         mListView = (ListView) findViewById(R.id.list);
-        LayoutInflater factory = LayoutInflater.from(this);
-        View v = factory.inflate(R.layout.no_downloads, null);
-        addContentView(v, new LayoutParams(LayoutParams.FILL_PARENT,
-                LayoutParams.FILL_PARENT));
-        mListView.setEmptyView(v);
+        mListView.setEmptyView(findViewById(R.id.empty));
         
         mDownloadCursor = managedQuery(Downloads.CONTENT_URI, 
-                new String [] {"_id", Downloads.TITLE, Downloads.STATUS,
-                Downloads.TOTAL_BYTES, Downloads.CURRENT_BYTES, 
-                Downloads._DATA, Downloads.DESCRIPTION, 
-                Downloads.MIMETYPE, Downloads.LAST_MODIFICATION,
-                Downloads.VISIBILITY}, 
+                new String [] {"_id", Downloads.COLUMN_TITLE, Downloads.COLUMN_STATUS,
+                Downloads.COLUMN_TOTAL_BYTES, Downloads.COLUMN_CURRENT_BYTES, 
+                Downloads._DATA, Downloads.COLUMN_DESCRIPTION, 
+                Downloads.COLUMN_MIME_TYPE, Downloads.COLUMN_LAST_MODIFICATION,
+                Downloads.COLUMN_VISIBILITY}, 
                 null, null);
         
         // only attach everything to the listbox if we can access
         // the download database. Otherwise, just show it empty
         if (mDownloadCursor != null) {
             mStatusColumnId = 
-                    mDownloadCursor.getColumnIndexOrThrow(Downloads.STATUS);
+                    mDownloadCursor.getColumnIndexOrThrow(Downloads.COLUMN_STATUS);
             mIdColumnId =
                     mDownloadCursor.getColumnIndexOrThrow(Downloads._ID);
             mTitleColumnId = 
-                    mDownloadCursor.getColumnIndexOrThrow(Downloads.TITLE);
+                    mDownloadCursor.getColumnIndexOrThrow(Downloads.COLUMN_TITLE);
             
             // Create a list "controller" for the data
             mDownloadAdapter = new BrowserDownloadAdapter(this, 
                     R.layout.browser_download_item, mDownloadCursor);
-            
+
             mListView.setAdapter(mDownloadAdapter);
             mListView.setScrollBarStyle(View.SCROLLBARS_INSIDE_INSET);
             mListView.setOnCreateContextMenuListener(this);
@@ -403,7 +399,7 @@
                 mDownloadCursor.getColumnIndexOrThrow(Downloads._DATA);
         String filename = mDownloadCursor.getString(filenameColumnId);
         int mimetypeColumnId =
-                mDownloadCursor.getColumnIndexOrThrow(Downloads.MIMETYPE);
+                mDownloadCursor.getColumnIndexOrThrow(Downloads.COLUMN_MIME_TYPE);
         String mimetype = mDownloadCursor.getString(mimetypeColumnId);
         Uri path = Uri.parse(filename);
         // If there is no scheme, then it must be a file
@@ -453,13 +449,13 @@
     private void hideCompletedDownload() {
         int status = mDownloadCursor.getInt(mStatusColumnId);
 
-        int visibilityColumn = mDownloadCursor.getColumnIndexOrThrow(Downloads.VISIBILITY);
+        int visibilityColumn = mDownloadCursor.getColumnIndexOrThrow(Downloads.COLUMN_VISIBILITY);
         int visibility = mDownloadCursor.getInt(visibilityColumn);
 
         if (Downloads.isStatusCompleted(status) &&
                 visibility == Downloads.VISIBILITY_VISIBLE_NOTIFY_COMPLETED) {
             ContentValues values = new ContentValues();
-            values.put(Downloads.VISIBILITY, Downloads.VISIBILITY_VISIBLE);
+            values.put(Downloads.COLUMN_VISIBILITY, Downloads.VISIBILITY_VISIBLE);
             getContentResolver().update(
                     ContentUris.withAppendedId(Downloads.CONTENT_URI,
                     mDownloadCursor.getLong(mIdColumnId)), values, null, null);
diff --git a/src/com/android/browser/BrowserHistoryPage.java b/src/com/android/browser/BrowserHistoryPage.java
index 42ca848..e333416 100644
--- a/src/com/android/browser/BrowserHistoryPage.java
+++ b/src/com/android/browser/BrowserHistoryPage.java
@@ -41,6 +41,7 @@
 import android.view.ViewGroup;
 import android.view.ViewGroup.LayoutParams;
 import android.view.ContextMenu.ContextMenuInfo;
+import android.view.ViewStub;
 import android.webkit.DateSorter;
 import android.webkit.WebIconDatabase.IconListener;
 import android.widget.AdapterView;
@@ -48,6 +49,7 @@
 import android.widget.ExpandableListView;
 import android.widget.ExpandableListView.ExpandableListContextMenuInfo;
 import android.widget.TextView;
+import android.widget.Toast;
 
 import java.util.List;
 import java.util.Vector;
@@ -110,8 +112,7 @@
         setListAdapter(mAdapter);
         final ExpandableListView list = getExpandableListView();
         list.setOnCreateContextMenuListener(this);
-        LayoutInflater factory = LayoutInflater.from(this);
-        View v = factory.inflate(R.layout.empty_history, null);
+        View v = new ViewStub(this, R.layout.empty_history);
         addContentView(v, new LayoutParams(LayoutParams.FILL_PARENT,
                 LayoutParams.FILL_PARENT));
         list.setEmptyView(v);
@@ -222,6 +223,11 @@
                 Browser.deleteFromHistory(getContentResolver(), url);
                 mAdapter.refreshData();
                 return true;
+            case R.id.homepage_context_menu_id:
+                BrowserSettings.getInstance().setHomePage(this, url);
+                Toast.makeText(this, R.string.homepage_set,
+                    Toast.LENGTH_LONG).show();
+                return true;
             default:
                 break;
         }
@@ -267,18 +273,25 @@
         
         // Array for each of our bins.  Each entry represents how many items are
         // in that bin.
-        int mItemMap[];
+        private int mItemMap[];
         // This is our GroupCount.  We will have at most DateSorter.DAY_COUNT
         // bins, less if the user has no items in one or more bins.
-        int mNumberOfBins;
-        Vector<DataSetObserver> mObservers;
-        Cursor mCursor;
+        private int mNumberOfBins;
+        private Vector<DataSetObserver> mObservers;
+        private Cursor mCursor;
         
         HistoryAdapter() {
             mObservers = new Vector<DataSetObserver>();
             
-            String whereClause = Browser.BookmarkColumns.VISITS + " > 0 ";
-            String orderBy = Browser.BookmarkColumns.DATE + " DESC";
+            final String whereClause = Browser.BookmarkColumns.VISITS + " > 0"
+                    // In AddBookmarkPage, where we save new bookmarks, we add
+                    // three visits to newly created bookmarks, so that
+                    // bookmarks that have not been visited will show up in the
+                    // most visited, and higher in the goto search box.
+                    // However, this puts the site in the history, unless we
+                    // ignore sites with a DATE of 0, which the next line does.
+                    + " AND " + Browser.BookmarkColumns.DATE + " > 0";
+            final String orderBy = Browser.BookmarkColumns.DATE + " DESC";
            
             mCursor = managedQuery(
                     Browser.BOOKMARKS_URI,
diff --git a/src/com/android/browser/BrowserHomepagePreference.java b/src/com/android/browser/BrowserHomepagePreference.java
index d4708c3..7324f24 100644
--- a/src/com/android/browser/BrowserHomepagePreference.java
+++ b/src/com/android/browser/BrowserHomepagePreference.java
@@ -50,8 +50,8 @@
         if (dialog != null) {
             String url = s.toString();
             dialog.getButton(DialogInterface.BUTTON_POSITIVE).setEnabled(
-                    url.length() == 0 || url.equals("about:blank") ||
-                    Regex.WEB_URL_PATTERN.matcher(url).matches());
+                url.length() == 0 || 
+                BrowserActivity.ACCEPTED_URI_SCHEMA.matcher(url).matches());
         }
     }
 
diff --git a/src/com/android/browser/BrowserPreferencesPage.java b/src/com/android/browser/BrowserPreferencesPage.java
index 5d6795b..c6ce8a6 100644
--- a/src/com/android/browser/BrowserPreferencesPage.java
+++ b/src/com/android/browser/BrowserPreferencesPage.java
@@ -17,12 +17,19 @@
 package com.android.browser;
 
 import java.util.List;
+import java.util.Vector;
 
+import android.content.Intent;
 import android.net.Uri;
 import android.os.Bundle;
 import android.preference.EditTextPreference;
+import android.preference.ListPreference;
 import android.preference.Preference;
 import android.preference.PreferenceActivity;
+import android.preference.PreferenceScreen;
+import android.util.Log;
+import android.webkit.Plugin;
+import android.webkit.WebStorage;
 import android.webkit.WebView;
 import android.webkit.Plugin;
 
@@ -30,6 +37,8 @@
         implements Preference.OnPreferenceChangeListener, 
         Preference.OnPreferenceClickListener {
 
+    String TAG = "BrowserPreferencesPage";
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -60,6 +69,32 @@
         
         e = findPreference(BrowserSettings.PREF_GEARS_SETTINGS);
         e.setOnPreferenceClickListener(this);
+
+        PreferenceScreen manageDatabases = (PreferenceScreen)
+            findPreference(BrowserSettings.PREF_WEBSTORAGE_SETTINGS);
+
+        Preference clearDatabases =
+            findPreference(BrowserSettings.PREF_WEBSTORAGE_CLEAR_ALL);
+
+        Vector origins = WebStorage.getInstance().getOrigins();
+        manageDatabases.setEnabled(false);
+        clearDatabases.setEnabled(false);
+        if (origins != null) {
+            if (origins.size() > 0) {
+                manageDatabases.setEnabled(true);
+                clearDatabases.setEnabled(true);
+            }
+            for (int i = 0;  i < origins.size(); i++) {
+                OriginSettings origin =
+                    new OriginSettings(this, (String) origins.get(i));
+                PreferenceScreen screen =
+                    getPreferenceManager().createPreferenceScreen(this);
+                origin.setScreen(screen);
+                origin.setRootScreen(manageDatabases);
+                origin.setup();
+                manageDatabases.addPreference(screen);
+            }
+        }
     }
 
     @Override
diff --git a/src/com/android/browser/BrowserProvider.java b/src/com/android/browser/BrowserProvider.java
index d2f4a0a..8ed889e 100644
--- a/src/com/android/browser/BrowserProvider.java
+++ b/src/com/android/browser/BrowserProvider.java
@@ -65,8 +65,9 @@
             "_id", "url", "title", "bookmark"
     };
     private static final String SUGGEST_SELECTION =
-            "url LIKE ? OR url LIKE ? OR url LIKE ? OR url LIKE ?";
-    private String[] SUGGEST_ARGS = new String[4];
+            "url LIKE ? OR url LIKE ? OR url LIKE ? OR url LIKE ?"
+                + " OR title LIKE ?";
+    private String[] SUGGEST_ARGS = new String[5];
 
     // shared suggestion array index, make sure to match COLUMNS
     private static final int SUGGEST_COLUMN_INTENT_ACTION_ID = 1;
@@ -92,6 +93,8 @@
 
     private static final int MAX_SUGGESTION_SHORT_ENTRIES = 3;
     private static final int MAX_SUGGESTION_LONG_ENTRIES = 6;
+    private static final String MAX_SUGGESTION_LONG_ENTRIES_STRING =
+            Integer.valueOf(MAX_SUGGESTION_LONG_ENTRIES).toString();
 
     // make sure that these match the index of TABLE_NAMES
     private static final int URI_MATCH_BOOKMARKS = 0;
@@ -407,22 +410,22 @@
                     case SUGGEST_COLUMN_ICON_1_ID:
                         if (mHistoryCount > mPos) {
                             if (mHistoryCursor.getInt(3) == 1) {
-                                return new Integer(
+                                return Integer.valueOf(
                                         R.drawable.ic_search_category_bookmark)
                                         .toString();
                             } else {
-                                return new Integer(
+                                return Integer.valueOf(
                                         R.drawable.ic_search_category_history)
                                         .toString();
                             }
                         } else {
-                            return new Integer(
+                            return Integer.valueOf(
                                     R.drawable.ic_search_category_suggest)
                                     .toString();
                         }
 
                     case SUGGEST_COLUMN_ICON_2_ID:
-                        return new String("0");
+                        return "0";
 
                     case SUGGEST_COLUMN_QUERY_ID:
                         if (mHistoryCount > mPos) {
@@ -573,7 +576,8 @@
                 myArgs = null;
             } else {
                 String like = selectionArgs[0] + "%";
-                if (selectionArgs[0].startsWith("http")) {
+                if (selectionArgs[0].startsWith("http")
+                        || selectionArgs[0].startsWith("file")) {
                     myArgs = new String[1];
                     myArgs[0] = like;
                     suggestSelection = selection;
@@ -582,6 +586,8 @@
                     SUGGEST_ARGS[1] = "http://www." + like;
                     SUGGEST_ARGS[2] = "https://" + like;
                     SUGGEST_ARGS[3] = "https://www." + like;
+                    // To match against titles.
+                    SUGGEST_ARGS[4] = like;
                     myArgs = SUGGEST_ARGS;
                     suggestSelection = SUGGEST_SELECTION;
                 }
@@ -589,8 +595,7 @@
 
             Cursor c = db.query(TABLE_NAMES[URI_MATCH_BOOKMARKS],
                     SUGGEST_PROJECTION, suggestSelection, myArgs, null, null,
-                    ORDER_BY,
-                    (new Integer(MAX_SUGGESTION_LONG_ENTRIES)).toString());
+                    ORDER_BY, MAX_SUGGESTION_LONG_ENTRIES_STRING);
 
             if (match == URI_MATCH_BOOKMARKS_SUGGEST
                     || Regex.WEB_URL_PATTERN.matcher(selectionArgs[0]).matches()) {
diff --git a/src/com/android/browser/BrowserQuotaPreference.java b/src/com/android/browser/BrowserQuotaPreference.java
new file mode 100644
index 0000000..e635bb2
--- /dev/null
+++ b/src/com/android/browser/BrowserQuotaPreference.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.browser;
+
+import android.preference.ListPreference;
+import android.content.Context;
+import android.preference.PreferenceScreen;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+import android.webkit.WebStorage;
+
+import java.util.Vector;
+
+/**
+ * Utility class to display and manage the choosen quota
+ * for an origin (HTML5 WebStorage feature)
+ */
+class BrowserQuotaPreference extends ListPreference {
+
+    private String TAG = "BrowserQuotaPreference";
+    private OriginSettings mOrigin = null;
+    private static long sOneMB = 1024 * 1024;
+
+    // This is the constructor called by the inflater
+    public BrowserQuotaPreference(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public BrowserQuotaPreference(Context context, OriginSettings origin) {
+        super(context);
+        mOrigin = origin;
+    }
+
+    /**
+     * Find the minimum quota fitting the current usage
+     * and only show larger quotas in the list
+     */
+    public void setQuotaList () {
+        CharSequence[] entries = getEntries();
+        CharSequence[] values = getEntryValues();
+        Vector<CharSequence> listEntries = new Vector<CharSequence>();
+        Vector<CharSequence> listValues = new Vector<CharSequence>();
+        long usage = 0;
+        if (mOrigin != null) {
+          usage = mOrigin.getUsage();
+        }
+        for (int i = 0; i < values.length; i++) {
+            long value = Long.parseLong(values[i].toString());
+            value *= sOneMB; // the string array is expressed in MB
+            if (value >= usage) {
+                listEntries.add(entries[i]);
+                listValues.add(values[i]);
+            }
+        }
+        CharSequence[] newEntries = new CharSequence[listEntries.size()];
+        CharSequence[] newValues = new CharSequence[listValues.size()];
+        for (int i = 0; i < listEntries.size(); i++) {
+            newEntries[i] = listEntries.get(i);
+            newValues[i] = listValues.get(i);
+        }
+        setEntries(newEntries);
+        setEntryValues(newValues);
+        setValueIndex(0);
+    }
+
+    @Override
+    protected View onCreateDialogView() {
+        setQuotaList();
+        return super.onCreateDialogView();
+    }
+
+    @Override
+    protected void onDialogClosed(boolean positiveResult) {
+        super.onDialogClosed(positiveResult);
+        if (mOrigin == null) {
+            return;
+        }
+        if (positiveResult) {
+            long quota = Long.parseLong(getValue());
+            quota *= sOneMB; // getValue() is in MB
+            mOrigin.setQuota(quota);
+        }
+    }
+}
diff --git a/src/com/android/browser/BrowserSettings.java b/src/com/android/browser/BrowserSettings.java
index 68438b3..34cab94 100644
--- a/src/com/android/browser/BrowserSettings.java
+++ b/src/com/android/browser/BrowserSettings.java
@@ -25,6 +25,9 @@
 import android.content.SharedPreferences;
 import android.content.SharedPreferences.Editor;
 import android.os.SystemProperties;
+import android.preference.PreferenceActivity;
+import android.preference.PreferenceScreen;
+import android.util.Log;
 import android.view.WindowManager;
 import android.webkit.CacheManager;
 import android.webkit.CookieManager;
@@ -32,6 +35,7 @@
 import android.webkit.WebViewDatabase;
 import android.webkit.WebIconDatabase;
 import android.webkit.WebSettings;
+import android.webkit.WebStorage;
 import android.preference.PreferenceManager;
 import android.provider.Browser;
 
@@ -53,7 +57,7 @@
  */
 class BrowserSettings extends Observable {
 
-    // Public variables for settings
+    // Private variables for settings
     // NOTE: these defaults need to be kept in sync with the XML
     // until the performance of PreferenceManager.setDefaultValues()
     // is improved.
@@ -70,7 +74,16 @@
     private String homeUrl = "";
     private boolean loginInitialized = false;
     private boolean autoFitPage = true;
+    private boolean landscapeOnly = false;
     private boolean showDebugSettings = false;
+    private String databasePath; // default value set in loadFromDb()
+    private boolean databaseEnabled = true;
+    private long webStorageDefaultQuota = 5 * 1024 * 1024;
+    // The Browser always enables Application Caches.
+    private boolean appCacheEnabled = true;
+    private String appCachePath;  // default value set in loadFromDb().
+
+    private final static String TAG = "BrowserSettings";
 
     // Development settings
     public WebSettings.LayoutAlgorithm layoutAlgorithm =
@@ -100,10 +113,20 @@
             "privacy_clear_form_data";
     public final static String PREF_CLEAR_PASSWORDS =
             "privacy_clear_passwords";
+    public final static String PREF_CLEAR_DATABASES =
+            "webstorage_clear_databases";
+    public final static String PREF_CLEAR_ALL_DATA =
+            "webstorage_clear_all_data";
+    public final static String PREF_MANAGE_QUOTA =
+            "webstorage_manage_quota";
+    public final static String PREF_DEFAULT_QUOTA =
+            "webstorage_default_quota";
     public final static String PREF_EXTRAS_RESET_DEFAULTS =
             "reset_default_preferences";
     public final static String PREF_DEBUG_SETTINGS = "debug_menu";
     public final static String PREF_GEARS_SETTINGS = "gears_settings";
+    public final static String PREF_WEBSTORAGE_SETTINGS = "webstorage_manage_databases";
+    public final static String PREF_WEBSTORAGE_CLEAR_ALL = "webstorage_clear_databases";
     public final static String PREF_TEXT_SIZE = "text_size";
     public final static String PREF_DEFAULT_TEXT_ENCODING =
             "default_text_encoding";
@@ -159,7 +182,6 @@
             s.setLoadsImagesAutomatically(b.loadsImagesAutomatically);
             s.setJavaScriptEnabled(b.javaScriptEnabled);
             s.setPluginsEnabled(b.pluginsEnabled);
-            s.setPluginsPath(b.pluginsPath);
             s.setJavaScriptCanOpenWindowsAutomatically(
                     b.javaScriptCanOpenWindowsAutomatically);
             s.setDefaultTextEncodingName(b.defaultTextEncodingName);
@@ -179,6 +201,14 @@
             s.setSupportMultipleWindows(true);
             // Turn off file access
             s.setAllowFileAccess(false);
+
+            s.setDatabasePath(b.databasePath);
+            s.setDatabaseEnabled(b.databaseEnabled);
+            s.setWebStorageDefaultQuota(b.webStorageDefaultQuota);
+
+            // Turn on Application Caches.
+            s.setAppCachePath(b.appCachePath);
+            s.setAppCacheEnabled(b.appCacheEnabled);
         }
     }
 
@@ -198,6 +228,10 @@
         // Set the default value for the plugins path to the application's
         // local directory.
         pluginsPath = ctx.getDir("plugins", 0).getPath();
+        // Set the default value for the Application Caches path.
+        appCachePath = ctx.getDir("appcache", 0).getPath();
+        // Set the default value for the Database path.
+        databasePath = ctx.getDir("databases", 0).getPath();
 
         homeUrl = getFactoryResetHomeUrl(ctx);
 
@@ -220,6 +254,13 @@
         pluginsEnabled = p.getBoolean("enable_plugins",
                 pluginsEnabled);
         pluginsPath = p.getString("plugins_path", pluginsPath);
+        databasePath = p.getString("database_path", databasePath);
+        databaseEnabled = p.getBoolean("enable_database", databaseEnabled);
+        webStorageDefaultQuota = Long.parseLong(p.getString(PREF_DEFAULT_QUOTA,
+                String.valueOf(webStorageDefaultQuota)));
+        appCacheEnabled = p.getBoolean("enable_appcache",
+            appCacheEnabled);
+        appCachePath = p.getString("appcache_path", appCachePath);
         javaScriptCanOpenWindowsAutomatically = !p.getBoolean(
             "block_popup_windows",
             !javaScriptCanOpenWindowsAutomatically);
@@ -237,6 +278,14 @@
         textSize = WebSettings.TextSize.valueOf(
                 p.getString(PREF_TEXT_SIZE, textSize.name()));
         autoFitPage = p.getBoolean("autofit_pages", autoFitPage);
+        boolean landscapeOnlyTemp =
+                p.getBoolean("landscape_only", landscapeOnly);
+        if (landscapeOnlyTemp != landscapeOnly) {
+            landscapeOnly = landscapeOnlyTemp;
+            mTabControl.getBrowserActivity().setRequestedOrientation(
+                    landscapeOnly ? ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
+                    : ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
+        }
         useWideViewPort = true; // use wide view port for either setting
         if (autoFitPage) {
             layoutAlgorithm = WebSettings.LayoutAlgorithm.NARROW_COLUMNS;
@@ -433,14 +482,24 @@
         db.clearHttpAuthUsernamePassword();
     }
 
-    /*package*/ void resetDefaultPreferences(Context context) {
+    /*package*/ void clearDatabases(Context context) {
+        WebStorage.getInstance().deleteAllDatabases();
+        // Remove all listed databases from the preferences
+        PreferenceActivity activity = (PreferenceActivity) context;
+        PreferenceScreen screen = (PreferenceScreen)
+            activity.findPreference(BrowserSettings.PREF_WEBSTORAGE_SETTINGS);
+        screen.removeAll();
+        screen.setEnabled(false);
+    }
+
+    /*package*/ void resetDefaultPreferences(Context ctx) {
         SharedPreferences p =
-            PreferenceManager.getDefaultSharedPreferences(context);
+            PreferenceManager.getDefaultSharedPreferences(ctx);
         p.edit().clear().commit();
-        PreferenceManager.setDefaultValues(context, R.xml.browser_preferences,
+        PreferenceManager.setDefaultValues(ctx, R.xml.browser_preferences,
                 true);
         // reset homeUrl
-        setHomePage(context, getFactoryResetHomeUrl(context));
+        setHomePage(ctx, getFactoryResetHomeUrl(ctx));
     }
 
     private String getFactoryResetHomeUrl(Context context) {
diff --git a/src/com/android/browser/BrowserYesNoPreference.java b/src/com/android/browser/BrowserYesNoPreference.java
index 65cde71..11a577b 100644
--- a/src/com/android/browser/BrowserYesNoPreference.java
+++ b/src/com/android/browser/BrowserYesNoPreference.java
@@ -23,11 +23,21 @@
 
 class BrowserYesNoPreference extends YesNoPreference {
 
+    // This is used for the HTML5 pref UI, where we construct
+    // BrowserYesNoPreference objects on the fly and where we need
+    // to save the corresponding origin.
+    OriginSettings mOrigin = null;
+
     // This is the constructor called by the inflater
     public BrowserYesNoPreference(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
 
+    public BrowserYesNoPreference(Context context, OriginSettings origin) {
+        super(context);
+        mOrigin = origin;
+    }
+
     @Override
     protected void onDialogClosed(boolean positiveResult) {
         super.onDialogClosed(positiveResult);
@@ -46,6 +56,12 @@
                 BrowserSettings.getInstance().clearFormData(context);
             } else if (BrowserSettings.PREF_CLEAR_PASSWORDS.equals(getKey())) {
                 BrowserSettings.getInstance().clearPasswords(context);
+            } else if (BrowserSettings.PREF_CLEAR_DATABASES.equals(getKey())) {
+                BrowserSettings.getInstance().clearDatabases(context);
+            } else if (BrowserSettings.PREF_CLEAR_ALL_DATA.equals(getKey())) {
+                if (mOrigin != null) {
+                    mOrigin.delete();
+                }
             } else if (BrowserSettings.PREF_EXTRAS_RESET_DEFAULTS.equals(
                     getKey())) {
                 BrowserSettings.getInstance().resetDefaultPreferences(context);
diff --git a/src/com/android/browser/FetchUrlMimeType.java b/src/com/android/browser/FetchUrlMimeType.java
index 8578643..c585dbb 100644
--- a/src/com/android/browser/FetchUrlMimeType.java
+++ b/src/com/android/browser/FetchUrlMimeType.java
@@ -58,7 +58,7 @@
         mValues = values[0];
 
         // Check to make sure we have a URI to download
-        String uri = mValues.getAsString(Downloads.URI);
+        String uri = mValues.getAsString(Downloads.COLUMN_URI);
         if (uri == null || uri.length() == 0) {
             return null;
         }
@@ -66,15 +66,15 @@
         // User agent is likely to be null, though the AndroidHttpClient
         // seems ok with that.
         AndroidHttpClient client = AndroidHttpClient.newInstance(
-                mValues.getAsString(Downloads.USER_AGENT));
+                mValues.getAsString(Downloads.COLUMN_USER_AGENT));
         HttpHead request = new HttpHead(uri);
 
-        String cookie = mValues.getAsString(Downloads.COOKIE_DATA);
+        String cookie = mValues.getAsString(Downloads.COLUMN_COOKIE_DATA);
         if (cookie != null && cookie.length() > 0) {
             request.addHeader("Cookie", cookie);
         }
 
-        String referer = mValues.getAsString(Downloads.REFERER);
+        String referer = mValues.getAsString(Downloads.COLUMN_REFERER);
         if (referer != null && referer.length() > 0) {
             request.addHeader("Referer", referer);
         }
@@ -111,19 +111,19 @@
    @Override
     public void onPostExecute(String mimeType) {
        if (mimeType != null) {
-           String url = mValues.getAsString(Downloads.URI);
+           String url = mValues.getAsString(Downloads.COLUMN_URI);
            if (mimeType.equalsIgnoreCase("text/plain") ||
                    mimeType.equalsIgnoreCase("application/octet-stream")) {
                String newMimeType =
                        MimeTypeMap.getSingleton().getMimeTypeFromExtension(
                            MimeTypeMap.getFileExtensionFromUrl(url));
                if (newMimeType != null) {
-                   mValues.put(Downloads.MIMETYPE, newMimeType);
+                   mValues.put(Downloads.COLUMN_MIME_TYPE, newMimeType);
                }
            }
            String filename = URLUtil.guessFileName(url,
                    null, mimeType);
-           mValues.put(Downloads.FILENAME_HINT, filename);
+           mValues.put(Downloads.COLUMN_FILE_NAME_HINT, filename);
        }
 
        // Start the download
diff --git a/src/com/android/browser/FindDialog.java b/src/com/android/browser/FindDialog.java
index 6e9574c..2049bd0 100644
--- a/src/com/android/browser/FindDialog.java
+++ b/src/com/android/browser/FindDialog.java
@@ -42,7 +42,6 @@
     private BrowserActivity mBrowserActivity;
     
     // Views with which the user can interact.
-    private View            mOk;
     private EditText        mEditText;
     private View            mNextButton;
     private View            mPrevButton;
@@ -129,7 +128,6 @@
         
         button = findViewById(R.id.done);
         button.setOnClickListener(mFindCancelListener);
-        mOk = button;
         
         mMatches = (TextView) findViewById(R.id.matches);
         mMatchesView = findViewById(R.id.matches_view);
@@ -143,23 +141,14 @@
         mBrowserActivity.closeFind();
         mWebView.clearMatches();
     }
-    
+
     @Override
     public boolean dispatchKeyEvent(KeyEvent event) {
-        int code = event.getKeyCode();
-        boolean up = event.getAction() == KeyEvent.ACTION_UP;
-        switch (code) {
-            case KeyEvent.KEYCODE_DPAD_CENTER:
-            case KeyEvent.KEYCODE_ENTER:
-                if (!mEditText.hasFocus()) {
-                    break;
-                }
-                if (up) {
-                    findNext();
-                }
-                return true;
-            default:
-                break;
+        if (event.getKeyCode() == KeyEvent.KEYCODE_ENTER
+                && event.getAction() == KeyEvent.ACTION_UP
+                && mEditText.hasFocus()) {
+            findNext();
+            return true;
         }
         return super.dispatchKeyEvent(event);
     }
diff --git a/src/com/android/browser/MostVisitedActivity.java b/src/com/android/browser/MostVisitedActivity.java
index 704ee27..90052d3 100644
--- a/src/com/android/browser/MostVisitedActivity.java
+++ b/src/com/android/browser/MostVisitedActivity.java
@@ -35,6 +35,7 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewGroup.LayoutParams;
+import android.view.ViewStub;
 
 import java.util.Vector;
 
@@ -50,8 +51,7 @@
                 .addListener(new IconReceiver());
         setListAdapter(mAdapter);
         ListView list = getListView();
-        LayoutInflater factory = LayoutInflater.from(this);
-        View v = factory.inflate(R.layout.empty_history, null);
+        View v = new ViewStub(this, R.layout.empty_history);
         addContentView(v, new LayoutParams(LayoutParams.FILL_PARENT,
                 LayoutParams.FILL_PARENT));
         list.setEmptyView(v);
@@ -84,9 +84,9 @@
         private Vector<DataSetObserver> mObservers;
         private Cursor mCursor;
         // These correspond with projection below.
-        private final int mUrlIndex = 0;
-        private final int mTitleIndex = 1;
-        private final int mBookmarkIndex = 2;
+        private static final int mUrlIndex = 0;
+        private static final int mTitleIndex = 1;
+        private static final int mBookmarkIndex = 2;
 
         MyAdapter() {
             mObservers = new Vector<DataSetObserver>();
diff --git a/src/com/android/browser/OriginSettings.java b/src/com/android/browser/OriginSettings.java
new file mode 100644
index 0000000..e80888a
--- /dev/null
+++ b/src/com/android/browser/OriginSettings.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.browser;
+
+import android.content.Context;
+import android.preference.Preference;
+import android.preference.PreferenceActivity;
+import android.preference.PreferenceScreen;
+import android.util.Log;
+import android.webkit.WebStorage;
+
+/**
+ * Manage the settings for an origin.
+ * We use it to keep track of the HTML5 settings, i.e. database (webstorage).
+ */
+class OriginSettings {
+
+    private String TAG = "OriginSettings";
+    private String mOrigin = null;
+    private long mQuota = 0;
+    private long mUsage = 0;
+    private PreferenceScreen mInfoScreen;
+    private PreferenceScreen mRootScreen;
+    private PreferenceActivity mActivity;
+
+    private static String sMBUsed = null;
+    private static String sNoQuotaLeft = null;
+    private static String sMBLeft = null;
+
+    public OriginSettings(PreferenceActivity activity, String origin) {
+        mOrigin = origin;
+        mUsage = WebStorage.getInstance().getUsageForOrigin(mOrigin);
+        mQuota = WebStorage.getInstance().getQuotaForOrigin(mOrigin);
+        mActivity = activity;
+        if (sMBUsed == null) {
+          sMBUsed = mActivity.getString(
+              R.string.webstorage_origin_summary_mb_used);
+          sNoQuotaLeft = mActivity.getString(
+              R.string.webstorage_origin_summary_no_quota_left);
+          sMBLeft = mActivity.getString(
+              R.string.webstorage_origin_summary_mb_left);
+        }
+    }
+
+    public String getOrigin() {
+        return mOrigin;
+    }
+
+    public long getQuota() {
+        return mQuota;
+    }
+
+    public long getUsage() {
+        return mUsage;
+    }
+
+    public void setScreen(PreferenceScreen screen) {
+        mInfoScreen = screen;
+    }
+
+    public void setRootScreen(PreferenceScreen screen) {
+        mRootScreen = screen;
+    }
+
+    private String sizeValueToString(long value) {
+        float mb = (float) value / (1024.0F * 1024.0F);
+        int val = (int) (mb * 10);
+        float ret = (float) (val / 10.0F);
+        if (ret <= 0) {
+            return "0";
+        }
+        return String.valueOf(ret);
+    }
+
+    public void updateSummary() {
+        String summary = sizeValueToString(mUsage) + " " + sMBUsed;
+        if ((mQuota <= 0) || ((mQuota - mUsage) <= 0)) {
+            summary += ", " + sNoQuotaLeft;
+        } else {
+            summary += " (" + sizeValueToString(mQuota - mUsage);
+            summary += " " + sMBLeft + ")";
+        }
+        mInfoScreen.setSummary(summary);
+        mActivity.onContentChanged();
+    }
+
+    public void setup() {
+        mInfoScreen.setTitle(mOrigin);
+        mInfoScreen.setKey(mOrigin);
+        updateSummary();
+
+        BrowserQuotaPreference manageSite = new BrowserQuotaPreference(mActivity, this);
+        BrowserYesNoPreference clearAllData = new BrowserYesNoPreference(mActivity, this);
+
+        manageSite.setTitle(R.string.webstorage_manage_quota_title);
+        manageSite.setSummary(R.string.webstorage_manage_quota_summary);
+        manageSite.setKey(BrowserSettings.PREF_MANAGE_QUOTA);
+        manageSite.setEntries(R.array.webstorage_quota_entries);
+        manageSite.setEntryValues(R.array.webstorage_quota_entries_values);
+
+        clearAllData.setTitle(R.string.webstorage_clear_data_title);
+        clearAllData.setSummary(R.string.webstorage_clear_data_summary);
+        clearAllData.setKey(BrowserSettings.PREF_CLEAR_ALL_DATA);
+        clearAllData.setDialogTitle(R.string.webstorage_clear_data_dialog_title);
+        clearAllData.setDialogMessage(R.string.webstorage_clear_data_dialog_message);
+        clearAllData.setDialogIcon(android.R.drawable.ic_dialog_alert);
+
+        mInfoScreen.addPreference(manageSite);
+        mInfoScreen.addPreference(clearAllData);
+    }
+
+    public void setQuota(long quota) {
+        mQuota = quota;
+        WebStorage.getInstance().setQuotaForOrigin(mOrigin, mQuota);
+        mInfoScreen.getDialog().dismiss();
+        updateSummary();
+    }
+
+    public void delete() {
+        WebStorage.getInstance().deleteOrigin(mOrigin);
+        mInfoScreen.removeAll();
+        mRootScreen.removePreference(mInfoScreen);
+        mInfoScreen.getDialog().dismiss();
+        if (mRootScreen.getPreferenceCount() == 0) {
+            mRootScreen.getDialog().dismiss();
+            mRootScreen.setEnabled(false);
+            Preference clearDatabases = mActivity.findPreference(
+                    BrowserSettings.PREF_WEBSTORAGE_CLEAR_ALL);
+            clearDatabases.setEnabled(false);
+        }
+    }
+}
diff --git a/src/com/android/browser/PermissionDialog.java b/src/com/android/browser/PermissionDialog.java
new file mode 100644
index 0000000..b71261a
--- /dev/null
+++ b/src/com/android/browser/PermissionDialog.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.browser;
+
+import android.app.Activity;
+import android.app.Dialog;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.Window;
+import android.widget.ImageView;
+import android.widget.TextView;
+import android.widget.Toast;
+
+/**
+ * Permission dialog for HTML5
+ * @hide
+ */
+public class PermissionDialog extends Activity {
+
+    private static final String TAG = "PermissionDialog";
+    public static final String PARAM_ORIGIN = "origin";
+    public static final String PARAM_QUOTA = "quota";
+
+    private String mWebStorageOrigin;
+    private long mWebStorageQuota = 0;
+    private int mNotification = 0;
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        getParameters();
+        setupDialog();
+    }
+
+    private void getParameters() {
+        Intent intent = getIntent();
+        mWebStorageOrigin = intent.getStringExtra(PARAM_ORIGIN);
+        mWebStorageQuota = intent.getLongExtra(PARAM_QUOTA, 0);
+    }
+
+    private void setupDialog() {
+        requestWindowFeature(Window.FEATURE_NO_TITLE);
+        setContentView(R.layout.permission_dialog);
+
+        setIcon(R.id.icon, android.R.drawable.ic_popup_disk_full);
+        setText(R.id.dialog_title, R.string.query_storage_quota_prompt);
+        setText(R.id.dialog_message, R.string.query_storage_quota_message);
+        setCharSequence(R.id.origin, mWebStorageOrigin);
+
+        setupButton(R.id.button_allow, R.string.permission_button_allow,
+            new View.OnClickListener() {
+                public void onClick(View v) { allow(); }
+            });
+        setupButton(R.id.button_alwaysdeny, R.string.permission_button_alwaysdeny,
+            new View.OnClickListener() {
+                public void onClick(View v) { alwaysdeny(); }
+            });
+        setupButton(R.id.button_deny, R.string.permission_button_deny,
+            new View.OnClickListener() {
+                public void onClick(View v) { deny(); }
+            });
+    }
+
+    private void setText(int viewID, int stringID) {
+        setCharSequence(viewID, getString(stringID));
+    }
+
+    private void setCharSequence(int viewID, CharSequence string) {
+        View view = findViewById(viewID);
+        if (view == null) {
+            return;
+        }
+        view.setVisibility(View.VISIBLE);
+        TextView textView = (TextView) view;
+        textView.setText(string);
+    }
+
+    private void setIcon(int viewID, int imageID) {
+        View view = findViewById(viewID);
+        if (view == null) {
+            return;
+        }
+        view.setVisibility(View.VISIBLE);
+        ImageView icon = (ImageView) view;
+        icon.setImageResource(imageID);
+    }
+
+    private void setupButton(int viewID, int stringID,
+                             View.OnClickListener listener) {
+        View view = findViewById(viewID);
+        if (view == null) {
+            return;
+        }
+        setText(viewID, stringID);
+        view.setOnClickListener(listener);
+    }
+
+    private void useNextQuota() {
+        CharSequence[] values = getResources().getTextArray(
+            R.array.webstorage_quota_entries_values);
+        for (int i=0; i<values.length; i++) {
+            long value = Long.parseLong(values[i].toString());
+            value *= (1024 * 1024); // the string array is expressed in MB
+            if (value > mWebStorageQuota) {
+                mWebStorageQuota = value;
+                break;
+            }
+        }
+    }
+
+    private void allow() {
+        // If somehow there is no "next quota" in the ladder,
+        // we'll add 1MB anyway.
+        mWebStorageQuota += 1024*1024;
+        useNextQuota();
+        mNotification = R.string.webstorage_notification;
+        closeDialog();
+    }
+
+    private void alwaysdeny() {
+        // Setting the quota to 0 will prevent any new data to be
+        // added, but the existing data will not be deleted.
+        mWebStorageQuota = 0;
+        mNotification = R.string.webstorage_notification;
+        closeDialog();
+    }
+
+    private void deny() {
+        closeDialog();
+    }
+
+    private void closeDialog() {
+        Intent intent = new Intent();
+        intent.putExtra(PARAM_QUOTA, mWebStorageQuota);
+        setResult(RESULT_OK, intent);
+        showToast();
+        finish();
+    }
+
+    private void showToast() {
+        if (mNotification != 0) {
+            Toast toast = Toast.makeText(this, mNotification, Toast.LENGTH_LONG);
+            toast.setGravity(Gravity.BOTTOM, 0, 0);
+            toast.show();
+        }
+    }
+
+    public boolean dispatchKeyEvent(KeyEvent event) {
+        if ((event.getKeyCode() == KeyEvent.KEYCODE_BACK)
+              && (event.getAction() == KeyEvent.ACTION_DOWN)) {
+            closeDialog();
+            return true; // event consumed
+        }
+        return super.dispatchKeyEvent(event);
+    }
+
+}
diff --git a/src/com/android/browser/TabControl.java b/src/com/android/browser/TabControl.java
index 581d144..f66df69 100644
--- a/src/com/android/browser/TabControl.java
+++ b/src/com/android/browser/TabControl.java
@@ -446,6 +446,9 @@
      * @return index of Tab or -1 if not found
      */
     int getTabIndex(Tab tab) {
+        if (tab == null) {
+            return -1;
+        }
         return mTabs.indexOf(tab);
     }
 
@@ -681,11 +684,11 @@
             return;
         }
 
-        // free the WebView cache
-        Log.w(LOGTAG, "Free WebView cache");
+        // free the WebView's unused memory (this includes the cache)
+        Log.w(LOGTAG, "Free WebView's unused memory and cache");
         WebView view = getCurrentWebView();
         if (view != null) {
-            view.clearCache(false);
+            view.freeMemory();
         }
         // force a gc
         System.gc();
@@ -864,6 +867,48 @@
         return setCurrentTab(newTab, false);
     }
 
+    /*package*/ void pauseCurrentTab() {
+        Tab t = getCurrentTab();
+        if (t != null) {
+            t.mMainView.onPause();
+            if (t.mSubView != null) {
+                t.mSubView.onPause();
+            }
+        }
+    }
+
+    /*package*/ void resumeCurrentTab() {
+        Tab t = getCurrentTab();
+        if (t != null) {
+            t.mMainView.onResume();
+            if (t.mSubView != null) {
+                t.mSubView.onResume();
+            }
+        }
+    }
+
+    private void putViewInForeground(WebView v, WebViewClient vc,
+                                     WebChromeClient cc) {
+        v.setWebViewClient(vc);
+        v.setWebChromeClient(cc);
+        v.setOnCreateContextMenuListener(mActivity);
+        v.setDownloadListener(mActivity);
+        v.onResume();
+    }
+
+    private void putViewInBackground(WebView v) {
+        // Set an empty callback so that default actions are not triggered.
+        v.setWebViewClient(mEmptyClient);
+        v.setWebChromeClient(mBackgroundChromeClient);
+        v.setOnCreateContextMenuListener(null);
+        // Leave the DownloadManager attached so that downloads can start in
+        // a non-active window. This can happen when going to a site that does
+        // a redirect after a period of time. The user could have switched to
+        // another tab while waiting for the download to start.
+        v.setDownloadListener(mActivity);
+        v.onPause();
+    }
+
     /**
      * If force is true, this method skips the check for newTab == current.
      */
@@ -889,7 +934,6 @@
         mTabQueue.add(newTab);
 
         WebView mainView;
-        WebView subView;
 
         // Display the new current tab
         mCurrentTab = mTabs.indexOf(newTab);
@@ -899,17 +943,12 @@
             // Same work as in createNewTab() except don't do new Tab()
             newTab.mMainView = mainView = createNewWebView();
         }
-        mainView.setWebViewClient(mActivity.getWebViewClient());
-        mainView.setWebChromeClient(mActivity.getWebChromeClient());
-        mainView.setOnCreateContextMenuListener(mActivity);
-        mainView.setDownloadListener(mActivity);
+        putViewInForeground(mainView, mActivity.getWebViewClient(),
+                            mActivity.getWebChromeClient());
         // Add the subwindow if it exists
         if (newTab.mSubViewContainer != null) {
-            subView = newTab.mSubView;
-            subView.setWebViewClient(newTab.mSubViewClient);
-            subView.setWebChromeClient(newTab.mSubViewChromeClient);
-            subView.setOnCreateContextMenuListener(mActivity);
-            subView.setDownloadListener(mActivity);
+            putViewInForeground(newTab.mSubView, newTab.mSubViewClient,
+                                newTab.mSubViewChromeClient);
         }
         if (needRestore) {
             // Have to finish setCurrentTab work before calling restoreState
@@ -924,23 +963,9 @@
      * Put the tab in the background using all the empty/background clients.
      */
     private void putTabInBackground(Tab t) {
-        WebView mainView = t.mMainView;
-        // Set an empty callback so that default actions are not triggered.
-        mainView.setWebViewClient(mEmptyClient);
-        mainView.setWebChromeClient(mBackgroundChromeClient);
-        mainView.setOnCreateContextMenuListener(null);
-        // Leave the DownloadManager attached so that downloads can start in
-        // a non-active window. This can happen when going to a site that does
-        // a redirect after a period of time. The user could have switched to
-        // another tab while waiting for the download to start.
-        mainView.setDownloadListener(mActivity);
-        WebView subView = t.mSubView;
-        if (subView != null) {
-            // Set an empty callback so that default actions are not triggered.
-            subView.setWebViewClient(mEmptyClient);
-            subView.setWebChromeClient(mBackgroundChromeClient);
-            subView.setOnCreateContextMenuListener(null);
-            subView.setDownloadListener(mActivity);
+        putViewInBackground(t.mMainView);
+        if (t.mSubView != null) {
+            putViewInBackground(t.mSubView);
         }
     }
 
diff --git a/src/com/android/browser/TitleBar.java b/src/com/android/browser/TitleBar.java
new file mode 100644
index 0000000..f43058b
--- /dev/null
+++ b/src/com/android/browser/TitleBar.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.browser;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.webkit.WebView;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+
+public class TitleBar extends LinearLayout {
+    private TextView        mTitle;
+    private TextView        mUrl;
+    private ImageView       mLftButton;
+    private Drawable        mBookmarkDrawable;
+    private View            mRtButton;
+    private View            mDivider;
+    private ProgressBar     mCircularProgress;
+    private ProgressBar     mHorizontalProgress;
+    private ImageView       mFavicon;
+    private ImageView       mLockIcon;
+    private boolean         mInLoad;
+
+    public TitleBar(Context context) {
+        this(context, null);
+    }
+
+    public TitleBar(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        LayoutInflater factory = LayoutInflater.from(context);
+        factory.inflate(R.layout.title_bar, this);
+
+        mTitle = (TextView) findViewById(R.id.title);
+        mUrl = (TextView) findViewById(R.id.url);
+
+        mLftButton = (ImageView) findViewById(R.id.lft_button);
+        mRtButton = findViewById(R.id.rt_button);
+
+        mCircularProgress = (ProgressBar) findViewById(R.id.progress_circular);
+        mHorizontalProgress = (ProgressBar) findViewById(
+                R.id.progress_horizontal);
+        mFavicon = (ImageView) findViewById(R.id.favicon);
+        mLockIcon = (ImageView) findViewById(R.id.lock_icon);
+        mDivider = findViewById(R.id.divider);
+    }
+
+    /* package */ void setBrowserActivity(final BrowserActivity activity) {
+        mLftButton.setOnClickListener(new View.OnClickListener() {
+                    public void onClick(View v) {
+                        if (mInLoad) {
+                            WebView webView = activity.getTopWindow();
+                            if (webView != null) {
+                                webView.stopLoading();
+                            }
+                        } else {
+                            activity.bookmarksOrHistoryPicker(false);
+                        }
+                    }
+                });
+        mRtButton.setOnClickListener(new View.OnClickListener() {
+                    public void onClick(View v) {
+                        WebView webView = activity.getTopWindow();
+                        if (webView != null) {
+                            webView.zoomScrollOut();
+                        }
+                    }
+                });
+        setOnClickListener(new View.OnClickListener() {
+            public void onClick(View v) {
+                activity.onSearchRequested();
+            }
+        });
+    }
+
+    /* package */ void setFavicon(Drawable d) {
+        mFavicon.setImageDrawable(d);
+    }
+
+    /* package */ void setLock(Drawable d) {
+        if (d == null) {
+            mLockIcon.setVisibility(View.GONE);
+        } else {
+            mLockIcon.setImageDrawable(d);
+            mLockIcon.setVisibility(View.VISIBLE);
+        }
+    }
+
+    /* package */ void setProgress(int newProgress) {
+        if (newProgress == mCircularProgress.getMax()) {
+            mCircularProgress.setVisibility(View.GONE);
+            mHorizontalProgress.setVisibility(View.GONE);
+            mDivider.setVisibility(View.VISIBLE);
+            mRtButton.setVisibility(View.VISIBLE);
+            mLftButton.setImageDrawable(mBookmarkDrawable);
+            mInLoad = false;
+        } else {
+            mCircularProgress.setProgress(newProgress);
+            mHorizontalProgress.setProgress(newProgress);
+            mCircularProgress.setVisibility(View.VISIBLE);
+            mHorizontalProgress.setVisibility(View.VISIBLE);
+            mDivider.setVisibility(View.GONE);
+            mRtButton.setVisibility(View.GONE);
+            if (mBookmarkDrawable == null) {
+                // The drawable was assigned in the xml file, so it already
+                // exists.  Keep a pointer to it when we switch to the resource
+                // so we can easily switch back.
+                mBookmarkDrawable = mLftButton.getDrawable();
+            }
+            mLftButton.setImageResource(
+                    com.android.internal.R.drawable.ic_menu_stop);
+            mInLoad = true;
+        }
+    }
+
+    /* package */ void setTitleAndUrl(CharSequence title, CharSequence url) {
+        if (null == title) {
+            mTitle.setText(R.string.title_bar_loading);
+        } else {
+            mTitle.setText(title);
+        }
+        mUrl.setText(url);
+    }
+
+    /* package */ void setToTabPicker() {
+        mTitle.setText(R.string.tab_picker_title);
+        setFavicon(null);
+        setLock(null);
+        mCircularProgress.setVisibility(View.GONE);
+        mHorizontalProgress.setVisibility(View.GONE);
+    }
+}