resolved conflicts for merge of e7c06a6e to master

Change-Id: If4f2cb14d9a05dc58322732a922e3300ff1a4558
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/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/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/drawable/button_selected.png b/res/drawable/button_selected.png
new file mode 100644
index 0000000..4fd1aa3
--- /dev/null
+++ b/res/drawable/button_selected.png
Binary files differ
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/ic_arrow_left.png b/res/drawable/ic_arrow_left.png
new file mode 100644
index 0000000..58fd2ca
--- /dev/null
+++ b/res/drawable/ic_arrow_left.png
Binary files differ
diff --git a/res/drawable/ic_arrow_right.png b/res/drawable/ic_arrow_right.png
new file mode 100644
index 0000000..aaf3fde
--- /dev/null
+++ b/res/drawable/ic_arrow_right.png
Binary files differ
diff --git a/res/drawable/ic_menu.png b/res/drawable/ic_menu.png
new file mode 100644
index 0000000..520b2c3
--- /dev/null
+++ b/res/drawable/ic_menu.png
Binary files differ
diff --git a/res/drawable/ic_menu_downloads.png b/res/drawable/ic_menu_downloads.png
new file mode 100644
index 0000000..fff5022
--- /dev/null
+++ b/res/drawable/ic_menu_downloads.png
Binary files differ
diff --git a/res/drawable/ic_menu_find.png b/res/drawable/ic_menu_find.png
new file mode 100644
index 0000000..4d96348
--- /dev/null
+++ b/res/drawable/ic_menu_find.png
Binary files differ
diff --git a/res/drawable/ic_menu_pageinfo.png b/res/drawable/ic_menu_pageinfo.png
new file mode 100644
index 0000000..c04f0e3
--- /dev/null
+++ b/res/drawable/ic_menu_pageinfo.png
Binary files differ
diff --git a/res/drawable/ic_menu_settings.png b/res/drawable/ic_menu_settings.png
new file mode 100644
index 0000000..7a642d6
--- /dev/null
+++ b/res/drawable/ic_menu_settings.png
Binary files differ
diff --git a/res/drawable/ic_menu_share.png b/res/drawable/ic_menu_share.png
new file mode 100644
index 0000000..ea2b672
--- /dev/null
+++ b/res/drawable/ic_menu_share.png
Binary files differ
diff --git a/res/drawable/ic_pages.png b/res/drawable/ic_pages.png
new file mode 100644
index 0000000..fba4651
--- /dev/null
+++ b/res/drawable/ic_pages.png
Binary files differ
diff --git a/res/drawable/ic_reload.png b/res/drawable/ic_reload.png
new file mode 100644
index 0000000..ec0c238
--- /dev/null
+++ b/res/drawable/ic_reload.png
Binary files differ
diff --git a/res/drawable/ic_star.png b/res/drawable/ic_star.png
new file mode 100644
index 0000000..20a40de
--- /dev/null
+++ b/res/drawable/ic_star.png
Binary files differ
diff --git a/res/drawable/ic_stop.png b/res/drawable/ic_stop.png
new file mode 100644
index 0000000..7ee56e9
--- /dev/null
+++ b/res/drawable/ic_stop.png
Binary files differ
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/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/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/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_xlarge.xml b/res/layout/title_bar_xlarge.xml
new file mode 100644
index 0000000..3070b8b
--- /dev/null
+++ b/res/layout/title_bar_xlarge.xml
@@ -0,0 +1,118 @@
+<?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="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"
+        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"
+            />
+
+        <LinearLayout android:id="@+id/title_bg"
+            android:background="@drawable/textfield_stroke"
+            android:layout_width="0dip"
+            android:layout_weight="1.0"
+            android:layout_height="wrap_content"
+            android:layout_marginRight="6dip"
+            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"
+                />
+        </LinearLayout>
+        <ImageButton android:id="@+id/stop"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            android:layout_marginRight="6dip"
+            android:src="@drawable/ic_stop"
+            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>
+
+    <!-- Should show translucent over the webpage -->
+    <ProgressBar android:id="@+id/progress_horizontal"
+        style="?android:attr/progressBarStyleHorizontal"
+        android:layout_width="match_parent"
+        android:layout_height="14dip"
+        android:max="100"
+        />
+
+</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/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..104a495 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);
@@ -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..dde0765 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;
@@ -133,6 +123,7 @@
 import java.util.Set;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
+import java.util.Vector;
 
 public class BrowserActivity extends Activity
     implements View.OnCreateContextMenuListener, DownloadListener {
@@ -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,10 +210,25 @@
         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;
+
+        if (mXLargeScreenSize) {
+            mTitleBar = new TitleBarXLarge(this);
+            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);
+        }
 
         // Create the tab control and our initial tab
         mTabControl = new TabControl(this);
@@ -305,9 +317,7 @@
                     }
                     if (permissionOk) {
                         PluginManager.getInstance(BrowserActivity.this)
-                                .refreshPlugins(
-                                        Intent.ACTION_PACKAGE_ADDED
-                                                .equals(action));
+                                .refreshPlugins(true);
                     }
                 }
             }
@@ -612,6 +622,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 +684,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 +709,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
@@ -827,6 +843,7 @@
     }
 
     private void showFakeTitleBar() {
+        if (mXLargeScreenSize) return;
         if (mFakeTitleBar.getParent() == null && mActiveTabsPage == null
                 && !mActivityInPause) {
             WebView mainView = mTabControl.getCurrentWebView();
@@ -834,6 +851,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 +892,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();
@@ -1113,12 +1137,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 +1171,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 +1288,7 @@
      */
     /* package */ void removeActiveTabPage(boolean needToAttach) {
         mContentView.removeView(mActiveTabsPage);
+        mTitleBar.setVisibility(View.VISIBLE);
         mActiveTabsPage = null;
         mMenuState = R.id.MAIN_MENU;
         if (needToAttach) {
@@ -1271,6 +1297,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 +1347,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 +1355,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 +1400,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 +1438,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 +1495,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 +1603,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 +1635,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 +1662,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 +1719,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 +1786,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 +1815,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 +1945,7 @@
             return true;
         }
 
+        @Override
         public void run() {
             Drawable oldWallpaper = BrowserActivity.this.getWallpaper();
             try {
@@ -1919,7 +2050,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 +2095,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 +2113,7 @@
         }
         mTabControl.setCurrentTab(mTabControl.getTab(currentIndex));
         resetTitleIconAndProgress();
+        updateLockIconToLatest();
     }
 
     /* package */ void goBackOnePageOrQuit() {
@@ -2169,9 +2305,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 +2331,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 +2339,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 +2377,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 +2425,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 +2502,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 +2516,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 +2526,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 +2567,7 @@
         onProgressChanged(view, INITIAL_PROGRESS);
         mDidStopLoad = false;
         if (!mIsNetworkUp) createAndShowNetworkDialog();
-
+        closeDialogs();
         if (mSettings.isTracing()) {
             String host;
             try {
@@ -2560,6 +2665,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 +2686,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 +2732,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 +2749,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 +2774,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 +2882,120 @@
      * 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 mediaSourceKey = "capture";
+        final String mediaSourceValueCamera = "camera";
+        final String mediaSourceValueFileSystem = "filesystem";
+        final String mediaSourceValueCamcorder = "camcorder";
+
+        // media source can be 'gallery' or 'camera' or 'camcorder'
+        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);
+
+        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 {
+            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 +3182,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 +3199,9 @@
             d = mMixLockIcon;
         }
         mTitleBar.setLock(d);
-        mFakeTitleBar.setLock(d);
+        if (!mXLargeScreenSize) {
+            mFakeTitleBar.setLock(d);
+        }
     }
 
     /**
@@ -3468,8 +3717,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 +3756,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(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 +3811,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 +3840,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 +4061,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 +4078,7 @@
             }
 
             // Executes on the UI thread
+            @Override
             protected void onPostExecute(Set<String> installedPackages) {
                 addPackageNames(installedPackages);
             }
@@ -3770,6 +4107,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 +4221,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..320c438 100644
--- a/src/com/android/browser/BrowserBookmarksPage.java
+++ b/src/com/android/browser/BrowserBookmarksPage.java
@@ -74,10 +74,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 +104,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) {
@@ -438,8 +432,7 @@
                     loadUrl(position);
                 }
             } else {
-                final Intent intent = createShortcutIntent(position);
-                setResultToParent(RESULT_OK, intent);
+                setResultToParent(RESULT_OK, createShortcutIntent(position));
                 finish();
             }
         }
@@ -449,99 +442,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() {
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..1eec52b 100644
--- a/src/com/android/browser/BrowserProvider.java
+++ b/src/com/android/browser/BrowserProvider.java
@@ -465,7 +465,7 @@
         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;
@@ -846,8 +846,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")
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/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..98e14fb 100644
--- a/src/com/android/browser/DownloadTouchIcon.java
+++ b/src/com/android/browser/DownloadTouchIcon.java
@@ -25,10 +25,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 +46,17 @@
     private Cursor mCursor;
     private final String mOriginalUrl;
     private final String mUrl;
-    private final String mUserAgent;
+    private final String mUserAgent; // Sites may serve a different icon to different UAs
+    private Message mMessage;
+
     private final BrowserActivity 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,6 +67,13 @@
         mUserAgent = view.getSettings().getUserAgentString();
     }
 
+    /**
+     * 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(ContentResolver cr, String url) {
         mTab = null;
         mActivity = null;
@@ -68,15 +83,33 @@
         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(Message msg, String userAgent) {
+        mMessage = msg;
+        mActivity = null;
+        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 +122,6 @@
 
             try {
                 HttpResponse response = client.execute(request);
-
                 if (response.getStatusLine().getStatusCode() == 200) {
                     HttpEntity entity = response.getEntity();
                     if (entity != null) {
@@ -97,7 +129,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 +146,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..a313651 100644
--- a/src/com/android/browser/Tab.java
+++ b/src/com/android/browser/Tab.java
@@ -87,7 +87,7 @@
     // The Geolocation permissions prompt
     private GeolocationPermissionsPrompt mGeolocationPermissionsPrompt;
     // Main WebView wrapper
-    private View mContainer;
+    private LinearLayout mContainer;
     // Main WebView
     private WebView mMainView;
     // Subwindow container
@@ -1041,6 +1041,16 @@
         }
 
         @Override
+        public void onSelectionDone() {
+            if (mInForeground) mActivity.closeDialogs();
+        }
+
+        @Override
+        public void onSelectionStart() {
+            if (mInForeground) mActivity.showSelectDialog();
+        }
+
+        @Override
         public void onShowCustomView(View view,
                 WebChromeClient.CustomViewCallback callback) {
             if (mInForeground) mActivity.onShowCustomView(view, callback);
@@ -1185,9 +1195,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);
             }
@@ -1220,9 +1230,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 +1331,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 +1442,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 +1451,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 +1490,7 @@
      */
     void dismissSubWindow() {
         if (mSubView != null) {
+            mActivity.closeDialogs();
             BrowserSettings.getInstance().deleteObserver(
                     mSubView.getSettings());
             mSubView.destroy();
@@ -1493,6 +1515,7 @@
     void removeSubWindow(ViewGroup content) {
         if (mSubView != null) {
             content.removeView(mSubViewContainer);
+            mActivity.closeDialogs();
         }
     }
 
@@ -1551,6 +1574,7 @@
                 (FrameLayout) mContainer.findViewById(R.id.webview_wrapper);
         wrapper.removeView(mMainView);
         content.removeView(mContainer);
+        mActivity.closeDialogs();
         removeSubWindow(content);
     }
 
@@ -1824,6 +1848,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 +1859,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();
@@ -1946,4 +1975,36 @@
         }
         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);
+    }
 }
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..3d234e8
--- /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;
+
+    private 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..0d799a8
--- /dev/null
+++ b/src/com/android/browser/TitleBarXLarge.java
@@ -0,0 +1,170 @@
+/*
+ * 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.res.Resources;
+import android.graphics.drawable.Animatable;
+import android.graphics.drawable.Drawable;
+import android.util.DisplayMetrics;
+import android.util.TypedValue;
+import android.view.ContextMenu;
+import android.view.LayoutInflater;
+import android.view.MenuInflater;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+
+import com.android.common.speech.LoggingEvents;
+
+/**
+ * This class represents a title bar for a particular "tab" or "window" in the
+ * browser.
+ */
+public class TitleBarXLarge extends TitleBarBase {
+    private Drawable        mCircularProgress;
+    private ProgressBar     mHorizontalProgress;
+    private Drawable        mStopDrawable;
+    private Drawable        mReloadDrawable;
+    private boolean         mInLoad;
+    private BrowserActivity mBrowserActivity;
+
+    private final View            mBackButton;
+    private final View            mForwardButton;
+    private final View            mStar;
+    private final View            mMenu;
+    private final ImageView       mStopButton;
+    private final TextView        mTitle;
+    private final View            mAllButton;
+
+    public TitleBarXLarge(BrowserActivity context) {
+        super(context);
+        Resources resources = context.getResources();
+        LayoutInflater factory = LayoutInflater.from(context);
+        factory.inflate(R.layout.title_bar_xlarge, this);
+        mBrowserActivity = context;
+
+        mTitle = (TextView) findViewById(R.id.title);
+        mTitle.setCompoundDrawablePadding(5);
+        mTitle.setLongClickable(true);
+
+        mLockIcon = (ImageView) findViewById(R.id.lock);
+        mFavicon = (ImageView) findViewById(R.id.favicon);
+        mStopButton = (ImageView) findViewById(R.id.stop);
+        mStopDrawable = mStopButton.getDrawable();
+        mReloadDrawable = resources.getDrawable(R.drawable.ic_reload);
+
+        mAllButton = (ImageView) findViewById(R.id.all_btn);
+        mCircularProgress = (Drawable) resources.getDrawable(
+                com.android.internal.R.drawable.search_spinner);
+        DisplayMetrics metrics = resources.getDisplayMetrics();
+        int iconDimension = (int) TypedValue.applyDimension(
+                TypedValue.COMPLEX_UNIT_DIP, 20f, metrics);
+        mCircularProgress.setBounds(0, 0, iconDimension, iconDimension);
+        mHorizontalProgress = (ProgressBar) findViewById(
+                R.id.progress_horizontal);
+        mHorizontalProgress.setProgressDrawable(
+                resources.getDrawable(R.drawable.progress));
+
+        // FIXME: 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 (mStopButton == v) {
+                        if (mInLoad) {
+                            mBrowserActivity.stopLoading();
+                        } else {
+                            mBrowserActivity.getTopWindow().reload();
+                        }
+                    } else if (mTitle == v) {
+                        mBrowserActivity.editUrl();
+                    } else if (mAllButton == v) {
+                        // FIXME: Show the new bookmarks/windows view.
+                        mBrowserActivity.bookmarksOrHistoryPicker(false);
+                    }
+                }
+        };
+        mBackButton.setOnClickListener(listener);
+        mForwardButton.setOnClickListener(listener);
+        mStar.setOnClickListener(listener);
+        mStopButton.setOnClickListener(listener);
+        mTitle.setOnClickListener(listener);
+        mAllButton.setOnClickListener(listener);
+        mMenu.setOnClickListener(listener);
+    }
+
+    @Override
+    public void createContextMenu(ContextMenu menu) {
+        MenuInflater inflater = mBrowserActivity.getMenuInflater();
+        inflater.inflate(R.menu.title_context, menu);
+        mBrowserActivity.onCreateContextMenu(menu, this, null);
+    }
+
+    /**
+     * Update the progress, from 0 to 100.
+     */
+    /* package */ void setProgress(int newProgress) {
+        if (newProgress >= mHorizontalProgress.getMax()) {
+            mTitle.setCompoundDrawables(null, null, null, null);
+            ((Animatable) mCircularProgress).stop();
+            mHorizontalProgress.setVisibility(View.GONE);
+            mInLoad = false;
+            mStopButton.setImageDrawable(mReloadDrawable);
+        } else {
+            mHorizontalProgress.setProgress(newProgress);
+            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)
+                mTitle.setCompoundDrawables(null, null, mCircularProgress,
+                        null);
+                ((Animatable) mCircularProgress).start();
+                mHorizontalProgress.setVisibility(View.VISIBLE);
+                mInLoad = true;
+                mStopButton.setImageDrawable(mStopDrawable);
+            }
+        }
+    }
+
+    /**
+     * Update the text displayed in the title bar.
+     * @param title String to display.  If null, the loading string will be
+     *      shown.
+     */
+    /* package */ void setDisplayTitle(String title) {
+        if (title == null) {
+            mTitle.setText(R.string.title_bar_loading);
+        } else {
+            mTitle.setText(title);
+        }
+    }
+
+}
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/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);
     }
 }