am 9acca15d: (-s ours) am 96f9a830: Import revised translations.  DO NOT MERGE

Merge commit '9acca15d763d11b4aa4f1c2366aeec4f1e6a34d7'

* commit '9acca15d763d11b4aa4f1c2366aeec4f1e6a34d7':
  Import revised translations.  DO NOT MERGE
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 7e98019..ac2b317 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -84,6 +84,16 @@
                 <data android:mimeType="application/xhtml+xml"/>
                 <data android:mimeType="application/vnd.wap.xhtml+xml"/>
             </intent-filter>
+            <!-- For viewing saved web archives. -->
+            <intent-filter>
+                <action android:name="android.intent.action.VIEW" />
+                <category android:name="android.intent.category.BROWSABLE" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <data android:scheme="http" />
+                <data android:scheme="https" />
+                <data android:scheme="file" />
+                <data android:mimeType="application/x-webarchive-xml"/>
+            </intent-filter>
             <!-- We are also the main entry point of the browser. -->
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
@@ -184,6 +194,10 @@
             </intent-filter>
         </activity>
 
+        <activity android:name="SaveToHomescreenDialog" android:label="Save to homescreen" android:theme="@android:style/Theme.Dialog"
+                  android:configChanges="orientation|keyboardHidden" android:windowSoftInputMode="stateHidden">
+        </activity>
+
         <!--receiver android:name=".widget.BookmarkWidgetProvider" android:label="@string/bookmarks">
             <intent-filter>
                 <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
diff --git a/res/anim/find_dialog_enter.xml b/res/anim/dialog_enter.xml
similarity index 82%
rename from res/anim/find_dialog_enter.xml
rename to res/anim/dialog_enter.xml
index 5e597a4..6fbcb9e 100644
--- a/res/anim/find_dialog_enter.xml
+++ b/res/anim/dialog_enter.xml
@@ -16,6 +16,6 @@
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
         android:interpolator="@android:anim/decelerate_interpolator">
-	<translate android:fromYDelta="25%" android:toYDelta="0" android:duration="75"/>
-	<alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="75" />
+    <translate android:fromYDelta="-25%" android:toYDelta="0" android:duration="75"/>
+    <alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="75" />
 </set>
diff --git a/res/anim/find_dialog_exit.xml b/res/anim/dialog_exit.xml
similarity index 82%
rename from res/anim/find_dialog_exit.xml
rename to res/anim/dialog_exit.xml
index 854abd0..9845849 100644
--- a/res/anim/find_dialog_exit.xml
+++ b/res/anim/dialog_exit.xml
@@ -16,7 +16,7 @@
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
         android:interpolator="@android:anim/accelerate_interpolator">
-	<translate android:fromYDelta="0" android:toYDelta="50%" android:duration="50"/>
-	<alpha android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="50" />
+    <translate android:fromYDelta="0" android:toYDelta="-50%" android:duration="50"/>
+    <alpha android:fromAlpha="1.0" android:toAlpha="0.0" android:duration="50" />
 </set>
 
diff --git a/res/drawable-hdpi/button_selected.png b/res/drawable-hdpi/button_selected.png
new file mode 100644
index 0000000..752deda
--- /dev/null
+++ b/res/drawable-hdpi/button_selected.png
Binary files differ
diff --git a/res/drawable-hdpi/default_video_poster.png b/res/drawable-hdpi/default_video_poster.png
new file mode 100644
index 0000000..9bbaf9c
--- /dev/null
+++ b/res/drawable-hdpi/default_video_poster.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_arrow_left.png b/res/drawable-hdpi/ic_arrow_left.png
new file mode 100644
index 0000000..bcbe3f6
--- /dev/null
+++ b/res/drawable-hdpi/ic_arrow_left.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_arrow_right.png b/res/drawable-hdpi/ic_arrow_right.png
new file mode 100644
index 0000000..6095533
--- /dev/null
+++ b/res/drawable-hdpi/ic_arrow_right.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_btn_copy.png b/res/drawable-hdpi/ic_btn_copy.png
new file mode 100644
index 0000000..04fda7f
--- /dev/null
+++ b/res/drawable-hdpi/ic_btn_copy.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_btn_find.png b/res/drawable-hdpi/ic_btn_find.png
new file mode 100755
index 0000000..20e1fbc
--- /dev/null
+++ b/res/drawable-hdpi/ic_btn_find.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_btn_select_all.png b/res/drawable-hdpi/ic_btn_select_all.png
new file mode 100644
index 0000000..839915b
--- /dev/null
+++ b/res/drawable-hdpi/ic_btn_select_all.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_btn_share.png b/res/drawable-hdpi/ic_btn_share.png
new file mode 100644
index 0000000..44db9b1
--- /dev/null
+++ b/res/drawable-hdpi/ic_btn_share.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_menu.png b/res/drawable-hdpi/ic_menu.png
new file mode 100644
index 0000000..00f784f
--- /dev/null
+++ b/res/drawable-hdpi/ic_menu.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_menu_downloads.png b/res/drawable-hdpi/ic_menu_downloads.png
new file mode 100644
index 0000000..c85f6a2
--- /dev/null
+++ b/res/drawable-hdpi/ic_menu_downloads.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_menu_find.png b/res/drawable-hdpi/ic_menu_find.png
new file mode 100644
index 0000000..17ac694
--- /dev/null
+++ b/res/drawable-hdpi/ic_menu_find.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_menu_pageinfo.png b/res/drawable-hdpi/ic_menu_pageinfo.png
new file mode 100644
index 0000000..293a021
--- /dev/null
+++ b/res/drawable-hdpi/ic_menu_pageinfo.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_menu_settings.png b/res/drawable-hdpi/ic_menu_settings.png
new file mode 100644
index 0000000..46be101
--- /dev/null
+++ b/res/drawable-hdpi/ic_menu_settings.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_menu_share.png b/res/drawable-hdpi/ic_menu_share.png
new file mode 100644
index 0000000..4b69736
--- /dev/null
+++ b/res/drawable-hdpi/ic_menu_share.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_pages.png b/res/drawable-hdpi/ic_pages.png
new file mode 100644
index 0000000..3fc2e46
--- /dev/null
+++ b/res/drawable-hdpi/ic_pages.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_reload.png b/res/drawable-hdpi/ic_reload.png
new file mode 100644
index 0000000..ebad6da
--- /dev/null
+++ b/res/drawable-hdpi/ic_reload.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_star.png b/res/drawable-hdpi/ic_star.png
new file mode 100644
index 0000000..666c670
--- /dev/null
+++ b/res/drawable-hdpi/ic_star.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_stop.png b/res/drawable-hdpi/ic_stop.png
new file mode 100644
index 0000000..0f1337f
--- /dev/null
+++ b/res/drawable-hdpi/ic_stop.png
Binary files differ
diff --git a/res/drawable-hdpi/pattern_carbon_fiber_dark.png b/res/drawable-hdpi/pattern_carbon_fiber_dark.png
new file mode 100644
index 0000000..cc8e0c5
--- /dev/null
+++ b/res/drawable-hdpi/pattern_carbon_fiber_dark.png
Binary files differ
diff --git a/res/drawable-hdpi/progress_stop.png b/res/drawable-hdpi/progress_stop.png
new file mode 100644
index 0000000..aacece2
--- /dev/null
+++ b/res/drawable-hdpi/progress_stop.png
Binary files differ
diff --git a/res/drawable-hdpi/tab_selected_bg.9.png b/res/drawable-hdpi/tab_selected_bg.9.png
new file mode 100644
index 0000000..4e0f740
--- /dev/null
+++ b/res/drawable-hdpi/tab_selected_bg.9.png
Binary files differ
diff --git a/res/drawable-hdpi/tab_unselected_bg.9.png b/res/drawable-hdpi/tab_unselected_bg.9.png
new file mode 100644
index 0000000..9ab7c56
--- /dev/null
+++ b/res/drawable-hdpi/tab_unselected_bg.9.png
Binary files differ
diff --git a/res/drawable-mdpi/button_selected.png b/res/drawable-mdpi/button_selected.png
new file mode 100644
index 0000000..4fd1aa3
--- /dev/null
+++ b/res/drawable-mdpi/button_selected.png
Binary files differ
diff --git a/res/drawable/default_video_poster.png b/res/drawable-mdpi/default_video_poster.png
similarity index 100%
rename from res/drawable/default_video_poster.png
rename to res/drawable-mdpi/default_video_poster.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_arrow_left.png b/res/drawable-mdpi/ic_arrow_left.png
new file mode 100644
index 0000000..58fd2ca
--- /dev/null
+++ b/res/drawable-mdpi/ic_arrow_left.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_arrow_right.png b/res/drawable-mdpi/ic_arrow_right.png
new file mode 100644
index 0000000..aaf3fde
--- /dev/null
+++ b/res/drawable-mdpi/ic_arrow_right.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_btn_copy.png b/res/drawable-mdpi/ic_btn_copy.png
new file mode 100644
index 0000000..04fda7f
--- /dev/null
+++ b/res/drawable-mdpi/ic_btn_copy.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_btn_find.png b/res/drawable-mdpi/ic_btn_find.png
new file mode 100755
index 0000000..20e1fbc
--- /dev/null
+++ b/res/drawable-mdpi/ic_btn_find.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_btn_select_all.png b/res/drawable-mdpi/ic_btn_select_all.png
new file mode 100644
index 0000000..839915b
--- /dev/null
+++ b/res/drawable-mdpi/ic_btn_select_all.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_btn_share.png b/res/drawable-mdpi/ic_btn_share.png
new file mode 100644
index 0000000..44db9b1
--- /dev/null
+++ b/res/drawable-mdpi/ic_btn_share.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_menu.png b/res/drawable-mdpi/ic_menu.png
new file mode 100644
index 0000000..520b2c3
--- /dev/null
+++ b/res/drawable-mdpi/ic_menu.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_menu_downloads.png b/res/drawable-mdpi/ic_menu_downloads.png
new file mode 100644
index 0000000..fff5022
--- /dev/null
+++ b/res/drawable-mdpi/ic_menu_downloads.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_menu_find.png b/res/drawable-mdpi/ic_menu_find.png
new file mode 100644
index 0000000..4d96348
--- /dev/null
+++ b/res/drawable-mdpi/ic_menu_find.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_menu_pageinfo.png b/res/drawable-mdpi/ic_menu_pageinfo.png
new file mode 100644
index 0000000..c04f0e3
--- /dev/null
+++ b/res/drawable-mdpi/ic_menu_pageinfo.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_menu_settings.png b/res/drawable-mdpi/ic_menu_settings.png
new file mode 100644
index 0000000..7a642d6
--- /dev/null
+++ b/res/drawable-mdpi/ic_menu_settings.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_menu_share.png b/res/drawable-mdpi/ic_menu_share.png
new file mode 100644
index 0000000..ea2b672
--- /dev/null
+++ b/res/drawable-mdpi/ic_menu_share.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_pages.png b/res/drawable-mdpi/ic_pages.png
new file mode 100644
index 0000000..fba4651
--- /dev/null
+++ b/res/drawable-mdpi/ic_pages.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_reload.png b/res/drawable-mdpi/ic_reload.png
new file mode 100644
index 0000000..ec0c238
--- /dev/null
+++ b/res/drawable-mdpi/ic_reload.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_star.png b/res/drawable-mdpi/ic_star.png
new file mode 100644
index 0000000..20a40de
--- /dev/null
+++ b/res/drawable-mdpi/ic_star.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_stop.png b/res/drawable-mdpi/ic_stop.png
new file mode 100644
index 0000000..7ee56e9
--- /dev/null
+++ b/res/drawable-mdpi/ic_stop.png
Binary files differ
diff --git a/res/drawable/pattern_carbon_fiber_dark.png b/res/drawable-mdpi/pattern_carbon_fiber_dark.png
similarity index 100%
rename from res/drawable/pattern_carbon_fiber_dark.png
rename to res/drawable-mdpi/pattern_carbon_fiber_dark.png
Binary files differ
diff --git a/res/drawable-mdpi/progress_stop.png b/res/drawable-mdpi/progress_stop.png
new file mode 100644
index 0000000..a85f987
--- /dev/null
+++ b/res/drawable-mdpi/progress_stop.png
Binary files differ
diff --git a/res/drawable-mdpi/tab_selected_bg.9.png b/res/drawable-mdpi/tab_selected_bg.9.png
new file mode 100644
index 0000000..5e6b1ed
--- /dev/null
+++ b/res/drawable-mdpi/tab_selected_bg.9.png
Binary files differ
diff --git a/res/drawable-mdpi/tab_unselected_bg.9.png b/res/drawable-mdpi/tab_unselected_bg.9.png
new file mode 100644
index 0000000..c19443a
--- /dev/null
+++ b/res/drawable-mdpi/tab_unselected_bg.9.png
Binary files differ
diff --git a/res/anim/find_dialog_enter.xml b/res/drawable/browserbarbutton.xml
similarity index 62%
copy from res/anim/find_dialog_enter.xml
copy to res/drawable/browserbarbutton.xml
index 5e597a4..35a6f48 100644
--- a/res/anim/find_dialog_enter.xml
+++ b/res/drawable/browserbarbutton.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2007 The Android Open Source Project
+<!-- Copyright (C) 2010 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -14,8 +14,8 @@
      limitations under the License.
 -->
 
-<set xmlns:android="http://schemas.android.com/apk/res/android"
-        android:interpolator="@android:anim/decelerate_interpolator">
-	<translate android:fromYDelta="25%" android:toYDelta="0" android:duration="75"/>
-	<alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="75" />
-</set>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_pressed="true"
+            android:drawable="@drawable/button_selected" />
+    <item android:state_pressed="false" android:drawable="@drawable/clear" />
+</selector>
diff --git a/res/anim/find_dialog_enter.xml b/res/drawable/clear.xml
similarity index 62%
copy from res/anim/find_dialog_enter.xml
copy to res/drawable/clear.xml
index 5e597a4..5973f5c 100644
--- a/res/anim/find_dialog_enter.xml
+++ b/res/drawable/clear.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2007 The Android Open Source Project
+<!-- Copyright (C) 2010 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -14,8 +14,10 @@
      limitations under the License.
 -->
 
-<set xmlns:android="http://schemas.android.com/apk/res/android"
-        android:interpolator="@android:anim/decelerate_interpolator">
-	<translate android:fromYDelta="25%" android:toYDelta="0" android:duration="75"/>
-	<alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="75" />
-</set>
+<!-- Used by browserbarbutton to show a clear background for the non pressed
+        state -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="#00000000"/>
+    <padding android:left="9dp" android:top="9dp"
+        android:right="9dp" android:bottom="9dp" />
+</shape>
diff --git a/res/drawable/progress.xml b/res/drawable/progress.xml
new file mode 100644
index 0000000..dd7c375
--- /dev/null
+++ b/res/drawable/progress.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <item android:id="@android:id/background">
+        <shape>
+            <solid android:color="#ffffffff"/>
+        </shape>
+    </item>
+    <item android:id="@android:id/progress">
+        <clip>
+            <shape>
+                <solid android:color="#ff94b73f"/>
+            </shape>
+        </clip>
+    </item>
+
+</layer-list>
diff --git a/res/anim/find_dialog_enter.xml b/res/drawable/tab_unselected.xml
similarity index 62%
copy from res/anim/find_dialog_enter.xml
copy to res/drawable/tab_unselected.xml
index 5e597a4..1f22ae1 100644
--- a/res/anim/find_dialog_enter.xml
+++ b/res/drawable/tab_unselected.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2007 The Android Open Source Project
+<!-- Copyright (C) 2010 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -14,8 +14,9 @@
      limitations under the License.
 -->
 
-<set xmlns:android="http://schemas.android.com/apk/res/android"
-        android:interpolator="@android:anim/decelerate_interpolator">
-	<translate android:fromYDelta="25%" android:toYDelta="0" android:duration="75"/>
-	<alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="75" />
-</set>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="#00000000"/>
+    <stroke android:width="3dp" android:color="#ff404040"/>
+    <padding android:left="9dp" android:top="9dp"
+        android:right="9dp" android:bottom="9dp" />
+</shape>
diff --git a/res/anim/find_dialog_enter.xml b/res/drawable/textfield_nostroke.xml
similarity index 62%
copy from res/anim/find_dialog_enter.xml
copy to res/drawable/textfield_nostroke.xml
index 5e597a4..2945056 100644
--- a/res/anim/find_dialog_enter.xml
+++ b/res/drawable/textfield_nostroke.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2007 The Android Open Source Project
+<!-- Copyright (C) 2010 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -14,8 +14,9 @@
      limitations under the License.
 -->
 
-<set xmlns:android="http://schemas.android.com/apk/res/android"
-        android:interpolator="@android:anim/decelerate_interpolator">
-	<translate android:fromYDelta="25%" android:toYDelta="0" android:duration="75"/>
-	<alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="75" />
-</set>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="#ffd0d0d0"/>
+    <stroke android:width="1dp" android:color="#ff94b73f"/>
+    <padding android:left="9dp" android:top="9dp"
+        android:right="9dp" android:bottom="9dp" />
+</shape>
diff --git a/res/anim/find_dialog_enter.xml b/res/drawable/textfield_stroke.xml
similarity index 62%
copy from res/anim/find_dialog_enter.xml
copy to res/drawable/textfield_stroke.xml
index 5e597a4..4d4c74e 100644
--- a/res/anim/find_dialog_enter.xml
+++ b/res/drawable/textfield_stroke.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2007 The Android Open Source Project
+<!-- Copyright (C) 2010 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -14,8 +14,9 @@
      limitations under the License.
 -->
 
-<set xmlns:android="http://schemas.android.com/apk/res/android"
-        android:interpolator="@android:anim/decelerate_interpolator">
-	<translate android:fromYDelta="25%" android:toYDelta="0" android:duration="75"/>
-	<alpha android:fromAlpha="0.0" android:toAlpha="1.0" android:duration="75" />
-</set>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="#ffffffff"/>
+    <stroke android:width="3dp" android:color="#ff94b73f"/>
+    <padding android:left="9dp" android:top="9dp"
+        android:right="9dp" android:bottom="9dp" />
+</shape>
diff --git a/res/layout-land/title_bar_tabbed.xml b/res/layout-land/title_bar_tabbed.xml
new file mode 100644
index 0000000..853dbeb
--- /dev/null
+++ b/res/layout-land/title_bar_tabbed.xml
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="utf-8"?>
+    <!--
+        Copyright 2010, The Android Open Source Project Licensed under the
+        Apache License, Version 2.0 (the "License"); you may not use this file
+        except in compliance with the License. You may obtain a copy of the
+        License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
+        applicable law or agreed to in writing, software distributed under the
+        License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+        CONDITIONS OF ANY KIND, either express or implied. See the License for
+        the specific language governing permissions and limitations under the
+        License.
+    -->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/tabbedtitleland"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="horizontal"
+    android:paddingLeft="6dip"
+    android:paddingRight="6dip"
+    android:background="#ffdddddd">
+    <ImageButton
+        android:id="@+id/back"
+        android:src="@drawable/ic_arrow_left"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:layout_marginRight="6dip"
+        android:background="@drawable/browserbarbutton" />
+    <ImageButton
+        android:id="@+id/forward"
+        android:src="@drawable/ic_arrow_right"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:layout_marginRight="6dip"
+        android:background="@drawable/browserbarbutton" />
+    <ImageButton
+        android:id="@+id/star"
+        android:src="@drawable/ic_star"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:layout_marginRight="6dip"
+        android:background="@drawable/browserbarbutton" />
+    <com.android.browser.TabScrollView
+        android:id="@+id/tabs"
+        android:layout_width="0dip"
+        android:layout_weight="1.0"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal" />
+    <com.android.browser.UrlInputView
+        android:id="@+id/editurl"
+        android:layout_width="0dip"
+        android:layout_weight="1.0"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="3dip"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:textColor="@color/black"
+        android:gravity="center_vertical"
+        android:singleLine="true"
+        android:ellipsize="end"
+        android:lines="1"
+        android:scrollHorizontally="true"
+        android:visibility="gone"
+        android:background="@drawable/textfield_stroke"
+        android:inputType="textUri"
+        android:imeOptions="actionGo" />
+    <ImageButton
+        android:id="@+id/newtab"
+        android:src="@drawable/ic_menu_new_window"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:layout_marginRight="6dip"
+        android:background="@drawable/browserbarbutton" />
+    <ImageButton
+        android:id="@+id/menu"
+        android:src="@drawable/ic_menu"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:layout_marginRight="6dip"
+        android:background="@drawable/browserbarbutton" />
+    <ImageButton
+        android:id="@+id/all_btn"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:scaleType="center"
+        android:background="@drawable/browserbarbutton"
+        android:src="@drawable/ic_pages" />
+</LinearLayout>
diff --git a/res/layout/bookmark_thumbnail.xml b/res/layout/bookmark_thumbnail.xml
index 1f017d0..363e632 100644
--- a/res/layout/bookmark_thumbnail.xml
+++ b/res/layout/bookmark_thumbnail.xml
@@ -35,7 +35,7 @@
     <LinearLayout android:id="@+id/holder"
         android:layout_height="match_parent"
         android:layout_width="match_parent"
-        android:orientation="horizontal"
+        android:orientation="vertical"
         android:background="#99000000"
         android:gravity="center"
         android:layout_alignBottom="@+id/thumb"
diff --git a/res/layout/browser_add_bookmark_const_url.xml b/res/layout/browser_add_bookmark_const_url.xml
new file mode 100644
index 0000000..c6603f4
--- /dev/null
+++ b/res/layout/browser_add_bookmark_const_url.xml
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical"
+    >
+
+    <ImageView android:id="@+id/titleDivider"
+        android:layout_width="match_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 xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:orientation="vertical"
+        android:paddingTop="5dip"
+        android:paddingBottom="13dip"
+        android:paddingLeft="20dip"
+        android:paddingRight="20dip" >
+
+        <TextView
+            android:id="@+id/titleText"
+            android:layout_height="wrap_content"
+            android:layout_width="wrap_content"
+            android:text="@string/name"
+            android:gravity="left"
+            android:textAppearance="?android:attr/textAppearanceMedium" />
+
+        <EditText
+            android:id="@+id/title"
+            android:layout_height="wrap_content"
+            android:layout_width="250dip"
+            android:gravity="fill_horizontal"
+            android:inputType="textCapSentences"
+            android:selectAllOnFocus="true"
+            android:textAppearance="?android:attr/textAppearanceMedium" />
+
+    </LinearLayout>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:background="#c6c3c6"
+        android:minHeight="54dip"
+        android:orientation="horizontal"
+        android:paddingTop="4dip"
+        android:paddingLeft="2dip"
+        android:paddingRight="2dip" >
+        <Button android:id="@+id/OK"
+            android:text="@string/save"
+            android:layout_width="0dip"
+            android:layout_gravity="left"
+            android:layout_weight="1"
+            android:maxLines="2"
+            android:layout_height="wrap_content" />
+        <Button android:id="@+id/cancel"
+            android:text="@string/do_not_save"
+            android:layout_width="0dip"
+            android:layout_gravity="right"
+            android:layout_weight="1"
+            android:maxLines="2"
+            android:layout_height="wrap_content" />
+    </LinearLayout>
+
+</LinearLayout>
+
diff --git a/res/layout/browser_select.xml b/res/layout/browser_select.xml
new file mode 100644
index 0000000..b30be8d
--- /dev/null
+++ b/res/layout/browser_select.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/selectControls"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:paddingTop="5dip"
+    android:paddingLeft="4dip"
+    android:paddingRight="4dip"
+    android:paddingBottom="1dip"
+    android:background="@android:drawable/bottom_bar">
+    <ImageButton
+        android:src="@drawable/ic_btn_copy"
+        android:id="@+id/copy"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        />
+
+    <ImageButton
+        android:src="@drawable/ic_btn_share"
+        android:id="@+id/share"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        />
+
+    <ImageButton
+        android:src="@drawable/ic_btn_select_all"
+        android:id="@+id/select_all"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        />
+
+    <ImageButton
+        android:src="@drawable/ic_btn_find"
+        android:id="@+id/find"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        />
+
+    <LinearLayout
+        android:layout_height="fill_parent"
+        android:layout_width="fill_parent"
+        android:layout_weight="1"
+        />
+
+    <ImageButton
+        android:src="@drawable/ic_btn_close_panel"
+        android:id="@+id/done"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        />
+</LinearLayout>
+
diff --git a/res/layout/browser_subwindow.xml b/res/layout/browser_subwindow.xml
index 76d72d5..adf3284 100644
--- a/res/layout/browser_subwindow.xml
+++ b/res/layout/browser_subwindow.xml
@@ -23,6 +23,7 @@
         android:layout_height="match_parent"
         android:padding="10dip" >
         <LinearLayout
+            android:id="@+id/inner_container"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             android:orientation="vertical"
diff --git a/res/layout/custom_screen.xml b/res/layout/custom_screen.xml
index 90dc324..525f30c 100644
--- a/res/layout/custom_screen.xml
+++ b/res/layout/custom_screen.xml
@@ -22,6 +22,7 @@
         android:layout_height="match_parent"
     />
     <LinearLayout android:orientation="vertical"
+        android:id="@+id/vertical_layout"
         android:layout_width="match_parent"
         android:layout_height="match_parent">
 
diff --git a/res/layout/simple_dropdown_item_2line.xml b/res/layout/simple_dropdown_item_2line.xml
new file mode 100644
index 0000000..8b955ec
--- /dev/null
+++ b/res/layout/simple_dropdown_item_2line.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/layout/simple_spinner_item.xml
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="?android:attr/listPreferredItemHeight"
+    android:orientation="horizontal"
+    android:gravity="center_vertical"
+    android:baselineAligned="false">
+    <ImageView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:id="@+id/icon1"
+        android:scaleType="center"
+        android:paddingLeft="2dip"
+        android:paddingRight="2dip" />
+    <TwoLineListItem
+        android:paddingTop="2dip"
+        android:paddingBottom="2dip"
+        android:layout_width="0dip"
+        android:layout_weight="1"
+        android:layout_height="wrap_content"
+        android:mode="twoLine">
+        <TextView
+            android:id="@android:id/text1"
+            style="?android:attr/dropDownItemStyle"
+            android:textAppearance="?android:attr/textAppearanceLargeInverse"
+            android:singleLine="true"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content" />
+        <TextView
+            android:id="@android:id/text2"
+            style="?android:attr/dropDownItemStyle"
+            android:textAppearance="?android:attr/textAppearanceSmallInverse"
+            android:textColor="#323232"
+            android:singleLine="true"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_below="@android:id/text1"
+            android:layout_alignLeft="@android:id/text1" />
+    </TwoLineListItem>
+</LinearLayout>
diff --git a/res/layout/tab_title.xml b/res/layout/tab_title.xml
new file mode 100644
index 0000000..28b553d
--- /dev/null
+++ b/res/layout/tab_title.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="utf-8"?>
+    <!--
+        Copyright 2010, The Android Open Source Project Licensed under the
+        Apache License, Version 2.0 (the "License"); you may not use this file
+        except in compliance with the License. You may obtain a copy of the
+        License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
+        applicable law or agreed to in writing, software distributed under the
+        License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+        CONDITIONS OF ANY KIND, either express or implied. See the License for
+        the specific language governing permissions and limitations under the
+        License.
+    -->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="0dip"
+    android:layout_weight="1.0"
+    android:layout_height="wrap_content"
+    android:gravity="center_vertical"
+    android:orientation="horizontal">
+    <ImageView
+        android:id="@+id/favicon"
+        android:layout_width="20dip"
+        android:layout_height="20dip"
+        android:layout_marginLeft="3dip" />
+    <ImageView
+        android:id="@+id/lock"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="6dip"
+        android:visibility="gone" />
+    <TextView
+        android:id="@+id/title"
+        android:layout_height="wrap_content"
+        android:layout_width="0dip"
+        android:layout_weight="1.0"
+        android:layout_marginLeft="3dip"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:textColor="@color/black"
+        android:gravity="center_vertical"
+        android:singleLine="true"
+        android:ellipsize="end" />
+    <com.android.browser.CircularProgressView
+        android:id="@+id/stop"
+        android:layout_width="36dip"
+        android:layout_height="36dip"
+        android:background="@null"
+        android:src="@drawable/progress_stop" />
+    <ImageView
+        android:id="@+id/close"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="6dip"
+        android:src="@drawable/btn_close_window" />
+</LinearLayout>
diff --git a/res/layout/title_bar.xml b/res/layout/title_bar.xml
index 9f0cb51..d6a77e0 100644
--- a/res/layout/title_bar.xml
+++ b/res/layout/title_bar.xml
@@ -90,7 +90,7 @@
             android:layout_marginRight="-5dip"
             android:scaleType="center"
             android:background="@drawable/btn_bookmark"
-            android:src="@drawable/ic_btn_bookmarks"
+            android:src="@drawable/ic_list_bookmark"
         />
     </LinearLayout>
 </LinearLayout>
diff --git a/res/layout/title_bar_tabbed.xml b/res/layout/title_bar_tabbed.xml
new file mode 100644
index 0000000..fc786e0
--- /dev/null
+++ b/res/layout/title_bar_tabbed.xml
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="utf-8"?>
+    <!--
+        Copyright 2010, The Android Open Source Project Licensed under the
+        Apache License, Version 2.0 (the "License"); you may not use this file
+        except in compliance with the License. You may obtain a copy of the
+        License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by
+        applicable law or agreed to in writing, software distributed under the
+        License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+        CONDITIONS OF ANY KIND, either express or implied. See the License for
+        the specific language governing permissions and limitations under the
+        License.
+    -->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/tabbedtitleport"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical"
+    android:background="#ffdddddd">
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+        <com.android.browser.TabScrollView
+            android:id="@+id/tabs"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1.0"
+            android:orientation="horizontal" />
+        <ImageButton
+            android:id="@+id/newtab"
+            android:src="@drawable/ic_menu_new_window"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:background="@drawable/browserbarbutton" />
+    </LinearLayout>
+    <LinearLayout
+        android:id="@+id/urlbar"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal"
+        android:paddingLeft="6dip"
+        android:paddingRight="6dip">
+        <ImageButton
+            android:id="@+id/back"
+            android:src="@drawable/ic_arrow_left"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:layout_marginRight="6dip"
+            android:background="@drawable/browserbarbutton" />
+        <ImageButton
+            android:id="@+id/forward"
+            android:src="@drawable/ic_arrow_right"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:layout_marginRight="6dip"
+            android:background="@drawable/browserbarbutton" />
+        <ImageButton
+            android:id="@+id/star"
+            android:src="@drawable/ic_star"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:layout_marginRight="6dip"
+            android:background="@drawable/browserbarbutton" />
+        <com.android.browser.UrlInputView
+            android:id="@+id/editurl"
+            android:layout_width="0dip"
+            android:layout_weight="1.0"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="3dip"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textColor="@color/black"
+            android:gravity="center_vertical"
+            android:singleLine="true"
+            android:ellipsize="end"
+            android:lines="1"
+            android:scrollHorizontally="true"
+            android:visibility="gone"
+            android:background="@drawable/textfield_nostroke"
+            android:inputType="textUri"
+            android:imeOptions="actionGo" />
+        <ImageButton
+            android:id="@+id/menu"
+            android:src="@drawable/ic_menu"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:layout_marginRight="6dip"
+            android:background="@drawable/browserbarbutton" />
+        <ImageButton
+            android:id="@+id/all_btn"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:scaleType="center"
+            android:background="@drawable/browserbarbutton"
+            android:src="@drawable/ic_pages" />
+    </LinearLayout>
+</LinearLayout>
diff --git a/res/menu-xlarge/browser.xml b/res/menu-xlarge/browser.xml
new file mode 100644
index 0000000..0fc20be
--- /dev/null
+++ b/res/menu-xlarge/browser.xml
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android">
+    <group android:id="@+id/MAIN_MENU">
+        <item android:id="@+id/new_tab_menu_id"
+            android:title="@string/new_tab"
+            android:icon="@drawable/ic_menu_new_window"
+            android:alphabeticShortcut="n" />
+        <item android:id="@+id/active_tabs_menu_id"
+            android:title="@string/active_tabs"
+            android:icon="@drawable/ic_menu_windows"
+            android:alphabeticShortcut="t" />
+        <item android:id="@+id/find_menu_id"
+            android:title="@string/find_dot"
+            android:icon="@drawable/ic_menu_find"
+            android:alphabeticShortcut="f" />
+        <item android:id="@+id/share_page_menu_id"
+            android:title="@string/share_page"
+            android:icon="@drawable/ic_menu_share"
+            android:alphabeticShortcut="s" />
+        <item android:id="@+id/page_info_menu_id"
+            android:title="@string/page_info"
+            android:icon="@drawable/ic_menu_pageinfo"
+            android:alphabeticShortcut="g" />
+        <item android:id="@+id/view_downloads_menu_id"
+            android:title="@string/menu_view_download"
+            android:icon="@drawable/ic_menu_downloads"
+            android:alphabeticShortcut="d" />
+        <item android:id="@+id/preferences_menu_id"
+            android:title="@string/menu_preferences"
+            android:icon="@drawable/ic_menu_settings"
+            android:alphabeticShortcut="p" />
+        <item android:id="@+id/save_webarchive_menu_id"
+            android:title="@string/menu_save_webarchive" />
+        <!-- followings are debug only -->
+        <item android:id="@+id/dump_nav_menu_id"
+            android:title="@string/dump_nav"
+            android:visible="false" />
+        <item android:id="@+id/dump_counters_menu_id"
+            android:title="@string/dump_counters"
+            android:visible="false" />
+    </group>
+    <group android:id="@+id/MAIN_SHORTCUT_MENU" android:visible="false">
+        <item android:id="@+id/homepage_menu_id"
+            android:alphabeticShortcut="&#32;" />
+        <item android:id="@+id/classic_history_menu_id"
+            android:alphabeticShortcut="h" />
+        <item android:id="@+id/zoom_in_menu_id"
+            android:alphabeticShortcut="i" />
+        <item android:id="@+id/zoom_out_menu_id"
+            android:alphabeticShortcut="o" />
+        <item android:id="@+id/window_one_menu_id"
+            android:alphabeticShortcut="1" />
+        <item android:id="@+id/window_two_menu_id"
+            android:alphabeticShortcut="2" />
+        <item android:id="@+id/window_three_menu_id"
+            android:alphabeticShortcut="3" />
+        <item android:id="@+id/window_four_menu_id"
+            android:alphabeticShortcut="4" />
+        <item android:id="@+id/window_five_menu_id"
+            android:alphabeticShortcut="5" />
+        <item android:id="@+id/window_six_menu_id"
+            android:alphabeticShortcut="6" />
+        <item android:id="@+id/window_seven_menu_id"
+            android:alphabeticShortcut="7" />
+        <item android:id="@+id/window_eight_menu_id"
+            android:alphabeticShortcut="8" />
+        <item android:id="@+id/back_menu_id"
+            android:alphabeticShortcut="j" />
+        <item android:id="@+id/forward_menu_id"
+            android:alphabeticShortcut="k" />
+        <item android:id="@+id/bookmarks_menu_id"
+            android:alphabeticShortcut="b" />
+        <item android:id="@+id/add_bookmark_menu_id"
+            android:alphabeticShortcut="a" />
+        <item android:id="@+id/stop_reload_menu_id"
+            android:alphabeticShortcut="r" />
+        <item android:id="@+id/goto_menu_id"
+            android:alphabeticShortcut="l" />
+        <item android:id="@+id/close_menu_id"
+            android:alphabeticShortcut="w" />
+    </group>
+</menu>
diff --git a/res/menu/browser.xml b/res/menu/browser.xml
index 4793c21..adb1bad 100644
--- a/res/menu/browser.xml
+++ b/res/menu/browser.xml
@@ -41,22 +41,26 @@
             android:alphabeticShortcut="a" />
         <item android:id="@+id/find_menu_id"
             android:title="@string/find_dot"
+            android:icon="@drawable/ic_menu_find"
             android:alphabeticShortcut="f" />
-        <item android:id="@+id/select_text_id"
-            android:title="@string/select_dot"
-            android:alphabeticShortcut="e" />
-        <item android:id="@+id/page_info_menu_id"
-            android:title="@string/page_info"
-            android:alphabeticShortcut="g" />
         <item android:id="@+id/share_page_menu_id"
             android:title="@string/share_page"
+            android:icon="@drawable/ic_menu_share"
             android:alphabeticShortcut="s" />
+        <item android:id="@+id/page_info_menu_id"
+            android:title="@string/page_info"
+            android:icon="@drawable/ic_menu_pageinfo"
+            android:alphabeticShortcut="g" />
         <item android:id="@+id/view_downloads_menu_id"
             android:title="@string/menu_view_download"
+            android:icon="@drawable/ic_menu_downloads"
             android:alphabeticShortcut="d" />
         <item android:id="@+id/preferences_menu_id"
             android:title="@string/menu_preferences"
+            android:icon="@drawable/ic_menu_settings"
             android:alphabeticShortcut="p" />
+        <item android:id="@+id/save_webarchive_menu_id"
+            android:title="@string/menu_save_webarchive" />
         <!-- followings are debug only -->
         <item android:id="@+id/dump_nav_menu_id"
             android:title="@string/dump_nav"
@@ -91,16 +95,10 @@
         <item android:id="@+id/window_eight_menu_id"
             android:alphabeticShortcut="8" />
         <item android:id="@+id/back_menu_id"
-            android:title="@string/back"
-            android:drawable="@*android:drawable/ic_menu_back"
             android:alphabeticShortcut="j" />
         <item android:id="@+id/goto_menu_id"
-            android:title="@string/goto_dot"
-            android:alphabeticShortcut="l"
-            android:icon="@android:drawable/ic_menu_search"/>
+            android:alphabeticShortcut="l" />
         <item android:id="@+id/close_menu_id"
-            android:icon="@drawable/ic_btn_close_panel"
-            android:title="@string/tab_picker_remove_tab"
             android:alphabeticShortcut="w" />
     </group>
     <!-- these items are toggled in and out of @+id/stop_reload_menu_id -->
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index e9df9f4..7efb620 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -38,7 +38,7 @@
     <item quantity="few" msgid="5544267486978946555">"<xliff:g id="NUMBER">%d</xliff:g> Treffer"</item>
     <item quantity="other" msgid="6616125067364315405">"<xliff:g id="NUMBER">%d</xliff:g> Treffer"</item>
   </plurals>
-    <string name="title_bar_loading" msgid="7438217780834640678">"Wird geladen..."</string>
+    <string name="title_bar_loading" msgid="7438217780834640678">"Ladevorgang läuft..."</string>
     <string name="page_info" msgid="4048529256302257195">"Seiteninfo"</string>
     <string name="page_info_view" msgid="5303490449842635158">"Seiteninfo anzeigen"</string>
     <string name="page_info_address" msgid="2222306609532903254">"Adresse:"</string>
@@ -112,7 +112,7 @@
     <string name="contextmenu_copylink" msgid="5153657160294534270">"Link-URL kopieren"</string>
     <string name="contextmenu_download_image" msgid="4243829645180686912">"Bild speichern"</string>
     <string name="contextmenu_view_image" msgid="3870625602053600905">"Bild anzeigen"</string>
-    <string name="contextmenu_set_wallpaper" msgid="3691902960115350686">"Als Hintergrund festlegen"</string>
+    <string name="contextmenu_set_wallpaper" msgid="3691902960115350686">"Als Hintergrundbild festlegen"</string>
     <string name="contextmenu_dial_dot" msgid="5856550683415933806">"Wählen..."</string>
     <string name="contextmenu_add_contact" msgid="3183511922223645716">"Kontakt hinzufügen"</string>
     <string name="contextmenu_send_mail" msgid="1014513374828775660">"E-Mail senden"</string>
@@ -289,5 +289,5 @@
     <string name="website_settings_clear_all_dialog_message" msgid="6150502090601476333">"Alle Websitedaten und Standortberechtigungen werden gelöscht."</string>
     <string name="website_settings_clear_all_dialog_ok_button" msgid="6401582240627669431">"Alle Daten löschen"</string>
     <string name="website_settings_clear_all_dialog_cancel_button" msgid="1896757051856611674">"Abbrechen"</string>
-    <string name="progress_dialog_setting_wallpaper" msgid="4871900779338536674">"Hintergrund wird eingestellt..."</string>
+    <string name="progress_dialog_setting_wallpaper" msgid="4871900779338536674">"Hintergrundbild wird eingestellt..."</string>
 </resources>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index 02b06b1..d69b315 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -22,7 +22,7 @@
     <string name="active_tabs" msgid="3050623868203544623">"Windows"</string>
     <string name="tab_bookmarks" msgid="2305793036003473653">"Marcadores"</string>
     <string name="tab_most_visited" msgid="1077402532455000703">"Más visitados"</string>
-    <string name="tab_history" msgid="1979267558744613746">"Historial "</string>
+    <string name="tab_history" msgid="1979267558744613746">"Historial"</string>
     <string name="added_to_bookmarks" msgid="1020224130695956728">"Agregado a marcadores"</string>
     <string name="removed_from_bookmarks" msgid="6063705902028438800">"Suprimido de los marcadores"</string>
     <string name="sign_in_to" msgid="5939425800148759165">"Iniciar sesión en <xliff:g id="HOSTNAME">%s1</xliff:g> \"<xliff:g id="REALM">%s2</xliff:g>\""</string>
@@ -226,17 +226,17 @@
     <string name="popup_window_attempt" msgid="2673111696288657989">"Este sitio está intentando abrir una ventana emergente."</string>
     <string name="allow" msgid="1157313689171991335">"Permitir"</string>
     <string name="block" msgid="9172175889884707800">"Bloquear"</string>
-    <string name="too_many_windows_dialog_title" msgid="5175503564948906442">"Se alcanzó el límite de la ventana "</string>
+    <string name="too_many_windows_dialog_title" msgid="5175503564948906442">"Se alcanzó el límite de la ventana"</string>
     <string name="too_many_windows_dialog_message" msgid="1398571800233959583">"No se ha podido abrir una ventana nueva porque ya has abierto el máximo permitido."</string>
     <string name="too_many_subwindows_dialog_title" msgid="3805453941587725944">"Ventana emergente ya abierta"</string>
     <string name="too_many_subwindows_dialog_message" msgid="5827289829907966657">"No es posible abrir una ventana emergente nueva porque sólo puede abrirse una por vez."</string>
     <string name="download_title" msgid="2122874021047565594">"Historial de descarga"</string>
     <string name="download_unknown_filename" msgid="4013465542563652175">"&lt;Desconocido&gt;"</string>
     <string name="download_menu_open" msgid="4888327480367757513">"Abrir"</string>
-    <string name="download_menu_clear" msgid="6264454531553418124">"Borrar de la lista\n "</string>
+    <string name="download_menu_clear" msgid="6264454531553418124">"Borrar de la lista"</string>
     <string name="download_menu_delete" msgid="8815502136393894148">"Eliminar"</string>
     <string name="download_menu_cancel" msgid="2545333007601851574">"Cancelar descarga"</string>
-    <string name="download_menu_cancel_all" msgid="2136550823151999166">"Cancelar todas las descargas\n "</string>
+    <string name="download_menu_cancel_all" msgid="2136550823151999166">"Cancelar todas las descargas"</string>
     <string name="download_cancel_dlg_title" msgid="8909108500262799748">"Cancelar descargas"</string>
     <string name="download_cancel_dlg_msg" msgid="6285389170052357797">"Las <xliff:g id="DOWNLOAD_COUNT">%d</xliff:g> descargas se cancelarán y se borrarán del historial de descarga."</string>
     <string name="download_delete_file" msgid="5330036497843073249">"El archivo se eliminará"</string>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index 6e19b2e..b976eeb 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -62,7 +62,7 @@
     <string name="expires_on" msgid="8061200430557020704">"Дата окончания действия:"</string>
     <string name="stopping" msgid="4839698519340302982">"Остановка..."</string>
     <string name="stop" msgid="5687251076030630074">"Стоп"</string>
-    <string name="reload" msgid="8585220783228408062">"Обновить"</string>
+    <string name="reload" msgid="8585220783228408062">"Обновление"</string>
     <string name="back" msgid="8414603107175713668">"Назад"</string>
     <string name="forward" msgid="4288210890526641577">"Вперед"</string>
     <string name="save" msgid="5922311934992468496">"ОК"</string>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index bbb698c..b4dafb1 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -90,7 +90,7 @@
     <string name="switch_to_thumbnails" msgid="5493351529609043151">"Miniatyrvy"</string>
     <string name="switch_to_list" msgid="8900531247982121055">"Listvy"</string>
     <string name="current_page" msgid="7510129573681663135">"från "</string>
-    <string name="delete_bookmark_warning" msgid="758043186202032205">"Bokmärket <xliff:g id="BOOKMARK">%s</xliff:g> tas bort. "</string>
+    <string name="delete_bookmark_warning" msgid="758043186202032205">"Bokmärket <xliff:g id="BOOKMARK">%s</xliff:g> tas bort."</string>
     <string name="open_in_new_window" msgid="6596775546468054510">"Öppna i nytt fönster"</string>
     <string name="goto_dot" msgid="3895839050522602723">"Kör"</string>
     <string name="find_dot" msgid="6259312434696611957">"Sök på sidan"</string>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 07c2eb9..0dcfa9e 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -50,17 +50,16 @@
     <!-- Label for a confirm button.  Used in multiple contexts. -->
     <string name="ok">OK</string>
 
-    <!-- Displayed on the Find dialog to display the number of matches
-         found in the current page. -->
+    <!-- Displayed on the Find dialog when there are no matches -->
+    <string name="no_matches">No matches</string>
+
+    <!-- Displayed on the Find dialog to display the index of the highlighted
+         match and total number of matches found in the current page. -->
     <plurals name="matches_found">
-        <!-- Case of no matches -->
-        <item quantity="zero">No matches</item>
         <!-- Case of one match -->
         <item quantity="one">1 match</item>
-        <!-- Case of "few" (two) matches -->
-        <item quantity="few"><xliff:g id="number" example="2">%d</xliff:g> matches</item>
-        <!-- Case of several matches -->
-        <item quantity="other"><xliff:g id="number" example="137">%d</xliff:g> matches</item>
+        <!-- Case of multiple total matches -->
+        <item quantity="other"><xliff:g id="index" example="2">%d</xliff:g> of <xliff:g id="total" example="137">%d</xliff:g></item>
     </plurals>
 
     <!-- Displayed on the title bar while the page is loading -->
@@ -138,12 +137,13 @@
     <string name="name">Name</string>
     <!-- Initial value in Location field in Bookmark dialog box -->
     <string name="http">http://</string>
-    <!-- Menu item that opens a dialog to save a bookmark, initialized with the current page -->
-    <string name="save_to_bookmarks">Add bookmark</string>
+    <!-- Menu item that opens a dialog to save a bookmark for the current page, also displayed as
+            the title of the dialog used for adding a bookmark -->
+    <string name="save_to_bookmarks">Add to Bookmarks</string>
     <!-- Menu item on the bookmarks page, to edit an existing bookmark -->
     <string name="edit_bookmark">Edit bookmark</string>
     <!-- Context menu item to create a shortcut to the bookmark on the desktop -->
-    <string name="create_shortcut_bookmark">Add shortcut to Home</string>
+    <string name="create_shortcut_bookmark">Add to Home</string>
     <!-- Context menu item to open the currently highlighted bookmark -->
     <string name="open_bookmark">Open</string>
     <!-- Menu item to remove the currently highlighted bookmark-->
@@ -217,6 +217,12 @@
     <string name="copy_page_url">Copy page url</string>
     <!-- Menu item -->
     <string name="share_page">Share page</string>
+    <!-- Menu item for saving a page as a web archive. -->
+    <string name="menu_save_webarchive">Save as Web Archive</string>
+    <!-- Toast informing the user that the page has been saved. -->
+    <string name="webarchive_saved">Web archive saved.</string>
+    <!-- Toast informing the user that saving the page has failed. -->
+    <string name="webarchive_failed">Failed to save web archive.</string>
     <!-- Context Menu item open the currently selected link in the current
             window.-->
     <string name="contextmenu_openlink">Open</string>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 4779aa1..2e8510a 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -30,11 +30,6 @@
         <item name="android:windowContentOverlay">@null</item>
     </style>
 
-    <style name="FindDialog">
-        <item name="android:windowEnterAnimation">@anim/find_dialog_enter</item>
-        <item name="android:windowExitAnimation">@anim/find_dialog_exit</item>
-    </style>
-
     <style name="TitleBar">
         <item name="android:windowEnterAnimation">@anim/title_bar_enter</item>
         <item name="android:windowExitAnimation">@anim/title_bar_exit</item>
diff --git a/res/values/themes.xml b/res/values/themes.xml
deleted file mode 100644
index bb922dd..0000000
--- a/res/values/themes.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<resources>
-    <style name="FindDialogTheme"> 
-        <item name="android:windowFrame">@null</item>
-        <item name="android:windowIsFloating">true</item>
-        <item name="android:windowIsTranslucent">true</item>
-        <item name="android:windowNoTitle">true</item>
-        <item name="android:background">@null</item>
-        <item name="android:windowBackground">@null</item>
-        <item name="android:windowAnimationStyle">@style/FindDialog</item>
-        <item name="android:backgroundDimEnabled">false</item>
-    </style>
-</resources>
diff --git a/src/com/android/browser/ActiveTabsPage.java b/src/com/android/browser/ActiveTabsPage.java
index 2de7787..52828b3 100644
--- a/src/com/android/browser/ActiveTabsPage.java
+++ b/src/com/android/browser/ActiveTabsPage.java
@@ -20,6 +20,7 @@
 import android.graphics.Bitmap;
 import android.os.Handler;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -32,6 +33,7 @@
 import android.widget.TextView;
 
 public class ActiveTabsPage extends LinearLayout {
+    private static final String LOGTAG = "TabPicker";
     private final BrowserActivity   mBrowserActivity;
     private final LayoutInflater    mFactory;
     private final TabControl        mControl;
@@ -152,7 +154,19 @@
                         (ImageView) convertView.findViewById(R.id.favicon);
                 View close = convertView.findViewById(R.id.close);
                 Tab tab = mControl.getTab(position);
+                if (tab.getWebView() == null) {
+                    // This means that populatePickerData will have to use the
+                    // saved state.
+                    Log.w(LOGTAG, "Tab " + position + " has a null WebView and "
+                            + (tab.getSavedState() == null ? "null" : "non-null")
+                            + " saved state ");
+                }
                 tab.populatePickerData();
+                if (tab.getTitle() == null || tab.getTitle().length() == 0) {
+                    Log.w(LOGTAG, "Tab " + position + " has no title. "
+                            + "Check above in the Logs to see whether it has a "
+                            + "null WebView or null WebHistoryItem");
+                }
                 title.setText(tab.getTitle());
                 url.setText(tab.getUrl());
                 Bitmap icon = tab.getFavicon();
diff --git a/src/com/android/browser/AddBookmarkPage.java b/src/com/android/browser/AddBookmarkPage.java
index 1104d5e..10c91f8 100644
--- a/src/com/android/browser/AddBookmarkPage.java
+++ b/src/com/android/browser/AddBookmarkPage.java
@@ -51,6 +51,7 @@
     private String      mTouchIconUrl;
     private Bitmap      mThumbnail;
     private String      mOriginalUrl;
+    private boolean     mIsUrlEditable = true;
 
     // Message IDs
     private static final int SAVE_BOOKMARK = 100;
@@ -74,13 +75,24 @@
     protected void onCreate(Bundle icicle) {
         super.onCreate(icicle);
         requestWindowFeature(Window.FEATURE_LEFT_ICON);
-        setContentView(R.layout.browser_add_bookmark);
+
+        mMap = getIntent().getExtras();
+        if (mMap != null) {
+            mIsUrlEditable = mMap.getBoolean("url_editable", true);
+        }
+
+        if (mIsUrlEditable) {
+            setContentView(R.layout.browser_add_bookmark);
+        } else {
+            setContentView(R.layout.browser_add_bookmark_const_url);
+        }
+
         setTitle(R.string.save_to_bookmarks);
         getWindow().setFeatureDrawableResource(Window.FEATURE_LEFT_ICON, R.drawable.ic_list_bookmark);
         
         String title = null;
         String url = null;
-        mMap = getIntent().getExtras();
+
         if (mMap != null) {
             Bundle b = mMap.getBundle("bookmark");
             if (b != null) {
@@ -96,8 +108,11 @@
 
         mTitle = (EditText) findViewById(R.id.title);
         mTitle.setText(title);
-        mAddress = (EditText) findViewById(R.id.address);
-        mAddress.setText(url);
+
+        if (mIsUrlEditable) {
+            mAddress = (EditText) findViewById(R.id.address);
+            mAddress.setText(url);
+        }
 
         View.OnClickListener accept = mSaveBookmark;
         mButton = (TextView) findViewById(R.id.OK);
@@ -135,7 +150,7 @@
                 final ContentResolver cr = getContentResolver();
                 Bookmarks.addBookmark(null, cr, url, title, thumbnail, true);
                 if (touchIconUrl != null) {
-                    new DownloadTouchIcon(cr, url).execute(mTouchIconUrl);
+                    new DownloadTouchIcon(AddBookmarkPage.this, cr, url).execute(mTouchIconUrl);
                 }
                 mMessage.arg1 = 1;
             } catch (IllegalStateException e) {
@@ -173,8 +188,14 @@
         createHandler();
 
         String title = mTitle.getText().toString().trim();
-        String unfilteredUrl = 
-                BrowserActivity.fixUrl(mAddress.getText().toString());
+        String unfilteredUrl;
+        if (mIsUrlEditable) {
+            unfilteredUrl =
+                    BrowserActivity.fixUrl(mAddress.getText().toString());
+        } else {
+            unfilteredUrl = mOriginalUrl;
+        }
+
         boolean emptyTitle = title.length() == 0;
         boolean emptyUrl = unfilteredUrl.trim().length() == 0;
         Resources r = getResources();
@@ -183,9 +204,15 @@
                 mTitle.setError(r.getText(R.string.bookmark_needs_title));
             }
             if (emptyUrl) {
-                mAddress.setError(r.getText(R.string.bookmark_needs_url));
+                if (mIsUrlEditable) {
+                    mAddress.setError(r.getText(R.string.bookmark_needs_url));
+                } else {
+                    Toast.makeText(AddBookmarkPage.this, R.string.bookmark_needs_url,
+                            Toast.LENGTH_LONG).show();
+                }
+                return false;
             }
-            return false;
+
         }
         String url = unfilteredUrl.trim();
         try {
@@ -200,7 +227,12 @@
                     // can't save their bookmark. If it was null, we'll assume
                     // they meant http when we parse it in the WebAddress class.
                     if (scheme != null) {
-                        mAddress.setError(r.getText(R.string.bookmark_cannot_save_url));
+                        if (mIsUrlEditable) {
+                            mAddress.setError(r.getText(R.string.bookmark_cannot_save_url));
+                        } else {
+                            Toast.makeText(AddBookmarkPage.this, R.string.bookmark_cannot_save_url,
+                                    Toast.LENGTH_LONG).show();
+                        }
                         return false;
                     }
                     WebAddress address;
@@ -216,7 +248,12 @@
                 }
             }
         } catch (URISyntaxException e) {
-            mAddress.setError(r.getText(R.string.bookmark_url_not_valid));
+            if (mIsUrlEditable) {
+                mAddress.setError(r.getText(R.string.bookmark_url_not_valid));
+            } else {
+                Toast.makeText(AddBookmarkPage.this, R.string.bookmark_url_not_valid,
+                        Toast.LENGTH_LONG).show();
+            }
             return false;
         }
 
diff --git a/src/com/android/browser/BookmarkUtils.java b/src/com/android/browser/BookmarkUtils.java
new file mode 100644
index 0000000..0fdad15
--- /dev/null
+++ b/src/com/android/browser/BookmarkUtils.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.browser;
+
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.net.Uri;
+import android.provider.Browser;
+import android.util.Log;
+
+class BookmarkUtils {
+    private final static String LOGTAG = "BookmarkUtils";
+
+    // XXX: There is no public string defining this intent so if Home changes the value, we
+    // have to update this string.
+    private static final String INSTALL_SHORTCUT = "com.android.launcher.action.INSTALL_SHORTCUT";
+
+    enum BookmarkIconType {
+        ICON_INSTALLABLE_WEB_APP, // Icon for an installable web app (launches WebAppRuntime).
+        ICON_HOME_SHORTCUT        // Icon for a shortcut on the home screen (launches Browser).
+    };
+
+    /**
+     * Creates an icon to be associated with this bookmark. If available, the apple touch icon
+     * will be used, else we draw our own depending on the type of "bookmark" being created.
+     */
+    static Bitmap createIcon(Context context, Bitmap touchIcon, Bitmap favicon,
+            BookmarkIconType type) {
+        int iconDimension = context.getResources().getDimensionPixelSize(
+                android.R.dimen.app_icon_size);
+
+        Bitmap bm = Bitmap.createBitmap(iconDimension, iconDimension, Bitmap.Config.ARGB_8888);
+        Canvas canvas = new Canvas(bm);
+        Rect iconBounds = new Rect(0, 0, bm.getWidth(), bm.getHeight());
+
+        // Use the apple-touch-icon if available
+        if (touchIcon != null) {
+            drawTouchIconToCanvas(touchIcon, canvas, iconBounds);
+        } else {
+            // No touch icon so create our own.
+            // Set the background based on the type of shortcut (either webapp or home shortcut).
+            Bitmap icon = getIconBackground(context, type);
+
+            if (icon != null) {
+                // Now draw the correct icon background into our new bitmap.
+                canvas.drawBitmap(icon, null, iconBounds, null);
+            }
+
+            // If we have a favicon, overlay it in a nice rounded white box on top of the
+            // background.
+            if (favicon != null) {
+                drawFaviconToCanvas(favicon, canvas, iconBounds,
+                        context.getResources().getDisplayMetrics().density);
+            }
+        }
+        return bm;
+    }
+
+    /**
+     * Convenience method for creating an intent that will add a shortcut to the home screen.
+     */
+    static Intent createAddToHomeIntent(Context context, String url, String title,
+            Bitmap touchIcon, Bitmap favicon) {
+        Intent i = new Intent(INSTALL_SHORTCUT);
+        Intent shortcutIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
+        long urlHash = url.hashCode();
+        long uniqueId = (urlHash << 32) | shortcutIntent.hashCode();
+        shortcutIntent.putExtra(Browser.EXTRA_APPLICATION_ID, Long.toString(uniqueId));
+        i.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
+        i.putExtra(Intent.EXTRA_SHORTCUT_NAME, title);
+        i.putExtra(Intent.EXTRA_SHORTCUT_ICON, createIcon(context, touchIcon, favicon,
+                BookmarkIconType.ICON_HOME_SHORTCUT));
+
+        // Do not allow duplicate items
+        i.putExtra("duplicate", false);
+        return i;
+    }
+
+    private static Bitmap getIconBackground(Context context, BookmarkIconType type) {
+        if (type == BookmarkIconType.ICON_HOME_SHORTCUT) {
+            // Want to create a shortcut icon on the homescreen, so the icon
+            // background is the red bookmark.
+            return BitmapFactory.decodeResource(context.getResources(),
+                    R.drawable.ic_launcher_shortcut_browser_bookmark);
+        } else if (type == BookmarkIconType.ICON_INSTALLABLE_WEB_APP) {
+            // Use the web browser icon as the background for the icon for an installable
+            // web app.
+            return BitmapFactory.decodeResource(context.getResources(),
+                    R.drawable.ic_launcher_browser);
+        }
+        return null;
+    }
+
+    private static void drawTouchIconToCanvas(Bitmap touchIcon, Canvas canvas, Rect iconBounds) {
+        Rect src = new Rect(0, 0, touchIcon.getWidth(), touchIcon.getHeight());
+
+        // Paint used for scaling the bitmap and drawing the rounded rect.
+        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
+        paint.setFilterBitmap(true);
+        canvas.drawBitmap(touchIcon, src, iconBounds, paint);
+
+        // Construct a path from a round rect. This will allow drawing with
+        // an inverse fill so we can punch a hole using the round rect.
+        Path path = new Path();
+        path.setFillType(Path.FillType.INVERSE_WINDING);
+        RectF rect = new RectF(iconBounds);
+        rect.inset(1, 1);
+        path.addRoundRect(rect, 8f, 8f, Path.Direction.CW);
+
+        // Reuse the paint and clear the outside of the rectangle.
+        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
+        canvas.drawPath(path, paint);
+    }
+
+    private static void drawFaviconToCanvas(Bitmap favicon, Canvas canvas, Rect iconBounds,
+            float density) {
+        // Make a Paint for the white background rectangle and for
+        // filtering the favicon.
+        Paint p = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
+        p.setStyle(Paint.Style.FILL_AND_STROKE);
+        p.setColor(Color.WHITE);
+
+        // Create a rectangle that is slightly wider than the favicon
+        final float iconSize = 16 * density; // 16x16 favicon
+        final float padding = 2 * density; // white padding around icon
+        final float rectSize = iconSize + 2 * padding;
+        final float x = iconBounds.exactCenterX() - (rectSize / 2);
+        // Note: Subtract 2 dip from the y position since the box is
+        // slightly higher than center. Use padding since it is already
+        // 2 * density.
+        final float y = iconBounds.exactCenterY() - (rectSize / 2) - padding;
+        RectF r = new RectF(x, y, x + rectSize, y + rectSize);
+
+        // Draw a white rounded rectangle behind the favicon
+        canvas.drawRoundRect(r, 2, 2, p);
+
+        // Draw the favicon in the same rectangle as the rounded
+        // rectangle but inset by the padding
+        // (results in a 16x16 favicon).
+        r.inset(padding, padding);
+        canvas.drawBitmap(favicon, null, r, p);
+    }
+
+};
diff --git a/src/com/android/browser/BrowserActivity.java b/src/com/android/browser/BrowserActivity.java
index 5e55789..8afd3b4 100644
--- a/src/com/android/browser/BrowserActivity.java
+++ b/src/com/android/browser/BrowserActivity.java
@@ -38,13 +38,11 @@
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.database.Cursor;
-import android.database.DatabaseUtils;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.Canvas;
 import android.graphics.Picture;
 import android.graphics.PixelFormat;
-import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.net.ConnectivityManager;
 import android.net.NetworkInfo;
@@ -64,14 +62,13 @@
 import android.os.SystemClock;
 import android.provider.Browser;
 import android.provider.ContactsContract;
-import android.provider.ContactsContract.Intents.Insert;
 import android.provider.Downloads;
 import android.provider.MediaStore;
+import android.provider.ContactsContract.Intents.Insert;
 import android.speech.RecognizerResultsIntent;
 import android.text.IClipboard;
 import android.text.TextUtils;
 import android.text.format.DateFormat;
-import android.util.AttributeSet;
 import android.util.Log;
 import android.util.Patterns;
 import android.view.ContextMenu;
@@ -87,6 +84,7 @@
 import android.view.WindowManager;
 import android.view.ContextMenu.ContextMenuInfo;
 import android.view.MenuItem.OnMenuItemClickListener;
+import android.view.accessibility.AccessibilityManager;
 import android.webkit.CookieManager;
 import android.webkit.CookieSyncManager;
 import android.webkit.DownloadListener;
@@ -104,12 +102,6 @@
 import android.widget.LinearLayout;
 import android.widget.TextView;
 import android.widget.Toast;
-import android.accounts.Account;
-import android.accounts.AccountManager;
-import android.accounts.AccountManagerFuture;
-import android.accounts.AuthenticatorException;
-import android.accounts.OperationCanceledException;
-import android.accounts.AccountManagerCallback;
 
 import com.android.common.Search;
 import com.android.common.speech.LoggingEvents;
@@ -119,11 +111,9 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.MalformedURLException;
-import java.net.URI;
 import java.net.URISyntaxException;
 import java.net.URL;
 import java.net.URLEncoder;
-import java.text.ParseException;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -131,6 +121,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.Vector;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -171,6 +162,8 @@
      */
     private FrameLayout mBrowserFrameLayout;
 
+    private boolean mXLargeScreenSize;
+
     @Override
     public void onCreate(Bundle icicle) {
         if (LOGV_ENABLED) {
@@ -186,7 +179,11 @@
             BitmapFactory.setDefaultConfig(Bitmap.Config.ARGB_8888);
         }
 
-        setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL);
+        if (AccessibilityManager.getInstance(this).isEnabled()) {
+            setDefaultKeyMode(DEFAULT_KEYS_DISABLE);
+        } else {
+            setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL);
+        }
 
         mResolver = getContentResolver();
 
@@ -213,14 +210,31 @@
         mCustomViewContainer = (FrameLayout) mBrowserFrameLayout
                 .findViewById(R.id.fullscreen_custom_content);
         frameLayout.addView(mBrowserFrameLayout, COVER_SCREEN_PARAMS);
-        mTitleBar = new TitleBar(this);
-        // mTitleBar will be always shown in the fully loaded mode
-        mTitleBar.setProgress(100);
-        mFakeTitleBar = new TitleBar(this);
+        mXLargeScreenSize = (getResources().getConfiguration().screenLayout
+                & Configuration.SCREENLAYOUT_SIZE_MASK)
+                == Configuration.SCREENLAYOUT_SIZE_XLARGE;
 
         // Create the tab control and our initial tab
         mTabControl = new TabControl(this);
 
+
+        if (mXLargeScreenSize) {
+            mTitleBar = new TitleBarXLarge(this, mTabControl);
+            LinearLayout layout = (LinearLayout) mBrowserFrameLayout.
+                    findViewById(R.id.vertical_layout);
+            layout.addView(mTitleBar, 0, new LinearLayout.LayoutParams(
+                    ViewGroup.LayoutParams.MATCH_PARENT,
+                    ViewGroup.LayoutParams.WRAP_CONTENT));
+        } else {
+            mTitleBar = new TitleBar(this);
+            // mTitleBar will be always be shown in the fully loaded mode on
+            // phone
+            mTitleBar.setProgress(100);
+            // Fake title bar is not needed in xlarge layout
+            mFakeTitleBar = new TitleBar(this);
+        }
+
+
         // Open the icon database and retain all the bookmark urls for favicons
         retainIconsOnStartup();
 
@@ -305,9 +319,7 @@
                     }
                     if (permissionOk) {
                         PluginManager.getInstance(BrowserActivity.this)
-                                .refreshPlugins(
-                                        Intent.ACTION_PACKAGE_ADDED
-                                                .equals(action));
+                                .refreshPlugins(true);
                     }
                 }
             }
@@ -358,6 +370,15 @@
             attachTabToContentView(mTabControl.getCurrentTab());
         }
 
+        // Delete old thumbnails to save space
+        File dir = mTabControl.getThumbnailDir();
+        if (dir.exists()) {
+            for (String child : dir.list()) {
+                File f = new File(dir, child);
+                f.delete();
+            }
+        }
+
         // Read JavaScript flags if it exists.
         String jsFlags = mSettings.getJsFlags();
         if (jsFlags.trim().length() != 0) {
@@ -612,6 +633,7 @@
         final ContentResolver cr = mResolver;
         final String newUrl = url;
         new AsyncTask<Void, Void, Void>() {
+            @Override
             protected Void doInBackground(Void... unused) {
                 Browser.updateVisitedHistory(cr, newUrl, false);
                 Browser.addSearchUrl(cr, newUrl);
@@ -673,6 +695,7 @@
                     final ContentResolver cr = mResolver;
                     final String newUrl = url;
                     new AsyncTask<Void, Void, Void>() {
+                        @Override
                         protected Void doInBackground(Void... unused) {
                             Browser.updateVisitedHistory(cr, newUrl, false);
                             return null;
@@ -697,17 +720,21 @@
     }
     /* package */ void showVoiceTitleBar(String title) {
         mTitleBar.setInVoiceMode(true);
-        mFakeTitleBar.setInVoiceMode(true);
-
         mTitleBar.setDisplayTitle(title);
-        mFakeTitleBar.setDisplayTitle(title);
+
+        if (!mXLargeScreenSize) {
+            mFakeTitleBar.setInVoiceMode(true);
+            mFakeTitleBar.setDisplayTitle(title);
+        }
     }
     /* package */ void revertVoiceTitleBar() {
         mTitleBar.setInVoiceMode(false);
-        mFakeTitleBar.setInVoiceMode(false);
-
         mTitleBar.setDisplayTitle(mUrl);
-        mFakeTitleBar.setDisplayTitle(mUrl);
+
+        if (!mXLargeScreenSize) {
+            mFakeTitleBar.setInVoiceMode(false);
+            mFakeTitleBar.setDisplayTitle(mUrl);
+        }
     }
     /* package */ static String fixUrl(String inUrl) {
         // FIXME: Converting the url to lower case
@@ -826,7 +853,14 @@
         return true;
     }
 
+    private void rebuildTitleBar() {
+        if (mXLargeScreenSize) {
+            ((TitleBarXLarge) mTitleBar).rebuildLayout();
+        }
+    }
+
     private void showFakeTitleBar() {
+        if (mXLargeScreenSize) return;
         if (mFakeTitleBar.getParent() == null && mActiveTabsPage == null
                 && !mActivityInPause) {
             WebView mainView = mTabControl.getCurrentWebView();
@@ -834,6 +868,13 @@
             if (mainView == null) {
                 return;
             }
+            // Do not need to check for null, since the current tab will have
+            // at least a main WebView, or we would have returned above.
+            if (dialogIsUp()) {
+                // Do not show the fake title bar, which would cover up the
+                // find or select dialog.
+                return;
+            }
 
             WindowManager manager
                     = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
@@ -868,7 +909,7 @@
     }
 
     private void hideFakeTitleBar() {
-        if (mFakeTitleBar.getParent() == null) return;
+        if (mXLargeScreenSize || mFakeTitleBar.getParent() == null) return;
         WindowManager.LayoutParams params = (WindowManager.LayoutParams)
                 mFakeTitleBar.getLayoutParams();
         WebView mainView = mTabControl.getCurrentWebView();
@@ -1027,6 +1068,7 @@
             showHttpAuthentication(mHttpAuthHandler, null, null, title,
                     name, password, focusId);
         }
+        rebuildTitleBar();
     }
 
     @Override
@@ -1113,12 +1155,14 @@
         if (mMenu == null) {
             return;
         }
+        MenuItem dest = mMenu.findItem(R.id.stop_reload_menu_id);
         MenuItem src = mInLoad ?
                 mMenu.findItem(R.id.stop_menu_id):
-                    mMenu.findItem(R.id.reload_menu_id);
-        MenuItem dest = mMenu.findItem(R.id.stop_reload_menu_id);
-        dest.setIcon(src.getIcon());
-        dest.setTitle(src.getTitle());
+                mMenu.findItem(R.id.reload_menu_id);
+        if (src != null) {
+            dest.setIcon(src.getIcon());
+            dest.setTitle(src.getTitle());
+        }
     }
 
     @Override
@@ -1145,7 +1189,6 @@
                 break;
             // -- Browser context menu
             case R.id.open_context_menu_id:
-            case R.id.open_newtab_context_menu_id:
             case R.id.bookmark_context_menu_id:
             case R.id.save_link_context_menu_id:
             case R.id.share_link_context_menu_id:
@@ -1263,6 +1306,7 @@
      */
     /* package */ void removeActiveTabPage(boolean needToAttach) {
         mContentView.removeView(mActiveTabsPage);
+        mTitleBar.setVisibility(View.VISIBLE);
         mActiveTabsPage = null;
         mMenuState = R.id.MAIN_MENU;
         if (needToAttach) {
@@ -1271,6 +1315,22 @@
         getTopWindow().requestFocus();
     }
 
+    private WebView showDialog(WebDialog dialog) {
+        // Need to do something special for Tablet
+        Tab tab = mTabControl.getCurrentTab();
+        if (tab.getSubWebView() == null) {
+            // If the find or select is being performed on the main webview,
+            // remove the embedded title bar.
+            WebView mainView = tab.getWebView();
+            if (mainView != null) {
+                mainView.setEmbeddedTitleBar(null);
+            }
+        }
+        hideFakeTitleBar();
+        mMenuState = EMPTY_MENU;
+        return tab.showDialog(dialog);
+    }
+
     @Override
     public boolean onOptionsItemSelected(MenuItem item) {
         if (!mCanChord) {
@@ -1305,6 +1365,7 @@
             case R.id.active_tabs_menu_id:
                 mActiveTabsPage = new ActiveTabsPage(this, mTabControl);
                 removeTabFromContentView(mTabControl.getCurrentTab());
+                mTitleBar.setVisibility(View.GONE);
                 hideFakeTitleBar();
                 mContentView.addView(mActiveTabsPage, COVER_SCREEN_PARAMS);
                 mActiveTabsPage.requestFocus();
@@ -1312,14 +1373,7 @@
                 break;
 
             case R.id.add_bookmark_menu_id:
-                Intent i = new Intent(BrowserActivity.this,
-                        AddBookmarkPage.class);
-                WebView w = getTopWindow();
-                i.putExtra("url", w.getUrl());
-                i.putExtra("title", w.getTitle());
-                i.putExtra("touch_icon_url", w.getTouchIconUrl());
-                i.putExtra("thumbnail", createScreenshot(w));
-                startActivity(i);
+                bookmarkCurrentPage();
                 break;
 
             case R.id.stop_reload_menu_id:
@@ -1364,18 +1418,26 @@
                 break;
 
             case R.id.find_menu_id:
-                if (null == mFindDialog) {
-                    mFindDialog = new FindDialog(this);
-                }
-                mFindDialog.setWebView(getTopWindow());
-                mFindDialog.show();
-                getTopWindow().setFindIsUp(true);
-                mMenuState = EMPTY_MENU;
+                showFindDialog();
                 break;
 
-            case R.id.select_text_id:
-                getTopWindow().emulateShiftHeld();
+            case R.id.save_webarchive_menu_id:
+                if (LOGD_ENABLED) {
+                    Log.d(LOGTAG, "Save as Web Archive");
+                }
+                String directory = getExternalFilesDir(null).getAbsolutePath() + File.separator;
+                getTopWindow().saveWebArchive(directory, true, new ValueCallback<String>() {
+                    @Override
+                    public void onReceiveValue(String value) {
+                        if (value != null) {
+                            Toast.makeText(BrowserActivity.this, R.string.webarchive_saved, Toast.LENGTH_SHORT).show();
+                        } else {
+                            Toast.makeText(BrowserActivity.this, R.string.webarchive_failed, Toast.LENGTH_SHORT).show();
+                        }
+                    }
+                });
                 break;
+
             case R.id.page_info_menu_id:
                 showPageInfo(mTabControl.getCurrentTab(), false);
                 break;
@@ -1394,7 +1456,8 @@
                 currentTab.populatePickerData();
                 sharePage(this, currentTab.getTitle(),
                         currentTab.getUrl(), currentTab.getFavicon(),
-                        createScreenshot(currentTab.getWebView()));
+                        createScreenshot(currentTab.getWebView(), getDesiredThumbnailWidth(this),
+                                getDesiredThumbnailHeight(this)));
                 break;
 
             case R.id.dump_nav_menu_id:
@@ -1450,8 +1513,74 @@
         return true;
     }
 
-    public void closeFind() {
+    /* package */ void bookmarkCurrentPage() {
+        Intent i = new Intent(BrowserActivity.this,
+                AddBookmarkPage.class);
+        WebView w = getTopWindow();
+        i.putExtra("url", w.getUrl());
+        i.putExtra("title", w.getTitle());
+        i.putExtra("touch_icon_url", w.getTouchIconUrl());
+        i.putExtra("thumbnail", createScreenshot(w, getDesiredThumbnailWidth(this),
+                getDesiredThumbnailHeight(this)));
+        i.putExtra("url_editable", false);
+        startActivity(i);
+    }
+
+    private boolean dialogIsUp() {
+        return null != mFindDialog && mFindDialog.isVisible() ||
+            null != mSelectDialog && mSelectDialog.isVisible();
+    }
+
+    private boolean closeDialog(WebDialog dialog) {
+        if (null == dialog || !dialog.isVisible()) return false;
+        Tab currentTab = mTabControl.getCurrentTab();
+        currentTab.closeDialog(dialog);
+        dialog.dismiss();
+        return true;
+    }
+
+    /*
+     * Remove the find dialog or select dialog.
+     */
+    public void closeDialogs() {
+        if (!(closeDialog(mFindDialog) || closeDialog(mSelectDialog))) return;
+        if (!mXLargeScreenSize) {
+            // If the Find was being performed in the main WebView, replace the
+            // embedded title bar.
+            Tab currentTab = mTabControl.getCurrentTab();
+            if (currentTab.getSubWebView() == null) {
+                WebView mainView = currentTab.getWebView();
+                if (mainView != null) {
+                    mainView.setEmbeddedTitleBar(mTitleBar);
+                }
+            }
+        }
         mMenuState = R.id.MAIN_MENU;
+        if (mInLoad) {
+            // The title bar was hidden, because otherwise it would cover up the
+            // find or select dialog.  Now that the dialog has been removed,
+            // show the fake title bar once again.
+            showFakeTitleBar();
+        }
+    }
+
+    public void showFindDialog() {
+        if (null == mFindDialog) {
+            mFindDialog = new FindDialog(this);
+        }
+        showDialog(mFindDialog).setFindIsUp(true);
+    }
+
+    public void setFindDialogText(String text) {
+        mFindDialog.setText(text);
+    }
+
+    public void showSelectDialog() {
+        if (null == mSelectDialog) {
+            mSelectDialog = new SelectDialog(this);
+        }
+        showDialog(mSelectDialog).setUpSelect();
+        mSelectDialog.hideSoftInput();
     }
 
     @Override
@@ -1492,11 +1621,11 @@
                 final MenuItem home = menu.findItem(R.id.homepage_menu_id);
                 home.setEnabled(!isHome);
 
-                menu.findItem(R.id.forward_menu_id)
-                        .setEnabled(canGoForward);
+                final MenuItem forward = menu.findItem(R.id.forward_menu_id);
+                forward.setEnabled(canGoForward);
 
-                menu.findItem(R.id.new_tab_menu_id).setEnabled(
-                        mTabControl.canCreateNewTab());
+                final MenuItem newtab = menu.findItem(R.id.new_tab_menu_id);
+                newtab.setEnabled(mTabControl.canCreateNewTab());
 
                 // decide whether to show the share link option
                 PackageManager pm = getPackageManager();
@@ -1524,7 +1653,7 @@
     @Override
     public void onCreateContextMenu(ContextMenu menu, View v,
             ContextMenuInfo menuInfo) {
-        if (v instanceof TitleBar) {
+        if (v instanceof TitleBarBase) {
             return;
         }
         WebView webview = (WebView) v;
@@ -1551,7 +1680,7 @@
         inflater.inflate(R.menu.browsercontext, menu);
 
         // Show the correct menu group
-        String extra = result.getExtra();
+        final String extra = result.getExtra();
         menu.setGroupVisible(R.id.PHONE_MENU,
                 type == WebView.HitTestResult.PHONE_TYPE);
         menu.setGroupVisible(R.id.EMAIL_MENU,
@@ -1608,8 +1737,23 @@
                 titleView.setText(extra);
                 menu.setHeaderView(titleView);
                 // decide whether to show the open link in new tab option
-                menu.findItem(R.id.open_newtab_context_menu_id).setVisible(
-                        mTabControl.canCreateNewTab());
+                boolean showNewTab = mTabControl.canCreateNewTab();
+                MenuItem newTabItem
+                        = menu.findItem(R.id.open_newtab_context_menu_id);
+                newTabItem.setVisible(showNewTab);
+                if (showNewTab) {
+                    newTabItem.setOnMenuItemClickListener(
+                            new MenuItem.OnMenuItemClickListener() {
+                                public boolean onMenuItemClick(MenuItem item) {
+                                    final Tab parent = mTabControl.getCurrentTab();
+                                    final Tab newTab = openTab(extra);
+                                    if (newTab != parent) {
+                                        parent.addChildTab(newTab);
+                                    }
+                                    return true;
+                                }
+                            });
+                }
                 menu.findItem(R.id.bookmark_context_menu_id).setVisible(
                         Bookmarks.urlHasAcceptableScheme(extra));
                 PackageManager pm = getPackageManager();
@@ -1660,8 +1804,10 @@
                                                   ViewGroup.LayoutParams.WRAP_CONTENT));
         }
 
-        WebView view = t.getWebView();
-        view.setEmbeddedTitleBar(mTitleBar);
+        if (!mXLargeScreenSize){
+            WebView view = t.getWebView();
+            view.setEmbeddedTitleBar(mTitleBar);
+        }
         if (t.isInVoiceSearchMode()) {
             showVoiceTitleBar(t.getVoiceDisplayTitle());
         } else {
@@ -1687,9 +1833,11 @@
             mErrorConsoleContainer.removeView(errorConsole);
         }
 
-        WebView view = t.getWebView();
-        if (view != null) {
-            view.setEmbeddedTitleBar(null);
+        if (!mXLargeScreenSize) {
+            WebView view = t.getWebView();
+            if (view != null) {
+                view.setEmbeddedTitleBar(null);
+            }
         }
     }
 
@@ -1815,6 +1963,7 @@
             return true;
         }
 
+        @Override
         public void run() {
             Drawable oldWallpaper = BrowserActivity.this.getWallpaper();
             try {
@@ -1919,7 +2068,9 @@
         // If we are in voice search mode, the title has already been set.
         if (mTabControl.getCurrentTab().isInVoiceSearchMode()) return;
         mTitleBar.setDisplayTitle(url);
-        mFakeTitleBar.setDisplayTitle(url);
+        if (!mXLargeScreenSize) {
+            mFakeTitleBar.setDisplayTitle(url);
+        }
     }
 
     /**
@@ -1962,7 +2113,9 @@
     // Set the favicon in the title bar.
     void setFavicon(Bitmap icon) {
         mTitleBar.setFavicon(icon);
-        mFakeTitleBar.setFavicon(icon);
+        if (!mXLargeScreenSize) {
+            mFakeTitleBar.setFavicon(icon);
+        }
     }
 
     /**
@@ -1978,6 +2131,7 @@
         }
         mTabControl.setCurrentTab(mTabControl.getTab(currentIndex));
         resetTitleIconAndProgress();
+        updateLockIconToLatest();
     }
 
     /* package */ void goBackOnePageOrQuit() {
@@ -2169,9 +2323,12 @@
 
     static final int UPDATE_BOOKMARK_THUMBNAIL       = 108;
 
+    private static final int TOUCH_ICON_DOWNLOADED   = 109;
+
     // Private handler for handling javascript and saving passwords
     private Handler mHandler = new Handler() {
 
+        @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
                 case FOCUS_NODE_HREF:
@@ -2192,13 +2349,6 @@
                         case R.id.view_image_context_menu_id:
                             loadUrlFromContext(getTopWindow(), url);
                             break;
-                        case R.id.open_newtab_context_menu_id:
-                            final Tab parent = mTabControl.getCurrentTab();
-                            final Tab newTab = openTab(url);
-                            if (newTab != parent) {
-                                parent.addChildTab(newTab);
-                            }
-                            break;
                         case R.id.bookmark_context_menu_id:
                             Intent intent = new Intent(BrowserActivity.this,
                                     AddBookmarkPage.class);
@@ -2207,41 +2357,8 @@
                             startActivity(intent);
                             break;
                         case R.id.share_link_context_menu_id:
-                            // See if this site has been visited before
-                            StringBuilder sb = new StringBuilder(
-                                    Browser.BookmarkColumns.URL + " = ");
-                            DatabaseUtils.appendEscapedSQLString(sb, url);
-                            Cursor c = mResolver.query(Browser.BOOKMARKS_URI,
-                                    Browser.HISTORY_PROJECTION,
-                                    sb.toString(),
-                                    null,
+                            sharePage(BrowserActivity.this, title, url, null,
                                     null);
-                            if (c.moveToFirst()) {
-                                // The site has been visited before, so grab the
-                                // info from the database.
-                                Bitmap favicon = null;
-                                Bitmap thumbnail = null;
-                                String linkTitle = c.getString(Browser.
-                                        HISTORY_PROJECTION_TITLE_INDEX);
-                                byte[] data = c.getBlob(Browser.
-                                        HISTORY_PROJECTION_FAVICON_INDEX);
-                                if (data != null) {
-                                    favicon = BitmapFactory.decodeByteArray(
-                                            data, 0, data.length);
-                                }
-                                data = c.getBlob(Browser.
-                                        HISTORY_PROJECTION_THUMBNAIL_INDEX);
-                                if (data != null) {
-                                    thumbnail = BitmapFactory.decodeByteArray(
-                                            data, 0, data.length);
-                                }
-                                sharePage(BrowserActivity.this,
-                                        linkTitle, url, favicon, thumbnail);
-                            } else {
-                                Browser.sendString(BrowserActivity.this, url,
-                                        getString(
-                                        R.string.choosertitle_sharevia));
-                            }
                             break;
                         case R.id.copy_link_context_menu_id:
                             copy(url);
@@ -2278,6 +2395,14 @@
                         updateScreenshot(view);
                     }
                     break;
+
+                case TOUCH_ICON_DOWNLOADED:
+                    Bundle b = msg.getData();
+                    showSaveToHomescreenDialog(b.getString("url"),
+                        b.getString("title"),
+                        (Bitmap) b.getParcelable("touchIcon"),
+                        (Bitmap) b.getParcelable("favicon"));
+                    break;
             }
         }
     };
@@ -2318,7 +2443,8 @@
         // draw, but the API for that (WebViewCore.pictureReady()) is not
         // currently accessible here.
 
-        final Bitmap bm = createScreenshot(view);
+        final Bitmap bm = createScreenshot(view, getDesiredThumbnailWidth(this),
+                getDesiredThumbnailHeight(this));
         if (bm == null) {
             return;
         }
@@ -2394,13 +2520,12 @@
         return THUMBNAIL_HEIGHT;
     }
 
-    private Bitmap createScreenshot(WebView view) {
+    private Bitmap createScreenshot(WebView view, int width, int height) {
         Picture thumbnail = view.capturePicture();
         if (thumbnail == null) {
             return null;
         }
-        Bitmap bm = Bitmap.createBitmap(getDesiredThumbnailWidth(this),
-                getDesiredThumbnailHeight(this), Bitmap.Config.RGB_565);
+        Bitmap bm = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
         Canvas canvas = new Canvas(bm);
         // May need to tweak these values to determine what is the
         // best scale factor
@@ -2409,8 +2534,7 @@
         float scaleFactorX = 1.0f;
         float scaleFactorY = 1.0f;
         if (thumbnailWidth > 0) {
-            scaleFactorX = (float) getDesiredThumbnailWidth(this) /
-                    (float)thumbnailWidth;
+            scaleFactorX = (float) width / (float)thumbnailWidth;
         } else {
             return null;
         }
@@ -2420,8 +2544,7 @@
             // If the device is in landscape and the page is shorter
             // than the height of the view, stretch the thumbnail to fill the
             // space.
-            scaleFactorY = (float) getDesiredThumbnailHeight(this) /
-                    (float)thumbnailHeight;
+            scaleFactorY = (float) height / (float)thumbnailHeight;
         } else {
             // In the portrait case, this looks nice.
             scaleFactorY = scaleFactorX;
@@ -2462,7 +2585,7 @@
         onProgressChanged(view, INITIAL_PROGRESS);
         mDidStopLoad = false;
         if (!mIsNetworkUp) createAndShowNetworkDialog();
-
+        closeDialogs();
         if (mSettings.isTracing()) {
             String host;
             try {
@@ -2560,6 +2683,18 @@
         }
     }
 
+    private void closeEmptyChildTab() {
+        Tab current = mTabControl.getCurrentTab();
+        if (current != null
+                && current.getWebView().copyBackForwardList().getSize() == 0) {
+            Tab parent = current.getParentTab();
+            if (parent != null) {
+                switchToTab(mTabControl.getTabIndex(parent));
+                closeTab(current);
+            }
+        }
+    }
+
     boolean shouldOverrideUrlLoading(WebView view, String url) {
         if (url.startsWith(SCHEME_WTAI)) {
             // wtai://wp/mc;number
@@ -2569,6 +2704,11 @@
                         Uri.parse(WebView.SCHEME_TEL +
                         url.substring(SCHEME_WTAI_MC.length())));
                 startActivity(intent);
+                // before leaving BrowserActivity, close the empty child tab.
+                // If a new tab is created through JavaScript open to load this
+                // url, we would like to close it as we will load this url in a
+                // different Activity.
+                closeEmptyChildTab();
                 return true;
             }
             // wtai://wp/sd;dtmf
@@ -2610,6 +2750,11 @@
                         .parse("market://search?q=pname:" + packagename));
                 intent.addCategory(Intent.CATEGORY_BROWSABLE);
                 startActivity(intent);
+                // before leaving BrowserActivity, close the empty child tab.
+                // If a new tab is created through JavaScript open to load this
+                // url, we would like to close it as we will load this url in a
+                // different Activity.
+                closeEmptyChildTab();
                 return true;
             } else {
                 return false;
@@ -2622,6 +2767,11 @@
         intent.setComponent(null);
         try {
             if (startActivityIfNeeded(intent, -1)) {
+                // before leaving BrowserActivity, close the empty child tab.
+                // If a new tab is created through JavaScript open to load this
+                // url, we would like to close it as we will load this url in a
+                // different Activity.
+                closeEmptyChildTab();
                 return true;
             }
         } catch (ActivityNotFoundException ex) {
@@ -2642,7 +2792,14 @@
     // -------------------------------------------------------------------------
 
     void onProgressChanged(WebView view, int newProgress) {
-        mFakeTitleBar.setProgress(newProgress);
+        if (mXLargeScreenSize) {
+            mTitleBar.setProgress(newProgress);
+        } else {
+            // On the phone, the fake title bar will always cover up the
+            // regular title bar (or the regular one is offscreen), so only the
+            // fake title bar needs to change its progress
+            mFakeTitleBar.setProgress(newProgress);
+        }
 
         if (newProgress == 100) {
             // onProgressChanged() may continue to be called after the main
@@ -2743,15 +2900,138 @@
      * The Object used to inform the WebView of the file to upload.
      */
     private ValueCallback<Uri> mUploadMessage;
+    private String mCameraFilePath;
 
-    void openFileChooser(ValueCallback<Uri> uploadMsg) {
-        if (mUploadMessage != null) return;
+    void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) {
+
+        final String imageMimeType = "image/*";
+        final String videoMimeType = "video/*";
+        final String audioMimeType = "audio/*";
+        final String mediaSourceKey = "capture";
+        final String mediaSourceValueCamera = "camera";
+        final String mediaSourceValueFileSystem = "filesystem";
+        final String mediaSourceValueCamcorder = "camcorder";
+        final String mediaSourceValueMicrophone = "microphone";
+
+        // media source can be 'filesystem' or 'camera' or 'camcorder' or 'microphone'.
+        String mediaSource = "";
+
+        // We add the camera intent if there was no accept type (or '*/*' or 'image/*').
+        boolean addCameraIntent = true;
+        // We add the camcorder intent if there was no accept type (or '*/*' or 'video/*').
+        boolean addCamcorderIntent = true;
+
+        if (mUploadMessage != null) {
+            // Already a file picker operation in progress.
+            return;
+        }
+
         mUploadMessage = uploadMsg;
+
+        // Parse the accept type.
+        String params[] = acceptType.split(";");
+        String mimeType = params[0];
+
+        for (String p : params) {
+            String[] keyValue = p.split("=");
+            if (keyValue.length == 2) {
+                // Process key=value parameters.
+                if (mediaSourceKey.equals(keyValue[0])) {
+                    mediaSource = keyValue[1];
+                }
+            }
+        }
+
+        // This intent will display the standard OPENABLE file picker.
         Intent i = new Intent(Intent.ACTION_GET_CONTENT);
         i.addCategory(Intent.CATEGORY_OPENABLE);
-        i.setType("*/*");
-        BrowserActivity.this.startActivityForResult(Intent.createChooser(i,
-                getString(R.string.choose_upload)), FILE_SELECTED);
+
+        // Create an intent to add to the standard file picker that will
+        // capture an image from the camera. We'll combine this intent with
+        // the standard OPENABLE picker unless the web developer specifically
+        // requested the camera or gallery be opened by passing a parameter
+        // in the accept type.
+        Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
+        File externalDataDir = Environment.getExternalStoragePublicDirectory(
+                Environment.DIRECTORY_DCIM);
+        File cameraDataDir = new File(externalDataDir.getAbsolutePath() +
+                File.separator + "browser-photos");
+        cameraDataDir.mkdirs();
+        mCameraFilePath = cameraDataDir.getAbsolutePath() + File.separator +
+                System.currentTimeMillis() + ".jpg";
+        cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(new File(mCameraFilePath)));
+
+        Intent camcorderIntent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
+
+        Intent soundRecIntent = new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION);
+
+        if (mimeType.equals(imageMimeType)) {
+            i.setType(imageMimeType);
+            addCamcorderIntent = false;
+            if (mediaSource.equals(mediaSourceValueCamera)) {
+                // Specified 'image/*' and requested the camera, so go ahead and launch the camera
+                // directly.
+                BrowserActivity.this.startActivityForResult(cameraIntent, FILE_SELECTED);
+                return;
+            } else if (mediaSource.equals(mediaSourceValueFileSystem)) {
+                // Specified filesytem as the source, so don't want to consider the camera.
+                addCameraIntent = false;
+            }
+        } else if (mimeType.equals(videoMimeType)) {
+            i.setType(videoMimeType);
+            addCameraIntent = false;
+            // The camcorder saves it's own file and returns it to us in the intent, so
+            // we don't need to generate one here.
+            mCameraFilePath = null;
+
+            if (mediaSource.equals(mediaSourceValueCamcorder)) {
+                // Specified 'video/*' and requested the camcorder, so go ahead and launch the
+                // camcorder directly.
+                BrowserActivity.this.startActivityForResult(camcorderIntent, FILE_SELECTED);
+                return;
+            } else if (mediaSource.equals(mediaSourceValueFileSystem)) {
+                // Specified filesystem as the source, so don't want to consider the camcorder.
+                addCamcorderIntent = false;
+            }
+        } else if (mimeType.equals(audioMimeType)) {
+            i.setType(audioMimeType);
+            addCameraIntent = false;
+            addCamcorderIntent = false;
+            if (mediaSource.equals(mediaSourceValueMicrophone)) {
+                // Specified 'audio/*' and requested microphone, so go ahead and launch the sound
+                // recorder.
+                BrowserActivity.this.startActivityForResult(soundRecIntent, FILE_SELECTED);
+                return;
+            }
+            // On a default system, there is no single option to open an audio "gallery". Both the
+            // sound recorder and music browser respond to the OPENABLE/audio/* intent unlike the
+            // image/* and video/* OPENABLE intents where the image / video gallery are the only
+            // respondants (and so the user is not prompted by default).
+        } else {
+            i.setType("*/*");
+        }
+
+        // Combine the chooser and the extra choices (like camera or camcorder)
+        Intent chooser = new Intent(Intent.ACTION_CHOOSER);
+        chooser.putExtra(Intent.EXTRA_INTENT, i);
+
+        Vector<Intent> extraInitialIntents = new Vector<Intent>(0);
+
+        if (addCameraIntent) {
+            extraInitialIntents.add(cameraIntent);
+        }
+
+        if (addCamcorderIntent) {
+            extraInitialIntents.add(camcorderIntent);
+        }
+
+        if (extraInitialIntents.size() > 0) {
+            Intent[] extraIntents = new Intent[extraInitialIntents.size()];
+            chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, extraInitialIntents.toArray(extraIntents));
+        }
+
+        chooser.putExtra(Intent.EXTRA_TITLE, getString(R.string.choose_upload));
+        BrowserActivity.this.startActivityForResult(chooser, FILE_SELECTED);
     }
 
     // -------------------------------------------------------------------------
@@ -2938,7 +3218,10 @@
      * Update the lock icon to correspond to our latest state.
      */
     private void updateLockIconToLatest() {
-        updateLockIconImage(mTabControl.getCurrentTab().getLockIconType());
+        Tab t = mTabControl.getCurrentTab();
+        if (t != null) {
+            updateLockIconImage(t.getLockIconType());
+        }
     }
 
     /**
@@ -2952,7 +3235,9 @@
             d = mMixLockIcon;
         }
         mTitleBar.setLock(d);
-        mFakeTitleBar.setLock(d);
+        if (!mXLargeScreenSize) {
+            mFakeTitleBar.setLock(d);
+        }
     }
 
     /**
@@ -3468,8 +3753,25 @@
                 if (null == mUploadMessage) break;
                 Uri result = intent == null || resultCode != RESULT_OK ? null
                         : intent.getData();
+
+                // As we ask the camera to save the result of the user taking
+                // a picture, the camera application does not return anything other
+                // than RESULT_OK. So we need to check whether the file we expected
+                // was written to disk in the in the case that we
+                // did not get an intent returned but did get a RESULT_OK. If it was,
+                // we assume that this result has came back from the camera.
+                if (result == null && intent == null && resultCode == RESULT_OK) {
+                    File cameraFile = new File(mCameraFilePath);
+                    if (cameraFile.exists()) {
+                        result = Uri.fromFile(cameraFile);
+                        // Broadcast to the media scanner that we have a new photo
+                        // so it will be added into the gallery for the user.
+                        sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, result));
+                    }
+                }
                 mUploadMessage.onReceiveValue(result);
                 mUploadMessage = null;
+                mCameraFilePath = null;
                 break;
             default:
                 break;
@@ -3490,6 +3792,47 @@
 
     }
 
+    /* package*/ void promptAddOrInstallBookmark() {
+        final Tab current = mTabControl.getCurrentTab();
+        Resources resources = getResources();
+        CharSequence[] choices = {
+                resources.getString(R.string.save_to_bookmarks),
+                resources.getString(R.string.create_shortcut_bookmark)
+        };
+
+        AlertDialog.Builder builder = new AlertDialog.Builder(this);
+        builder.setTitle(R.string.add_new_bookmark);
+        builder.setItems(choices, new DialogInterface.OnClickListener() {
+                public void onClick(DialogInterface dialog, int item) {
+                    if (item == 0) {
+                        bookmarkCurrentPage();
+                    } else if (item == 1) {
+                        current.populatePickerData();
+                        String touchIconUrl = mTabControl.getCurrentWebView().getTouchIconUrl();
+                        if (touchIconUrl != null) {
+                            // Download the touch icon for this site then save it to the
+                            // homescreen.
+                            Bundle b = new Bundle();
+                            b.putString("url", current.getUrl());
+                            b.putString("title", current.getTitle());
+                            b.putParcelable("favicon", current.getFavicon());
+                            Message msg = mHandler.obtainMessage(TOUCH_ICON_DOWNLOADED);
+                            msg.setData(b);
+                            new DownloadTouchIcon(BrowserActivity.this, msg,
+                                    mTabControl.getCurrentWebView().getSettings()
+                                    .getUserAgentString()).execute(touchIconUrl);
+                        } else {
+                            // add to homescreen, can do it immediately as there is no touch
+                            // icon.
+                            showSaveToHomescreenDialog(current.getUrl(), current.getTitle(),
+                                    null, current.getFavicon());
+                        }
+                     }
+                 }
+        });
+        builder.create().show();
+    }
+
     /**
      * Open the Go page.
      * @param startWithHistory If true, open starting on the history tab.
@@ -3504,7 +3847,8 @@
                 CombinedBookmarkHistoryActivity.class);
         String title = current.getTitle();
         String url = current.getUrl();
-        Bitmap thumbnail = createScreenshot(current);
+        Bitmap thumbnail = createScreenshot(current, getDesiredThumbnailWidth(this),
+                getDesiredThumbnailHeight(this));
 
         // Just in case the user opens bookmarks before a page finishes loading
         // so the current history item, and therefore the page, is null.
@@ -3532,6 +3876,33 @@
         startActivityForResult(intent, COMBO_PAGE);
     }
 
+    private void showSaveToHomescreenDialog(String url, String title, Bitmap touchIcon,
+            Bitmap favicon) {
+        Intent intent = new Intent(this, SaveToHomescreenDialog.class);
+
+        // Just in case the user tries to save before a page finishes loading
+        // so the current history item, and therefore the page, is null.
+        if (null == url) {
+            url = mLastEnteredUrl;
+            // This can happen.
+            if (null == url) {
+                url = mSettings.getHomePage();
+            }
+        }
+
+        // In case the web page has not yet received its associated title.
+        if (title == null) {
+            title = url;
+        }
+
+        intent.putExtra("title", title);
+        intent.putExtra("url", url);
+        intent.putExtra("favicon", favicon);
+        intent.putExtra("touchIcon", touchIcon);
+        startActivity(intent);
+    }
+
+
     // Called when loading from context menu or LOAD_URL message
     private void loadUrlFromContext(WebView view, String url) {
         // In case the user enters nothing.
@@ -3726,6 +4097,7 @@
     private void getInstalledPackages() {
         AsyncTask<Void, Void, Set<String> > task =
             new AsyncTask<Void, Void, Set<String> >() {
+            @Override
             protected Set<String> doInBackground(Void... unused) {
                 Set<String> installedPackages = new HashSet<String>();
                 PackageManager pm = BrowserActivity.this.getPackageManager();
@@ -3742,6 +4114,7 @@
             }
 
             // Executes on the UI thread
+            @Override
             protected void onPostExecute(Set<String> installedPackages) {
                 addPackageNames(installedPackages);
             }
@@ -3770,6 +4143,7 @@
     private Menu mMenu;
 
     private FindDialog mFindDialog;
+    private SelectDialog mSelectDialog;
     // Used to prevent chording to result in firing two shortcuts immediately
     // one after another.  Fixes bug 1211714.
     boolean mCanChord;
@@ -3883,7 +4257,7 @@
 
     private Toast mStopToast;
 
-    private TitleBar mTitleBar;
+    private TitleBarBase mTitleBar;
 
     private LinearLayout mErrorConsoleContainer = null;
     private boolean mShouldShowErrorConsole = false;
diff --git a/src/com/android/browser/BrowserBookmarksPage.java b/src/com/android/browser/BrowserBookmarksPage.java
index 7560c78..6af14e8 100644
--- a/src/com/android/browser/BrowserBookmarksPage.java
+++ b/src/com/android/browser/BrowserBookmarksPage.java
@@ -23,16 +23,6 @@
 import android.content.SharedPreferences;
 import android.content.SharedPreferences.Editor;
 import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffXfermode;
-import android.graphics.Rect;
-import android.graphics.RectF;
-import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.Handler;
@@ -53,6 +43,7 @@
 import android.widget.GridView;
 import android.widget.ListView;
 import android.widget.Toast;
+import android.widget.AdapterView.OnItemClickListener;
 
 /*package*/ enum BookmarkViewMode { NONE, GRID, LIST }
 /**
@@ -74,10 +65,6 @@
     private boolean                 mMostVisited;
     private View                    mEmptyView;
     private int                     mIconSize;
-    // XXX: There is no public string defining this intent so if Home changes
-    // the value, we have to update this string.
-    private static final String     INSTALL_SHORTCUT =
-            "com.android.launcher.action.INSTALL_SHORTCUT";
 
     private final static String LOGTAG = "browser";
     private final static String PREF_BOOKMARK_VIEW_MODE = "pref_bookmark_view_mode";
@@ -108,9 +95,7 @@
             editBookmark(i.position);
             break;
         case R.id.shortcut_context_menu_id:
-            final Intent send = createShortcutIntent(i.position);
-            send.setAction(INSTALL_SHORTCUT);
-            sendBroadcast(send);
+            sendBroadcast(createShortcutIntent(i.position));
             break;
         case R.id.delete_context_menu_id:
             if (mMostVisited) {
@@ -275,13 +260,14 @@
         new AsyncTask<Void, Void, Void>() {
             @Override
             protected Void doInBackground(Void... unused) {
-                BrowserBookmarksAdapter adapter = new BrowserBookmarksAdapter(
-                        BrowserBookmarksPage.this,
-                        url,
-                        title,
-                        thumbnail,
-                        createShortcut,
-                        mostVisited);
+                BrowserBookmarksAdapter adapter =
+                    new BrowserBookmarksAdapter(
+                            BrowserBookmarksPage.this,
+                            url,
+                            title,
+                            thumbnail,
+                            createShortcut,
+                            mostVisited);
                 mHandler.obtainMessage(ADAPTER_CREATED, adapter).sendToTarget();
                 return null;
             }
@@ -358,7 +344,7 @@
                 }
                 listView.setDrawSelectorOnTop(false);
                 listView.setVerticalScrollBarEnabled(true);
-                listView.setOnItemClickListener(mListener);
+                listView.setOnItemClickListener(mListListener);
                 if (mMostVisited) {
                     listView.setEmptyView(mEmptyView);
                 }
@@ -422,7 +408,7 @@
         }
     };
 
-    private AdapterView.OnItemClickListener mListener = new AdapterView.OnItemClickListener() {
+    private OnItemClickListener mListener = new OnItemClickListener() {
         public void onItemClick(AdapterView parent, View v, int position, long id) {
             // It is possible that the view has been canceled when we get to
             // this point as back has a higher priority
@@ -438,8 +424,29 @@
                     loadUrl(position);
                 }
             } else {
-                final Intent intent = createShortcutIntent(position);
-                setResultToParent(RESULT_OK, intent);
+                setResultToParent(RESULT_OK, createShortcutIntent(position));
+                finish();
+            }
+        }
+    };
+
+    private OnItemClickListener mListListener = new OnItemClickListener() {
+        public void onItemClick(AdapterView parent, View v, int position, long id) {
+            // It is possible that the view has been canceled when we get to
+            // this point as back has a higher priority
+            if (mCanceled) {
+                android.util.Log.e(LOGTAG, "item clicked when dismissing");
+                return;
+            }
+            if (!mCreateShortcut) {
+                if (0 == position && !mMostVisited) {
+                    // XXX: Work-around for a framework issue.
+                    mHandler.sendEmptyMessage(SAVE_CURRENT_PAGE);
+                } else {
+                    loadUrl(position);
+                }
+            } else {
+                setResultToParent(RESULT_OK, createShortcutIntent(position));
                 finish();
             }
         }
@@ -449,99 +456,8 @@
         String url = getUrl(position);
         String title = getBookmarkTitle(position);
         Bitmap touchIcon = getTouchIcon(position);
-
-        final Intent i = new Intent();
-        final Intent shortcutIntent = new Intent(Intent.ACTION_VIEW,
-                Uri.parse(url));
-        long urlHash = url.hashCode();
-        long uniqueId = (urlHash << 32) | shortcutIntent.hashCode();
-        shortcutIntent.putExtra(Browser.EXTRA_APPLICATION_ID,
-                Long.toString(uniqueId));
-        i.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
-        i.putExtra(Intent.EXTRA_SHORTCUT_NAME, title);
-        // Use the apple-touch-icon if available
-        if (touchIcon != null) {
-            // Make a copy so we can modify the pixels.  We can't use
-            // createScaledBitmap or copy since they will preserve the config
-            // and lose the ability to add alpha.
-            Bitmap bm = Bitmap.createBitmap(mIconSize, mIconSize,
-                    Bitmap.Config.ARGB_8888);
-            Canvas canvas = new Canvas(bm);
-            Rect src = new Rect(0, 0, touchIcon.getWidth(),
-                                touchIcon.getHeight());
-            Rect dest = new Rect(0, 0, bm.getWidth(), bm.getHeight());
-
-            // Paint used for scaling the bitmap and drawing the rounded rect.
-            Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
-            paint.setFilterBitmap(true);
-            canvas.drawBitmap(touchIcon, src, dest, paint);
-
-            // Construct a path from a round rect. This will allow drawing with
-            // an inverse fill so we can punch a hole using the round rect.
-            Path path = new Path();
-            path.setFillType(Path.FillType.INVERSE_WINDING);
-            RectF rect = new RectF(0, 0, bm.getWidth(), bm.getHeight());
-            rect.inset(1, 1);
-            path.addRoundRect(rect, 8f, 8f, Path.Direction.CW);
-
-            // Reuse the paint and clear the outside of the rectangle.
-            paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
-            canvas.drawPath(path, paint);
-
-            i.putExtra(Intent.EXTRA_SHORTCUT_ICON, bm);
-        } else {
-            Bitmap favicon = getFavicon(position);
-            if (favicon == null) {
-                i.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE,
-                        Intent.ShortcutIconResource.fromContext(
-                                BrowserBookmarksPage.this,
-                                R.drawable.ic_launcher_shortcut_browser_bookmark));
-            } else {
-                Bitmap icon = BitmapFactory.decodeResource(getResources(),
-                        R.drawable.ic_launcher_shortcut_browser_bookmark_icon);
-
-                // Make a copy of the regular icon so we can modify the pixels.
-                Bitmap copy = icon.copy(Bitmap.Config.ARGB_8888, true);
-                Canvas canvas = new Canvas(copy);
-
-                // Make a Paint for the white background rectangle and for
-                // filtering the favicon.
-                Paint p = new Paint(Paint.ANTI_ALIAS_FLAG
-                        | Paint.FILTER_BITMAP_FLAG);
-                p.setStyle(Paint.Style.FILL_AND_STROKE);
-                p.setColor(Color.WHITE);
-
-                final float density =
-                        getResources().getDisplayMetrics().density;
-                // Create a rectangle that is slightly wider than the favicon
-                final float iconSize = 16 * density; // 16x16 favicon
-                final float padding = 2 * density; // white padding around icon
-                final float rectSize = iconSize + 2 * padding;
-
-                final Rect iconBounds =
-                        new Rect(0, 0, icon.getWidth(), icon.getHeight());
-                final float x = iconBounds.exactCenterX() - (rectSize / 2);
-                // Note: Subtract 2 dip from the y position since the box is
-                // slightly higher than center. Use padding since it is already
-                // 2 * density.
-                final float y = iconBounds.exactCenterY() - (rectSize / 2)
-                        - padding;
-                RectF r = new RectF(x, y, x + rectSize, y + rectSize);
-
-                // Draw a white rounded rectangle behind the favicon
-                canvas.drawRoundRect(r, 2, 2, p);
-
-                // Draw the favicon in the same rectangle as the rounded
-                // rectangle but inset by the padding
-                // (results in a 16x16 favicon).
-                r.inset(padding, padding);
-                canvas.drawBitmap(favicon, null, r, p);
-                i.putExtra(Intent.EXTRA_SHORTCUT_ICON, copy);
-            }
-        }
-        // Do not allow duplicate items
-        i.putExtra("duplicate", false);
-        return i;
+        Bitmap favicon = getFavicon(position);
+        return BookmarkUtils.createAddToHomeIntent(this, url, title, touchIcon, favicon);
     }
 
     private void saveCurrentPage() {
@@ -756,4 +672,5 @@
                     resultCode, data);
         }
     }
+
 }
diff --git a/src/com/android/browser/BrowserDownloadAdapter.java b/src/com/android/browser/BrowserDownloadAdapter.java
index 0f8f721..f22c9fe 100644
--- a/src/com/android/browser/BrowserDownloadAdapter.java
+++ b/src/com/android/browser/BrowserDownloadAdapter.java
@@ -26,6 +26,7 @@
 import android.drm.mobile1.DrmRawContent;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
+import android.os.Handler;
 import android.provider.Downloads;
 import android.text.format.Formatter;
 import android.view.LayoutInflater;
@@ -55,8 +56,9 @@
     private int mMimetypeColumnId;
     private int mDateColumnId;
 
-    public BrowserDownloadAdapter(Context context, Cursor c, int index) {
-        super(context, c, index);
+    public BrowserDownloadAdapter(Context context, Cursor c, int index,
+            Handler handler) {
+        super(context, c, index, handler);
         mTitleColumnId = c.getColumnIndexOrThrow(Downloads.Impl.COLUMN_TITLE);
         mDescColumnId = c.getColumnIndexOrThrow(Downloads.Impl.COLUMN_DESCRIPTION);
         mStatusColumnId = c.getColumnIndexOrThrow(Downloads.Impl.COLUMN_STATUS);
diff --git a/src/com/android/browser/BrowserDownloadPage.java b/src/com/android/browser/BrowserDownloadPage.java
index 18faf8b..bbf1191 100644
--- a/src/com/android/browser/BrowserDownloadPage.java
+++ b/src/com/android/browser/BrowserDownloadPage.java
@@ -63,6 +63,7 @@
     // Only meaningful while a ContentObserver is registered.  The ContextMenu
     // will be reopened on this View.
     private View                    mSelectedView;
+    private Handler                 mHandler;
 
     private final static String LOGTAG = "BrowserDownloadPage";
     @Override 
@@ -85,7 +86,7 @@
                 Downloads.Impl._DATA,
                 Downloads.Impl.COLUMN_MIME_TYPE},
                 null, Downloads.Impl.COLUMN_LAST_MODIFICATION + " DESC");
-        
+        mHandler = new Handler();
         // only attach everything to the listbox if we can access
         // the download database. Otherwise, just show it empty
         if (mDownloadCursor != null) {
@@ -99,7 +100,7 @@
             // Create a list "controller" for the data
             mDownloadAdapter = new BrowserDownloadAdapter(this, 
                     mDownloadCursor, mDownloadCursor.getColumnIndexOrThrow(
-                    Downloads.Impl.COLUMN_LAST_MODIFICATION));
+                    Downloads.Impl.COLUMN_LAST_MODIFICATION), mHandler);
 
             setListAdapter(mDownloadAdapter);
             mListView.setOnCreateContextMenuListener(this);
@@ -241,8 +242,8 @@
      */
     private class ChangeObserver extends ContentObserver {
         private final Uri mTrack;
-        public ChangeObserver(Uri track) {
-            super(new Handler());
+        public ChangeObserver(Uri track, Handler handler) {
+            super(handler);
             mTrack = track;
         }
 
@@ -313,7 +314,7 @@
                     getContentResolver().unregisterContentObserver(
                             mContentObserver);
                 }
-                mContentObserver = new ChangeObserver(track);
+                mContentObserver = new ChangeObserver(track, mHandler);
                 mSelectedView = v;
                 getContentResolver().registerContentObserver(track, false,
                         mContentObserver);
diff --git a/src/com/android/browser/BrowserHistoryPage.java b/src/com/android/browser/BrowserHistoryPage.java
index 23080f8..0281087 100644
--- a/src/com/android/browser/BrowserHistoryPage.java
+++ b/src/com/android/browser/BrowserHistoryPage.java
@@ -25,7 +25,10 @@
 import android.database.Cursor;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
+import android.os.AsyncTask;
 import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
 import android.os.ServiceManager;
 import android.provider.Browser;
 import android.text.IClipboard;
@@ -92,47 +95,75 @@
         }
     }
 
+    private static final int ADAPTER_CREATED = 1000;
+    private Handler mHandler = new Handler() {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case ADAPTER_CREATED:
+                    mAdapter = (HistoryAdapter) msg.obj;
+                    setListAdapter(mAdapter);
+                    final ExpandableListView list = getExpandableListView();
+                    // Add an empty view late, so it does not claim an empty
+                    // history before the adapter is present
+                    View v = new ViewStub(BrowserHistoryPage.this,
+                            R.layout.empty_history);
+                    addContentView(v, new LayoutParams(
+                            LayoutParams.MATCH_PARENT,
+                            LayoutParams.MATCH_PARENT));
+                    list.setEmptyView(v);
+                    list.setOnCreateContextMenuListener(
+                            BrowserHistoryPage.this);
+                    // Do not post the runnable if there is nothing in the list.
+                    if (list.getExpandableListAdapter().getGroupCount() > 0) {
+                        list.post(new Runnable() {
+                            public void run() {
+                                // In case the history gets cleared before this
+                                // event happens
+                                if (list.getExpandableListAdapter()
+                                        .getGroupCount() > 0) {
+                                    list.expandGroup(0);
+                                }
+                            }
+                        });
+                    }
+                    break;
+            }
+        }
+    };
+
     @Override
     protected void onCreate(Bundle icicle) {
         super.onCreate(icicle);
         setTitle(R.string.browser_history);
 
-        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";
+        new AsyncTask<Void, Void, Void>() {
+            @Override
+            protected Void doInBackground(Void... unused) {
+                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";
 
-        Cursor cursor = managedQuery(
-                Browser.BOOKMARKS_URI,
-                Browser.HISTORY_PROJECTION,
-                whereClause, null, orderBy);
+                Cursor cursor = managedQuery(
+                        Browser.BOOKMARKS_URI,
+                        Browser.HISTORY_PROJECTION,
+                        whereClause, null, orderBy);
 
-        mAdapter = new HistoryAdapter(this, cursor,
-                Browser.HISTORY_PROJECTION_DATE_INDEX);
-        setListAdapter(mAdapter);
-        final ExpandableListView list = getExpandableListView();
-        list.setOnCreateContextMenuListener(this);
-        View v = new ViewStub(this, R.layout.empty_history);
-        addContentView(v, new LayoutParams(LayoutParams.MATCH_PARENT,
-                LayoutParams.MATCH_PARENT));
-        list.setEmptyView(v);
-        // Do not post the runnable if there is nothing in the list.
-        if (list.getExpandableListAdapter().getGroupCount() > 0) {
-            list.post(new Runnable() {
-                public void run() {
-                    // In case the history gets cleared before this event
-                    // happens.
-                    if (list.getExpandableListAdapter().getGroupCount() > 0) {
-                        list.expandGroup(0);
-                    }
-                }
-            });
-        }
+                HistoryAdapter adapter = new HistoryAdapter(
+                        BrowserHistoryPage.this, cursor,
+                        Browser.HISTORY_PROJECTION_DATE_INDEX, mHandler);
+                mHandler.obtainMessage(ADAPTER_CREATED, adapter).sendToTarget();
+                return null;
+            }
+        }.execute();
         mDisableNewWindow = getIntent().getBooleanExtra("disable_new_window",
                 false);
 
@@ -153,6 +184,7 @@
 
     @Override
     protected void onDestroy() {
+        mHandler.removeCallbacksAndMessages(null);
         super.onDestroy();
         CombinedBookmarkHistoryActivity.getIconListenerSet()
                 .removeListener(mIconReceiver);
@@ -181,7 +213,7 @@
                 // CombinedBookmarkHistoryActivity
                 ((CombinedBookmarkHistoryActivity) getParent())
                         .removeParentChildRelationShips();
-                mAdapter.refreshData();
+                if (mAdapter != null) mAdapter.refreshData();
                 return true;
                 
             default:
@@ -265,7 +297,7 @@
                 return true;
             case R.id.delete_context_menu_id:
                 Browser.deleteFromHistory(getContentResolver(), url);
-                mAdapter.refreshData();
+                if (mAdapter != null) mAdapter.refreshData();
                 return true;
             case R.id.homepage_context_menu_id:
                 BrowserSettings.getInstance().setHomePage(this, url);
@@ -297,8 +329,9 @@
     }
 
     private class HistoryAdapter extends DateSortedExpandableListAdapter {
-        HistoryAdapter(Context context, Cursor cursor, int index) {
-            super(context, cursor, index);
+        HistoryAdapter(Context context, Cursor cursor, int index,
+                Handler handler) {
+            super(context, cursor, index, handler);
             
         }
 
diff --git a/src/com/android/browser/BrowserProvider.java b/src/com/android/browser/BrowserProvider.java
index bf1f9d5..7064180 100644
--- a/src/com/android/browser/BrowserProvider.java
+++ b/src/com/android/browser/BrowserProvider.java
@@ -29,8 +29,7 @@
 import android.content.SharedPreferences;
 import android.content.UriMatcher;
 import android.content.SharedPreferences.Editor;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
+import android.content.res.Configuration;
 import android.database.AbstractCursor;
 import android.database.ContentObserver;
 import android.database.Cursor;
@@ -47,8 +46,6 @@
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.Patterns;
-import android.util.TypedValue;
-
 
 import java.io.File;
 import java.io.FilenameFilter;
@@ -91,6 +88,17 @@
     private static final int SUGGEST_COLUMN_QUERY_ID = 8;
     private static final int SUGGEST_COLUMN_INTENT_EXTRA_DATA = 9;
 
+    // how many suggestions will be shown in dropdown
+    // 0..SHORT: filled by browser db
+    private static final int MAX_SUGGEST_SHORT_SMALL = 3;
+    // SHORT..LONG: filled by search suggestions
+    private static final int MAX_SUGGEST_LONG_SMALL = 6;
+
+    // large screen size shows more
+    private static final int MAX_SUGGEST_SHORT_LARGE = 6;
+    private static final int MAX_SUGGEST_LONG_LARGE = 9;
+
+
     // shared suggestion columns
     private static final String[] COLUMNS = new String[] {
             "_id",
@@ -104,10 +112,6 @@
             SearchManager.SUGGEST_COLUMN_QUERY,
             SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA};
 
-    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;
@@ -167,6 +171,9 @@
 
     private SearchManager mSearchManager;
 
+    private int mMaxSuggestionShortSize;
+    private int mMaxSuggestionLongSize;
+
     public BrowserProvider() {
     }
 
@@ -350,6 +357,20 @@
     @Override
     public boolean onCreate() {
         final Context context = getContext();
+        boolean xlargeScreenSize = (context.getResources().getConfiguration().screenLayout
+                & Configuration.SCREENLAYOUT_SIZE_MASK)
+                == Configuration.SCREENLAYOUT_SIZE_XLARGE;
+        boolean isPortrait = (context.getResources().getConfiguration().orientation
+                == Configuration.ORIENTATION_PORTRAIT);
+
+
+        if (xlargeScreenSize && isPortrait) {
+            mMaxSuggestionLongSize = MAX_SUGGEST_LONG_LARGE;
+            mMaxSuggestionShortSize = MAX_SUGGEST_SHORT_LARGE;
+        } else {
+            mMaxSuggestionLongSize = MAX_SUGGEST_LONG_SMALL;
+            mMaxSuggestionShortSize = MAX_SUGGEST_SHORT_SMALL;
+        }
         mOpenHelper = new DatabaseHelper(context);
         mBackupManager = new BackupManager(context);
         // we added "picasa web album" into default bookmarks for version 19.
@@ -465,10 +486,10 @@
         public MySuggestionCursor(Cursor hc, Cursor sc, String string) {
             mHistoryCursor = hc;
             mSuggestCursor = sc;
-            mHistoryCount = hc.getCount();
+            mHistoryCount = hc != null ? hc.getCount() : 0;
             mSuggestionCount = sc != null ? sc.getCount() : 0;
-            if (mSuggestionCount > (MAX_SUGGESTION_LONG_ENTRIES - mHistoryCount)) {
-                mSuggestionCount = MAX_SUGGESTION_LONG_ENTRIES - mHistoryCount;
+            if (mSuggestionCount > (mMaxSuggestionLongSize - mHistoryCount)) {
+                mSuggestionCount = mMaxSuggestionLongSize - mHistoryCount;
             }
             mString = string;
             mIncludeWebSearch = string.length() > 0;
@@ -682,6 +703,7 @@
         }
 
         // TODO Temporary change, finalize after jq's changes go in
+        @Override
         public void deactivate() {
             if (mHistoryCursor != null) {
                 mHistoryCursor.deactivate();
@@ -692,12 +714,14 @@
             super.deactivate();
         }
 
+        @Override
         public boolean requery() {
             return (mHistoryCursor != null ? mHistoryCursor.requery() : false) |
                     (mSuggestCursor != null ? mSuggestCursor.requery() : false);
         }
 
         // TODO Temporary change, finalize after jq's changes go in
+        @Override
         public void close() {
             super.close();
             if (mHistoryCursor != null) {
@@ -762,12 +786,15 @@
         public ResultsCursor(ArrayList<String> results) {
             mResults = results;
         }
+        @Override
         public int getCount() { return mResults.size(); }
 
+        @Override
         public String[] getColumnNames() {
             return RESULTS_COLUMNS;
         }
 
+        @Override
         public String getString(int column) {
             switch (column) {
                 case RESULT_ACTION_ID:
@@ -789,24 +816,30 @@
                     return null;
             }
         }
+        @Override
         public short getShort(int column) {
             throw new UnsupportedOperationException();
         }
+        @Override
         public int getInt(int column) {
             throw new UnsupportedOperationException();
         }
+        @Override
         public long getLong(int column) {
             if ((mPos != -1) && column == 0) {
                 return mPos;        // use row# as the _id
             }
             throw new UnsupportedOperationException();
         }
+        @Override
         public float getFloat(int column) {
             throw new UnsupportedOperationException();
         }
+        @Override
         public double getDouble(int column) {
             throw new UnsupportedOperationException();
         }
+        @Override
         public boolean isNull(int column) {
             throw new UnsupportedOperationException();
         }
@@ -846,8 +879,7 @@
             String suggestSelection;
             String [] myArgs;
             if (selectionArgs[0] == null || selectionArgs[0].equals("")) {
-                suggestSelection = null;
-                myArgs = null;
+                return new MySuggestionCursor(null, null, "");
             } else {
                 String like = selectionArgs[0] + "%";
                 if (selectionArgs[0].startsWith("http")
@@ -869,7 +901,7 @@
 
             Cursor c = db.query(TABLE_NAMES[URI_MATCH_BOOKMARKS],
                     SUGGEST_PROJECTION, suggestSelection, myArgs, null, null,
-                    ORDER_BY, MAX_SUGGESTION_LONG_ENTRIES_STRING);
+                    ORDER_BY, Integer.toString(mMaxSuggestionLongSize));
 
             if (match == URI_MATCH_BOOKMARKS_SUGGEST
                     || Patterns.WEB_URL.matcher(selectionArgs[0]).matches()) {
@@ -878,7 +910,7 @@
                 // get Google suggest if there is still space in the list
                 if (myArgs != null && myArgs.length > 1
                         && mSearchableInfo != null
-                        && c.getCount() < (MAX_SUGGESTION_SHORT_ENTRIES - 1)) {
+                        && c.getCount() < (mMaxSuggestionShortSize - 1)) {
                     Cursor sc = mSearchManager.getSuggestions(mSearchableInfo, selectionArgs[0]);
                     return new MySuggestionCursor(c, sc, selectionArgs[0]);
                 }
@@ -1121,4 +1153,10 @@
         }
     }
 
+    public static Cursor getBookmarksSuggestions(ContentResolver cr, String constraint) {
+        Uri uri = Uri.parse("content://browser/" + SearchManager.SUGGEST_URI_PATH_QUERY);
+        return cr.query(uri, SUGGEST_PROJECTION, SUGGEST_SELECTION,
+            new String[] { constraint }, ORDER_BY);
+    }
+
 }
diff --git a/src/com/android/browser/BrowserSettings.java b/src/com/android/browser/BrowserSettings.java
index 769dfca..94bed2d 100644
--- a/src/com/android/browser/BrowserSettings.java
+++ b/src/com/android/browser/BrowserSettings.java
@@ -106,8 +106,8 @@
     private boolean showConsole = true;
 
     // Private preconfigured values
-    private static int minimumFontSize = 8;
-    private static int minimumLogicalFontSize = 8;
+    private static int minimumFontSize = 1;
+    private static int minimumLogicalFontSize = 1;
     private static int defaultFontSize = 16;
     private static int defaultFixedFontSize = 13;
     private static WebSettings.TextSize textSize =
@@ -219,6 +219,9 @@
             s.setNeedInitialFocus(false);
             // Browser supports multiple windows
             s.setSupportMultipleWindows(true);
+            // enable smooth transition for better performance during panning or
+            // zooming
+            s.setEnableSmoothTransition(true);
 
             // HTML5 API flags
             s.setAppCacheEnabled(b.appCacheEnabled);
diff --git a/src/com/android/browser/CircularProgressView.java b/src/com/android/browser/CircularProgressView.java
new file mode 100644
index 0000000..48f293a
--- /dev/null
+++ b/src/com/android/browser/CircularProgressView.java
@@ -0,0 +1,140 @@
+
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.browser;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.RectF;
+import android.util.AttributeSet;
+import android.widget.ImageButton;
+
+/**
+ *
+ */
+public class CircularProgressView extends ImageButton {
+
+    private static final int[] ALPHAS = {
+       64, 96, 128, 160, 192, 192, 160, 128, 96, 64
+    };
+
+    // 100 ms delay between frames, 10fps
+    private static int ALPHA_REFRESH_DELAY = 100;
+
+    private int     mEndAngle;
+    private int     mProgress;
+    private Paint   mPaint;
+    private int     mAlpha;
+    private boolean mAnimated;
+    private RectF   mRect;
+    private int     mMaxProgress;
+
+    /**
+     * @param context
+     * @param attrs
+     * @param defStyle
+     */
+    public CircularProgressView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        init(context);
+    }
+
+    /**
+     * @param context
+     * @param attrs
+     */
+    public CircularProgressView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        init(context);
+    }
+
+    /**
+     * @param context
+     */
+    public CircularProgressView(Context context) {
+        super(context);
+        init(context);
+    }
+
+    private void init(Context ctx) {
+        mEndAngle = 0;
+        mProgress = 0;
+        mMaxProgress = 100;
+        mPaint = new Paint();
+        mPaint.setAntiAlias(true);
+        mPaint.setColor(Color.BLACK);
+        mRect = new RectF();
+    }
+
+    void setMaxProgress(int max) {
+        mMaxProgress = max;
+    }
+
+    private synchronized boolean isAnimated() {
+        return mAnimated;
+    }
+
+    private synchronized void setAnimated(boolean animated) {
+        mAnimated = animated;
+    }
+
+    void setProgress(int progress) {
+        mProgress = progress;
+        mEndAngle = 360 * progress / mMaxProgress;
+        invalidate();
+        if (!isAnimated() && (progress > 0) && (progress < mMaxProgress)) {
+            setAnimated(true);
+            mAlpha = 0;
+            post(new Runnable() {
+                @Override
+                public void run() {
+                    if (isAnimated()) {
+                        mAlpha = (mAlpha + 1) % ALPHAS.length;
+                        mPaint.setAlpha(ALPHAS[mAlpha]);
+                        invalidate();
+                        postDelayed(this, ALPHA_REFRESH_DELAY);
+                    }
+                }
+            });
+        } else if ((progress <= 0) || (progress >= mMaxProgress))  {
+            setAnimated(false);
+        }
+    }
+
+    @Override
+    public void onDraw(Canvas canvas) {
+        int w = getWidth();
+        int h = getHeight();
+        float cx = w * 0.5f;
+        float cy = h * 0.5f;
+        mRect.set(0, 0, w, h);
+        if ((mProgress > 0) && (mProgress < mMaxProgress)) {
+            Path p = new Path();
+            p.moveTo(cx, cy);
+            p.lineTo(cx, 0);
+            p.arcTo(mRect, 270, mEndAngle);
+            p.lineTo(cx, cy);
+            int state = canvas.save();
+            canvas.drawPath(p, mPaint);
+            canvas.restoreToCount(state);
+        }
+        super.onDraw(canvas);
+    }
+
+}
diff --git a/src/com/android/browser/DateSortedExpandableListAdapter.java b/src/com/android/browser/DateSortedExpandableListAdapter.java
index 1d04493..f8261d8 100644
--- a/src/com/android/browser/DateSortedExpandableListAdapter.java
+++ b/src/com/android/browser/DateSortedExpandableListAdapter.java
@@ -51,8 +51,8 @@
     private Context mContext;
 
     private class ChangeObserver extends ContentObserver {
-        public ChangeObserver() {
-            super(new Handler());
+        public ChangeObserver(Handler handler) {
+            super(handler);
         }
 
         @Override
@@ -67,13 +67,13 @@
     }
 
     public DateSortedExpandableListAdapter(Context context, Cursor cursor,
-            int dateIndex) {
+            int dateIndex, Handler handler) {
         mContext = context;
         mDateSorter = new DateSorter(context);
         mObservers = new Vector<DataSetObserver>();
         mCursor = cursor;
         mIdIndex = cursor.getColumnIndexOrThrow(BaseColumns._ID);
-        cursor.registerContentObserver(new ChangeObserver());
+        cursor.registerContentObserver(new ChangeObserver(handler));
         mDateIndex = dateIndex;
         buildMap();
     }
diff --git a/src/com/android/browser/DownloadTouchIcon.java b/src/com/android/browser/DownloadTouchIcon.java
index 14404ff..765d288 100644
--- a/src/com/android/browser/DownloadTouchIcon.java
+++ b/src/com/android/browser/DownloadTouchIcon.java
@@ -16,6 +16,7 @@
 
 package com.android.browser;
 
+import android.app.Activity;
 import android.content.ContentResolver;
 import android.content.ContentUris;
 import android.content.ContentValues;
@@ -25,10 +26,11 @@
 import android.net.http.AndroidHttpClient;
 import android.net.Proxy;
 import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.Message;
 import android.provider.Browser;
 import android.webkit.WebView;
 
-
 import org.apache.http.HttpEntity;
 import org.apache.http.HttpHost;
 import org.apache.http.HttpResponse;
@@ -45,10 +47,17 @@
     private Cursor mCursor;
     private final String mOriginalUrl;
     private final String mUrl;
-    private final String mUserAgent;
-    private final BrowserActivity mActivity;
+    private final String mUserAgent; // Sites may serve a different icon to different UAs
+    private Message mMessage;
+
+    private final Activity mActivity;
     /* package */ Tab mTab;
 
+    /**
+     * Use this ctor to store the touch icon in the bookmarks database for
+     * the originalUrl so we take account of redirects. Used when the user
+     * bookmarks a page from outside the bookmarks activity.
+     */
     public DownloadTouchIcon(Tab tab, BrowserActivity activity, ContentResolver cr, WebView view) {
         mTab = tab;
         mActivity = activity;
@@ -59,24 +68,49 @@
         mUserAgent = view.getSettings().getUserAgentString();
     }
 
-    public DownloadTouchIcon(ContentResolver cr, String url) {
+    /**
+     * Use this ctor to download the touch icon and update the bookmarks database
+     * entry for the given url. Used when the user creates a bookmark from
+     * within the bookmarks activity and there haven't been any redirects.
+     * TODO: Would be nice to set the user agent here so that there is no
+     * potential for the three different ctors here to return different icons.
+     */
+    public DownloadTouchIcon(AddBookmarkPage activity, ContentResolver cr, String url) {
         mTab = null;
-        mActivity = null;
+        mActivity = activity;
         mContentResolver = cr;
         mOriginalUrl = null;
         mUrl = url;
         mUserAgent = null;
     }
 
+    /**
+     * Use this ctor to not store the touch icon in a database, rather add it to
+     * the passed Message's data bundle with the key "touchIcon" and then send
+     * the message.
+     */
+    public DownloadTouchIcon(BrowserActivity activity, Message msg, String userAgent) {
+        mMessage = msg;
+        mActivity = activity;
+        mContentResolver = null;
+        mOriginalUrl = null;
+        mUrl = null;
+        mUserAgent = userAgent;
+    }
+
     @Override
     public Void doInBackground(String... values) {
-        mCursor = BrowserBookmarksAdapter.queryBookmarksForUrl(mContentResolver,
-                mOriginalUrl, mUrl, true);
-        if (mCursor != null && mCursor.getCount() > 0) {
-            String url = values[0];
+        if (mContentResolver != null) {
+            mCursor = BrowserBookmarksAdapter.queryBookmarksForUrl(mContentResolver,
+                    mOriginalUrl, mUrl, true);
+        }
 
-            AndroidHttpClient client = AndroidHttpClient.newInstance(
-                    mUserAgent);
+        boolean inBookmarksDatabase = mCursor != null && mCursor.getCount() > 0;
+
+        String url = values[0];
+
+        if (inBookmarksDatabase || mMessage != null) {
+            AndroidHttpClient client = AndroidHttpClient.newInstance(mUserAgent);
             HttpHost httpHost = Proxy.getPreferredHttpHost(mActivity, url);
             if (httpHost != null) {
                 ConnRouteParams.setDefaultProxy(client.getParams(), httpHost);
@@ -89,7 +123,6 @@
 
             try {
                 HttpResponse response = client.execute(request);
-
                 if (response.getStatusLine().getStatusCode() == 200) {
                     HttpEntity entity = response.getEntity();
                     if (entity != null) {
@@ -97,7 +130,12 @@
                         if (content != null) {
                             Bitmap icon = BitmapFactory.decodeStream(
                                     content, null, null);
-                            storeIcon(icon);
+                            if (inBookmarksDatabase) {
+                                storeIcon(icon);
+                            } else if (mMessage != null) {
+                                Bundle b = mMessage.getData();
+                                b.putParcelable("touchIcon", icon);
+                            }
                         }
                     }
                 }
@@ -109,9 +147,15 @@
                 client.close();
             }
         }
+
         if (mCursor != null) {
             mCursor.close();
         }
+
+        if (mMessage != null) {
+            mMessage.sendToTarget();
+        }
+
         return null;
     }
 
diff --git a/src/com/android/browser/FindDialog.java b/src/com/android/browser/FindDialog.java
index 45c8016..9d0ac4b 100644
--- a/src/com/android/browser/FindDialog.java
+++ b/src/com/android/browser/FindDialog.java
@@ -16,27 +16,25 @@
 
 package com.android.browser;
 
-import android.app.Dialog;
 import android.content.Context;
-import android.os.Bundle;
 import android.text.Editable;
+import android.text.Selection;
 import android.text.Spannable;
 import android.text.TextWatcher;
 import android.view.Gravity;
 import android.view.KeyEvent;
+import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.Window;
-import android.view.WindowManager;
+import android.view.animation.AnimationUtils;
 import android.view.inputmethod.InputMethodManager;
 import android.webkit.WebView;
 import android.widget.EditText;
+import android.widget.LinearLayout;
 import android.widget.TextView;
 
-/* package */ class FindDialog extends Dialog implements TextWatcher {
-    private WebView         mWebView;
+/* package */ class FindDialog extends WebDialog implements TextWatcher {
     private TextView        mMatches;
-    private BrowserActivity mBrowserActivity;
     
     // Views with which the user can interact.
     private EditText        mEditText;
@@ -44,39 +42,30 @@
     private View            mPrevButton;
     private View            mMatchesView;
 
+    // When the dialog is opened up with old text, enter needs to be pressed
+    // (or the text needs to be changed) before WebView.findAll can be called.
+    // Once it has been called, enter should move to the next match.
+    private boolean         mMatchesFound;
+    private int             mNumberOfMatches;
+
     private View.OnClickListener mFindListener = new View.OnClickListener() {
         public void onClick(View v) {
             findNext();
         }
     };
 
-    private View.OnClickListener mFindCancelListener  = 
-            new View.OnClickListener() {
-        public void onClick(View v) {
-            dismiss();
-        }
-    };
-    
-    private View.OnClickListener mFindPreviousListener  = 
+    private View.OnClickListener mFindPreviousListener  =
             new View.OnClickListener() {
         public void onClick(View v) {
             if (mWebView == null) {
                 throw new AssertionError("No WebView for FindDialog::onClick");
             }
             mWebView.findNext(false);
+            updateMatchesString();
             hideSoftInput();
         }
     };
 
-    /*
-     * Remove the soft keyboard from the screen.
-     */
-    private void hideSoftInput() {
-        InputMethodManager imm = (InputMethodManager)
-                mBrowserActivity.getSystemService(Context.INPUT_METHOD_SERVICE);
-        imm.hideSoftInputFromWindow(mEditText.getWindowToken(), 0);
-    }
-
     private void disableButtons() {
         mPrevButton.setEnabled(false);
         mNextButton.setEnabled(false);
@@ -84,28 +73,13 @@
         mNextButton.setFocusable(false);
     }
 
-    /* package */ void setWebView(WebView webview) {
-        mWebView = webview;
-    }
-
     /* package */ FindDialog(BrowserActivity context) {
-        super(context, R.style.FindDialogTheme);
-        mBrowserActivity = context;
-        setCanceledOnTouchOutside(true);
-    }
+        super(context);
 
-    @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
+        LayoutInflater factory = LayoutInflater.from(context);
+        factory.inflate(R.layout.browser_find, this);
 
-        Window theWindow = getWindow();
-        theWindow.setGravity(Gravity.BOTTOM|Gravity.FILL_HORIZONTAL);
-
-        setContentView(R.layout.browser_find);
-
-        theWindow.setLayout(ViewGroup.LayoutParams.MATCH_PARENT,
-                ViewGroup.LayoutParams.WRAP_CONTENT);
-
+        addCancel();
         mEditText = (EditText) findViewById(R.id.edit);
         
         View button = findViewById(R.id.next);
@@ -116,29 +90,59 @@
         button.setOnClickListener(mFindPreviousListener);
         mPrevButton = button;
         
-        button = findViewById(R.id.done);
-        button.setOnClickListener(mFindCancelListener);
-        
         mMatches = (TextView) findViewById(R.id.matches);
         mMatchesView = findViewById(R.id.matches_view);
         disableButtons();
-        theWindow.setSoftInputMode(
-                WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
+
     }
-    
+
+    /**
+     * Called by BrowserActivity.closeDialog.  Start the animation to hide
+     * the dialog, inform the WebView that the dialog is being dismissed,
+     * and hide the soft keyboard.
+     */
     public void dismiss() {
         super.dismiss();
-        mBrowserActivity.closeFind();
         mWebView.notifyFindDialogDismissed();
+        hideSoftInput();
+    }
+
+    @Override
+    public boolean dispatchKeyEventPreIme(KeyEvent event) {
+        if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
+            KeyEvent.DispatcherState state = getKeyDispatcherState();
+            if (state != null) {
+                int action = event.getAction();
+                if (KeyEvent.ACTION_DOWN == action
+                        && event.getRepeatCount() == 0) {
+                    state.startTracking(event, this);
+                    return true;
+                } else if (KeyEvent.ACTION_UP == action
+                        && !event.isCanceled() && state.isTracking(event)) {
+                    mBrowserActivity.closeDialogs();
+                    return true;
+                }
+            }
+        }
+        return super.dispatchKeyEventPreIme(event);
     }
 
     @Override
     public boolean dispatchKeyEvent(KeyEvent event) {
-        if (event.getKeyCode() == KeyEvent.KEYCODE_ENTER
-                && event.getAction() == KeyEvent.ACTION_UP
-                && mEditText.hasFocus()) {
-            findNext();
-            return true;
+        int keyCode = event.getKeyCode();
+        if (event.getAction() == KeyEvent.ACTION_UP) {
+            if (keyCode == KeyEvent.KEYCODE_ENTER
+                    && mEditText.hasFocus()) {
+                if (mMatchesFound) {
+                    findNext();
+                } else {
+                    findAll();
+                    // Set the selection to the end.
+                    Spannable span = (Spannable) mEditText.getText();
+                    Selection.setSelection(span, span.length());
+                }
+                return true;
+            }
         }
         return super.dispatchKeyEvent(event);
     }
@@ -148,18 +152,26 @@
             throw new AssertionError("No WebView for FindDialog::findNext");
         }
         mWebView.findNext(true);
+        updateMatchesString();
         hideSoftInput();
     }
 
     public void show() {
         super.show();
+        // In case the matches view is showing from a previous search
+        mMatchesView.setVisibility(View.INVISIBLE);
+        mMatchesFound = false;
+        // This text is only here to ensure that mMatches has a height.
+        mMatches.setText("0");
         mEditText.requestFocus();
-        mEditText.setText("");
         Spannable span = (Spannable) mEditText.getText();
-        span.setSpan(this, 0, span.length(), 
-                     Spannable.SPAN_INCLUSIVE_INCLUSIVE);
-        setMatchesFound(0);
+        int length = span.length();
+        Selection.setSelection(span, 0, length);
+        span.setSpan(this, 0, length, Spannable.SPAN_INCLUSIVE_INCLUSIVE);
         disableButtons();
+        InputMethodManager imm = (InputMethodManager)
+                mBrowserActivity.getSystemService(Context.INPUT_METHOD_SERVICE);
+        imm.showSoftInput(mEditText, 0);
     }
     
     // TextWatcher methods
@@ -173,9 +185,13 @@
                               int start, 
                               int before, 
                               int count) {
+        findAll();
+    }
+
+    private void findAll() {
         if (mWebView == null) {
             throw new AssertionError(
-                    "No WebView for FindDialog::onTextChanged");
+                    "No WebView for FindDialog::findAll");
         }
         CharSequence find = mEditText.getText();
         if (0 == find.length()) {
@@ -184,14 +200,16 @@
             mMatchesView.setVisibility(View.INVISIBLE);
         } else {
             mMatchesView.setVisibility(View.VISIBLE);
-            mWebView.setFindDialogHeight(
-                getWindow().getDecorView().getHeight());
             int found = mWebView.findAll(find.toString());
+            mMatchesFound = true;
             setMatchesFound(found);
             if (found < 2) {
                 disableButtons();
                 if (found == 0) {
-                    setMatchesFound(0);
+                    // Cannot use getQuantityString, which ignores the "zero"
+                    // quantity.
+                    mMatches.setText(mBrowserActivity.getResources().getString(
+                            R.string.no_matches));
                 }
             } else {
                 mPrevButton.setFocusable(true);
@@ -203,8 +221,21 @@
     }
 
     private void setMatchesFound(int found) {
+        mNumberOfMatches = found;
+        updateMatchesString();
+    }
+
+    public void setText(String text) {
+        mEditText.setText(text);
+        findAll();
+    }
+
+    private void updateMatchesString() {
+        // Note: updateMatchesString is only called by methods that have already
+        // checked mWebView for null.
         String template = mBrowserActivity.getResources().
-                getQuantityString(R.plurals.matches_found, found, found);
+                getQuantityString(R.plurals.matches_found, mNumberOfMatches,
+                mWebView.findIndex() + 1, mNumberOfMatches);
 
         mMatches.setText(template);
     }
diff --git a/src/com/android/browser/SaveToHomescreenDialog.java b/src/com/android/browser/SaveToHomescreenDialog.java
new file mode 100644
index 0000000..15f0aea
--- /dev/null
+++ b/src/com/android/browser/SaveToHomescreenDialog.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.browser;
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.database.Cursor;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.net.ParseException;
+import android.net.Uri;
+import android.net.WebAddress;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.provider.Browser;
+import android.util.Log;
+import android.view.View;
+import android.view.Window;
+import android.widget.Button;
+import android.widget.CheckBox;
+import android.widget.EditText;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Date;
+
+public class SaveToHomescreenDialog extends Activity {
+
+    private EditText    mTitle;
+    private String      mUrl;
+    private Bitmap      mFavicon;
+    private Bitmap      mTouchIcon;
+
+    private View.OnClickListener mOk = new View.OnClickListener() {
+        public void onClick(View v) {
+            if (save()) {
+                finish();
+            }
+        }
+    };
+
+    private View.OnClickListener mCancel = new View.OnClickListener() {
+        public void onClick(View v) {
+            finish();
+        }
+    };
+
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        requestWindowFeature(Window.FEATURE_LEFT_ICON);
+        setContentView(R.layout.browser_add_bookmark_const_url);
+        setTitle(R.string.create_shortcut_bookmark);
+        getWindow().setFeatureDrawableResource(Window.FEATURE_LEFT_ICON,
+                R.drawable.ic_list_bookmark);
+
+        String title = null;
+        String url = null;
+        Bundle map = getIntent().getExtras();
+        if (map != null) {
+            title = map.getString("title");
+        }
+
+        mUrl = map.getString("url");
+        mFavicon = (Bitmap)map.getParcelable("favicon");
+        mTouchIcon = (Bitmap)map.getParcelable("touchIcon");
+
+        Bitmap icon = BookmarkUtils.createIcon(this, mTouchIcon, mFavicon,
+               BookmarkUtils.BookmarkIconType.ICON_HOME_SHORTCUT);
+        getWindow().setFeatureDrawable(Window.FEATURE_LEFT_ICON, new BitmapDrawable(icon));
+
+        mTitle = (EditText) findViewById(R.id.title);
+        mTitle.setText(title);
+
+        Button okButton = (Button) findViewById(R.id.OK);
+        okButton.setOnClickListener(mOk);
+
+        Button cancelButton = (Button) findViewById(R.id.cancel);
+        cancelButton.setOnClickListener(mCancel);
+
+        if (!getWindow().getDecorView().isInTouchMode()) {
+            okButton.requestFocus();
+        }
+    }
+
+    /**
+     * Parse the data entered in the dialog and send an intent to create an
+     * icon on the homescreen.
+     */
+    private boolean save() {
+        String title = mTitle.getText().toString().trim();
+        String unfilteredUrl = BrowserActivity.fixUrl(mUrl);
+        if (title.length() == 0) {
+            mTitle.setError(getResources().getText(R.string.bookmark_needs_title));
+            return false;
+        }
+
+        String url = unfilteredUrl.trim();
+
+        sendBroadcast(BookmarkUtils.createAddToHomeIntent(this, url, title,
+                mTouchIcon, mFavicon));
+        setResult(RESULT_OK);
+        return true;
+    }
+}
diff --git a/src/com/android/browser/SelectDialog.java b/src/com/android/browser/SelectDialog.java
new file mode 100644
index 0000000..461127a
--- /dev/null
+++ b/src/com/android/browser/SelectDialog.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.browser;
+
+import android.provider.Browser;
+import android.view.LayoutInflater;
+import android.view.View;
+
+/* package */ class SelectDialog extends WebDialog {
+    private View mCopyButton;
+    private View mSelectAllButton;
+    private View mShareButton;
+    private View mFindButton;
+
+    SelectDialog(BrowserActivity context) {
+        super(context);
+        LayoutInflater factory = LayoutInflater.from(context);
+        factory.inflate(R.layout.browser_select, this);
+        addCancel();
+
+        mCopyButton = findViewById(R.id.copy);
+        mCopyButton.setOnClickListener(mCopyListener);
+        mSelectAllButton = findViewById(R.id.select_all);
+        mSelectAllButton.setOnClickListener(mSelectAllListener);
+        mShareButton = findViewById(R.id.share);
+        mShareButton.setOnClickListener(mShareListener);
+        mFindButton = findViewById(R.id.find);
+        mFindButton.setOnClickListener(mFindListener);
+    }
+
+    private View.OnClickListener mCopyListener = new View.OnClickListener() {
+        public void onClick(View v) {
+            mWebView.copySelection();
+            mBrowserActivity.closeDialogs();
+        }
+    };
+
+    private View.OnClickListener mSelectAllListener = new View.OnClickListener() {
+        public void onClick(View v) {
+            mWebView.selectAll();
+        }
+    };
+
+    private View.OnClickListener mShareListener = new View.OnClickListener() {
+        public void onClick(View v) {
+            String selection = mWebView.getSelection();
+            Browser.sendString(mBrowserActivity, selection);
+            mBrowserActivity.closeDialogs();
+        }
+    };
+
+    private View.OnClickListener mFindListener = new View.OnClickListener() {
+        public void onClick(View v) {
+            String selection = mWebView.getSelection();
+            mBrowserActivity.closeDialogs();
+            mBrowserActivity.showFindDialog();
+            mBrowserActivity.setFindDialogText(selection);
+        }
+    };
+
+    /**
+     * Called by BrowserActivity.closeDialog.  Start the animation to hide
+     * the dialog, and inform the WebView that the dialog is being dismissed.
+     */
+    @Override
+    public void dismiss() {
+        super.dismiss();
+        mWebView.notifySelectDialogDismissed();
+    }
+
+}
diff --git a/src/com/android/browser/Tab.java b/src/com/android/browser/Tab.java
index 5795b05..1d9482b 100644
--- a/src/com/android/browser/Tab.java
+++ b/src/com/android/browser/Tab.java
@@ -16,21 +16,13 @@
 
 package com.android.browser;
 
-import java.io.File;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.Map;
-import java.util.Vector;
-
 import android.app.AlertDialog;
 import android.app.SearchManager;
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.content.DialogInterface;
-import android.content.DialogInterface.OnCancelListener;
 import android.content.Intent;
+import android.content.DialogInterface.OnCancelListener;
 import android.database.Cursor;
 import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteException;
@@ -71,8 +63,17 @@
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
+import com.android.browser.TabControl.TabChangeListener;
 import com.android.common.speech.LoggingEvents;
 
+import java.io.File;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Vector;
+
 /**
  * Class for maintaining Tabs with a main WebView and a subwindow.
  */
@@ -87,7 +88,7 @@
     // The Geolocation permissions prompt
     private GeolocationPermissionsPrompt mGeolocationPermissionsPrompt;
     // Main WebView wrapper
-    private View mContainer;
+    private LinearLayout mContainer;
     // Main WebView
     private WebView mMainView;
     // Subwindow container
@@ -151,7 +152,6 @@
     static final String CURRTAB = "currentTab";
     static final String CURRURL = "currentUrl";
     static final String CURRTITLE = "currentTitle";
-    static final String CURRPICTURE = "currentPicture";
     static final String CLOSEONEXIT = "closeonexit";
     static final String PARENTTAB = "parentTab";
     static final String APPID = "appid";
@@ -503,6 +503,9 @@
             if (mInForeground) {
                 mActivity.onPageStarted(view, url, favicon);
             }
+            if (getTabChangeListener() != null) {
+                getTabChangeListener().onPageStarted(Tab.this);
+            }
         }
 
         @Override
@@ -524,6 +527,9 @@
             if (mInForeground) {
                 mActivity.onPageFinished(view, url);
             }
+            if (getTabChangeListener() != null) {
+                getTabChangeListener().onPageFinished(Tab.this);
+            }
         }
 
         // return true if want to hijack the url to let another app to handle it
@@ -673,6 +679,7 @@
             final ContentResolver cr = mActivity.getContentResolver();
             final String newUrl = url;
             new AsyncTask<Void, Void, Void>() {
+                @Override
                 protected Void doInBackground(Void... unused) {
                     Browser.updateVisitedHistory(cr, newUrl, true);
                     return null;
@@ -949,6 +956,9 @@
             if (mInForeground) {
                 mActivity.onProgressChanged(view, newProgress);
             }
+            if (getTabChangeListener() != null) {
+                getTabChangeListener().onProgress(Tab.this, newProgress);
+            }
         }
 
         @Override
@@ -958,11 +968,16 @@
                 // here, if url is null, we want to reset the title
                 mActivity.setUrlTitle(pageUrl, title);
             }
+            TabChangeListener tcl = getTabChangeListener();
+            if (tcl != null) {
+                tcl.onUrlAndTitle(Tab.this, pageUrl,title);
+            }
             if (pageUrl == null || pageUrl.length()
                     >= SQLiteDatabase.SQLITE_MAX_LIKE_PATTERN_LENGTH) {
                 return;
             }
             new AsyncTask<Void, Void, Void>() {
+                @Override
                 protected Void doInBackground(Void... unused) {
                     // See if we can find the current url in our history
                     // database and add the new title to it.
@@ -1021,6 +1036,9 @@
             if (mInForeground) {
                 mActivity.setFavicon(icon);
             }
+            if (getTabChangeListener() != null) {
+                getTabChangeListener().onFavicon(Tab.this, icon);
+            }
         }
 
         @Override
@@ -1041,6 +1059,16 @@
         }
 
         @Override
+        public void onSelectionDone(WebView view) {
+            if (mInForeground) mActivity.closeDialogs();
+        }
+
+        @Override
+        public void onSelectionStart(WebView view) {
+            if (mInForeground) mActivity.showSelectDialog();
+        }
+
+        @Override
         public void onShowCustomView(View view,
                 WebChromeClient.CustomViewCallback callback) {
             if (mInForeground) mActivity.onShowCustomView(view, callback);
@@ -1185,9 +1213,9 @@
         }
 
         @Override
-        public void openFileChooser(ValueCallback<Uri> uploadMsg) {
+        public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType) {
             if (mInForeground) {
-                mActivity.openFileChooser(uploadMsg);
+                mActivity.openFileChooser(uploadMsg, acceptType);
             } else {
                 uploadMsg.onReceiveValue(null);
             }
@@ -1199,10 +1227,12 @@
         @Override
         public void getVisitedHistory(final ValueCallback<String[]> callback) {
             AsyncTask<Void, Void, String[]> task = new AsyncTask<Void, Void, String[]>() {
+                @Override
                 public String[] doInBackground(Void... unused) {
                     return Browser.getVisitedHistory(mActivity
                             .getContentResolver());
                 }
+                @Override
                 public void onPostExecute(String[] result) {
                     callback.onReceiveValue(result);
                 };
@@ -1220,9 +1250,18 @@
     private static class SubWindowClient extends WebViewClient {
         // The main WebViewClient.
         private final WebViewClient mClient;
+        private final BrowserActivity mBrowserActivity;
 
-        SubWindowClient(WebViewClient client) {
+        SubWindowClient(WebViewClient client, BrowserActivity activity) {
             mClient = client;
+            mBrowserActivity = activity;
+        }
+        @Override
+        public void onPageStarted(WebView view, String url, Bitmap favicon) {
+            // Unlike the others, do not call mClient's version, which would
+            // change the progress bar.  However, we do want to remove the
+            // find or select dialog.
+            mBrowserActivity.closeDialogs();
         }
         @Override
         public void doUpdateVisitedHistory(WebView view, String url,
@@ -1312,7 +1351,7 @@
 
         // The tab consists of a container view, which contains the main
         // WebView, as well as any other UI elements associated with the tab.
-        mContainer = mInflateService.inflate(R.layout.tab, null);
+        mContainer = (LinearLayout) mInflateService.inflate(R.layout.tab, null);
 
         mDownloadListener = new DownloadListener() {
             public void onDownloadStart(String url, String userAgent,
@@ -1423,6 +1462,7 @@
      */
     boolean createSubWindow() {
         if (mSubView == null) {
+            mActivity.closeDialogs();
             mSubViewContainer = mInflateService.inflate(
                     R.layout.browser_subwindow, null);
             mSubView = (WebView) mSubViewContainer.findViewById(R.id.webview);
@@ -1431,7 +1471,8 @@
             mSubView.setMapTrackballToArrowKeys(false);
             // Enable the built-in zoom
             mSubView.getSettings().setBuiltInZoomControls(true);
-            mSubView.setWebViewClient(new SubWindowClient(mWebViewClient));
+            mSubView.setWebViewClient(new SubWindowClient(mWebViewClient,
+                    mActivity));
             mSubView.setWebChromeClient(new SubWindowChromeClient(
                     mWebChromeClient));
             // Set a different DownloadListener for the mSubView, since it will
@@ -1469,6 +1510,7 @@
      */
     void dismissSubWindow() {
         if (mSubView != null) {
+            mActivity.closeDialogs();
             BrowserSettings.getInstance().deleteObserver(
                     mSubView.getSettings());
             mSubView.destroy();
@@ -1493,6 +1535,7 @@
     void removeSubWindow(ViewGroup content) {
         if (mSubView != null) {
             content.removeView(mSubViewContainer);
+            mActivity.closeDialogs();
         }
     }
 
@@ -1551,6 +1594,7 @@
                 (FrameLayout) mContainer.findViewById(R.id.webview_wrapper);
         wrapper.removeView(mMainView);
         content.removeView(mContainer);
+        mActivity.closeDialogs();
         removeSubWindow(content);
     }
 
@@ -1824,6 +1868,9 @@
         // FIXME: The only place we cared about subwindow was for
         // bookmarking (i.e. not when saving state). Was this deliberate?
         final WebBackForwardList list = mMainView.copyBackForwardList();
+        if (list == null) {
+            Log.w(LOGTAG, "populatePickerData called and WebBackForwardList is null");
+        }
         final WebHistoryItem item = list != null ? list.getCurrentItem() : null;
         populatePickerData(item);
     }
@@ -1832,7 +1879,9 @@
     // WebView.
     private void populatePickerData(WebHistoryItem item) {
         mPickerData = new PickerData();
-        if (item != null) {
+        if (item == null) {
+            Log.w(LOGTAG, "populatePickerData called with a null WebHistoryItem");
+        } else {
             mPickerData.mUrl = item.getUrl();
             mPickerData.mTitle = item.getTitle();
             mPickerData.mFavicon = item.getFavicon();
@@ -1883,17 +1932,6 @@
 
         mSavedState = new Bundle();
         final WebBackForwardList list = mMainView.saveState(mSavedState);
-        if (list != null) {
-            final File f = new File(mActivity.getTabControl().getThumbnailDir(),
-                    mMainView.hashCode() + "_pic.save");
-            if (mMainView.savePicture(mSavedState, f)) {
-                mSavedState.putString(CURRPICTURE, f.getPath());
-            } else {
-                // if savePicture returned false, we can't trust the contents,
-                // and it may be large, so we delete it right away
-                f.delete();
-            }
-        }
 
         // Store some extra info for displaying the tab in the picker.
         final WebHistoryItem item = list != null ? list.getCurrentItem() : null;
@@ -1939,11 +1977,47 @@
         if (list == null) {
             return false;
         }
-        if (b.containsKey(CURRPICTURE)) {
-            final File f = new File(b.getString(CURRPICTURE));
-            mMainView.restorePicture(b, f);
-            f.delete();
-        }
         return true;
     }
+
+    /*
+     * Opens the find and select text dialogs.  Called by BrowserActivity.
+     */
+    WebView showDialog(WebDialog dialog) {
+        LinearLayout container;
+        WebView view;
+        if (mSubView != null) {
+            view = mSubView;
+            container = (LinearLayout) mSubViewContainer.findViewById(
+                    R.id.inner_container);
+        } else {
+            view = mMainView;
+            container = mContainer;
+        }
+        dialog.show();
+        container.addView(dialog, 0, new LinearLayout.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.WRAP_CONTENT));
+        dialog.setWebView(view);
+        return view;
+    }
+
+    /*
+     * Close the find or select dialog. Called by BrowserActivity.closeDialog.
+     */
+    void closeDialog(WebDialog dialog) {
+        // The dialog may be attached to the subwindow.  Ensure that the
+        // correct parent has it removed.
+        LinearLayout parent = (LinearLayout) dialog.getParent();
+        if (parent != null) parent.removeView(dialog);
+    }
+
+    /**
+     * always get the TabChangeListener form the tab control
+     * @return the TabControl change listener
+     */
+    private TabChangeListener getTabChangeListener() {
+        return mActivity.getTabControl().getTabChangeListener();
+    }
+
 }
diff --git a/src/com/android/browser/TabControl.java b/src/com/android/browser/TabControl.java
index 7cd2ccb..0fbdd7a 100644
--- a/src/com/android/browser/TabControl.java
+++ b/src/com/android/browser/TabControl.java
@@ -132,7 +132,7 @@
     int getCurrentIndex() {
         return mCurrentTab;
     }
-    
+
     /**
      * Given a Tab, find it's index
      * @param Tab to find
@@ -167,6 +167,9 @@
         mTabs.add(t);
         // Initially put the tab in the background.
         t.putInBackground();
+        if (mTabChangeListener != null) {
+            mTabChangeListener.onNewTab(t);
+        }
         return t;
     }
 
@@ -229,17 +232,11 @@
             }
         }
 
-        // This tab may have been pushed in to the background and then closed.
-        // If the saved state contains a picture file, delete the file.
-        Bundle savedState = t.getSavedState();
-        if (savedState != null) {
-            if (savedState.containsKey(Tab.CURRPICTURE)) {
-                new File(savedState.getString(Tab.CURRPICTURE)).delete();
-            }
-        }
-
         // Remove it from the queue of viewed tabs.
         mTabQueue.remove(t);
+        if (mTabChangeListener != null) {
+            mTabChangeListener.onRemoveTab(t);
+        }
         return true;
     }
 
@@ -626,6 +623,47 @@
                 mainView.loadUrl(BrowserSettings.getInstance().getHomePage());
             }
         }
+        if (mTabChangeListener != null) {
+            mTabChangeListener.onCurrentTab(newTab);
+        }
         return true;
     }
+
+    interface TabChangeListener {
+
+        public void onNewTab(Tab tab);
+
+        public void onRemoveTab(Tab tab);
+
+        public void onCurrentTab(Tab tab);
+
+        public void onProgress(Tab tab, int progress);
+
+        public void onUrlAndTitle(Tab tab, String url, String title);
+
+        public void onFavicon(Tab tab, Bitmap favicon);
+
+        public void onPageStarted(Tab tab);
+
+        public void onPageFinished(Tab tab);
+
+    }
+
+    private TabChangeListener mTabChangeListener;
+
+    /**
+     * register the TabChangeListener with the tab control
+     * @param listener
+     */
+    void setOnTabChangeListener(TabChangeListener listener) {
+        mTabChangeListener = listener;
+    }
+
+    /**
+     * get the current TabChangeListener (used by the tabs)
+     */
+    TabChangeListener getTabChangeListener() {
+        return mTabChangeListener;
+    }
+
 }
diff --git a/src/com/android/browser/TabScrollView.java b/src/com/android/browser/TabScrollView.java
new file mode 100644
index 0000000..6d8b91b
--- /dev/null
+++ b/src/com/android/browser/TabScrollView.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.browser;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.HorizontalScrollView;
+import android.widget.LinearLayout;
+
+/**
+ * custom view for displaying tabs in the tabbed title bar
+ */
+public class TabScrollView extends HorizontalScrollView {
+
+    private Context mContext;
+
+    private LinearLayout mContentView;
+
+    private int mSelected;
+
+    /**
+     * @param context
+     * @param attrs
+     * @param defStyle
+     */
+    public TabScrollView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        init(context);
+    }
+
+    /**
+     * @param context
+     * @param attrs
+     */
+    public TabScrollView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        init(context);
+    }
+
+    /**
+     * @param context
+     */
+    public TabScrollView(Context context) {
+        super(context);
+        init(context);
+    }
+
+    private void init(Context ctx) {
+        mContext = ctx;
+        setHorizontalScrollBarEnabled(false);
+        mContentView = new LinearLayout(mContext);
+        mContentView.setOrientation(LinearLayout.HORIZONTAL);
+        mContentView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
+                LayoutParams.WRAP_CONTENT));
+        addView(mContentView);
+        mSelected = -1;
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        super.onLayout(changed, left, top, right, bottom);
+        ensureChildVisible(getSelectedTab());
+    }
+
+    void setSelectedTab(int position) {
+        View v = getSelectedTab();
+        if (v != null) {
+            v.setSelected(false);
+        }
+        mSelected = position;
+        v = getSelectedTab();
+        if (v != null) {
+            v.setSelected(true);
+        }
+        requestLayout();
+    }
+
+    View getSelectedTab() {
+        if ((mSelected >= 0) && (mSelected < mContentView.getChildCount())) {
+            return mContentView.getChildAt(mSelected);
+        } else {
+            return null;
+        }
+    }
+
+    void clearTabs() {
+        mContentView.removeAllViews();
+    }
+
+    void addTab(View tab) {
+        mContentView.addView(tab);
+        tab.setSelected(false);
+    }
+
+    void addTab(View tab, int pos) {
+        mContentView.addView(tab, pos);
+        tab.setSelected(false);
+    }
+
+    void removeTab(View tab) {
+        mContentView.removeView(tab);
+    }
+
+    void ensureChildVisible(View child) {
+        if (child != null) {
+            int childl = child.getLeft();
+            int childr = childl + child.getWidth();
+            int viewl = getScrollX();
+            int viewr = viewl + getWidth();
+            if (childl < viewl) {
+                // need scrolling to left
+                scrollTo(childl, 0);
+            } else if (childr > viewr) {
+                // need scrolling to right
+                scrollTo(childr - viewr + viewl, 0);
+            }
+        }
+    }
+
+
+}
diff --git a/src/com/android/browser/TitleBar.java b/src/com/android/browser/TitleBar.java
index dc4979b..f45025d 100644
--- a/src/com/android/browser/TitleBar.java
+++ b/src/com/android/browser/TitleBar.java
@@ -21,14 +21,8 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.Color;
-import android.graphics.Rect;
 import android.graphics.drawable.Animatable;
-import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
-import android.graphics.drawable.LayerDrawable;
-import android.graphics.drawable.PaintDrawable;
 import android.os.Handler;
 import android.os.Message;
 import android.speech.RecognizerIntent;
@@ -45,7 +39,6 @@
 import android.view.View;
 import android.view.ViewConfiguration;
 import android.widget.ImageView;
-import android.widget.LinearLayout;
 import android.widget.ProgressBar;
 import android.widget.TextView;
 
@@ -55,21 +48,16 @@
  * This class represents a title bar for a particular "tab" or "window" in the
  * browser.
  */
-public class TitleBar extends LinearLayout {
+public class TitleBar extends TitleBarBase {
     private TextView        mTitle;
-    private Drawable        mCloseDrawable;
     private ImageView       mRtButton;
     private Drawable        mCircularProgress;
     private ProgressBar     mHorizontalProgress;
-    private ImageView       mFavicon;
-    private ImageView       mLockIcon;
     private ImageView       mStopButton;
     private Drawable        mBookmarkDrawable;
     private Drawable        mVoiceDrawable;
     private boolean         mInLoad;
     private BrowserActivity mBrowserActivity;
-    private Drawable        mGenericFavicon;
-    private int             mIconDimension;
     private View            mTitleBg;
     private MyHandler       mHandler;
     private Intent          mVoiceSearchIntent;
@@ -84,7 +72,7 @@
     private static int LONG_PRESS = 1;
 
     public TitleBar(BrowserActivity context) {
-        super(context, null);
+        super(context);
         mHandler = new MyHandler();
         LayoutInflater factory = LayoutInflater.from(context);
         factory.inflate(R.layout.title_bar, this);
@@ -107,13 +95,11 @@
                 TypedValue.COMPLEX_UNIT_DIP, 8f, metrics);
         mRightMargin = (int) TypedValue.applyDimension(
                 TypedValue.COMPLEX_UNIT_DIP, 6f, metrics);
-        mIconDimension = (int) TypedValue.applyDimension(
+        int iconDimension = (int) TypedValue.applyDimension(
                 TypedValue.COMPLEX_UNIT_DIP, 20f, metrics);
-        mCircularProgress.setBounds(0, 0, mIconDimension, mIconDimension);
+        mCircularProgress.setBounds(0, 0, iconDimension, iconDimension);
         mHorizontalProgress = (ProgressBar) findViewById(
                 R.id.progress_horizontal);
-        mGenericFavicon = context.getResources().getDrawable(
-                R.drawable.app_web_browser_sm);
         mVoiceSearchIntent = new Intent(RecognizerIntent.ACTION_WEB_SEARCH);
         mVoiceSearchIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
                 RecognizerIntent.LANGUAGE_MODEL_WEB_SEARCH);
@@ -219,7 +205,7 @@
                     } else if (mInLoad) {
                         mBrowserActivity.stopLoading();
                     } else {
-                        mBrowserActivity.bookmarksOrHistoryPicker(false);
+                        mBrowserActivity.promptAddOrInstallBookmark();
                     }
                     button.setPressed(false);
                 } else if (mTitleBg.isPressed()) {
@@ -248,25 +234,6 @@
     }
 
     /**
-     * Set a new Bitmap for the Favicon.
-     */
-    /* package */ void setFavicon(Bitmap icon) {
-        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);
-        mFavicon.setImageDrawable(d);
-    }
-
-    /**
      * Change the TitleBar to or from voice mode.  If there is no package to
      * handle voice search, the TitleBar cannot be set to voice mode.
      */
@@ -302,18 +269,6 @@
     }
 
     /**
-     * Set the Drawable for the lock icon, or null to hide it.
-     */
-    /* package */ void setLock(Drawable d) {
-        if (null == d) {
-            mLockIcon.setVisibility(View.GONE);
-        } else {
-            mLockIcon.setImageDrawable(d);
-            mLockIcon.setVisibility(View.VISIBLE);
-        }
-    }
-
-    /**
      * Update the progress, from 0 to 100.
      */
     /* package */ void setProgress(int newProgress) {
@@ -374,11 +329,4 @@
             }
         }
     }
-
-    /* package */ void setToTabPicker() {
-        mTitle.setText(R.string.tab_picker_title);
-        setFavicon(null);
-        setLock(null);
-        mHorizontalProgress.setVisibility(View.GONE);
-    }
 }
diff --git a/src/com/android/browser/TitleBarBase.java b/src/com/android/browser/TitleBarBase.java
new file mode 100644
index 0000000..7016dc0
--- /dev/null
+++ b/src/com/android/browser/TitleBarBase.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.browser;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.LayerDrawable;
+import android.graphics.drawable.PaintDrawable;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+
+/**
+ * Base class for a title bar used by the browser.
+ */
+public class TitleBarBase extends LinearLayout {
+    // These need to be set by the subclass.
+    protected ImageView mFavicon;
+    protected ImageView mLockIcon;
+
+    protected Drawable mGenericFavicon;
+
+    public TitleBarBase(Context context) {
+        super(context, null);
+        mGenericFavicon = context.getResources().getDrawable(
+                R.drawable.app_web_browser_sm);
+    }
+
+    /* package */ void setProgress(int newProgress) {}
+    /* package */ void setDisplayTitle(String title) {}
+
+    /* package */ void setLock(Drawable d) {
+        assert mLockIcon != null;
+        if (null == d) {
+            mLockIcon.setVisibility(View.GONE);
+        } else {
+            mLockIcon.setImageDrawable(d);
+            mLockIcon.setVisibility(View.VISIBLE);
+        }
+    }
+
+    /* package */ void setFavicon(Bitmap icon) {
+        assert mFavicon != null;
+        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);
+        mFavicon.setImageDrawable(d);
+    }
+
+    /* package */ void setInVoiceMode(boolean inVoiceMode) {}
+
+}
diff --git a/src/com/android/browser/TitleBarXLarge.java b/src/com/android/browser/TitleBarXLarge.java
new file mode 100644
index 0000000..fd6d67b
--- /dev/null
+++ b/src/com/android/browser/TitleBarXLarge.java
@@ -0,0 +1,507 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.browser;
+
+import android.app.SearchManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.LayerDrawable;
+import android.graphics.drawable.PaintDrawable;
+import android.view.ContextMenu;
+import android.view.LayoutInflater;
+import android.view.MenuInflater;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.browser.TabControl.TabChangeListener;
+import com.android.browser.UrlInputView.UrlInputListener;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * tabbed title bar for xlarge screen browser
+ */
+public class TitleBarXLarge extends TitleBarBase
+    implements TabChangeListener, UrlInputListener {
+
+    private static final int PROGRESS_MAX = 100;
+
+    private static final int TAB_WIDTH_SELECTED = 400;
+    private static final int TAB_WIDTH_UNSELECTED = 150;
+
+    private BrowserActivity       mBrowserActivity;
+    private Drawable              mStopDrawable;
+    private Drawable              mReloadDrawable;
+    private Drawable              mSelectedBackground;
+    private Drawable              mUnselectedBackground;
+
+    private View                  mBackButton;
+    private View                  mForwardButton;
+    private View                  mStar;
+    private View                  mMenu;
+    private View                  mAllButton;
+    private TabScrollView         mTabs;
+    private View                  mNewButton;
+    private TabControl            mControl;
+    private UrlInputView          mUrlView;
+
+    private boolean               mIsInLandscape;
+    private Map<Tab, TabViewData> mTabMap;
+
+    private float                 mDensityScale;
+
+    public TitleBarXLarge(BrowserActivity context, TabControl tabcontrol) {
+        super(context);
+        mDensityScale = context.getResources().getDisplayMetrics().density;
+        mTabMap = new HashMap<Tab, TabViewData>();
+        mBrowserActivity = context;
+        mControl = tabcontrol;
+        Resources resources = context.getResources();
+        mSelectedBackground = resources.getDrawable(R.drawable.tab_selected_bg);
+        mUnselectedBackground = resources.getDrawable(R.drawable.tab_unselected_bg);
+        mStopDrawable = resources.getDrawable(R.drawable.progress_stop);
+        mReloadDrawable = resources.getDrawable(R.drawable.ic_reload);
+        rebuildLayout(context, true);
+        // register the tab change listener
+        mControl.setOnTabChangeListener(this);
+    }
+
+    void rebuildLayout() {
+        rebuildLayout(mBrowserActivity, false);
+    }
+
+    private void rebuildLayout(Context context, boolean rebuildData) {
+        removeAllViews();
+        LayoutInflater factory = LayoutInflater.from(context);
+        factory.inflate(R.layout.title_bar_tabbed, this);
+
+        mTabs = (TabScrollView) findViewById(R.id.tabs);
+        mNewButton = findViewById(R.id.newtab);
+        mUrlView = (UrlInputView) findViewById(R.id.editurl);
+        mAllButton = findViewById(R.id.all_btn);
+        // TODO: Change enabled states based on whether you can go
+        // back/forward.  Probably should be done inside onPageStarted.
+        mBackButton = findViewById(R.id.back);
+        mForwardButton = findViewById(R.id.forward);
+        mStar = findViewById(R.id.star);
+        mMenu = findViewById(R.id.menu);
+        View.OnClickListener listener = new View.OnClickListener() {
+            public void onClick(View v) {
+                if (mBackButton == v) {
+                    mBrowserActivity.getTopWindow().goBack();
+                } else if (mForwardButton == v) {
+                    mBrowserActivity.getTopWindow().goForward();
+                } else if (mStar == v) {
+                    mBrowserActivity.promptAddOrInstallBookmark();
+                } else if (mMenu == v) {
+                    mBrowserActivity.openOptionsMenu();
+                } else if (mAllButton == v) {
+                    // TODO: Show the new bookmarks/windows view.
+                    mBrowserActivity.bookmarksOrHistoryPicker(false);
+                } else if (mNewButton == v) {
+                    mBrowserActivity.openTabToHomePage();
+                }
+            }
+        };
+        mBackButton.setOnClickListener(listener);
+        mForwardButton.setOnClickListener(listener);
+        mStar.setOnClickListener(listener);
+        mAllButton.setOnClickListener(listener);
+        mMenu.setOnClickListener(listener);
+        mNewButton.setOnClickListener(listener);
+
+        mIsInLandscape = mBrowserActivity.getResources().getConfiguration().orientation
+                == Configuration.ORIENTATION_LANDSCAPE;
+        mUrlView.setVisibility(mIsInLandscape ? View.GONE : View.VISIBLE);
+        mUrlView.setUrlInputListener(this);
+        buildTabs(rebuildData);
+        // ensure title bar state
+        onCurrentTab(mControl.getCurrentTab());
+    }
+
+    void showUrlEditor(TabViewData tabdata) {
+        mUrlView.setVisibility(View.VISIBLE);
+        if (mIsInLandscape) {
+            mTabs.setVisibility(View.GONE);
+            mUrlView.requestFocus();
+            mUrlView.forceIme();
+        }
+    }
+
+    void hideUrlEditor() {
+        Tab tab = mControl.getCurrentTab();
+        if (mIsInLandscape) {
+            mUrlView.setVisibility(View.GONE);
+            mTabs.setVisibility(View.VISIBLE);
+        } else {
+            // portrait mode
+            mUrlView.setText(tab.getWebView().getUrl());
+        }
+        tab.getWebView().requestFocus();
+    }
+
+
+    // UrlInputListener implementation
+
+    @Override
+    public void onAction(String text) {
+        hideUrlEditor();
+        Intent i = new Intent();
+        i.setAction(Intent.ACTION_SEARCH);
+        i.putExtra(SearchManager.QUERY, text);
+        mBrowserActivity.onNewIntent(i);
+    }
+
+    @Override
+    public void onDismiss() {
+        hideUrlEditor();
+    }
+
+    @Override
+    public void createContextMenu(ContextMenu menu) {
+        MenuInflater inflater = mBrowserActivity.getMenuInflater();
+        inflater.inflate(R.menu.title_context, menu);
+        mBrowserActivity.onCreateContextMenu(menu, this, null);
+    }
+
+    @Override
+    /* package */ void setLock(Drawable d) {
+        // TODO: handle in tab specific callback
+    }
+
+    @Override
+    /* package */ void setFavicon(Bitmap icon) {
+        // this is handled in the tab specific callback
+    }
+
+    /**
+     * Update the progress, from 0 to 100.
+     */
+    @Override
+    /* package */ void setProgress(int newProgress) {
+        // this is handled in tab specific callback
+    }
+
+    @Override
+    /* package */ void setDisplayTitle(String title) {
+        // this is done in tab specific callback
+    }
+
+    private void buildTabs(boolean needsRebuilding) {
+        mTabs.clearTabs();
+        for (int i = 0; i < mControl.getTabCount(); i++) {
+            Tab tab = mControl.getTab(i);
+            TabViewData data = buildTab(needsRebuilding, tab);
+            TabView tv = buildView(data);
+        }
+        mTabs.setSelectedTab(mControl.getCurrentIndex());
+    }
+
+    private TabViewData buildTab(boolean needsRebuilding, Tab tab) {
+        TabViewData data = null;
+        if (needsRebuilding) {
+            data = new TabViewData(tab);
+            mTabMap.put(tab, data);
+        } else {
+            data = mTabMap.get(tab);
+        }
+        return data;
+    }
+
+    private TabView buildView(final TabViewData data) {
+        TabView tv = new TabView(mBrowserActivity, data);
+        tv.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                if (mTabs.getSelectedTab() == v) {
+                    showUrlEditor(data);
+                } else {
+                    int ix = mControl.getTabIndex(data.mTab);
+                    mTabs.setSelectedTab(ix);
+                    mBrowserActivity.switchToTab(ix);
+                }
+            }
+        });
+        mTabs.addTab(tv);
+        return tv;
+    }
+
+    /**
+     * the views used in the tab bar
+     */
+    class TabView extends LinearLayout {
+
+        TabViewData          mTabData;
+        View                 mTabContent;
+        TextView             mTitle;
+        ImageView            mIconView;
+        ImageView            mLock;
+        CircularProgressView mStop;
+        ImageView            mClose;
+        boolean              mSelected;
+        boolean              mInLoad;
+
+        /**
+         * @param context
+         */
+        public TabView(Context context, TabViewData tab) {
+            super(context);
+            mTabData = tab;
+            LayoutInflater inflater = LayoutInflater.from(mContext);
+            mTabContent = inflater.inflate(R.layout.tab_title, this);
+            mTitle = (TextView) mTabContent.findViewById(R.id.title);
+            mIconView = (ImageView) mTabContent.findViewById(R.id.favicon);
+            mLock = (ImageView) mTabContent.findViewById(R.id.lock);
+            mStop = (CircularProgressView) mTabContent.findViewById(R.id.stop);
+            mStop.setMaxProgress(PROGRESS_MAX);
+            mClose = (ImageView) mTabContent.findViewById(R.id.close);
+            mClose.setOnClickListener(new OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    closeTab();
+                }
+            });
+            mStop.setOnClickListener(new OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    if (mInLoad) {
+                        mBrowserActivity.stopLoading();
+                    } else {
+                        mBrowserActivity.getTopWindow().reload();
+                    }
+                }
+            });
+            mSelected = false;
+            mInLoad = false;
+            // update the status
+            updateFromData();
+        }
+
+        private void updateFromData() {
+            mTabData.mTabView = this;
+            if (mTabData.mUrl != null) {
+                setDisplayTitle(mTabData.mUrl);
+            }
+            if (mTabData.mTitle != null) {
+                setDisplayTitle(mTabData.mTitle);
+            }
+            setProgress(mTabData.mProgress);
+            if (mTabData.mIcon != null) {
+                setFavicon(mTabData.mIcon);
+            }
+            if (mTabData.mLock != null) {
+                setLock(mTabData.mLock);
+            }
+        }
+
+        @Override
+        public void setSelected(boolean selected) {
+            mSelected = selected;
+            mStop.setVisibility(mSelected ? View.VISIBLE : View.GONE);
+            mIconView.setVisibility(mSelected ? View.VISIBLE : View.GONE);
+            super.setSelected(selected);
+            setBackgroundDrawable(selected ? mSelectedBackground
+                    : mUnselectedBackground);
+            setLayoutParams(new LayoutParams(selected ?
+                    (int) (TAB_WIDTH_SELECTED * mDensityScale)
+                    : (int) (TAB_WIDTH_UNSELECTED * mDensityScale),
+                    LayoutParams.WRAP_CONTENT));
+        }
+
+        void setDisplayTitle(String title) {
+            mTitle.setText(title);
+        }
+
+        void setFavicon(Drawable d) {
+            mIconView.setImageDrawable(d);
+        }
+
+        void setLock(Drawable d) {
+            if (null == d) {
+                mLock.setVisibility(View.GONE);
+            } else {
+                mLock.setImageDrawable(d);
+                mLock.setVisibility(View.VISIBLE);
+            }
+        }
+
+        void setTitleCompoundDrawables(Drawable left, Drawable top,
+                                              Drawable right, Drawable bottom) {
+            mTitle.setCompoundDrawables(left, top, right, bottom);
+        }
+
+        void setProgress(int newProgress) {
+            mStop.setProgress(newProgress);
+            if (newProgress >= PROGRESS_MAX) {
+                mInLoad = false;
+                mStop.setImageDrawable(mReloadDrawable);
+            } else {
+                if (!mInLoad && getWindowToken() != null) {
+                    // checking the window token lets us be sure that we
+                    // are attached to a window before starting the animation,
+                    // preventing a potential race condition
+                    // (fix for bug http://b/2115736)
+                    mInLoad = true;
+                    mStop.setImageDrawable(mStopDrawable);
+                }
+            }
+        }
+
+        private void closeTab() {
+            if (mTabData.mTab == mControl.getCurrentTab()) {
+                mBrowserActivity.closeCurrentWindow();
+            } else {
+                mBrowserActivity.closeTab(mTabData.mTab);
+            }
+        }
+
+    }
+
+    /**
+     * class to store tab state within the title bar
+     */
+    class TabViewData {
+
+        Tab mTab;
+        TabView mTabView;
+        int mProgress;
+        Drawable mIcon;
+        Drawable mLock;
+        String mTitle;
+        String mUrl;
+
+        TabViewData(Tab tab) {
+            mTab = tab;
+        }
+
+        void setUrlAndTitle(String url, String title) {
+            mUrl = url;
+            mTitle = title;
+            if (mTabView != null) {
+                if (title != null) {
+                    mTabView.setDisplayTitle(title);
+                } else if (url != null) {
+                    mTabView.setDisplayTitle(url);
+                }
+            }
+        }
+
+        void setProgress(int newProgress) {
+            mProgress = newProgress;
+            if (mTabView != null) {
+                mTabView.setProgress(mProgress);
+            }
+        }
+
+        void setFavicon(Bitmap icon) {
+            Drawable[] array = new Drawable[3];
+            array[0] = new PaintDrawable(Color.BLACK);
+            array[1] = new PaintDrawable(Color.WHITE);
+            if (icon == null) {
+                array[2] = mGenericFavicon;
+            } else {
+                array[2] = new BitmapDrawable(icon);
+            }
+            LayerDrawable d = new LayerDrawable(array);
+            d.setLayerInset(1, 1, 1, 1, 1);
+            d.setLayerInset(2, 2, 2, 2, 2);
+            mIcon = d;
+            if (mTabView != null) {
+                mTabView.setFavicon(mIcon);
+            }
+        }
+
+    }
+
+    // TabChangeListener implementation
+
+    @Override
+    public void onCurrentTab(Tab tab) {
+        mTabs.setSelectedTab(mControl.getCurrentIndex());
+        TabViewData tvd = mTabMap.get(tab);
+        if (tvd != null) {
+            if (tvd.mUrl != null) {
+                mUrlView.setText(tvd.mUrl);
+            }
+            setProgress(tvd.mProgress);
+        }
+    }
+
+    @Override
+    public void onFavicon(Tab tab, Bitmap favicon) {
+        TabViewData tvd = mTabMap.get(tab);
+        if (tvd != null) {
+            tvd.setFavicon(favicon);
+        }
+    }
+
+    @Override
+    public void onNewTab(Tab tab) {
+        TabViewData tvd = buildTab(true, tab);
+        buildView(tvd);
+    }
+
+    @Override
+    public void onProgress(Tab tab, int progress) {
+        TabViewData tvd = mTabMap.get(tab);
+        if (tvd != null) {
+            tvd.setProgress(progress);
+        }
+        if (tab == mControl.getCurrentTab()) {
+            setProgress(progress);
+        }
+    }
+
+    @Override
+    public void onRemoveTab(Tab tab) {
+        TabViewData tvd = mTabMap.get(tab);
+        TabView tv = tvd.mTabView;
+        if (tv != null) {
+            mTabs.removeTab(tv);
+        }
+        mTabMap.remove(tab);
+    }
+
+    @Override
+    public void onUrlAndTitle(Tab tab, String url, String title) {
+        TabViewData tvd = mTabMap.get(tab);
+        if (tvd != null) {
+            tvd.setUrlAndTitle(url, title);
+        }
+        if ((url != null) && (tab == mControl.getCurrentTab())) {
+            mUrlView.setText(url);
+        }
+    }
+
+    @Override
+    public void onPageFinished(Tab tab) {
+    }
+
+    @Override
+    public void onPageStarted(Tab tab) {
+    }
+
+}
diff --git a/src/com/android/browser/UrlInputView.java b/src/com/android/browser/UrlInputView.java
new file mode 100644
index 0000000..3841257
--- /dev/null
+++ b/src/com/android/browser/UrlInputView.java
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.browser;
+
+import android.app.SearchManager;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.Cursor;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.AdapterView;
+import android.widget.AutoCompleteTextView;
+import android.widget.CursorAdapter;
+import android.widget.Filterable;
+import android.widget.ImageView;
+import android.widget.TextView;
+import android.widget.AdapterView.OnItemClickListener;
+
+/**
+ * url/search input view
+ * handling suggestions
+ */
+public class UrlInputView extends AutoCompleteTextView {
+
+    private UrlInputListener   mListener;
+    private InputMethodManager mInputManager;
+    private SuggestionsAdapter mAdapter;
+    private Drawable           mFocusDrawable;
+    private Drawable           mNoFocusDrawable;
+
+
+    public UrlInputView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        init(context);
+    }
+
+    public UrlInputView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        init(context);
+    }
+
+    public UrlInputView(Context context) {
+        super(context);
+        init(context);
+    }
+
+    private void init(Context ctx) {
+        mFocusDrawable = ctx.getResources().getDrawable(R.drawable.textfield_stroke);
+        mNoFocusDrawable = ctx.getResources().getDrawable(R.drawable.textfield_nostroke);
+        mInputManager = (InputMethodManager) ctx.getSystemService(Context.INPUT_METHOD_SERVICE);
+        setOnEditorActionListener(new OnEditorActionListener() {
+            @Override
+            public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+                finishInput(getText().toString());
+                return true;
+            }
+        });
+        setOnFocusChangeListener(new OnFocusChangeListener() {
+            @Override
+            public void onFocusChange(View v, boolean hasFocus) {
+                setBackgroundDrawable(hasFocus ? mFocusDrawable : mNoFocusDrawable);
+            }
+        });
+        final ContentResolver cr = mContext.getContentResolver();
+        mAdapter = new SuggestionsAdapter(mContext,
+                BrowserProvider.getBookmarksSuggestions(cr, null));
+        setAdapter(mAdapter);
+        setOnItemClickListener(new OnItemClickListener() {
+            @Override
+            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+                String url = mAdapter.getViewString(view);
+                finishInput(url);
+            }
+        });
+        setSelectAllOnFocus(true);
+    }
+
+    public void setUrlInputListener(UrlInputListener listener) {
+        mListener = listener;
+    }
+
+    public void forceIme() {
+        mInputManager.showSoftInput(this, 0);
+    }
+
+    private void finishInput(String url) {
+        this.dismissDropDown();
+        mInputManager.hideSoftInputFromWindow(getWindowToken(), 0);
+        if (url == null) {
+            mListener.onDismiss();
+        } else {
+            mListener.onAction(url);
+        }
+
+    }
+
+    @Override
+    public boolean onKeyPreIme(int keyCode, KeyEvent evt) {
+        if (keyCode == KeyEvent.KEYCODE_BACK) {
+            // catch back key in order to do slightly more cleanup than usual
+            finishInput(null);
+            return true;
+        }
+        return super.onKeyPreIme(keyCode, evt);
+    }
+
+    interface UrlInputListener {
+
+        public void onDismiss();
+
+        public void onAction(String text);
+
+    }
+
+    /**
+     * adapter used by suggestion dropdown
+     */
+    class SuggestionsAdapter extends CursorAdapter implements Filterable {
+
+        private Cursor          mLastCursor;
+        private ContentResolver mContent;
+        private int             mIndexText1;
+        private int             mIndexText2;
+        private int             mIndexIcon;
+
+        public SuggestionsAdapter(Context context, Cursor c) {
+            super(context, c);
+            mContent = context.getContentResolver();
+            mIndexText1 = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_1);
+            mIndexText2 = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_2_URL);
+            mIndexIcon = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_ICON_1);
+        }
+
+        public String getViewString(View view) {
+            TextView tv2 = (TextView) view.findViewById(android.R.id.text2);
+            if (tv2.getText().length() > 0) {
+                return tv2.getText().toString();
+            } else {
+                TextView tv1 = (TextView) view.findViewById(android.R.id.text1);
+                return tv1.getText().toString();
+            }
+        }
+
+        @Override
+        public View newView(Context context, Cursor cursor, ViewGroup parent) {
+            final LayoutInflater inflater = LayoutInflater.from(context);
+            final View view = inflater.inflate(
+                    R.layout.simple_dropdown_item_2line, parent, false);
+            bindView(view, context, cursor);
+            return view;
+        }
+
+        @Override
+        public void bindView(View view, Context context, Cursor cursor) {
+            TextView tv1 = (TextView) view.findViewById(android.R.id.text1);
+            TextView tv2 = (TextView) view.findViewById(android.R.id.text2);
+            ImageView ic1 = (ImageView) view.findViewById(R.id.icon1);
+            tv1.setText(cursor.getString(mIndexText1));
+            String url = cursor.getString(mIndexText2);
+            tv2.setText((url != null) ? url : "");
+            // assume an id
+            try {
+                int id = Integer.parseInt(cursor.getString(mIndexIcon));
+                Drawable d = context.getResources().getDrawable(id);
+                ic1.setImageDrawable(d);
+            } catch (NumberFormatException nfx) {
+            }
+        }
+
+        @Override
+        public String convertToString(Cursor cursor) {
+            return cursor.getString(mIndexText1);
+        }
+
+        @Override
+        public Cursor runQueryOnBackgroundThread(CharSequence constraint) {
+            if (getFilterQueryProvider() != null) {
+                return getFilterQueryProvider().runQuery(constraint);
+            }
+            mLastCursor = BrowserProvider.getBookmarksSuggestions(mContent,
+                    (constraint != null) ? constraint.toString() : null);
+            return mLastCursor;
+        }
+
+    }
+
+}
diff --git a/src/com/android/browser/WebDialog.java b/src/com/android/browser/WebDialog.java
new file mode 100644
index 0000000..9995e8f
--- /dev/null
+++ b/src/com/android/browser/WebDialog.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.browser;
+
+import android.content.Context;
+import android.view.View;
+import android.view.animation.AnimationUtils;
+import android.view.inputmethod.InputMethodManager;
+import android.webkit.WebView;
+import android.widget.LinearLayout;
+
+/* package */ class WebDialog extends LinearLayout {
+    protected WebView         mWebView;
+    protected BrowserActivity mBrowserActivity;
+    private boolean           mIsVisible;
+
+    /* package */ WebDialog(BrowserActivity context) {
+        super(context);
+        mBrowserActivity = context;
+    }
+
+    /* dialogs that have cancel buttons can optionally share code by including a
+     * view with an id of 'done'.
+     */
+    protected void addCancel() {
+        View button = findViewById(R.id.done);
+        if (button != null) button.setOnClickListener(mCancelListener);
+    }
+
+    private View.OnClickListener mCancelListener = new View.OnClickListener() {
+        public void onClick(View v) {
+            mBrowserActivity.closeDialogs();
+        }
+    };
+
+    protected void dismiss() {
+        startAnimation(AnimationUtils.loadAnimation(mBrowserActivity,
+                R.anim.dialog_exit));
+        mIsVisible = false;
+    }
+
+    /*
+     * Remove the soft keyboard from the screen.
+     */
+    protected void hideSoftInput() {
+        InputMethodManager imm = (InputMethodManager)
+                mBrowserActivity.getSystemService(Context.INPUT_METHOD_SERVICE);
+        imm.hideSoftInputFromWindow(mWebView.getWindowToken(), 0);
+    }
+
+    protected boolean isVisible() {
+        return mIsVisible;
+    }
+
+    /* package */ void setWebView(WebView webview) {
+        mWebView = webview;
+    }
+
+    protected void show() {
+        startAnimation(AnimationUtils.loadAnimation(mBrowserActivity,
+            R.anim.dialog_enter));
+        mIsVisible = true;
+    }
+
+}
diff --git a/tests/src/com/android/browser/PopularUrlsTest.java b/tests/src/com/android/browser/PopularUrlsTest.java
index b1760e9..547cb9f 100644
--- a/tests/src/com/android/browser/PopularUrlsTest.java
+++ b/tests/src/com/android/browser/PopularUrlsTest.java
@@ -307,7 +307,6 @@
 
         public void write() throws IOException {
             FileWriter output = null;
-            OutputStreamWriter writer = null;
             if (mFile.exists()) {
                 mFile.delete();
             }
@@ -317,14 +316,8 @@
                 output.write(page + newLine);
                 output.write(url + newLine);
             } finally {
-                try {
-                    if (writer != null) {
-                        writer.close();
-                    }
-                } finally {
-                    if (output != null) {
-                        output.close();
-                    }
+                if (output != null) {
+                    output.close();
                 }
             }
         }
@@ -394,6 +387,7 @@
 
         if (mStatus.getIsRecovery()) {
             Log.e(TAG, "Recovering after crash: " + iterator.next());
+            mStatus.incrementPage();
         }
 
         while (mStatus.getIteration() < loopCount) {
diff --git a/tests/src/com/android/browser/TestWebChromeClient.java b/tests/src/com/android/browser/TestWebChromeClient.java
index d78eaed..53f8db3 100644
--- a/tests/src/com/android/browser/TestWebChromeClient.java
+++ b/tests/src/com/android/browser/TestWebChromeClient.java
@@ -195,7 +195,7 @@
 
     /** {@inheritDoc} */
     @Override
-    public void openFileChooser(ValueCallback<Uri> uploadFile) {
-        mWrappedClient.openFileChooser(uploadFile);
+    public void openFileChooser(ValueCallback<Uri> uploadFile, String acceptType) {
+        mWrappedClient.openFileChooser(uploadFile, acceptType);
     }
 }