am 83d785eb: (-s ours) am 7cbd511d: am 866f576b: (-s ours) Import revised translations.  DO NOT MERGE

* commit '83d785eb53d3648f82c6f299639740d0b6d16be5':
  Import revised translations.  DO NOT MERGE
diff --git a/Android.mk b/Android.mk
index ff1b7e2..1c9dcc4 100644
--- a/Android.mk
+++ b/Android.mk
@@ -5,7 +5,11 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_STATIC_JAVA_LIBRARIES := com.android.phone.common com.android.vcard android-common
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    com.android.phone.common \
+    com.android.vcard \
+    android-common \
+    guava
 
 LOCAL_PACKAGE_NAME := Contacts
 LOCAL_CERTIFICATE := shared
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 52562e0..458553e 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -185,16 +185,6 @@
                 <category android:name="android.intent.category.LAUNCHER" />
                 <category android:name="android.intent.category.BROWSABLE" />
             </intent-filter>
-
-            <intent-filter>
-                <action android:name="android.intent.action.VIEW" />
-                <category android:name="android.intent.category.DEFAULT" />
-                <data android:mimeType="vnd.android.cursor.dir/person" />
-                <data android:mimeType="vnd.android.cursor.dir/contact" />
-                <data android:mimeType="vnd.android.cursor.item/person" />
-                <data android:mimeType="vnd.android.cursor.item/contact" />
-                <data android:mimeType="vnd.android.cursor.item/raw_contact" />
-            </intent-filter>
         </activity>
 
         <!-- The actual list of contacts -->
@@ -291,6 +281,7 @@
                 <data android:mimeType="vnd.android.cursor.dir/phone" />
                 <data android:mimeType="vnd.android.cursor.dir/postal-address_v2" />
                 <data android:mimeType="vnd.android.cursor.dir/postal-address" />
+                <data android:mimeType="vnd.android.cursor.dir/email_v2" />
             </intent-filter>
 
             <intent-filter>
@@ -335,7 +326,7 @@
 
         <activity
             android:name=".activities.ShowOrCreateActivity"
-            android:theme="@style/FullyTranslucent">
+            android:theme="@android:style/Theme.Translucent.NoTitleBar">
 
             <intent-filter>
                 <action android:name="com.android.contacts.action.SHOW_OR_CREATE_CONTACT" />
@@ -348,13 +339,12 @@
         <!-- Used to show QuickContact window over a translucent activity, which is a
              temporary hack until we add better framework support. -->
         <activity
-            android:name=".quickcontact.QuickContactActivity"
-            android:theme="@style/FullyTranslucent.QuickContact"
+            android:name=".quickcontact.QuickContactWindow"
+            android:theme="@style/Theme.QuickContact"
             android:launchMode="singleTop"
             android:excludeFromRecents="true"
             android:taskAffinity="android.task.quickcontact"
-            android:windowSoftInputMode="stateUnchanged"
-            >
+            android:windowSoftInputMode="stateUnchanged">
 
             <intent-filter>
                 <action android:name="com.android.contacts.action.QUICK_CONTACT" />
@@ -442,6 +432,11 @@
             <intent-filter android:label="@string/viewContactDesription">
                 <action android:name="android.intent.action.VIEW" />
                 <category android:name="android.intent.category.DEFAULT" />
+                <data android:mimeType="vnd.android.cursor.dir/person" />
+                <data android:mimeType="vnd.android.cursor.dir/contact" />
+                <data android:mimeType="vnd.android.cursor.item/person" />
+                <data android:mimeType="vnd.android.cursor.item/contact" />
+                <data android:mimeType="vnd.android.cursor.item/raw_contact" />
             </intent-filter>
         </activity>
 
@@ -550,7 +545,7 @@
 
         <!-- vCard related -->
         <activity android:name=".vcard.ImportVCardActivity"
-            android:configChanges="orientation"
+            android:configChanges="orientation|screenSize|keyboardHidden"
             android:theme="@style/BackgroundOnly">
             <intent-filter>
                 <action android:name="android.intent.action.VIEW" />
diff --git a/res/drawable-xlarge-hdpi/panel_message.9.png b/res/drawable-hdpi/panel_message.9.png
similarity index 100%
rename from res/drawable-xlarge-hdpi/panel_message.9.png
rename to res/drawable-hdpi/panel_message.9.png
Binary files differ
diff --git a/res/drawable-xlarge-mdpi/panel_message.9.png b/res/drawable-mdpi/panel_message.9.png
similarity index 100%
rename from res/drawable-xlarge-mdpi/panel_message.9.png
rename to res/drawable-mdpi/panel_message.9.png
Binary files differ
diff --git a/res/drawable/quickactions_arrow_left_holo_light.xml b/res/drawable/quickactions_arrow_left_holo_light.xml
new file mode 100644
index 0000000..c1e18bd
--- /dev/null
+++ b/res/drawable/quickactions_arrow_left_holo_light.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_first="true" android:drawable="@drawable/quickactions_arrowdown_left_holo_light" />
+    <item android:state_last="true" android:drawable="@drawable/quickactions_arrowup_left_holo_light" />
+    <!-- TODO: provide callout-less state -->
+    <item android:drawable="@drawable/quickactions_arrowup_left_holo_light" />
+</selector>
diff --git a/res/drawable/quickactions_arrow_middle_holo_light.xml b/res/drawable/quickactions_arrow_middle_holo_light.xml
new file mode 100644
index 0000000..f88b513
--- /dev/null
+++ b/res/drawable/quickactions_arrow_middle_holo_light.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_first="true" android:drawable="@drawable/quickactions_arrowdown_middle_holo_light" />
+    <item android:state_last="true" android:drawable="@drawable/quickactions_arrowup_middle_holo_light" />
+    <!-- TODO: provide callout-less state -->
+    <item android:drawable="@drawable/quickactions_arrowup_middle_holo_light" />
+</selector>
diff --git a/res/drawable/quickactions_arrow_right_holo_light.xml b/res/drawable/quickactions_arrow_right_holo_light.xml
new file mode 100644
index 0000000..3e309fe
--- /dev/null
+++ b/res/drawable/quickactions_arrow_right_holo_light.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_first="true" android:drawable="@drawable/quickactions_arrowdown_right_holo_light" />
+    <item android:state_last="true" android:drawable="@drawable/quickactions_arrowup_right_holo_light" />
+    <!-- TODO: provide callout-less state -->
+    <item android:drawable="@drawable/quickactions_arrowup_right_holo_light" />
+</selector>
diff --git a/res/layout-long/twelve_key_dialer.xml b/res/layout-long/twelve_key_dialer.xml
index bd90df4..2580625 100644
--- a/res/layout-long/twelve_key_dialer.xml
+++ b/res/layout-long/twelve_key_dialer.xml
@@ -14,11 +14,14 @@
      limitations under the License.
 -->
 
+<!-- TODO (stopship) We don't want to specify a background color here. For now we just
+keep it because otherwise the dialer needs some imagination to use (white on white) -->
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/top"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:orientation="vertical"
+    android:background="@android:color/black"
 >
 
     <!-- Text field above the keypad where the digits are displayed.
diff --git a/res/layout-xlarge/aggregation_suggestions_item.xml b/res/layout-xlarge/aggregation_suggestions_item.xml
index f12c608..5ea8347 100644
--- a/res/layout-xlarge/aggregation_suggestions_item.xml
+++ b/res/layout-xlarge/aggregation_suggestions_item.xml
@@ -24,6 +24,8 @@
     android:orientation="horizontal"
     android:paddingLeft="5dip"
     android:paddingRight="15dip"
+    android:background="?android:attr/selectableItemBackground"
+    android:focusable="true"
 >
     <ImageView
         android:id="@+id/aggregation_suggestion_photo"
diff --git a/res/layout-xlarge/list_section.xml b/res/layout-xlarge/list_section.xml
deleted file mode 100644
index c684a0f..0000000
--- a/res/layout-xlarge/list_section.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2009 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<!-- Layout used for list section separators. -->
-<RelativeLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="37dip"
-    android:background="@drawable/section_header_holo"
-    >
-    <TextView
-        android:id="@+id/header_text"
-        android:layout_width="56dip"
-        android:layout_height="wrap_content"
-        android:layout_centerVertical="true"
-        android:layout_alignParentLeft="true"
-        android:textStyle="bold"
-        android:textColor="@color/section_header_text_color"
-        android:textSize="14sp"
-        android:gravity="center"
-    />
-</RelativeLayout>
diff --git a/res/layout/aggregation_suggestions_item.xml b/res/layout/aggregation_suggestions_item.xml
index f2477cb..9ed1bf3 100644
--- a/res/layout/aggregation_suggestions_item.xml
+++ b/res/layout/aggregation_suggestions_item.xml
@@ -24,6 +24,8 @@
     android:orientation="horizontal"
     android:paddingLeft="5dip"
     android:paddingRight="15dip"
+    android:background="?android:attr/selectableItemBackground"
+    android:focusable="true"
 >
 
     <ImageView
diff --git a/res/layout/contact_browser.xml b/res/layout/contact_browser.xml
index 0b4bb63..8affd46 100644
--- a/res/layout/contact_browser.xml
+++ b/res/layout/contact_browser.xml
@@ -18,4 +18,25 @@
     android:id="@+id/list_container"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
+    <FrameLayout
+        android:id="@+id/main_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+        <fragment
+            android:id="@+id/list_fragment"
+            class="com.android.contacts.list.DefaultContactBrowseListFragment"
+            android:layout_height="match_parent"
+            android:layout_width="match_parent"
+        />
+    </FrameLayout>
+    <FrameLayout
+        android:id="@+id/contacts_unavailable_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:visibility="gone">
+        <FrameLayout
+            android:id="@+id/contacts_unavailable_container"
+            android:layout_height="match_parent"
+            android:layout_width="match_parent" />
+    </FrameLayout>
 </FrameLayout>
diff --git a/res/layout/contact_editor_activity.xml b/res/layout/contact_editor_activity.xml
index 630e82c..8c13629 100644
--- a/res/layout/contact_editor_activity.xml
+++ b/res/layout/contact_editor_activity.xml
@@ -22,21 +22,4 @@
             android:id="@+id/contact_editor_fragment"
             android:layout_width="match_parent"
             android:layout_height="match_parent" />
-    <LinearLayout
-        android:layout_width="wrap_content"
-        android:layout_height="50dip"
-        android:orientation="horizontal"
-        android:gravity="center_horizontal">
-
-        <Button
-            android:id="@+id/done"
-            android:layout_width="150dip"
-            android:layout_height="match_parent"
-            android:text="@string/menu_done" />
-        <Button
-            android:id="@+id/revert"
-            android:layout_width="150dip"
-            android:layout_height="match_parent"
-            android:text="@string/menu_doNotSave" />
-    </LinearLayout>
 </FrameLayout>
diff --git a/res/layout/item_kind_section.xml b/res/layout/item_kind_section.xml
index fdb55c9..c0e42a0 100644
--- a/res/layout/item_kind_section.xml
+++ b/res/layout/item_kind_section.xml
@@ -53,18 +53,23 @@
             android:ellipsize="marquee"
             android:fadingEdge="horizontal" />
 
-        <ImageButton
-            android:id="@+id/kind_plus"
+        <FrameLayout
+            android:id="@+id/kind_plus_container"
             android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:duplicateParentState="true"
-            android:background="?android:attr/selectableItemBackground"
-            android:src="@drawable/ic_menu_add_field_holo_light"
-            android:paddingLeft="@dimen/editor_round_button_padding_left"
-            android:paddingRight="@dimen/editor_round_button_padding_right"
-            android:paddingTop="@dimen/editor_round_button_padding_top"
-            android:paddingBottom="@dimen/editor_round_button_padding_bottom"
-            android:contentDescription="@string/description_plus_button" />
+            android:layout_height="@dimen/editor_min_line_item_height">
+            <ImageButton
+                android:id="@+id/kind_plus"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:duplicateParentState="true"
+                android:background="?android:attr/selectableItemBackground"
+                android:src="@drawable/ic_menu_add_field_holo_light"
+                android:paddingLeft="@dimen/editor_round_button_padding_left"
+                android:paddingRight="@dimen/editor_round_button_padding_right"
+                android:paddingTop="@dimen/editor_round_button_padding_top"
+                android:paddingBottom="@dimen/editor_round_button_padding_bottom"
+                android:contentDescription="@string/description_plus_button" />
+        </FrameLayout>
 
     </LinearLayout>
 
diff --git a/res/layout/list_section.xml b/res/layout/list_section.xml
index e920673..5265f88 100644
--- a/res/layout/list_section.xml
+++ b/res/layout/list_section.xml
@@ -18,8 +18,7 @@
 <RelativeLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
-    android:layout_height="25dip"
-    android:background="@drawable/section_header"
+    android:layout_height="@dimen/list_section_height"
     >
     <TextView
         android:id="@+id/header_text"
diff --git a/res/layout/quickcontact.xml b/res/layout/quickcontact.xml
index a74424c..e2b291c 100644
--- a/res/layout/quickcontact.xml
+++ b/res/layout/quickcontact.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
 <!-- Copyright (C) 2009 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
@@ -12,13 +13,12 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-
-<view
+<LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
-    class="com.android.contacts.quickcontact.QuickContactRootLayout"
-    android:id="@+id/root"
-    android:layout_width="match_parent"
+    android:id="@android:id/content"
+    android:layout_width="@dimen/quick_contact_width"
     android:layout_height="wrap_content"
+    android:visibility="invisible"
     android:orientation="vertical">
 
     <FrameLayout
@@ -133,4 +133,4 @@
                 android:text="@string/quickcontact_clear_defaults_button" />
         </LinearLayout>
     </FrameLayout>
-</view>
+</LinearLayout>
diff --git a/res/layout/quickcontact_activity.xml b/res/layout/quickcontact_activity.xml
new file mode 100644
index 0000000..aced4a8
--- /dev/null
+++ b/res/layout/quickcontact_activity.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<view
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    class="com.android.contacts.quickcontact.FloatingChildLayout"
+    android:id="@+id/floating_layout"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:focusable="true"
+    android:focusableInTouchMode="true"
+    android:descendantFocusability="afterDescendants">
+
+    <include layout="@layout/quickcontact" />
+
+</view>
diff --git a/res/layout/quickcontact_default_item.xml b/res/layout/quickcontact_default_item.xml
index 25b6910..3a918f0 100755
--- a/res/layout/quickcontact_default_item.xml
+++ b/res/layout/quickcontact_default_item.xml
@@ -28,13 +28,13 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:textStyle="bold"
-        android:textAppearance="?android:attr/textAppearanceMediumInverse" />
+        android:textAppearance="?android:attr/textAppearanceMedium" />
 
     <TextView
         android:id="@android:id/text2"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_marginTop="-4dip"
-        android:textAppearance="?android:attr/textAppearanceSmallInverse" />
+        android:textAppearance="?android:attr/textAppearanceSmall" />
 
 </LinearLayout>
diff --git a/res/layout/quickcontact_resolve_item.xml b/res/layout/quickcontact_resolve_item.xml
index 55de80e..2805722 100755
--- a/res/layout/quickcontact_resolve_item.xml
+++ b/res/layout/quickcontact_resolve_item.xml
@@ -28,13 +28,13 @@
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:textStyle="bold"
-        android:textAppearance="?android:attr/textAppearanceMediumInverse" />
+        android:textAppearance="?android:attr/textAppearanceMedium" />
 
     <TextView
         android:id="@android:id/text2"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_marginTop="-4dip"
-        android:textAppearance="?android:attr/textAppearanceSmallInverse" />
+        android:textAppearance="?android:attr/textAppearanceSmall" />
 
 </LinearLayout>
diff --git a/res/layout/twelve_key_dialer.xml b/res/layout/twelve_key_dialer.xml
index d4c9d8f..2cae9ae 100644
--- a/res/layout/twelve_key_dialer.xml
+++ b/res/layout/twelve_key_dialer.xml
@@ -14,11 +14,14 @@
      limitations under the License.
 -->
 
+<!-- TODO (stopship) We don't want to specify a background color here. For now we just
+keep it because otherwise the dialer needs some imagination to use (white on white) -->
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/top"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:orientation="vertical"
+    android:background="@android:color/black"
 >
 
     <!-- Text field above the keypad where the digits are displayed.
diff --git a/res/menu/list.xml b/res/menu/list.xml
index 2b3f453..56d92f8 100644
--- a/res/menu/list.xml
+++ b/res/menu/list.xml
@@ -27,9 +27,9 @@
         android:alphabeticShortcut="n" />
 
     <item
-        android:id="@+id/menu_display_groups"
-        android:icon="@*android:drawable/ic_menu_allfriends"
-        android:title="@string/menu_displayGroup" />
+        android:id="@+id/menu_settings"
+        android:icon="@drawable/ic_menu_settings_holo_light"
+        android:title="@string/menu_settings" />
 
     <item
         android:id="@+id/menu_accounts"
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index dcca0f1..c0e2581 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -149,6 +149,7 @@
     <string name="recentCalls_empty" msgid="247053222448663107">"سجل المكالمات فارغ."</string>
     <string name="clearCallLogConfirmation_title" msgid="718072843006222703">"محو سجل المكالمات"</string>
     <string name="clearCallLogConfirmation" msgid="7625927669136267636">"هل أنت متأكد من أنك تريد محو سجل المكالمات؟"</string>
+    <string name="clearCallLogProgress_title" msgid="6870412675015656948">"جارٍ محو سجل المكالمات"</string>
     <string name="imei" msgid="3045126336951684285">"IMEI"</string>
     <string name="meid" msgid="6210568493746275750">"MEID"</string>
     <string name="voicemail" msgid="3851469869202611441">"البريد الصوتي"</string>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index 6f62119..9061389 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -149,6 +149,7 @@
     <string name="recentCalls_empty" msgid="247053222448663107">"Списъкът на обажданията е празен."</string>
     <string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Изчистване на списъка с обажданията"</string>
     <string name="clearCallLogConfirmation" msgid="7625927669136267636">"Наистина ли искате да изчистите списъка на обажданията?"</string>
+    <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Списъкът с обажданията се изчиства"</string>
     <string name="imei" msgid="3045126336951684285">"IMEI"</string>
     <string name="meid" msgid="6210568493746275750">"MEID"</string>
     <string name="voicemail" msgid="3851469869202611441">"Гласова поща"</string>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index 31de36e..685f2a1 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -149,6 +149,7 @@
     <string name="recentCalls_empty" msgid="247053222448663107">"El registre de trucades és buit."</string>
     <string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Esborrament del registre de trucades"</string>
     <string name="clearCallLogConfirmation" msgid="7625927669136267636">"Esteu segur que voleu esborrar el registre de trucades?"</string>
+    <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Esborrant el registre de trucada"</string>
     <string name="imei" msgid="3045126336951684285">"IMEI"</string>
     <string name="meid" msgid="6210568493746275750">"MEID"</string>
     <string name="voicemail" msgid="3851469869202611441">"Correu de veu"</string>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index b4ec252..c353045 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -149,6 +149,7 @@
     <string name="recentCalls_empty" msgid="247053222448663107">"Záznam hovorů je prázdný."</string>
     <string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Vymazat hovory"</string>
     <string name="clearCallLogConfirmation" msgid="7625927669136267636">"Opravdu chcete vymazat hovory?"</string>
+    <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Vymazání hovorů"</string>
     <string name="imei" msgid="3045126336951684285">"IMEI"</string>
     <string name="meid" msgid="6210568493746275750">"MEID"</string>
     <string name="voicemail" msgid="3851469869202611441">"Hlasová schránka"</string>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index 92d2477..18a1214 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -149,6 +149,7 @@
     <string name="recentCalls_empty" msgid="247053222448663107">"Opkaldslisten er tom."</string>
     <string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Ryd opkaldsliste"</string>
     <string name="clearCallLogConfirmation" msgid="7625927669136267636">"Er du sikker på, at du vil rydde opkaldslisten?"</string>
+    <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Rydder opkaldsliste"</string>
     <string name="imei" msgid="3045126336951684285">"IMEI-nummer"</string>
     <string name="meid" msgid="6210568493746275750">"MEID"</string>
     <string name="voicemail" msgid="3851469869202611441">"Voicemail"</string>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index 1f8cec6..54c6490 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -149,6 +149,7 @@
     <string name="recentCalls_empty" msgid="247053222448663107">"Anrufliste ist leer"</string>
     <string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Anrufprotokoll löschen"</string>
     <string name="clearCallLogConfirmation" msgid="7625927669136267636">"Möchten Sie das Anrufprotokoll wirklich löschen?"</string>
+    <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Anrufprotokoll wird gelöscht."</string>
     <string name="imei" msgid="3045126336951684285">"IMEI"</string>
     <string name="meid" msgid="6210568493746275750">"MEID"</string>
     <string name="voicemail" msgid="3851469869202611441">"Mailbox"</string>
@@ -231,7 +232,7 @@
     <string name="fail_reason_io_error" msgid="5922864781066136340">"E/A-Fehler"</string>
     <string name="fail_reason_low_memory_during_import" msgid="7514918659342886381">"Zu wenig Speicherplatz (Datei ist eventuell zu groß)"</string>
     <string name="fail_reason_vcard_parse_error" msgid="1201233722762680214">"Die vCard konnte aus einem unbekannten Grund nicht geparst werden."</string>
-    <string name="fail_reason_not_supported" msgid="294499264620201243">"Das Format wird nicht unterstützt."</string>
+    <string name="fail_reason_not_supported" msgid="294499264620201243">"Format wird nicht unterstützt."</string>
     <string name="vcard_import_failed" msgid="7718330063493653085">"vCard kann nicht importiert werden."</string>
     <string name="import_failure_no_vcard_file" product="nosdcard" msgid="6339234836196984924">"Im Speicher wurde keine vCard-Datei gefunden."</string>
     <string name="import_failure_no_vcard_file" product="default" msgid="1730986357514922756">"Auf der SD-Karte wurde keine vCard-Datei gefunden."</string>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index ce14e4d..9ca7e41 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -149,6 +149,7 @@
     <string name="recentCalls_empty" msgid="247053222448663107">"Το αρχείο καταγραφής κλήσεων είναι κενό."</string>
     <string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Εκκαθάριση αρχείου καταγραφής κλήσεων"</string>
     <string name="clearCallLogConfirmation" msgid="7625927669136267636">"Είστε βέβαιοι ότι θέλετε να γίνει εκκαθάριση του αρχείου καταγραφής κλήσεων;"</string>
+    <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Εκκαθάριση αρχείου καταγρ. κλήσεων"</string>
     <string name="imei" msgid="3045126336951684285">"Αριθμός ΙΜΕΙ"</string>
     <string name="meid" msgid="6210568493746275750">"MEID"</string>
     <string name="voicemail" msgid="3851469869202611441">"Αυτόματος τηλεφωνητής"</string>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index 551be6d..5004706 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -149,6 +149,7 @@
     <string name="recentCalls_empty" msgid="247053222448663107">"Call log is empty."</string>
     <string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Clear call log"</string>
     <string name="clearCallLogConfirmation" msgid="7625927669136267636">"Are you sure that you want to clear the call log?"</string>
+    <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Clearing call log"</string>
     <string name="imei" msgid="3045126336951684285">"IMEI"</string>
     <string name="meid" msgid="6210568493746275750">"MEID"</string>
     <string name="voicemail" msgid="3851469869202611441">"Voicemail"</string>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index 1dfa06c..9938ce4 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -149,6 +149,7 @@
     <string name="recentCalls_empty" msgid="247053222448663107">"El registro de llamadas está vacío."</string>
     <string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Borrar registro de llamadas"</string>
     <string name="clearCallLogConfirmation" msgid="7625927669136267636">"¿Estás seguro de que deseas borrar el registro de llamadas?"</string>
+    <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Borrando el registro de llamadas"</string>
     <string name="imei" msgid="3045126336951684285">"IMEI"</string>
     <string name="meid" msgid="6210568493746275750">"MEID"</string>
     <string name="voicemail" msgid="3851469869202611441">"Correo de voz"</string>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index c9dcac8..49e12d8 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -149,6 +149,7 @@
     <string name="recentCalls_empty" msgid="247053222448663107">"El registro de llamadas está vacío."</string>
     <string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Borrar registro de llamadas"</string>
     <string name="clearCallLogConfirmation" msgid="7625927669136267636">"¿Estás seguro de que quieres borrar el registro de llamadas?"</string>
+    <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Borrando registro de llamadas"</string>
     <string name="imei" msgid="3045126336951684285">"IMEI"</string>
     <string name="meid" msgid="6210568493746275750">"MEID"</string>
     <string name="voicemail" msgid="3851469869202611441">"Buzón de voz"</string>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index 627d3eb..ee2a356 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -149,6 +149,7 @@
     <string name="recentCalls_empty" msgid="247053222448663107">"گزارش تماس خالی است."</string>
     <string name="clearCallLogConfirmation_title" msgid="718072843006222703">"پاک کردن گزارش تماس"</string>
     <string name="clearCallLogConfirmation" msgid="7625927669136267636">"آیا مطمئن هستید که می خواهید گزارش تماس را پاک کنید؟"</string>
+    <string name="clearCallLogProgress_title" msgid="6870412675015656948">"پاک کردن گزارش تماس"</string>
     <string name="imei" msgid="3045126336951684285">"IMEI"</string>
     <string name="meid" msgid="6210568493746275750">"MEID"</string>
     <string name="voicemail" msgid="3851469869202611441">"پست صوتی"</string>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index 6a9586c..1d8fb8d 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -149,6 +149,7 @@
     <string name="recentCalls_empty" msgid="247053222448663107">"Puheluloki on tyhjä."</string>
     <string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Tyhjennä puheluloki"</string>
     <string name="clearCallLogConfirmation" msgid="7625927669136267636">"Haluatko varmasti tyhjentää puhelulokin?"</string>
+    <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Tyhjennetään puhelulokia"</string>
     <string name="imei" msgid="3045126336951684285">"IMEI-koodi"</string>
     <string name="meid" msgid="6210568493746275750">"MEID"</string>
     <string name="voicemail" msgid="3851469869202611441">"Vastaaja"</string>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index 707119a..2473b4c 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -149,6 +149,7 @@
     <string name="recentCalls_empty" msgid="247053222448663107">"Aucun appel."</string>
     <string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Effacer le journal d\'appels"</string>
     <string name="clearCallLogConfirmation" msgid="7625927669136267636">"Voulez-vous vraiment effacer le journal d\'appels ?"</string>
+    <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Suppression du journal d\'appels"</string>
     <string name="imei" msgid="3045126336951684285">"Code IMEI"</string>
     <string name="meid" msgid="6210568493746275750">"MEID"</string>
     <string name="voicemail" msgid="3851469869202611441">"Messagerie vocale"</string>
@@ -161,12 +162,12 @@
     <string name="simContacts_title" msgid="27341688347689769">"Contacts de carte SIM"</string>
     <string name="noContactsHelpTextWithSyncForCreateShortcut" msgid="801504710275614594">"Vous n\'avez aucun contact à afficher. Si vous venez d\'ajouter un compte, la synchronisation des contacts peut prendre quelques minutes."</string>
     <string name="noContactsHelpTextForCreateShortcut" msgid="3081286388667108335">"Vous n\'avez aucun contact à afficher."</string>
-    <!-- syntax error in translation for noContactsHelpText (6450346791169710787) org.xmlpull.v1.XmlPullParserException: expected: /b read: font (position:END_TAG </font>@1:560 in java.io.StringReader@2666e815)  -->
-    <!-- syntax error in translation for noContactsHelpText (7633826236417884130) org.xmlpull.v1.XmlPullParserException: expected: /b read: font (position:END_TAG </font>@1:567 in java.io.StringReader@2e0ece65)  -->
+    <!-- syntax error in translation for noContactsHelpText (6450346791169710787) org.xmlpull.v1.XmlPullParserException: expected: /b read: font (position:END_TAG </font>@1:560 in java.io.StringReader@658fb1f7)  -->
+    <!-- syntax error in translation for noContactsHelpText (7633826236417884130) org.xmlpull.v1.XmlPullParserException: expected: /b read: font (position:END_TAG </font>@1:567 in java.io.StringReader@3ced0338)  -->
     <string name="noContactsHelpTextWithSync" product="tablet" msgid="2364665535969139880">"Vous n\'avez aucun contact à afficher (si vous venez d\'ajouter un compte, la synchronisation des contacts peut prendre quelques minutes)."\n\n"Pour ajouter des contacts, appuyez sur "<font fgcolor="#ffffffff"><b>"Menu"</b></font>", puis sur :"\n" "\n<li><font fgcolor="#ffffffff"><b>"Comptes"</b></font>" pour ajouter ou configurer un compte dont vous pourrez synchroniser les contacts vers la tablette ;"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Options d\'affichage"</b></font>" pour modifier les paramètres de visibilité des contacts ;"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Nouveau contact"</b></font>" pour créer un contact ;"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importer/Exporter"</b></font>" pour importer des contacts depuis votre carte SIM ou SD."\n</li></string>
     <string name="noContactsHelpTextWithSync" product="default" msgid="3017521127042216243">"Vous n\'avez aucun contact à afficher (si vous venez d\'ajouter un compte, la synchronisation des contacts peut prendre quelques minutes)."\n\n"Pour ajouter des contacts, appuyez sur "<font fgcolor="#ffffffff"><b>"Menu"</b></font>" et sélectionnez :"\n" "\n<li><font fgcolor="#ffffffff"><b>"Comptes"</b></font>" pour ajouter ou configurer un compte dont vous pourrez synchroniser les contacts sur le téléphone ;"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Options d\'affichage"</b></font>" pour modifier le paramètre de visibilité des contacts ;"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Nouveau contact"</b></font>" pour créer un contact ;"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importer/Exporter"</b></font>" pour importer des contacts depuis votre carte SIM ou SD."\n</li></string>
-    <!-- syntax error in translation for noContactsNoSimHelpText (6031363021287849874) org.xmlpull.v1.XmlPullParserException: expected: /b read: font (position:END_TAG </font>@1:565 in java.io.StringReader@4e106082)  -->
-    <!-- syntax error in translation for noContactsNoSimHelpText (467658807711582876) org.xmlpull.v1.XmlPullParserException: expected: /b read: font (position:END_TAG </font>@1:571 in java.io.StringReader@15301ed8)  -->
+    <!-- syntax error in translation for noContactsNoSimHelpText (6031363021287849874) org.xmlpull.v1.XmlPullParserException: expected: /b read: font (position:END_TAG </font>@1:565 in java.io.StringReader@6c6e70c7)  -->
+    <!-- syntax error in translation for noContactsNoSimHelpText (467658807711582876) org.xmlpull.v1.XmlPullParserException: expected: /b read: font (position:END_TAG </font>@1:571 in java.io.StringReader@46ae506e)  -->
     <string name="noContactsNoSimHelpTextWithSync" product="tablet" msgid="6222739731808897565">"Vous n\'avez aucun contact à afficher (si vous venez d\'ajouter un compte, la synchronisation des contacts peut prendre quelques minutes)."\n\n"Pour ajouter des contacts, appuyez sur "<font fgcolor="#ffffffff"><b>"Menu"</b></font>", puis sur :"\n" "\n<li><font fgcolor="#ffffffff"><b>"Comptes"</b></font>" pour ajouter ou configurer un compte dont vous pourrez synchroniser les contacts vers la tablette ;"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Options d\'affichage"</b></font>" pour modifier les paramètres de visibilité des contacts ;"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Nouveau contact"</b></font>" pour créer un contact ;"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importer/Exporter"</b></font>" pour importer des contacts depuis votre carte SD."\n</li></string>
     <string name="noContactsNoSimHelpTextWithSync" product="default" msgid="9040060730467973050">"Vous n\'avez aucun contact à afficher (si vous venez d\'ajouter un compte, la synchronisation des contacts peut prendre quelques minutes)."\n\n"Pour ajouter des contacts, appuyez sur "<font fgcolor="#ffffffff"><b>"Menu"</b></font>" et sélectionnez :"\n" "\n<li><font fgcolor="#ffffffff"><b>"Comptes"</b></font>" pour ajouter ou configurer un compte dont vous pourrez synchroniser les contacts sur le téléphone ;"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Options d\'affichage"</b></font>" pour modifier le paramètre de visibilité des contacts ;"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Nouveau contact"</b></font>" pour créer un contact ;"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importer/Exporter"</b></font>" pour importer des contacts depuis votre carte SD."\n</li></string>
     <string name="noFavoritesHelpText" msgid="3744655776704833277">"Vous ne disposez d\'aucun favoris."\n\n"Pour ajouter un contact à la liste de favoris :"\n\n"        "<li>"Appuyez sur l\'onglet "<b>"Contacts"</b>"."\n</li>" "\n<li>"Appuyez sur le contact à ajouter à vos favoris."\n</li>" "\n<li>"Appuyez sur l\'étoile en regard du nom du contact."\n</li></string>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index 3f06446..7c24f3a 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -149,6 +149,7 @@
     <string name="recentCalls_empty" msgid="247053222448663107">"Zapisnik poziva je prazan"</string>
     <string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Izbriši zapisnik poziva"</string>
     <string name="clearCallLogConfirmation" msgid="7625927669136267636">"Jeste li sigurni da želite izbrisati zapisnik poziva?"</string>
+    <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Brisanje zapisnika poziva"</string>
     <string name="imei" msgid="3045126336951684285">"IMEI"</string>
     <string name="meid" msgid="6210568493746275750">"MEID"</string>
     <string name="voicemail" msgid="3851469869202611441">"Govorna pošta"</string>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index abe737f..76903dc 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -149,6 +149,7 @@
     <string name="recentCalls_empty" msgid="247053222448663107">"A híváslista üres."</string>
     <string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Híváslista törlése"</string>
     <string name="clearCallLogConfirmation" msgid="7625927669136267636">"Biztosan törli a híváslistát?"</string>
+    <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Hívási napló törölve"</string>
     <string name="imei" msgid="3045126336951684285">"IMEI"</string>
     <string name="meid" msgid="6210568493746275750">"MEID"</string>
     <string name="voicemail" msgid="3851469869202611441">"Hangposta"</string>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index c031cac..08302b4 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -149,6 +149,7 @@
     <string name="recentCalls_empty" msgid="247053222448663107">"Log panggilan kosong."</string>
     <string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Hapus log panggilan"</string>
     <string name="clearCallLogConfirmation" msgid="7625927669136267636">"Apakah Anda yakin ingin menghapus log panggilan?"</string>
+    <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Membersihkan log panggilan"</string>
     <string name="imei" msgid="3045126336951684285">"IMEI"</string>
     <string name="meid" msgid="6210568493746275750">"MEID"</string>
     <string name="voicemail" msgid="3851469869202611441">"Kotak Pesan"</string>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index 8568daf..6f494d1 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -149,6 +149,7 @@
     <string name="recentCalls_empty" msgid="247053222448663107">"Il registro chiamate è vuoto."</string>
     <string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Cancella registro chiamate"</string>
     <string name="clearCallLogConfirmation" msgid="7625927669136267636">"Cancellare il registro chiamate?"</string>
+    <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Cancellazione registro chiamate"</string>
     <string name="imei" msgid="3045126336951684285">"IMEI"</string>
     <string name="meid" msgid="6210568493746275750">"MEID"</string>
     <string name="voicemail" msgid="3851469869202611441">"Segreteria"</string>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index a8fc33e..eeaa9f1 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -149,6 +149,7 @@
     <string name="recentCalls_empty" msgid="247053222448663107">"יומן השיחות ריק."</string>
     <string name="clearCallLogConfirmation_title" msgid="718072843006222703">"נקה את יומן השיחות"</string>
     <string name="clearCallLogConfirmation" msgid="7625927669136267636">"האם אתה בטוח שברצונך לנקות את יומן השיחות?"</string>
+    <string name="clearCallLogProgress_title" msgid="6870412675015656948">"ניקוי יומן שיחות"</string>
     <string name="imei" msgid="3045126336951684285">"IMEI"</string>
     <string name="meid" msgid="6210568493746275750">"MEID"</string>
     <string name="voicemail" msgid="3851469869202611441">"דואר קולי"</string>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index 4f2354a..b684255 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -149,6 +149,7 @@
     <string name="recentCalls_empty" msgid="247053222448663107">"通話履歴なし"</string>
     <string name="clearCallLogConfirmation_title" msgid="718072843006222703">"通話履歴を消去"</string>
     <string name="clearCallLogConfirmation" msgid="7625927669136267636">"通話履歴を消去してもよろしいですか?"</string>
+    <string name="clearCallLogProgress_title" msgid="6870412675015656948">"通話履歴の消去中"</string>
     <string name="imei" msgid="3045126336951684285">"IMEI(端末識別番号)"</string>
     <string name="meid" msgid="6210568493746275750">"MEID"</string>
     <string name="voicemail" msgid="3851469869202611441">"ボイスメール"</string>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index ee93888..e2fc708 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -149,6 +149,7 @@
     <string name="recentCalls_empty" msgid="247053222448663107">"통화기록이 없습니다."</string>
     <string name="clearCallLogConfirmation_title" msgid="718072843006222703">"통화 기록 지우기"</string>
     <string name="clearCallLogConfirmation" msgid="7625927669136267636">"통화 기록을 삭제하시겠습니까?"</string>
+    <string name="clearCallLogProgress_title" msgid="6870412675015656948">"통화기록 지우기"</string>
     <string name="imei" msgid="3045126336951684285">"IMEI"</string>
     <string name="meid" msgid="6210568493746275750">"MEID"</string>
     <string name="voicemail" msgid="3851469869202611441">"음성사서함"</string>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index 7eb3506..034e12e 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -149,6 +149,7 @@
     <string name="recentCalls_empty" msgid="247053222448663107">"Skambučių žurnalas tuščias."</string>
     <string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Išvalyti skambučių žurnalą"</string>
     <string name="clearCallLogConfirmation" msgid="7625927669136267636">"Ar tikrai norite išvalyti skambučių žurnalą?"</string>
+    <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Valomas skambučių žurnalas"</string>
     <string name="imei" msgid="3045126336951684285">"IMEI"</string>
     <string name="meid" msgid="6210568493746275750">"MEID"</string>
     <string name="voicemail" msgid="3851469869202611441">"Balso paštas"</string>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index 31f4cee..abf7f50 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -149,6 +149,7 @@
     <string name="recentCalls_empty" msgid="247053222448663107">"Zvanu žurnāls ir tukšs."</string>
     <string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Notīrīt zvanu žurnālu"</string>
     <string name="clearCallLogConfirmation" msgid="7625927669136267636">"Vai tiešām vēlaties notīrīt zvanu žurnālu?"</string>
+    <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Zvanu žurnāla tīrīšana"</string>
     <string name="imei" msgid="3045126336951684285">"IMEI"</string>
     <string name="meid" msgid="6210568493746275750">"MEID"</string>
     <string name="voicemail" msgid="3851469869202611441">"Balss pasts"</string>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index dcf8a0a..7b2c783 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -149,6 +149,7 @@
     <string name="recentCalls_empty" msgid="247053222448663107">"Anropsloggen er tom."</string>
     <string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Tøm samtalelogg"</string>
     <string name="clearCallLogConfirmation" msgid="7625927669136267636">"Er du sikker på at du vil tømme samtaleloggen?"</string>
+    <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Tømming av anropslogg"</string>
     <string name="imei" msgid="3045126336951684285">"IMEI"</string>
     <string name="meid" msgid="6210568493746275750">"MEID"</string>
     <string name="voicemail" msgid="3851469869202611441">"Telefonsvarer"</string>
@@ -161,12 +162,12 @@
     <string name="simContacts_title" msgid="27341688347689769">"Kontakter på SIM-kort"</string>
     <string name="noContactsHelpTextWithSyncForCreateShortcut" msgid="801504710275614594">"Du har ingen kontakter å vise. (Hvis du nettopp har lagt til en konto, kan det ta noen minutter å synkronisere kontaktene.)"</string>
     <string name="noContactsHelpTextForCreateShortcut" msgid="3081286388667108335">"Du har ingen kontakter å vise."</string>
-    <!-- syntax error in translation for noContactsHelpText (6450346791169710787) org.xmlpull.v1.XmlPullParserException: expected: /li read: font (position:END_TAG </font>@1:292 in java.io.StringReader@1aa8c488)  -->
-    <!-- syntax error in translation for noContactsHelpText (7633826236417884130) org.xmlpull.v1.XmlPullParserException: expected: /li read: font (position:END_TAG </font>@1:293 in java.io.StringReader@3dfeca64)  -->
+    <!-- syntax error in translation for noContactsHelpText (6450346791169710787) org.xmlpull.v1.XmlPullParserException: expected: /li read: font (position:END_TAG </font>@1:292 in java.io.StringReader@22998b08)  -->
+    <!-- syntax error in translation for noContactsHelpText (7633826236417884130) org.xmlpull.v1.XmlPullParserException: expected: /li read: font (position:END_TAG </font>@1:293 in java.io.StringReader@e76cbf7)  -->
     <string name="noContactsHelpTextWithSync" product="tablet" msgid="2364665535969139880">"Du har ingen kontakter å vise. (Hvis du nylig la til en konto, kan det ta noen minutter å synkronisere kontaktene.)"\n\n"Slik legger du til kontakter: Trykk på "<font fgcolor="#ffffffff"><b>"Meny"</b></font>", og trykk deretter på:"\n" "\n<li><font fgcolor="#ffffffff"><b>"Kontoer"</b></font>" for å legge til eller konfigurere en konto med kontakter som kan synkroniseres til nettbrettet"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Visningsalternativer"</b></font>" for å endre hvilke kontakter som vises"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Ny kontakt"</b></font>" for å opprette en ny kontakt fra grunnen av"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importer/Eksporter"</b></font>" for å importere kontakter fra SIM- eller SD-kort"\n</li></string>
     <string name="noContactsHelpTextWithSync" product="default" msgid="3017521127042216243">"Du har ingen kontakter å vise. (Hvis du nylig la til en konto, kan det ta noen minutter å synkronisere kontaktene.)"\n\n"Slik legger du til kontakter: Trykk på "<font fgcolor="#ffffffff"><b>"Meny"</b></font>" og trykk deretter på: "\n" "\n<li><font fgcolor="#ffffffff"><b>"Kontoer "</b></font>" for å legge til eller konfigurere en konto med kontakter som kan synkroniseres til telefonen"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Visningsalternativer"</b></font>" for å endre hvilke kontakter som vises"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Ny kontakt"</b></font>" for å opprette en ny kontakt"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importér/Eksportér"</b></font>" for å importere kontakter fra SIM- eller SD-kort"\n</li></string>
-    <!-- syntax error in translation for noContactsNoSimHelpText (6031363021287849874) org.xmlpull.v1.XmlPullParserException: expected: /li read: font (position:END_TAG </font>@1:297 in java.io.StringReader@22998b08)  -->
-    <!-- syntax error in translation for noContactsNoSimHelpText (467658807711582876) org.xmlpull.v1.XmlPullParserException: expected: /li read: font (position:END_TAG </font>@1:297 in java.io.StringReader@e76cbf7)  -->
+    <!-- syntax error in translation for noContactsNoSimHelpText (6031363021287849874) org.xmlpull.v1.XmlPullParserException: expected: /li read: font (position:END_TAG </font>@1:297 in java.io.StringReader@1948cc8c)  -->
+    <!-- syntax error in translation for noContactsNoSimHelpText (467658807711582876) org.xmlpull.v1.XmlPullParserException: expected: /li read: font (position:END_TAG </font>@1:297 in java.io.StringReader@7a6d084b)  -->
     <string name="noContactsNoSimHelpTextWithSync" product="tablet" msgid="6222739731808897565">"Du har ingen kontakter å vise. (Hvis du nylig la til en konto, kan det ta noen minutter å synkronisere kontaktene.)"\n\n"Slik legger du til kontakter: Trykk på "<font fgcolor="#ffffffff"><b>"Meny"</b></font>", og trykk deretter på: "\n" "\n<li><font fgcolor="#ffffffff"><b>"Kontoer"</b></font>" for å legge til eller konfigurere en konto med kontakter som kan synkroniseres til nettbrettet"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Visningsalternativer"</b></font>" for å endre hvilke kontakter som vises"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Ny kontakt"</b></font>" for å opprette en ny kontakt fra grunnen av"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importer/eksporter"</b></font>" for å importere kontakter fra SD-kortet"\n</li></string>
     <string name="noContactsNoSimHelpTextWithSync" product="default" msgid="9040060730467973050">"Du har ingen kontakter å vise. (Hvis du nylig la til en konto, kan det ta noen minutter å synkronisere kontaktene.)"\n\n"Slik legger du til kontakter: Trykk på "<font fgcolor="#ffffffff"><b>"Meny"</b></font>" og trykk deretter på: "\n" "\n<li><font fgcolor="#ffffffff"><b>"Kontoer "</b></font>" for å legge til eller konfigurere en konto med kontakter som kan synkroniseres til telefonen"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Visningsalternativer"</b></font>" for å endre hvilke kontakter som vises"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Ny kontakt"</b></font>" for å opprette en ny kontakt"\n</li>" "\n<li><font fgcolor="#ffffffff"><b>"Importér/eksportér"</b></font>" for å importere kontakter fra SD-kortet"\n</li></string>
     <string name="noFavoritesHelpText" msgid="3744655776704833277">"Du har ingen favoritter."\n\n"Slik legger du til en kontakt i favorittlisten:"\n\n" "<li>"Trykk på fanen "<b>"Kontakter"</b>" "\n</li>" "\n<li>"Trykk på kontakten du vil legge til i favoritter"\n</li>" "\n<li>"Trykk på stjernen ved siden av kontaktnavnet"\n</li></string>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index cc70f61..021dd61 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -149,6 +149,7 @@
     <string name="recentCalls_empty" msgid="247053222448663107">"Gesprekken is leeg"</string>
     <string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Oproeplogboek wissen"</string>
     <string name="clearCallLogConfirmation" msgid="7625927669136267636">"Weet u zeker dat u het oproeplogboek wilt wissen?"</string>
+    <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Oproeplogboek wissen"</string>
     <string name="imei" msgid="3045126336951684285">"IMEI-nummer"</string>
     <string name="meid" msgid="6210568493746275750">"MEID"</string>
     <string name="voicemail" msgid="3851469869202611441">"Voicemail"</string>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index 98cc2e8..991b556 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -149,6 +149,7 @@
     <string name="recentCalls_empty" msgid="247053222448663107">"Rejestr połączeń jest pusty."</string>
     <string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Wyczyść rejestr połączeń"</string>
     <string name="clearCallLogConfirmation" msgid="7625927669136267636">"Czy na pewno chcesz wyczyścić rejestr połączeń?"</string>
+    <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Czyszczenie dziennika połączeń"</string>
     <string name="imei" msgid="3045126336951684285">"IMEI"</string>
     <string name="meid" msgid="6210568493746275750">"Numer MEID"</string>
     <string name="voicemail" msgid="3851469869202611441">"Poczta głosowa"</string>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index 556e529..3527d6a 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -149,6 +149,7 @@
     <string name="recentCalls_empty" msgid="247053222448663107">"O registo de chamadas está vazio."</string>
     <string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Limpar registo de chamadas"</string>
     <string name="clearCallLogConfirmation" msgid="7625927669136267636">"Tem a certeza de que pretende limpar o registo de chamadas?"</string>
+    <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Limpar registo de chamadas"</string>
     <string name="imei" msgid="3045126336951684285">"IMEI"</string>
     <string name="meid" msgid="6210568493746275750">"MEID"</string>
     <string name="voicemail" msgid="3851469869202611441">"Correio de voz"</string>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index 6a573f7..e138aaa 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -149,6 +149,7 @@
     <string name="recentCalls_empty" msgid="247053222448663107">"O registro de chamadas está vazio."</string>
     <string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Limpar registro de chamadas"</string>
     <string name="clearCallLogConfirmation" msgid="7625927669136267636">"Tem certeza de que deseja limpar o registro de chamadas?"</string>
+    <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Limpando registro de chamadas"</string>
     <string name="imei" msgid="3045126336951684285">"IMEI"</string>
     <string name="meid" msgid="6210568493746275750">"MEID"</string>
     <string name="voicemail" msgid="3851469869202611441">"Correio de voz"</string>
diff --git a/res/values-rm/strings.xml b/res/values-rm/strings.xml
index 7892abb..cdc8d90 100644
--- a/res/values-rm/strings.xml
+++ b/res/values-rm/strings.xml
@@ -153,6 +153,8 @@
     <string name="recentCalls_empty" msgid="247053222448663107">"La glista da cloms e vida"</string>
     <string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Stizzar il protocol da cloms"</string>
     <string name="clearCallLogConfirmation" msgid="7625927669136267636">"Vulais Vus propi stizzar il protocol da cloms?"</string>
+    <!-- no translation found for clearCallLogProgress_title (6870412675015656948) -->
+    <skip />
     <string name="imei" msgid="3045126336951684285">"IMEI"</string>
     <string name="meid" msgid="6210568493746275750">"MEID"</string>
     <string name="voicemail" msgid="3851469869202611441">"Mailbox"</string>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index b52a70c..a831658 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -149,6 +149,7 @@
     <string name="recentCalls_empty" msgid="247053222448663107">"Jurnalul de apeluri este gol."</string>
     <string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Ştergeţi jurnalul de apeluri"</string>
     <string name="clearCallLogConfirmation" msgid="7625927669136267636">"Sigur doriţi ştergerea jurnalului de apeluri?"</string>
+    <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Se goleşte jurnalul de apeluri"</string>
     <string name="imei" msgid="3045126336951684285">"IMEI"</string>
     <string name="meid" msgid="6210568493746275750">"MEID"</string>
     <string name="voicemail" msgid="3851469869202611441">"Mesagerie vocală"</string>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index 4dade70..653942c 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -149,6 +149,7 @@
     <string name="recentCalls_empty" msgid="247053222448663107">"Список вызовов пуст."</string>
     <string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Очистить список вызовов"</string>
     <string name="clearCallLogConfirmation" msgid="7625927669136267636">"Действительно очистить список вызовов?"</string>
+    <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Очистка списка вызовов"</string>
     <string name="imei" msgid="3045126336951684285">"IMEI"</string>
     <string name="meid" msgid="6210568493746275750">"MEID"</string>
     <string name="voicemail" msgid="3851469869202611441">"Голосовая почта"</string>
@@ -233,7 +234,7 @@
     <string name="fail_reason_vcard_parse_error" msgid="1201233722762680214">"Не удалось обработать vCard по неизвестной причине."</string>
     <string name="fail_reason_not_supported" msgid="294499264620201243">"Формат не поддерживается."</string>
     <string name="vcard_import_failed" msgid="7718330063493653085">"Не удалось импортировать vCard"</string>
-    <string name="import_failure_no_vcard_file" product="nosdcard" msgid="6339234836196984924">"На накопителе отсутствуют файлы vCard"</string>
+    <string name="import_failure_no_vcard_file" product="nosdcard" msgid="6339234836196984924">"На накопителе нет vCard-файлов"</string>
     <string name="import_failure_no_vcard_file" product="default" msgid="1730986357514922756">"На SD-карте не найдены файлы VCard"</string>
     <string name="fail_reason_failed_to_collect_vcard_meta_info" msgid="4154492282316067754">"Не удалось собрать метаинформацию файлов VCard."</string>
     <string name="fail_reason_failed_to_read_files" msgid="3659521123567134029">"Не удалось импортировать один или несколько файлов (%s)."</string>
@@ -259,7 +260,7 @@
     <string name="exporting_contact_failed_title" msgid="585823094820602526">"Не удалось экспортировать данные контакта."</string>
     <string name="exporting_contact_failed_message" msgid="4151348002470298092">"Не удалось экспортировать данные контакта."\n"Причина: \"<xliff:g id="FAIL_REASON">%s</xliff:g>\""</string>
     <string name="fail_reason_no_exportable_contact" msgid="4919714086648344495">"Нет контактов, которые можно экспортировать."</string>
-    <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="3745507837635270265">"Слишком много файлов vCard на накопителе"</string>
+    <string name="fail_reason_too_many_vcard" product="nosdcard" msgid="3745507837635270265">"Слишком много vCard-файлов на накопителе"</string>
     <string name="fail_reason_too_many_vcard" product="default" msgid="7084146295639672658">"Слишком много файлов VCard на SD-карте."</string>
     <string name="fail_reason_too_long_filename" msgid="1915716071321839166">"Название файла слишком длинное (<xliff:g id="FILENAME">%s</xliff:g>)."</string>
     <string name="exporting_vcard_finished_title" msgid="4259736138838583213">"Экспорт <xliff:g id="FILENAME">%s</xliff:g> завершен"</string>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index 6a78891..ab3eb74 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -149,6 +149,7 @@
     <string name="recentCalls_empty" msgid="247053222448663107">"Záznam hovorov je prázdny."</string>
     <string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Vymazať záznam hovorov"</string>
     <string name="clearCallLogConfirmation" msgid="7625927669136267636">"Naozaj chcete odstrániť denník hovorov?"</string>
+    <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Vymazávanie denníka hovorov"</string>
     <string name="imei" msgid="3045126336951684285">"IMEI"</string>
     <string name="meid" msgid="6210568493746275750">"MEID"</string>
     <string name="voicemail" msgid="3851469869202611441">"Hlasová schránka"</string>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index 0bb51c4..2c4c983 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -149,6 +149,7 @@
     <string name="recentCalls_empty" msgid="247053222448663107">"Dnevnik klicev je prazen."</string>
     <string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Počisti dnevnik klicev"</string>
     <string name="clearCallLogConfirmation" msgid="7625927669136267636">"Ali ste prepričani, da želite počistiti dnevnik klicev?"</string>
+    <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Brisanje dnevnika klicev"</string>
     <string name="imei" msgid="3045126336951684285">"IMEI"</string>
     <string name="meid" msgid="6210568493746275750">"MEID"</string>
     <string name="voicemail" msgid="3851469869202611441">"Glasovna pošta"</string>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index 614548e..bddf143 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -149,6 +149,7 @@
     <string name="recentCalls_empty" msgid="247053222448663107">"Евиденција позива је празна."</string>
     <string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Обриши евиденцију позива"</string>
     <string name="clearCallLogConfirmation" msgid="7625927669136267636">"Желите ли заиста да обришете евиденцију позива?"</string>
+    <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Брисање евиденције позива"</string>
     <string name="imei" msgid="3045126336951684285">"IMEI"</string>
     <string name="meid" msgid="6210568493746275750">"MEID"</string>
     <string name="voicemail" msgid="3851469869202611441">"Говорна пошта"</string>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index dbe0f1b..f0b0605 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -149,6 +149,7 @@
     <string name="recentCalls_empty" msgid="247053222448663107">"Samtalshistoriken är tom."</string>
     <string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Rensa samtalshistorik"</string>
     <string name="clearCallLogConfirmation" msgid="7625927669136267636">"Vill du rensa samtalshistoriken?"</string>
+    <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Rensar samtalshistorik"</string>
     <string name="imei" msgid="3045126336951684285">"IMEI-kod"</string>
     <string name="meid" msgid="6210568493746275750">"MEID"</string>
     <string name="voicemail" msgid="3851469869202611441">"Röstbrevlåda"</string>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index d545369..c5cbe5c 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -149,6 +149,7 @@
     <string name="recentCalls_empty" msgid="247053222448663107">"บันทึกการโทรว่างเปล่า"</string>
     <string name="clearCallLogConfirmation_title" msgid="718072843006222703">"ล้างบันทึกการโทร"</string>
     <string name="clearCallLogConfirmation" msgid="7625927669136267636">"คุณแน่ใจหรือไม่ว่าต้องการล้างบันทึกการโทรทั้งหมด"</string>
+    <string name="clearCallLogProgress_title" msgid="6870412675015656948">"การล้างบันทึกการโทร"</string>
     <string name="imei" msgid="3045126336951684285">"IMEI"</string>
     <string name="meid" msgid="6210568493746275750">"MEID"</string>
     <string name="voicemail" msgid="3851469869202611441">"ข้อความเสียง"</string>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index d8321ce..274c5e0 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -149,6 +149,7 @@
     <string name="recentCalls_empty" msgid="247053222448663107">"Walang laman ang log ng tawag."</string>
     <string name="clearCallLogConfirmation_title" msgid="718072843006222703">"I-clear ang log ng tawag"</string>
     <string name="clearCallLogConfirmation" msgid="7625927669136267636">"Sigurado ka bang gusto mong i-clear ang log ng tawag?"</string>
+    <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Kini-clear ang log ng tawag"</string>
     <string name="imei" msgid="3045126336951684285">"IMEI"</string>
     <string name="meid" msgid="6210568493746275750">"MEID"</string>
     <string name="voicemail" msgid="3851469869202611441">"Voicemail"</string>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index 3857046..366edf7 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -149,6 +149,7 @@
     <string name="recentCalls_empty" msgid="247053222448663107">"Çağrı kaydı boş."</string>
     <string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Çağrı kaydını temizle"</string>
     <string name="clearCallLogConfirmation" msgid="7625927669136267636">"Çağrı kaydını silmek istediğinizden emin misiniz?"</string>
+    <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Çağrı kaydı temizleniyor"</string>
     <string name="imei" msgid="3045126336951684285">"IMEI"</string>
     <string name="meid" msgid="6210568493746275750">"MEID"</string>
     <string name="voicemail" msgid="3851469869202611441">"Sesli Mesaj"</string>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index 35576b4..419b70f 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -149,6 +149,7 @@
     <string name="recentCalls_empty" msgid="247053222448663107">"Журн. викл. порожній."</string>
     <string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Очист. журнал викл."</string>
     <string name="clearCallLogConfirmation" msgid="7625927669136267636">"Дійсно очистити журнал викликів?"</string>
+    <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Очищення журналу викликів"</string>
     <string name="imei" msgid="3045126336951684285">"IMEI"</string>
     <string name="meid" msgid="6210568493746275750">"MEID"</string>
     <string name="voicemail" msgid="3851469869202611441">"Голос. пошта"</string>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index 4c78800..30691ff 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -149,6 +149,7 @@
     <string name="recentCalls_empty" msgid="247053222448663107">"Nhật ký cuộc gọi trống."</string>
     <string name="clearCallLogConfirmation_title" msgid="718072843006222703">"Xoá nhật ký cuộc gọi"</string>
     <string name="clearCallLogConfirmation" msgid="7625927669136267636">"Bạn có chắc chắn muốn xoá nhật ký cuộc gọi không?"</string>
+    <string name="clearCallLogProgress_title" msgid="6870412675015656948">"Đang xóa nhật ký cuộc gọi"</string>
     <string name="imei" msgid="3045126336951684285">"IMEI"</string>
     <string name="meid" msgid="6210568493746275750">"MEID"</string>
     <string name="voicemail" msgid="3851469869202611441">"Thư thoại"</string>
diff --git a/res/values-xlarge/dimens.xml b/res/values-xlarge/dimens.xml
index d29eba2..d18b789 100644
--- a/res/values-xlarge/dimens.xml
+++ b/res/values-xlarge/dimens.xml
@@ -23,4 +23,5 @@
     <dimen name="action_bar_search_max_width">300dip</dimen>
     <dimen name="action_bar_search_spacing">12dip</dimen>
     <dimen name="shortcut_icon_size">64dip</dimen>
+    <dimen name="list_section_height">37dip</dimen>
 </resources>
diff --git a/res/values-xlarge/donottranslate_config.xml b/res/values-xlarge/donottranslate_config.xml
new file mode 100644
index 0000000..fcb7da9
--- /dev/null
+++ b/res/values-xlarge/donottranslate_config.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2011, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<resources>
+    <bool name="config_use_two_panes">true</bool>
+</resources>
diff --git a/res/values-xlarge/styles.xml b/res/values-xlarge/styles.xml
index e601590..6f6b334 100644
--- a/res/values-xlarge/styles.xml
+++ b/res/values-xlarge/styles.xml
@@ -57,9 +57,6 @@
         <item name="list_item_header_text_size">14sp</item>
     </style>
 
-    <style name="ContactsPreferencesTheme" parent="@android:Theme.Holo.Light">
-    </style>
-
     <style name="CustomContactListFilterTheme" parent="@android:Theme.Holo.Light.Dialog">
     </style>
 
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index a4aef23..0a53881 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -149,6 +149,7 @@
     <string name="recentCalls_empty" msgid="247053222448663107">"通话记录为空。"</string>
     <string name="clearCallLogConfirmation_title" msgid="718072843006222703">"清除通话记录"</string>
     <string name="clearCallLogConfirmation" msgid="7625927669136267636">"确定要清除通话记录吗?"</string>
+    <string name="clearCallLogProgress_title" msgid="6870412675015656948">"正在清除通话记录"</string>
     <string name="imei" msgid="3045126336951684285">"移动通信国际识别码"</string>
     <string name="meid" msgid="6210568493746275750">"MEID"</string>
     <string name="voicemail" msgid="3851469869202611441">"语音信箱"</string>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index 3cfddeb..4e97538 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -149,6 +149,7 @@
     <string name="recentCalls_empty" msgid="247053222448663107">"無通話記錄。"</string>
     <string name="clearCallLogConfirmation_title" msgid="718072843006222703">"清除通話記錄"</string>
     <string name="clearCallLogConfirmation" msgid="7625927669136267636">"確定要清除通話記錄嗎?"</string>
+    <string name="clearCallLogProgress_title" msgid="6870412675015656948">"正在清除通話記錄"</string>
     <string name="imei" msgid="3045126336951684285">"IMEI"</string>
     <string name="meid" msgid="6210568493746275750">"MEID"</string>
     <string name="voicemail" msgid="3851469869202611441">"語音留言"</string>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 47150b4..2255cd8 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -75,4 +75,7 @@
 
     <!-- Size of the shortcut icon. 0dip means: use the system default -->    
     <dimen name="shortcut_icon_size">0dip</dimen>
+
+    <!-- Height of list sections (A, B, C) that show the first character of the contacts -->
+    <dimen name="list_section_height">25dip</dimen>
 </resources>
diff --git a/res/values/donottranslate_config.xml b/res/values/donottranslate_config.xml
index f5efa13..e310953 100644
--- a/res/values/donottranslate_config.xml
+++ b/res/values/donottranslate_config.xml
@@ -99,4 +99,8 @@
 
     <!-- If true, phonetic name is included in the contact editor by default -->
     <bool name="config_editor_include_phonetic_name">false</bool>
+
+    <!-- If true, Contacts uses two panes: List and Detail. If false, Details are
+         shown in their own screens. This flag must be in sync with the layout definitions. -->
+    <bool name="config_use_two_panes">false</bool>
 </resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index ff69899..c16a135 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -388,6 +388,9 @@
     <!-- Confirmation dialog for clearing the call log  -->
     <string name="clearCallLogConfirmation">Are you sure you want to clear the call log?</string>
 
+    <!-- Title of the "Clearing call log" progress-dialog [CHAR LIMIT=35] -->
+    <string name="clearCallLogProgress_title">Clearing call log</string>
+
     <!-- The title of a dialog that displays the IMEI of the phone -->
     <string name="imei">IMEI</string>
 
diff --git a/res/values/styles.xml b/res/values/styles.xml
index db50204..c4a588f 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -14,18 +14,18 @@
      limitations under the License.
 -->
 <resources>
-    <style name="DialtactsTheme" parent="@android:Theme">
+    <style name="DialtactsTheme" parent="android:Theme.Holo.Light">
         <item name="android:windowNoTitle">true</item>
         <item name="android:windowContentOverlay">@null</item>
     </style>
 
-    <style name="CallDetailActivityTheme" parent="android:Theme.NoTitleBar">
+    <style name="CallDetailActivityTheme" parent="android:Theme.Holo.Light">
         <item name="android:windowContentOverlay">@null</item>
     </style>
-    <style name="ContactDetailActivityTheme" parent="android:Theme.NoTitleBar">
+    <style name="ContactDetailActivityTheme" parent="android:Theme.Holo.Light">
         <item name="android:windowContentOverlay">@null</item>
     </style>
-    <style name="ContactEditorActivityTheme" parent="android:Theme.NoTitleBar">
+    <style name="ContactEditorActivityTheme" parent="android:Theme.Holo.Light">
         <item name="android:windowContentOverlay">@null</item>
     </style>
 
@@ -38,38 +38,19 @@
         <item name="android:windowIsFloating">true</item>
     </style>
 
-    <style name="FullyTranslucent" parent="android:Theme.Translucent.NoTitleBar">
-        <item name="android:windowContentOverlay">@null</item>
+    <style name="Theme">
     </style>
 
-    <style name="FullyTranslucent.QuickContact">
-        <!-- This is a hack because we want to be able to animate away the
-             QuickContact window, and we close its containing activity at the
-             same time.  So put in a dummy animation so this guy sticks around
-             while the fast track window is animating. -->
-        <item name="android:windowAnimationStyle">@style/DummyAnimation</item>
-    </style>
-
-    <style name="QuickContact" parent="@android:Theme.Holo.Light">
-        <item name="android:windowNoTitle">true</item>
-        <item name="android:windowFrame">@null</item>
+    <style name="Theme.QuickContact" parent="@android:style/Theme.Holo.Light">
         <item name="android:windowBackground">@android:color/transparent</item>
-        <item name="android:windowIsFloating">true</item>
+        <item name="android:colorBackgroundCacheHint">@null</item>
+        <item name="android:windowFrame">@null</item>
         <item name="android:windowContentOverlay">@null</item>
-        <!-- TODO: create our own animation style in framework -->
-        <!--
-        <item name="android:windowAnimationStyle">@*android:style/Animation.ZoomButtons</item>
-        -->
-    </style>
-
-    <style name="QuickContactAboveAnimation">
-        <item name="android:windowEnterAnimation">@anim/quickcontact_above_enter</item>
-        <item name="android:windowExitAnimation">@anim/quickcontact_above_exit</item>
-    </style>
-
-    <style name="QuickContactBelowAnimation">
-        <item name="android:windowEnterAnimation">@anim/quickcontact_below_enter</item>
-        <item name="android:windowExitAnimation">@anim/quickcontact_below_exit</item>
+        <item name="android:windowAnimationStyle">@null</item>
+        <item name="android:windowIsFloating">false</item>
+        <item name="android:backgroundDimEnabled">false</item>
+        <item name="android:windowIsTranslucent">true</item>
+        <item name="android:windowNoTitle">true</item>
     </style>
 
     <style name="ContactsSearchAnimation">
@@ -110,7 +91,7 @@
     <style name="ContactBrowserTheme" parent="@android:Theme">
         <item name="list_item_height">?android:attr/listPreferredItemHeight</item>
         <item name="activated_background">@drawable/list_item_activated_background</item>
-        <item name="section_header_background">@drawable/section_header</item>
+        <item name="section_header_background">@drawable/list_title_holo</item>
         <item name="list_section_header_height">32dip</item>
         <item name="list_item_divider">@drawable/list_item_divider</item>
         <item name="list_item_padding_top">4dip</item>
@@ -152,7 +133,7 @@
     <style name="JoinContactActivityTheme" parent="ContactPickerTheme" >
     </style>
 
-    <style name="ContactsPreferencesTheme" parent="@android:Theme">
+    <style name="ContactsPreferencesTheme" parent="@android:Theme.Holo.Light">
     </style>
 
     <style name="CustomContactListFilterTheme" parent="@android:Theme">
diff --git a/src/com/android/contacts/ContactsUtils.java b/src/com/android/contacts/ContactsUtils.java
index 0e75a7f..76cbc7d 100644
--- a/src/com/android/contacts/ContactsUtils.java
+++ b/src/com/android/contacts/ContactsUtils.java
@@ -16,6 +16,11 @@
 
 package com.android.contacts;
 
+import com.google.i18n.phonenumbers.NumberParseException;
+import com.google.i18n.phonenumbers.PhoneNumberUtil;
+import com.google.i18n.phonenumbers.PhoneNumberUtil.MatchType;
+import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber;
+
 import android.content.Context;
 import android.content.Intent;
 import android.location.CountryDetector;
@@ -114,9 +119,19 @@
             if (dataParts1.length != dataParts2.length) {
                 return false;
             }
+            PhoneNumberUtil util = PhoneNumberUtil.getInstance();
             for (int i = 0; i < dataParts1.length; i++) {
-                if (!PhoneNumberUtils.compare(context, dataParts1[i], dataParts2[i])) {
-                    return false;
+                try {
+                    PhoneNumber phoneNumber1 = util.parse(dataParts1[i], "ZZ" /* Unknown */);
+                    PhoneNumber phoneNumber2 = util.parse(dataParts2[i], "ZZ" /* Unknown */);
+                    MatchType matchType = util.isNumberMatch(phoneNumber1, phoneNumber2);
+                    if (matchType != MatchType.SHORT_NSN_MATCH) {
+                        return false;
+                    }
+                } catch (NumberParseException e) {
+                    if (!TextUtils.equals(dataParts1[i], dataParts2[i])) {
+                        return false;
+                    }
                 }
             }
 
diff --git a/src/com/android/contacts/DialtactsActivity.java b/src/com/android/contacts/DialtactsActivity.java
index dc69194..5ad57e4 100644
--- a/src/com/android/contacts/DialtactsActivity.java
+++ b/src/com/android/contacts/DialtactsActivity.java
@@ -151,7 +151,7 @@
     }
 
     private void setupContactsTab() {
-        Intent intent = new Intent(UI.LIST_DEFAULT);
+        Intent intent = new Intent(UI.LIST_ALL_CONTACTS_ACTION);
         intent.setClass(this, ContactBrowserActivity.class);
 
         mTabHost.addTab(mTabHost.newTabSpec("contacts")
diff --git a/src/com/android/contacts/RecentCallsListActivity.java b/src/com/android/contacts/RecentCallsListActivity.java
index 0a3c178..fb4ee10 100644
--- a/src/com/android/contacts/RecentCallsListActivity.java
+++ b/src/com/android/contacts/RecentCallsListActivity.java
@@ -23,8 +23,10 @@
 import android.app.AlertDialog;
 import android.app.Dialog;
 import android.app.ListActivity;
+import android.app.ProgressDialog;
 import android.content.ActivityNotFoundException;
 import android.content.AsyncQueryHandler;
+import android.content.ContentResolver;
 import android.content.ContentUris;
 import android.content.ContentValues;
 import android.content.Context;
@@ -39,6 +41,7 @@
 import android.database.sqlite.SQLiteFullException;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
+import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
@@ -1040,21 +1043,42 @@
     protected Dialog onCreateDialog(int id, Bundle args) {
         switch (id) {
             case DIALOG_CONFIRM_DELETE_ALL:
+                final ContentResolver resolver = getContentResolver();
+                final OnClickListener okListener = new OnClickListener() {
+                    @Override
+                    public void onClick(DialogInterface dialog, int which) {
+                        final ProgressDialog progressDialog = ProgressDialog.show(
+                                RecentCallsListActivity.this,
+                                getString(R.string.clearCallLogProgress_title),
+                                "", true, false);
+                        final AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
+                            @Override
+                            protected Void doInBackground(Void... params) {
+                                resolver.delete(Calls.CONTENT_URI, null, null);
+                                return null;
+                            }
+                            @Override
+                            protected void onPostExecute(Void result) {
+                                progressDialog.dismiss();
+                                // TODO The change notification should do this automatically, but
+                                // it isn't working right now. Remove this when the change
+                                // notification is working properly.
+                                startQuery();
+                            }
+                        };
+                        // TODO: Once we have the API, we should configure this ProgressDialog
+                        // to only show up after a certain time (e.g. 150ms)
+                        progressDialog.show();
+                        task.execute();
+                    }
+                };
                 return new AlertDialog.Builder(this)
                     .setTitle(R.string.clearCallLogConfirmation_title)
                     .setIconAttribute(android.R.attr.alertDialogIcon)
                     .setMessage(R.string.clearCallLogConfirmation)
                     .setNegativeButton(android.R.string.cancel, null)
-                    .setPositiveButton(android.R.string.ok, new OnClickListener() {
-                        public void onClick(DialogInterface dialog, int which) {
-                            getContentResolver().delete(Calls.CONTENT_URI, null, null);
-                            // TODO The change notification should do this automatically, but it
-                            // isn't working right now. Remove this when the change notification
-                            // is working properly.
-                            startQuery();
-                        }
-                    })
-                    .setCancelable(false)
+                    .setPositiveButton(android.R.string.ok, okListener)
+                    .setCancelable(true)
                     .create();
         }
         return null;
diff --git a/src/com/android/contacts/TypePrecedence.java b/src/com/android/contacts/TypePrecedence.java
index 2adf3b5..e89c5aa 100644
--- a/src/com/android/contacts/TypePrecedence.java
+++ b/src/com/android/contacts/TypePrecedence.java
@@ -42,6 +42,7 @@
     //TODO These may need to be tweaked.
     private static final int[] TYPE_PRECEDENCE_PHONES = {
             Phone.TYPE_CUSTOM,
+            Phone.TYPE_MAIN,
             Phone.TYPE_MOBILE,
             Phone.TYPE_HOME,
             Phone.TYPE_WORK,
diff --git a/src/com/android/contacts/activities/ContactBrowserActivity.java b/src/com/android/contacts/activities/ContactBrowserActivity.java
index e888bc0..066b862 100644
--- a/src/com/android/contacts/activities/ContactBrowserActivity.java
+++ b/src/com/android/contacts/activities/ContactBrowserActivity.java
@@ -105,7 +105,13 @@
     private boolean mSearchMode;
 
     private ContactBrowseListFragment mListFragment;
+
+    /**
+     * Whether we have a right-side contact pane for displaying contact info while browsing.
+     * Generally means "this is a tablet".
+     */
     private boolean mContactContentDisplayed;
+
     private ContactDetailFragment mDetailFragment;
     private DetailFragmentListener mDetailFragmentListener = new DetailFragmentListener();
 
@@ -125,7 +131,6 @@
 
     private boolean mOptionsMenuContactsAvailable;
     private boolean mOptionsMenuGroupActionsEnabled;
-    private boolean mOptionsMenuCustomFilterChangeable;
 
     public ContactBrowserActivity() {
         mIntentResolver = new ContactsIntentResolver(this);
@@ -234,7 +239,6 @@
         }
 
         mOptionsMenuContactsAvailable = false;
-        mOptionsMenuCustomFilterChangeable = false;
         mOptionsMenuGroupActionsEnabled = false;
 
         mProviderStatus = -1;
@@ -635,7 +639,7 @@
             final MenuItem addContact = menu.findItem(R.id.menu_add);
             addContact.setActionView(mAddContactImageView);
             return true;
-        } else if (mRequest.getActionCode() == ContactsRequest.ACTION_DEFAULT ||
+        } else if (mRequest.getActionCode() == ContactsRequest.ACTION_ALL_CONTACTS ||
                 mRequest.getActionCode() == ContactsRequest.ACTION_STREQUENT) {
             inflater.inflate(R.menu.list, menu);
             return true;
@@ -663,10 +667,6 @@
             return true;
         }
 
-        if (mOptionsMenuCustomFilterChangeable != isCustomFilterChangeable()) {
-            return true;
-        }
-
         if (mListFragment != null && mListFragment.isOptionsMenuChanged()) {
             return true;
         }
@@ -686,13 +686,8 @@
         }
 
         MenuItem settings = menu.findItem(R.id.menu_settings);
-        settings.setVisible(!ContactsPreferenceActivity.isEmpty(this));
-
-        mOptionsMenuCustomFilterChangeable = isCustomFilterChangeable();
-
-        MenuItem displayGroups = menu.findItem(R.id.menu_display_groups);
-        if (displayGroups != null) {
-            displayGroups.setVisible(mOptionsMenuCustomFilterChangeable);
+        if (settings != null) {
+            settings.setVisible(!ContactsPreferenceActivity.isEmpty(this));
         }
 
         mOptionsMenuGroupActionsEnabled = areGroupActionsEnabled();
@@ -723,10 +718,6 @@
         return groupActionsEnabled;
     }
 
-    public boolean isCustomFilterChangeable() {
-        return mRequest != null && mRequest.getActionCode() == ContactsRequest.ACTION_DEFAULT;
-    }
-
     @Override
     public boolean onOptionsItemSelected(MenuItem item) {
         switch (item.getItemId()) {
@@ -853,7 +844,7 @@
 
             case SUBACTIVITY_EDIT_CONTACT:
             case SUBACTIVITY_NEW_CONTACT: {
-                if (resultCode == RESULT_OK) {
+                if (resultCode == RESULT_OK && mContactContentDisplayed) {
                     mRequest.setActionCode(ContactsRequest.ACTION_VIEW_CONTACT);
                     mListFragment.reloadDataAndSetSelectedUri(data.getData());
                 }
@@ -910,8 +901,7 @@
             default: {
                 // Bring up the search UI if the user starts typing
                 final int unicodeChar = event.getUnicodeChar();
-
-                if (unicodeChar != 0) {
+                if (unicodeChar != 0 && !Character.isWhitespace(unicodeChar)) {
                     String query = new String(new int[]{ unicodeChar }, 0, 1);
                     if (mHasActionBar) {
                         if (!mActionBarAdapter.isSearchMode()) {
diff --git a/src/com/android/contacts/activities/ContactDetailActivity.java b/src/com/android/contacts/activities/ContactDetailActivity.java
index 56e8353..0036256 100644
--- a/src/com/android/contacts/activities/ContactDetailActivity.java
+++ b/src/com/android/contacts/activities/ContactDetailActivity.java
@@ -22,6 +22,7 @@
 import com.android.contacts.R;
 import com.android.contacts.detail.ContactDetailFragment;
 import com.android.contacts.interactions.ContactDeletionInteraction;
+import com.android.contacts.util.PhoneCapabilityTester;
 
 import android.accounts.Account;
 import android.content.ActivityNotFoundException;
@@ -44,6 +45,23 @@
     public void onCreate(Bundle savedState) {
         super.onCreate(savedState);
 
+        if (PhoneCapabilityTester.isUsingTwoPanes(this)) {
+            // This activity must not be shown. We have to select the contact in the
+            // ContactBrowserActivity instead ==> Create a forward intent and finish
+            final Intent originalIntent = getIntent();
+            Intent intent = new Intent();
+            intent.setAction(originalIntent.getAction());
+            intent.setDataAndType(originalIntent.getData(), originalIntent.getType());
+            intent.setFlags(
+                    Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS | Intent.FLAG_ACTIVITY_FORWARD_RESULT
+                            | Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+
+            intent.setClass(this, ContactBrowserActivity.class);
+            startActivity(intent);
+            finish();
+            return;
+        }
+
         setContentView(R.layout.contact_detail_activity);
 
         mFragment = (ContactDetailFragment) getFragmentManager().findFragmentById(
diff --git a/src/com/android/contacts/activities/ContactEditorActivity.java b/src/com/android/contacts/activities/ContactEditorActivity.java
index 35f7413..cedde4e 100644
--- a/src/com/android/contacts/activities/ContactEditorActivity.java
+++ b/src/com/android/contacts/activities/ContactEditorActivity.java
@@ -53,8 +53,6 @@
     public static final String ACTION_SAVE_COMPLETED = "saveCompleted";
 
     private ContactEditorFragment mFragment;
-    private Button mDoneButton;
-    private Button mRevertButton;
 
     private DialogManager mDialogManager = new DialogManager(this);
 
@@ -90,22 +88,6 @@
         mFragment.setListener(mFragmentListener);
         Uri uri = Intent.ACTION_EDIT.equals(action) ? getIntent().getData() : null;
         mFragment.load(action, uri, getIntent().getExtras());
-
-        // Depending on the use-case, this activity has Done and Revert buttons or not.
-        mDoneButton = (Button) findViewById(R.id.done);
-        mRevertButton = (Button) findViewById(R.id.revert);
-        if (mDoneButton != null) mDoneButton.setOnClickListener(new OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                mFragment.save(SaveMode.CLOSE);
-            }
-        });
-        if (mRevertButton != null) mRevertButton.setOnClickListener(new OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                finish();
-            }
-        });
     }
 
     @Override
diff --git a/src/com/android/contacts/activities/ContactSelectionActivity.java b/src/com/android/contacts/activities/ContactSelectionActivity.java
index 4efc43f..c255ba1 100644
--- a/src/com/android/contacts/activities/ContactSelectionActivity.java
+++ b/src/com/android/contacts/activities/ContactSelectionActivity.java
@@ -23,7 +23,9 @@
 import com.android.contacts.list.ContactsIntentResolver;
 import com.android.contacts.list.ContactsRequest;
 import com.android.contacts.list.DirectoryListLoader;
+import com.android.contacts.list.EmailAddressPickerFragment;
 import com.android.contacts.list.OnContactPickerActionListener;
+import com.android.contacts.list.OnEmailAddressPickerActionListener;
 import com.android.contacts.list.OnPhoneNumberPickerActionListener;
 import com.android.contacts.list.OnPostalAddressPickerActionListener;
 import com.android.contacts.list.PhoneNumberPickerFragment;
@@ -171,6 +173,11 @@
                 break;
             }
 
+            case ContactsRequest.ACTION_PICK_EMAIL: {
+                setTitle(R.string.contactPickerActivityTitle);
+                break;
+            }
+
             case ContactsRequest.ACTION_CREATE_SHORTCUT_CALL: {
                 setTitle(R.string.callShortcutActivityTitle);
                 break;
@@ -236,6 +243,11 @@
                 break;
             }
 
+            case ContactsRequest.ACTION_PICK_EMAIL: {
+                mListFragment = new EmailAddressPickerFragment();
+                break;
+            }
+
             case ContactsRequest.ACTION_CREATE_SHORTCUT_CALL: {
                 PhoneNumberPickerFragment fragment = new PhoneNumberPickerFragment();
                 fragment.setShortcutAction(Intent.ACTION_CALL);
@@ -284,6 +296,9 @@
         } else if (mListFragment instanceof PostalAddressPickerFragment) {
             ((PostalAddressPickerFragment) mListFragment).setOnPostalAddressPickerActionListener(
                     new PostalAddressPickerActionListener());
+        } else if (mListFragment instanceof EmailAddressPickerFragment) {
+            ((EmailAddressPickerFragment) mListFragment).setOnEmailAddressPickerActionListener(
+                    new EmailAddressPickerActionListener());
         } else {
             throw new IllegalStateException("Unsupported list fragment type: " + mListFragment);
         }
@@ -334,6 +349,14 @@
         }
     }
 
+    private final class EmailAddressPickerActionListener implements
+            OnEmailAddressPickerActionListener {
+        @Override
+        public void onPickEmailAddressAction(Uri dataUri) {
+            returnPickerResult(dataUri);
+        }
+    }
+
     public void startActivityAndForwardResult(final Intent intent) {
         intent.setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
 
diff --git a/src/com/android/contacts/activities/ContactsFrontDoor.java b/src/com/android/contacts/activities/ContactsFrontDoor.java
index 3677cce..1f8a491 100644
--- a/src/com/android/contacts/activities/ContactsFrontDoor.java
+++ b/src/com/android/contacts/activities/ContactsFrontDoor.java
@@ -39,12 +39,12 @@
                         | Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
         intent.putExtra(EXTRA_FRONT_DOOR, true);
 
-        if (PhoneCapabilityTester.isPhone(this)) {
-            // Default to the normal dialtacts layout
-            intent.setClass(this, DialtactsActivity.class);
-        } else {
+        if (PhoneCapabilityTester.isUsingTwoPanes(this)) {
             // No tabs, just a contact list
             intent.setClass(this, ContactBrowserActivity.class);
+        } else {
+            // Default to the normal dialtacts layout
+            intent.setClass(this, DialtactsActivity.class);
         }
 
         startActivity(intent);
diff --git a/src/com/android/contacts/detail/ContactDetailFragment.java b/src/com/android/contacts/detail/ContactDetailFragment.java
index 42b3293..91e7f9e 100644
--- a/src/com/android/contacts/detail/ContactDetailFragment.java
+++ b/src/com/android/contacts/detail/ContactDetailFragment.java
@@ -27,9 +27,9 @@
 import com.android.contacts.TypePrecedence;
 import com.android.contacts.editor.SelectAccountDialogFragment;
 import com.android.contacts.model.AccountType;
-import com.android.contacts.model.AccountType.DataKind;
 import com.android.contacts.model.AccountType.EditType;
 import com.android.contacts.model.AccountTypeManager;
+import com.android.contacts.model.DataKind;
 import com.android.contacts.util.Constants;
 import com.android.contacts.util.DataStatus;
 import com.android.contacts.util.DateUtils;
@@ -1262,7 +1262,7 @@
 
         @Override
         public void onLoadFinished(Loader<ContactLoader.Result> loader, ContactLoader.Result data) {
-            if (!((ContactLoader)loader).getLookupUri().equals(mLookupUri)) {
+            if (!mLookupUri.equals(data.getUri())) {
                 return;
             }
 
diff --git a/src/com/android/contacts/editor/Editor.java b/src/com/android/contacts/editor/Editor.java
index d733e68..d87aea4 100644
--- a/src/com/android/contacts/editor/Editor.java
+++ b/src/com/android/contacts/editor/Editor.java
@@ -16,8 +16,8 @@
 
 package com.android.contacts.editor;
 
+import com.android.contacts.model.DataKind;
 import com.android.contacts.model.EntityDelta;
-import com.android.contacts.model.AccountType.DataKind;
 import com.android.contacts.model.EntityDelta.ValuesDelta;
 
 import android.provider.ContactsContract.Data;
diff --git a/src/com/android/contacts/editor/EventFieldEditorView.java b/src/com/android/contacts/editor/EventFieldEditorView.java
index 906dbad..f021deb 100644
--- a/src/com/android/contacts/editor/EventFieldEditorView.java
+++ b/src/com/android/contacts/editor/EventFieldEditorView.java
@@ -20,9 +20,9 @@
 import com.android.contacts.datepicker.DatePicker;
 import com.android.contacts.datepicker.DatePickerDialog;
 import com.android.contacts.datepicker.DatePickerDialog.OnDateSetListener;
-import com.android.contacts.model.AccountType.DataKind;
 import com.android.contacts.model.AccountType.EditField;
 import com.android.contacts.model.AccountType.EventEditType;
+import com.android.contacts.model.DataKind;
 import com.android.contacts.model.EntityDelta;
 import com.android.contacts.model.EntityDelta.ValuesDelta;
 import com.android.contacts.util.DateUtils;
diff --git a/src/com/android/contacts/editor/ExternalRawContactEditorView.java b/src/com/android/contacts/editor/ExternalRawContactEditorView.java
index aaa1e44..01286ff 100644
--- a/src/com/android/contacts/editor/ExternalRawContactEditorView.java
+++ b/src/com/android/contacts/editor/ExternalRawContactEditorView.java
@@ -20,7 +20,7 @@
 import com.android.contacts.R;
 import com.android.contacts.editor.ExternalRawContactEditorView.Listener;
 import com.android.contacts.model.AccountType;
-import com.android.contacts.model.AccountType.DataKind;
+import com.android.contacts.model.DataKind;
 import com.android.contacts.model.EntityDelta;
 import com.android.contacts.model.EntityDelta.ValuesDelta;
 import com.android.contacts.model.EntityModifier;
diff --git a/src/com/android/contacts/editor/GroupMembershipView.java b/src/com/android/contacts/editor/GroupMembershipView.java
index 8845aa3..d242a1b 100644
--- a/src/com/android/contacts/editor/GroupMembershipView.java
+++ b/src/com/android/contacts/editor/GroupMembershipView.java
@@ -19,7 +19,7 @@
 import com.android.contacts.GroupMetaDataLoader;
 import com.android.contacts.R;
 import com.android.contacts.interactions.GroupCreationDialogFragment;
-import com.android.contacts.model.AccountType.DataKind;
+import com.android.contacts.model.DataKind;
 import com.android.contacts.model.EntityDelta;
 import com.android.contacts.model.EntityDelta.ValuesDelta;
 import com.android.contacts.model.EntityModifier;
diff --git a/src/com/android/contacts/editor/KindSectionView.java b/src/com/android/contacts/editor/KindSectionView.java
index aaeafac..bc76ba8 100644
--- a/src/com/android/contacts/editor/KindSectionView.java
+++ b/src/com/android/contacts/editor/KindSectionView.java
@@ -18,7 +18,7 @@
 
 import com.android.contacts.R;
 import com.android.contacts.editor.Editor.EditorListener;
-import com.android.contacts.model.AccountType.DataKind;
+import com.android.contacts.model.DataKind;
 import com.android.contacts.model.EntityDelta;
 import com.android.contacts.model.EntityDelta.ValuesDelta;
 import com.android.contacts.model.EntityModifier;
diff --git a/src/com/android/contacts/editor/LabeledEditorView.java b/src/com/android/contacts/editor/LabeledEditorView.java
index a6815a7..96f234b 100644
--- a/src/com/android/contacts/editor/LabeledEditorView.java
+++ b/src/com/android/contacts/editor/LabeledEditorView.java
@@ -18,8 +18,8 @@
 
 import com.android.contacts.ContactsUtils;
 import com.android.contacts.R;
-import com.android.contacts.model.AccountType.DataKind;
 import com.android.contacts.model.AccountType.EditType;
+import com.android.contacts.model.DataKind;
 import com.android.contacts.model.EntityDelta;
 import com.android.contacts.model.EntityDelta.ValuesDelta;
 import com.android.contacts.model.EntityModifier;
diff --git a/src/com/android/contacts/editor/PhoneticNameEditorView.java b/src/com/android/contacts/editor/PhoneticNameEditorView.java
index d3aa00d..70e50a7 100644
--- a/src/com/android/contacts/editor/PhoneticNameEditorView.java
+++ b/src/com/android/contacts/editor/PhoneticNameEditorView.java
@@ -16,7 +16,7 @@
 
 package com.android.contacts.editor;
 
-import com.android.contacts.model.AccountType.DataKind;
+import com.android.contacts.model.DataKind;
 import com.android.contacts.model.EntityDelta;
 import com.android.contacts.model.EntityDelta.ValuesDelta;
 
diff --git a/src/com/android/contacts/editor/PhotoEditorView.java b/src/com/android/contacts/editor/PhotoEditorView.java
index 89633fd..6942912 100644
--- a/src/com/android/contacts/editor/PhotoEditorView.java
+++ b/src/com/android/contacts/editor/PhotoEditorView.java
@@ -17,8 +17,8 @@
 package com.android.contacts.editor;
 
 import com.android.contacts.R;
+import com.android.contacts.model.DataKind;
 import com.android.contacts.model.EntityDelta;
-import com.android.contacts.model.AccountType.DataKind;
 import com.android.contacts.model.EntityDelta.ValuesDelta;
 
 import android.content.Context;
diff --git a/src/com/android/contacts/editor/RawContactEditorView.java b/src/com/android/contacts/editor/RawContactEditorView.java
index 633b343..4813f29 100644
--- a/src/com/android/contacts/editor/RawContactEditorView.java
+++ b/src/com/android/contacts/editor/RawContactEditorView.java
@@ -19,8 +19,8 @@
 import com.android.contacts.GroupMetaDataLoader;
 import com.android.contacts.R;
 import com.android.contacts.model.AccountType;
-import com.android.contacts.model.AccountType.DataKind;
 import com.android.contacts.model.AccountType.EditType;
+import com.android.contacts.model.DataKind;
 import com.android.contacts.model.EntityDelta;
 import com.android.contacts.model.EntityDelta.ValuesDelta;
 import com.android.contacts.model.EntityModifier;
diff --git a/src/com/android/contacts/editor/StructuredNameEditorView.java b/src/com/android/contacts/editor/StructuredNameEditorView.java
index cf97c6c..e7277f9 100644
--- a/src/com/android/contacts/editor/StructuredNameEditorView.java
+++ b/src/com/android/contacts/editor/StructuredNameEditorView.java
@@ -16,7 +16,7 @@
 
 package com.android.contacts.editor;
 
-import com.android.contacts.model.AccountType.DataKind;
+import com.android.contacts.model.DataKind;
 import com.android.contacts.model.EntityDelta;
 import com.android.contacts.model.EntityDelta.ValuesDelta;
 
diff --git a/src/com/android/contacts/editor/TextFieldsEditorView.java b/src/com/android/contacts/editor/TextFieldsEditorView.java
index 031ab18..3187eaa 100644
--- a/src/com/android/contacts/editor/TextFieldsEditorView.java
+++ b/src/com/android/contacts/editor/TextFieldsEditorView.java
@@ -18,8 +18,8 @@
 
 import com.android.contacts.ContactsUtils;
 import com.android.contacts.R;
-import com.android.contacts.model.AccountType.DataKind;
 import com.android.contacts.model.AccountType.EditField;
+import com.android.contacts.model.DataKind;
 import com.android.contacts.model.EntityDelta;
 import com.android.contacts.model.EntityDelta.ValuesDelta;
 import com.android.contacts.util.ThemeUtils;
diff --git a/src/com/android/contacts/editor/ViewIdGenerator.java b/src/com/android/contacts/editor/ViewIdGenerator.java
index 93bb002..c3cd08b 100644
--- a/src/com/android/contacts/editor/ViewIdGenerator.java
+++ b/src/com/android/contacts/editor/ViewIdGenerator.java
@@ -16,8 +16,8 @@
 
 package com.android.contacts.editor;
 
+import com.android.contacts.model.DataKind;
 import com.android.contacts.model.EntityDelta;
-import com.android.contacts.model.AccountType.DataKind;
 import com.android.contacts.model.EntityDelta.ValuesDelta;
 
 import android.os.Bundle;
diff --git a/src/com/android/contacts/interactions/ContactDeletionInteraction.java b/src/com/android/contacts/interactions/ContactDeletionInteraction.java
index 08f8d00..f195c2f 100644
--- a/src/com/android/contacts/interactions/ContactDeletionInteraction.java
+++ b/src/com/android/contacts/interactions/ContactDeletionInteraction.java
@@ -206,8 +206,13 @@
 
         final Uri contactUri = Contacts.getLookupUri(contactId, lookupKey);
         showDialog(mMessageId, contactUri);
+
+        // We don't want onLoadFinished() calls any more, which may come when the database is
+        // updating.
+        getLoaderManager().destroyLoader(R.id.dialog_delete_contact_loader_id);
     }
 
+    @Override
     public void onLoaderReset(Loader<Cursor> loader) {
     }
 
@@ -235,7 +240,6 @@
     public void onDismiss(DialogInterface dialog) {
         mActive = false;
         mDialog = null;
-        getLoaderManager().destroyLoader(R.id.dialog_delete_contact_loader_id);
     }
 
     @Override
diff --git a/src/com/android/contacts/interactions/PhoneNumberInteraction.java b/src/com/android/contacts/interactions/PhoneNumberInteraction.java
index 277fa56..399b0ea 100644
--- a/src/com/android/contacts/interactions/PhoneNumberInteraction.java
+++ b/src/com/android/contacts/interactions/PhoneNumberInteraction.java
@@ -16,14 +16,19 @@
 package com.android.contacts.interactions;
 
 
+import com.google.i18n.phonenumbers.NumberParseException;
+import com.google.i18n.phonenumbers.PhoneNumberUtil;
+import com.google.i18n.phonenumbers.PhoneNumberUtil.MatchType;
+import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber;
+
 import com.android.contacts.Collapser;
 import com.android.contacts.Collapser.Collapsible;
 import com.android.contacts.ContactSaveService;
 import com.android.contacts.R;
 import com.android.contacts.model.AccountType;
-import com.android.contacts.model.AccountType.DataKind;
 import com.android.contacts.model.AccountType.StringInflater;
 import com.android.contacts.model.AccountTypeManager;
+import com.android.contacts.model.DataKind;
 
 import android.app.Activity;
 import android.app.AlertDialog;
@@ -46,7 +51,7 @@
 import android.provider.ContactsContract.Contacts;
 import android.provider.ContactsContract.Data;
 import android.provider.ContactsContract.RawContacts;
-import android.telephony.PhoneNumberUtils;
+import android.text.TextUtils;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -112,8 +117,16 @@
         }
 
         public boolean shouldCollapseWith(PhoneItem phoneItem) {
-            if (PhoneNumberUtils.compareStrictly(phoneNumber, phoneItem.phoneNumber)) {
-                return true;
+            try {
+                PhoneNumberUtil util = PhoneNumberUtil.getInstance();
+                PhoneNumber phoneNumber1 = util.parse(phoneNumber, "ZZ" /* Unknown */);
+                PhoneNumber phoneNumber2 = util.parse(phoneItem.phoneNumber, "ZZ" /* Unknown */);
+                MatchType matchType = util.isNumberMatch(phoneNumber1, phoneNumber2);
+                if (matchType == MatchType.SHORT_NSN_MATCH) {
+                    return true;
+                }
+            } catch (NumberParseException e) {
+                return TextUtils.equals(phoneNumber, phoneItem.phoneNumber);
             }
             return false;
         }
diff --git a/src/com/android/contacts/list/ContactBrowseListFragment.java b/src/com/android/contacts/list/ContactBrowseListFragment.java
index be920db..1ecfff1 100644
--- a/src/com/android/contacts/list/ContactBrowseListFragment.java
+++ b/src/com/android/contacts/list/ContactBrowseListFragment.java
@@ -583,7 +583,7 @@
 
     public void viewContact(Uri contactUri) {
         setSelectedContactUri(contactUri, false, false, true, false);
-        if (mListener != null) { mListener.onViewContactAction(contactUri); }
+        if (mListener != null) mListener.onViewContactAction(contactUri);
     }
 
     public void editContact(Uri contactUri) {
diff --git a/src/com/android/contacts/list/ContactsIntentResolver.java b/src/com/android/contacts/list/ContactsIntentResolver.java
index afe29df..3ef68d8 100644
--- a/src/com/android/contacts/list/ContactsIntentResolver.java
+++ b/src/com/android/contacts/list/ContactsIntentResolver.java
@@ -27,6 +27,7 @@
 import android.provider.Contacts.ContactMethods;
 import android.provider.Contacts.People;
 import android.provider.Contacts.Phones;
+import android.provider.ContactsContract.CommonDataKinds.Email;
 import android.provider.ContactsContract.CommonDataKinds.Phone;
 import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
 import android.provider.ContactsContract.Contacts;
@@ -95,6 +96,8 @@
             } else if (ContactMethods.CONTENT_POSTAL_TYPE.equals(resolvedType)) {
                 request.setActionCode(ContactsRequest.ACTION_PICK_POSTAL);
                 request.setLegacyCompatibilityMode(true);
+            } else if (Email.CONTENT_TYPE.equals(resolvedType)) {
+                request.setActionCode(ContactsRequest.ACTION_PICK_EMAIL);
             }
         } else if (Intent.ACTION_CREATE_SHORTCUT.equals(action)) {
             String component = intent.getComponent().getClassName();
diff --git a/src/com/android/contacts/list/ContactsRequest.java b/src/com/android/contacts/list/ContactsRequest.java
index aefa451..e20d189 100644
--- a/src/com/android/contacts/list/ContactsRequest.java
+++ b/src/com/android/contacts/list/ContactsRequest.java
@@ -62,6 +62,9 @@
     /** Show all postal addresses and pick them when clicking */
     public static final int ACTION_PICK_POSTAL = 100;
 
+    /** Show all postal addresses and pick them when clicking */
+    public static final int ACTION_PICK_EMAIL = 105;
+
     /** Show all contacts and create a shortcut for the picked contact */
     public static final int ACTION_CREATE_SHORTCUT_CONTACT = 110;
 
diff --git a/src/com/android/contacts/list/EmailAddressListAdapter.java b/src/com/android/contacts/list/EmailAddressListAdapter.java
new file mode 100644
index 0000000..96c69f9
--- /dev/null
+++ b/src/com/android/contacts/list/EmailAddressListAdapter.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.contacts.list;
+
+import android.content.ContentUris;
+import android.content.Context;
+import android.content.CursorLoader;
+import android.database.Cursor;
+import android.net.Uri;
+import android.net.Uri.Builder;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.ContactCounts;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.text.TextUtils;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * A cursor adapter for the {@link Email#CONTENT_TYPE} content type.
+ */
+public class EmailAddressListAdapter extends ContactEntryListAdapter {
+
+    static final String[] EMAILS_PROJECTION = new String[] {
+        Email._ID,                       // 0
+        Email.TYPE,                      // 1
+        Email.LABEL,                     // 2
+        Email.DATA,                      // 3
+        Email.DISPLAY_NAME_PRIMARY,      // 4
+        Email.DISPLAY_NAME_ALTERNATIVE,  // 5
+        Email.PHOTO_ID,                  // 6
+    };
+
+    protected static final int EMAIL_ID_COLUMN_INDEX = 0;
+    protected static final int EMAIL_TYPE_COLUMN_INDEX = 1;
+    protected static final int EMAIL_LABEL_COLUMN_INDEX = 2;
+    protected static final int EMAIL_ADDRESS_COLUMN_INDEX = 3;
+    protected static final int EMAIL_PRIMARY_DISPLAY_NAME_COLUMN_INDEX = 4;
+    protected static final int EMAIL_ALTERNATIVE_DISPLAY_NAME_COLUMN_INDEX = 5;
+    protected static final int EMAIL_PHOTO_ID_COLUMN_INDEX = 6;
+
+    private CharSequence mUnknownNameText;
+    private int mDisplayNameColumnIndex;
+    private int mAlternativeDisplayNameColumnIndex;
+
+    public EmailAddressListAdapter(Context context) {
+        super(context);
+
+        mUnknownNameText = context.getText(android.R.string.unknownName);
+    }
+
+    @Override
+    public void configureLoader(CursorLoader loader, long directoryId) {
+        final Builder builder;
+        if (isSearchMode()) {
+            builder = Email.CONTENT_FILTER_URI.buildUpon();
+            String query = getQueryString();
+            builder.appendPath(TextUtils.isEmpty(query) ? "" : query);
+        } else {
+            builder = Email.CONTENT_URI.buildUpon();
+        }
+        builder.appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY,
+                String.valueOf(directoryId));
+        applyDataRestriction(builder);
+        loader.setUri(builder.build());
+        loader.setProjection(EMAILS_PROJECTION);
+
+        if (getSortOrder() == ContactsContract.Preferences.SORT_ORDER_PRIMARY) {
+            loader.setSortOrder(Email.SORT_KEY_PRIMARY);
+        } else {
+            loader.setSortOrder(Email.SORT_KEY_ALTERNATIVE);
+        }
+    }
+
+    protected static Builder buildSectionIndexerUri(Uri uri) {
+        return uri.buildUpon()
+                .appendQueryParameter(ContactCounts.ADDRESS_BOOK_INDEX_EXTRAS, "true");
+    }
+
+    @Override
+    public String getContactDisplayName(int position) {
+        return ((Cursor)getItem(position)).getString(mDisplayNameColumnIndex);
+    }
+
+    @Override
+    public void setContactNameDisplayOrder(int displayOrder) {
+        super.setContactNameDisplayOrder(displayOrder);
+        if (getContactNameDisplayOrder() == ContactsContract.Preferences.DISPLAY_ORDER_PRIMARY) {
+            mDisplayNameColumnIndex = EMAIL_PRIMARY_DISPLAY_NAME_COLUMN_INDEX;
+            mAlternativeDisplayNameColumnIndex = EMAIL_ALTERNATIVE_DISPLAY_NAME_COLUMN_INDEX;
+        } else {
+            mDisplayNameColumnIndex = EMAIL_ALTERNATIVE_DISPLAY_NAME_COLUMN_INDEX;
+            mAlternativeDisplayNameColumnIndex = EMAIL_PRIMARY_DISPLAY_NAME_COLUMN_INDEX;
+        }
+    }
+
+    /**
+     * Builds a {@link Data#CONTENT_URI} for the current cursor
+     * position.
+     */
+    public Uri getDataUri(int position) {
+        long id = ((Cursor)getItem(position)).getLong(EMAIL_ID_COLUMN_INDEX);
+        return ContentUris.withAppendedId(Data.CONTENT_URI, id);
+    }
+
+    @Override
+    protected View newView(Context context, int partition, Cursor cursor, int position,
+            ViewGroup parent) {
+        final ContactListItemView view = new ContactListItemView(context, null);
+        view.setUnknownNameText(mUnknownNameText);
+        view.setTextWithHighlightingFactory(getTextWithHighlightingFactory());
+        view.setQuickContactEnabled(isQuickContactEnabled());
+        return view;
+    }
+
+    @Override
+    protected void bindView(View itemView, int partition, Cursor cursor, int position) {
+        ContactListItemView view = (ContactListItemView)itemView;
+        bindSectionHeaderAndDivider(view, position);
+        bindName(view, cursor);
+        bindPhoto(view, cursor);
+        bindEmailAddress(view, cursor);
+    }
+
+    protected void bindEmailAddress(ContactListItemView view, Cursor cursor) {
+        CharSequence label = null;
+        if (!cursor.isNull(EMAIL_TYPE_COLUMN_INDEX)) {
+            final int type = cursor.getInt(EMAIL_TYPE_COLUMN_INDEX);
+            final String customLabel = cursor.getString(EMAIL_LABEL_COLUMN_INDEX);
+
+            // TODO cache
+            label = Email.getTypeLabel(getContext().getResources(), type, customLabel);
+        }
+        view.setLabel(label);
+        view.showData(cursor, EMAIL_ADDRESS_COLUMN_INDEX);
+    }
+
+    protected void bindSectionHeaderAndDivider(final ContactListItemView view, int position) {
+        final int section = getSectionForPosition(position);
+        if (getPositionForSection(section) == position) {
+            String title = (String)getSections()[section];
+            view.setSectionHeader(title);
+        } else {
+            view.setDividerVisible(false);
+            view.setSectionHeader(null);
+        }
+
+        // move the divider for the last item in a section
+        if (getPositionForSection(section + 1) - 1 == position) {
+            view.setDividerVisible(false);
+        } else {
+            view.setDividerVisible(true);
+        }
+    }
+
+    protected void bindName(final ContactListItemView view, Cursor cursor) {
+        view.showDisplayName(cursor, mDisplayNameColumnIndex, isNameHighlightingEnabled(),
+                mAlternativeDisplayNameColumnIndex);
+//        view.showPhoneticName(cursor, PHONE_PHONETIC_NAME_COLUMN_INDEX);
+    }
+
+    protected void bindPhoto(final ContactListItemView view, Cursor cursor) {
+        long photoId = 0;
+        if (!cursor.isNull(EMAIL_PHOTO_ID_COLUMN_INDEX)) {
+            photoId = cursor.getLong(EMAIL_PHOTO_ID_COLUMN_INDEX);
+        }
+
+        getPhotoLoader().loadPhoto(view.getPhotoView(), photoId);
+    }
+//
+//    protected void bindSearchSnippet(final ContactListItemView view, Cursor cursor) {
+//        view.showSnippet(cursor, SUMMARY_SNIPPET_MIMETYPE_COLUMN_INDEX,
+//                SUMMARY_SNIPPET_DATA1_COLUMN_INDEX, SUMMARY_SNIPPET_DATA4_COLUMN_INDEX);
+//    }
+
+}
diff --git a/src/com/android/contacts/list/EmailAddressPickerFragment.java b/src/com/android/contacts/list/EmailAddressPickerFragment.java
new file mode 100644
index 0000000..168e135
--- /dev/null
+++ b/src/com/android/contacts/list/EmailAddressPickerFragment.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.contacts.list;
+
+import com.android.contacts.R;
+
+import android.net.Uri;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * Fragment containing an email list for picking.
+ */
+public class EmailAddressPickerFragment extends ContactEntryListFragment<ContactEntryListAdapter> {
+    private OnEmailAddressPickerActionListener mListener;
+
+    public EmailAddressPickerFragment() {
+        setQuickContactEnabled(false);
+        setPhotoLoaderEnabled(true);
+        setSectionHeaderDisplayEnabled(true);
+        setDirectorySearchMode(DirectoryListLoader.SEARCH_MODE_DATA_SHORTCUT);
+    }
+
+    public void setOnEmailAddressPickerActionListener(OnEmailAddressPickerActionListener listener) {
+        mListener = listener;
+    }
+
+    @Override
+    protected void onItemClick(int position, long id) {
+        EmailAddressListAdapter adapter = (EmailAddressListAdapter)getAdapter();
+        pickEmailAddress(adapter.getDataUri(position));
+    }
+
+    @Override
+    protected ContactEntryListAdapter createListAdapter() {
+        EmailAddressListAdapter adapter = new EmailAddressListAdapter(getActivity());
+        adapter.setSectionHeaderDisplayEnabled(true);
+        adapter.setDisplayPhotos(true);
+        return adapter;
+    }
+
+    @Override
+    protected View inflateView(LayoutInflater inflater, ViewGroup container) {
+        return inflater.inflate(R.layout.contacts_list_content, null);
+    }
+
+    private void pickEmailAddress(Uri uri) {
+        mListener.onPickEmailAddressAction(uri);
+    }
+}
diff --git a/src/com/android/contacts/list/OnEmailAddressPickerActionListener.java b/src/com/android/contacts/list/OnEmailAddressPickerActionListener.java
new file mode 100644
index 0000000..e785323
--- /dev/null
+++ b/src/com/android/contacts/list/OnEmailAddressPickerActionListener.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.contacts.list;
+
+import android.net.Uri;
+
+/**
+ * Action callbacks that can be sent by a email address picker.
+ */
+public interface OnEmailAddressPickerActionListener  {
+
+    /**
+     * Returns the selected phone number to the requester.
+     */
+    void onPickEmailAddressAction(Uri dataUri);
+}
diff --git a/src/com/android/contacts/list/PostalAddressListAdapter.java b/src/com/android/contacts/list/PostalAddressListAdapter.java
index e622ec6..8b3c75d 100644
--- a/src/com/android/contacts/list/PostalAddressListAdapter.java
+++ b/src/com/android/contacts/list/PostalAddressListAdapter.java
@@ -131,7 +131,7 @@
             final String customLabel = cursor.getString(POSTAL_LABEL_COLUMN_INDEX);
 
             // TODO cache
-            label = StructuredPostal.getTypeLabel(getContext().getResources(), type, label);
+            label = StructuredPostal.getTypeLabel(getContext().getResources(), type, customLabel);
         }
         view.setLabel(label);
         view.showData(cursor, POSTAL_ADDRESS_COLUMN_INDEX);
diff --git a/src/com/android/contacts/list/PostalAddressPickerFragment.java b/src/com/android/contacts/list/PostalAddressPickerFragment.java
index f14b718..5f7ca56 100644
--- a/src/com/android/contacts/list/PostalAddressPickerFragment.java
+++ b/src/com/android/contacts/list/PostalAddressPickerFragment.java
@@ -73,7 +73,7 @@
         return inflater.inflate(R.layout.contacts_list_content, null);
     }
 
-    public void pickPostalAddress(Uri uri) {
+    private void pickPostalAddress(Uri uri) {
         mListener.onPickPostalAddressAction(uri);
     }
 }
diff --git a/src/com/android/contacts/model/AccountType.java b/src/com/android/contacts/model/AccountType.java
index aef5c06..5dda38e 100644
--- a/src/com/android/contacts/model/AccountType.java
+++ b/src/com/android/contacts/model/AccountType.java
@@ -30,15 +30,12 @@
 import android.provider.ContactsContract.Contacts;
 import android.provider.ContactsContract.Data;
 import android.provider.ContactsContract.RawContacts;
-import android.view.View;
 import android.widget.EditText;
 
-import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
-import java.util.List;
 
 /**
  * Internal structure that represents constraints and styles for a specific data
@@ -160,87 +157,6 @@
     }
 
     /**
-     * Description of a specific data type, usually marked by a unique
-     * {@link Data#MIMETYPE}. Includes details about how to view and edit
-     * {@link Data} rows of this kind, including the possible {@link EditType}
-     * labels and editable {@link EditField}.
-     */
-    public static class DataKind {
-
-        public static final String PSEUDO_MIME_TYPE_DISPLAY_NAME = "#displayName";
-        public static final String PSEUDO_MIME_TYPE_PHONETIC_NAME = "#phoneticName";
-        public static final String PSEUDO_COLUMN_PHONETIC_NAME = "#phoneticName";
-
-        public String resPackageName;
-        public String mimeType;
-        public int titleRes;
-        public int iconRes;
-        public int iconAltRes;
-        public int weight;
-        public boolean editable;
-
-        /**
-         * If this is true (default), the user can add and remove values.
-         * If false, the editor will always show a single field (which might be empty).
-         */
-        public boolean isList;
-
-        public StringInflater actionHeader;
-        public StringInflater actionAltHeader;
-        public StringInflater actionBody;
-
-        public boolean actionBodySocial = false;
-
-        public String typeColumn;
-
-        /**
-         * Maximum number of values allowed in the list. -1 represents infinity.
-         * If {@link DataKind#isList} is false, this value is ignored.
-         */
-        public int typeOverallMax;
-
-        public List<EditType> typeList;
-        public List<EditField> fieldList;
-
-        public ContentValues defaultValues;
-
-        public Class<? extends View> editorClass;
-
-        /**
-         * If this is a date field, this specifies the format of the date when saving. The
-         * date includes year, month and day. If this is not a date field or the date field is not
-         * editable, this value should be ignored.
-         */
-        public SimpleDateFormat dateFormatWithoutYear;
-
-        /**
-         * If this is a date field, this specifies the format of the date when saving. The
-         * date includes month and day. If this is not a date field, the field is not editable or
-         * dates without year are not supported, this value should be ignored.
-         */
-        public SimpleDateFormat dateFormatWithYear;
-
-        public DataKind() {
-        }
-
-        public DataKind(String mimeType, int titleRes, int iconRes, int weight, boolean editable) {
-            this(mimeType, titleRes, iconRes, weight, editable, null);
-        }
-
-        public DataKind(String mimeType, int titleRes, int iconRes, int weight, boolean editable,
-                Class<? extends View> editorClass) {
-            this.mimeType = mimeType;
-            this.titleRes = titleRes;
-            this.iconRes = iconRes;
-            this.weight = weight;
-            this.editable = editable;
-            this.isList = true;
-            this.typeOverallMax = -1;
-            this.editorClass = editorClass;
-        }
-    }
-
-    /**
      * Description of a specific "type" or "label" of a {@link DataKind} row,
      * such as {@link Phone#TYPE_WORK}. Includes constraints on total number of
      * rows a {@link Contacts} may have of this type, and details on how
diff --git a/src/com/android/contacts/model/AccountTypeManager.java b/src/com/android/contacts/model/AccountTypeManager.java
index 06bb9bd..58195a1 100644
--- a/src/com/android/contacts/model/AccountTypeManager.java
+++ b/src/com/android/contacts/model/AccountTypeManager.java
@@ -16,7 +16,6 @@
 
 package com.android.contacts.model;
 
-import com.android.contacts.model.AccountType.DataKind;
 import com.google.android.collect.Lists;
 import com.google.android.collect.Maps;
 import com.google.i18n.phonenumbers.PhoneNumberUtil;
diff --git a/src/com/android/contacts/model/DataKind.java b/src/com/android/contacts/model/DataKind.java
new file mode 100644
index 0000000..837dafe
--- /dev/null
+++ b/src/com/android/contacts/model/DataKind.java
@@ -0,0 +1,93 @@
+package com.android.contacts.model;
+
+import com.android.contacts.model.AccountType.EditField;
+import com.android.contacts.model.AccountType.EditType;
+import com.android.contacts.model.AccountType.StringInflater;
+
+import android.content.ContentValues;
+import android.provider.ContactsContract.Data;
+import android.view.View;
+
+import java.text.SimpleDateFormat;
+import java.util.List;
+
+/**
+ * Description of a specific data type, usually marked by a unique
+ * {@link Data#MIMETYPE}. Includes details about how to view and edit
+ * {@link Data} rows of this kind, including the possible {@link EditType}
+ * labels and editable {@link EditField}.
+ */
+public class DataKind {
+
+    public static final String PSEUDO_MIME_TYPE_DISPLAY_NAME = "#displayName";
+    public static final String PSEUDO_MIME_TYPE_PHONETIC_NAME = "#phoneticName";
+    public static final String PSEUDO_COLUMN_PHONETIC_NAME = "#phoneticName";
+
+    public String resPackageName;
+    public String mimeType;
+    public int titleRes;
+    public int iconRes;
+    public int iconAltRes;
+    public int weight;
+    public boolean editable;
+
+    /**
+     * If this is true (default), the user can add and remove values.
+     * If false, the editor will always show a single field (which might be empty).
+     */
+    public boolean isList;
+
+    public StringInflater actionHeader;
+    public StringInflater actionAltHeader;
+    public StringInflater actionBody;
+
+    public boolean actionBodySocial = false;
+
+    public String typeColumn;
+
+    /**
+     * Maximum number of values allowed in the list. -1 represents infinity.
+     * If {@link DataKind#isList} is false, this value is ignored.
+     */
+    public int typeOverallMax;
+
+    public List<EditType> typeList;
+    public List<EditField> fieldList;
+
+    public ContentValues defaultValues;
+
+    public Class<? extends View> editorClass;
+
+    /**
+     * If this is a date field, this specifies the format of the date when saving. The
+     * date includes year, month and day. If this is not a date field or the date field is not
+     * editable, this value should be ignored.
+     */
+    public SimpleDateFormat dateFormatWithoutYear;
+
+    /**
+     * If this is a date field, this specifies the format of the date when saving. The
+     * date includes month and day. If this is not a date field, the field is not editable or
+     * dates without year are not supported, this value should be ignored.
+     */
+    public SimpleDateFormat dateFormatWithYear;
+
+    public DataKind() {
+    }
+
+    public DataKind(String mimeType, int titleRes, int iconRes, int weight, boolean editable) {
+        this(mimeType, titleRes, iconRes, weight, editable, null);
+    }
+
+    public DataKind(String mimeType, int titleRes, int iconRes, int weight, boolean editable,
+            Class<? extends View> editorClass) {
+        this.mimeType = mimeType;
+        this.titleRes = titleRes;
+        this.iconRes = iconRes;
+        this.weight = weight;
+        this.editable = editable;
+        this.isList = true;
+        this.typeOverallMax = -1;
+        this.editorClass = editorClass;
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/contacts/model/EntityModifier.java b/src/com/android/contacts/model/EntityModifier.java
index 1e014ef..3d40f11 100644
--- a/src/com/android/contacts/model/EntityModifier.java
+++ b/src/com/android/contacts/model/EntityModifier.java
@@ -17,7 +17,6 @@
 package com.android.contacts.model;
 
 import com.android.contacts.ContactsUtils;
-import com.android.contacts.model.AccountType.DataKind;
 import com.android.contacts.model.AccountType.EditField;
 import com.android.contacts.model.AccountType.EditType;
 import com.android.contacts.model.EntityDelta.ValuesDelta;
diff --git a/src/com/android/contacts/model/GoogleAccountType.java b/src/com/android/contacts/model/GoogleAccountType.java
index af25691..7983a65 100644
--- a/src/com/android/contacts/model/GoogleAccountType.java
+++ b/src/com/android/contacts/model/GoogleAccountType.java
@@ -63,9 +63,10 @@
 
         kind.typeColumn = Phone.TYPE;
         kind.typeList = Lists.newArrayList();
-        kind.typeList.add(buildPhoneType(Phone.TYPE_HOME));
         kind.typeList.add(buildPhoneType(Phone.TYPE_MOBILE));
         kind.typeList.add(buildPhoneType(Phone.TYPE_WORK));
+        kind.typeList.add(buildPhoneType(Phone.TYPE_HOME));
+        kind.typeList.add(buildPhoneType(Phone.TYPE_MAIN));
         kind.typeList.add(buildPhoneType(Phone.TYPE_FAX_WORK).setSecondary(true));
         kind.typeList.add(buildPhoneType(Phone.TYPE_FAX_HOME).setSecondary(true));
         kind.typeList.add(buildPhoneType(Phone.TYPE_PAGER).setSecondary(true));
diff --git a/src/com/android/contacts/quickcontact/DataAction.java b/src/com/android/contacts/quickcontact/DataAction.java
index bd59856..787d482 100644
--- a/src/com/android/contacts/quickcontact/DataAction.java
+++ b/src/com/android/contacts/quickcontact/DataAction.java
@@ -2,7 +2,7 @@
 
 import com.android.contacts.ContactsUtils;
 import com.android.contacts.R;
-import com.android.contacts.model.AccountType.DataKind;
+import com.android.contacts.model.DataKind;
 import com.android.contacts.util.Constants;
 import com.android.contacts.util.PhoneCapabilityTester;
 
diff --git a/src/com/android/contacts/quickcontact/FloatingChildLayout.java b/src/com/android/contacts/quickcontact/FloatingChildLayout.java
new file mode 100644
index 0000000..ddba609
--- /dev/null
+++ b/src/com/android/contacts/quickcontact/FloatingChildLayout.java
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.contacts.quickcontact;
+
+import com.android.contacts.R;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.animation.Animation;
+import android.view.animation.Animation.AnimationListener;
+import android.view.animation.AnimationUtils;
+import android.widget.FrameLayout;
+import android.widget.PopupWindow;
+
+/**
+ * Layout containing single child {@link View} which it attempts to center
+ * around {@link #setChildTargetScreen(Rect)}.
+ * <p>
+ * Updates drawable state to be {@link android.R.attr#state_first} when child is
+ * above target, and {@link android.R.attr#state_last} when child is below
+ * target. Also updates {@link Drawable#setLevel(int)} on child
+ * {@link View#getBackground()} to reflect horizontal center of target.
+ * <p>
+ * The reason for this approach is because target {@link Rect} is in screen
+ * coordinates disregarding decor insets; otherwise something like
+ * {@link PopupWindow} might work better.
+ */
+public class FloatingChildLayout extends FrameLayout {
+    private static final String TAG = "FloatingChild";
+
+    public FloatingChildLayout(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    private View mChild;
+
+    private Rect mTargetScreen = new Rect();
+
+    private int mCalloutState = 0;
+    private int mCalloutLeft;
+
+    @Override
+    protected void onFinishInflate() {
+        mChild = findViewById(android.R.id.content);
+        mChild.setDuplicateParentStateEnabled(true);
+    }
+
+    public View getChild() {
+        return mChild;
+    }
+
+    /**
+     * Set {@link Rect} in screen coordinates that {@link #getChild()} should be
+     * centered around.
+     */
+    public void setChildTargetScreen(Rect targetScreen) {
+        mTargetScreen = targetScreen;
+        requestLayout();
+    }
+
+    /**
+     * Return {@link #mTargetScreen} in local window coordinates, taking any
+     * decor insets into account.
+     */
+    private Rect getTargetInWindow() {
+        final Rect windowScreen = new Rect();
+        getWindowVisibleDisplayFrame(windowScreen);
+
+        final Rect target = new Rect(mTargetScreen);
+        target.offset(-windowScreen.left, -windowScreen.top);
+        return target;
+    }
+
+    private void updateCallout(int calloutState, int calloutLeft) {
+        if (mCalloutState != calloutState) {
+            mCalloutState = calloutState;
+            mChild.refreshDrawableState();
+        }
+
+        final Drawable background = mChild.getBackground();
+        if (background != null && mCalloutLeft != calloutLeft) {
+            mCalloutLeft = calloutLeft;
+            background.setLevel(calloutLeft);
+        }
+    }
+
+    @Override
+    protected int[] onCreateDrawableState(int extraSpace) {
+        final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
+        mergeDrawableStates(drawableState, new int[] { mCalloutState });
+        return drawableState;
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+
+        final View child = mChild;
+        final Rect target = getTargetInWindow();
+
+        final int childWidth = child.getMeasuredWidth();
+        final int childHeight = child.getMeasuredHeight();
+
+        // default is no callout, left-aligned, and vertically centered
+        int calloutState = 0;
+        int childLeft = target.left;
+        int childTop = target.centerY() - (childHeight / 2);
+
+        // when target is wide, horizontally center instead of left-align
+        if (target.width() > childWidth / 2) {
+            childLeft = target.centerX() - (childWidth / 2);
+        }
+
+        final int areaAboveTarget = target.top;
+        final int areaBelowTarget = getHeight() - target.bottom;
+
+        if (areaAboveTarget >= childHeight) {
+            // enough room above target, place above and callout down
+            calloutState = android.R.attr.state_first;
+            childTop = target.top - childHeight;
+
+        } else if (areaBelowTarget >= childHeight) {
+            // enough room below target, place below and callout up
+            calloutState = android.R.attr.state_last;
+            childTop = target.bottom;
+        }
+
+        // when child is outside bounds, nudge back inside
+        childLeft = clampDimension(childLeft, childWidth, getWidth());
+        childTop = clampDimension(childTop, childHeight, getHeight());
+
+        final int calloutLeft = target.centerX() - childLeft;
+        updateCallout(calloutState, calloutLeft);
+        layoutChild(child, childLeft, childTop);
+
+    }
+
+    private static int clampDimension(int value, int size, int max) {
+        // when larger than bounds, just center
+        if (size > max) {
+            return (max - size) / 2;
+        }
+
+        // clamp to lower bound
+        value = Math.max(value, 0);
+        // clamp to higher bound
+        value = Math.min(value, max - size);
+
+        return value;
+    }
+
+    private static void layoutChild(View child, int left, int top) {
+        child.layout(left, top, left + child.getMeasuredWidth(), top + child.getMeasuredHeight());
+    }
+
+    /**
+     * Begin animating {@link #getChild()} visible.
+     */
+    public void showChild() {
+        final boolean calloutAbove = mCalloutState == android.R.attr.state_first;
+        final Animation anim = AnimationUtils.loadAnimation(getContext(),
+                calloutAbove ? R.anim.quickcontact_above_enter : R.anim.quickcontact_below_enter);
+        mChild.startAnimation(anim);
+        mChild.setVisibility(View.VISIBLE);
+    }
+
+    /**
+     * Begin animating {@link #getChild()} invisible.
+     */
+    public void hideChild(final Runnable onAnimationEnd) {
+        final boolean calloutAbove = mCalloutState == android.R.attr.state_first;
+        final Animation anim = AnimationUtils.loadAnimation(getContext(),
+                calloutAbove ? R.anim.quickcontact_above_exit : R.anim.quickcontact_below_exit);
+
+        if (onAnimationEnd != null) {
+            anim.setAnimationListener(new AnimationListener() {
+                /** {@inheritDoc} */
+                public void onAnimationStart(Animation animation) {
+                    // ignored
+                }
+
+                /** {@inheritDoc} */
+                public void onAnimationRepeat(Animation animation) {
+                    // ignored
+                }
+
+                /** {@inheritDoc} */
+                public void onAnimationEnd(Animation animation) {
+                    onAnimationEnd.run();
+                }
+            });
+        }
+
+        mChild.startAnimation(anim);
+        mChild.setVisibility(View.INVISIBLE);
+    }
+
+    private View.OnTouchListener mOutsideTouchListener;
+
+    public void setOnOutsideTouchListener(View.OnTouchListener listener) {
+        mOutsideTouchListener = listener;
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        // at this point, touch wasn't handled by child view; assume outside
+        if (mOutsideTouchListener != null) {
+            return mOutsideTouchListener.onTouch(this, event);
+        } else {
+            return false;
+        }
+    }
+}
diff --git a/src/com/android/contacts/quickcontact/QuickContactActivity.java b/src/com/android/contacts/quickcontact/QuickContactActivity.java
deleted file mode 100644
index 5032386..0000000
--- a/src/com/android/contacts/quickcontact/QuickContactActivity.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.contacts.quickcontact;
-
-import com.android.contacts.ContactsActivity;
-
-import android.content.ContentUris;
-import android.content.Intent;
-import android.graphics.Rect;
-import android.net.Uri;
-import android.os.Bundle;
-import android.provider.ContactsContract.QuickContact;
-import android.provider.ContactsContract.RawContacts;
-import android.util.Log;
-
-/**
- * Stub translucent activity that just shows {@link QuickContactWindow} floating
- * above the caller. This temporary hack should eventually be replaced with
- * direct framework support.
- */
-public final class QuickContactActivity extends ContactsActivity
-        implements QuickContactWindow.OnDismissListener {
-    private static final String TAG = "QuickContactActivity";
-
-    static final boolean LOGV = false;
-    static final boolean FORCE_CREATE = true;
-
-    private QuickContactWindow mQuickContact;
-
-    @Override
-    protected void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-        if (LOGV) Log.d(TAG, "onCreate");
-
-        this.onNewIntent(getIntent());
-    }
-
-    @Override
-    public void onNewIntent(Intent intent) {
-        super.onNewIntent(intent);
-        if (LOGV) Log.d(TAG, "onNewIntent");
-
-        if (QuickContactWindow.TRACE_LAUNCH) {
-            android.os.Debug.startMethodTracing(QuickContactWindow.TRACE_TAG);
-        }
-
-        if (mQuickContact == null || FORCE_CREATE) {
-            if (LOGV) Log.d(TAG, "Preparing window");
-            mQuickContact = new QuickContactWindow(this, this);
-        }
-
-        // Use our local window token for now
-        Uri lookupUri = intent.getData();
-        // Check to see whether it comes from the old version.
-        if (android.provider.Contacts.AUTHORITY.equals(lookupUri.getAuthority())) {
-            final long rawContactId = ContentUris.parseId(lookupUri);
-            lookupUri = RawContacts.getContactLookupUri(getContentResolver(),
-                    ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId));
-        }
-        final Bundle extras = intent.getExtras();
-
-        // Read requested parameters for displaying
-        final Rect target = intent.getSourceBounds();
-        final int mode = extras.getInt(QuickContact.EXTRA_MODE, QuickContact.MODE_MEDIUM);
-        final String[] excludeMimes = extras.getStringArray(QuickContact.EXTRA_EXCLUDE_MIMES);
-
-        mQuickContact.show(lookupUri, target, mode, excludeMimes);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public void onBackPressed() {
-        if (LOGV) Log.w(TAG, "Unexpected back captured by stub activity");
-        finish();
-    }
-
-    @Override
-    protected void onPause() {
-        super.onPause();
-        if (LOGV) Log.d(TAG, "onPause");
-
-        // Dismiss any dialog when pausing
-        mQuickContact.dismiss();
-    }
-
-    @Override
-    protected void onDestroy() {
-        super.onDestroy();
-        if (LOGV) Log.d(TAG, "onDestroy");
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public void onDismiss(QuickContactWindow dialog) {
-        if (LOGV) Log.d(TAG, "onDismiss");
-
-        if (isTaskRoot() && !FORCE_CREATE) {
-            // Instead of stopping, simply push this to the back of the stack.
-            // This is only done when running at the top of the stack;
-            // otherwise, we have been launched by someone else so need to
-            // allow the user to go back to the caller.
-            moveTaskToBack(false);
-        } else {
-            finish();
-        }
-    }
-}
diff --git a/src/com/android/contacts/quickcontact/QuickContactBackgroundDrawable.java b/src/com/android/contacts/quickcontact/QuickContactBackgroundDrawable.java
index 9118480..15311f9 100644
--- a/src/com/android/contacts/quickcontact/QuickContactBackgroundDrawable.java
+++ b/src/com/android/contacts/quickcontact/QuickContactBackgroundDrawable.java
@@ -26,37 +26,43 @@
 import android.graphics.drawable.Drawable;
 
 /**
- * Drawable that draws three pictures for the QuickContact-Background. ColorFilter is ignored
+ * Background {@link Drawable} for {@link QuickContactWindow} that draws arrow
+ * centered around requested position.
  */
 public class QuickContactBackgroundDrawable extends Drawable {
     private Drawable mLeftDrawable;
     private Drawable mMiddleDrawable;
     private Drawable mRightDrawable;
-    private int mRequestedX = Integer.MIN_VALUE;
-    private boolean mBoundsSet = false;
-    private int mAlpha = -1;
+
     private int mBottomOverride = Integer.MIN_VALUE;
 
+    public QuickContactBackgroundDrawable(Resources res) {
+        mLeftDrawable = res.getDrawable(R.drawable.quickactions_arrow_left_holo_light);
+        mMiddleDrawable = res.getDrawable(R.drawable.quickactions_arrow_middle_holo_light);
+        mRightDrawable = res.getDrawable(R.drawable.quickactions_arrow_right_holo_light);
+    }
+
     @Override
     public void setAlpha(int alpha) {
-        mAlpha = alpha;
-        setChildAlpha();
+        mLeftDrawable.setAlpha(alpha);
+        mMiddleDrawable.setAlpha(alpha);
+        mRightDrawable.setAlpha(alpha);
     }
 
     /**
-     * Overrides the bottom bounds. This is used for the animation when the QuickContact
-     * expands/collapses options
+     * Overrides the bottom bounds. This is used for the animation when the
+     * QuickContact expands/collapses options
      */
     public void setBottomOverride(int value) {
         mBottomOverride = value;
-        setChildBounds();
+        onBoundsChange(getBounds());
         invalidateSelf();
     }
 
     public void clearBottomOverride() {
         mBottomOverride = Integer.MIN_VALUE;
+        onBoundsChange(getBounds());
         invalidateSelf();
-        setChildBounds();
     }
 
     public float getBottomOverride() {
@@ -64,7 +70,29 @@
     }
 
     @Override
+    public boolean isStateful() {
+        return true;
+    }
+
+    @Override
+    protected boolean onStateChange(int[] state) {
+        super.onStateChange(state);
+        mLeftDrawable.setState(state);
+        mMiddleDrawable.setState(state);
+        mRightDrawable.setState(state);
+        return true;
+    }
+
+    @Override
+    protected boolean onLevelChange(int level) {
+        return true;
+    }
+
+    @Override
     public void setColorFilter(ColorFilter cf) {
+        mLeftDrawable.setColorFilter(cf);
+        mMiddleDrawable.setColorFilter(cf);
+        mRightDrawable.setColorFilter(cf);
     }
 
     @Override
@@ -72,54 +100,22 @@
         return PixelFormat.TRANSLUCENT;
     }
 
-    public void configure(Resources resources, boolean arrowUp, int requestedX) {
-        mLeftDrawable = resources.getDrawable(arrowUp
-                ? R.drawable.quickactions_arrowup_left_holo_light
-                : R.drawable.quickactions_arrowdown_left_holo_light);
-        mMiddleDrawable = resources.getDrawable(arrowUp
-                ? R.drawable.quickactions_arrowup_middle_holo_light
-                : R.drawable.quickactions_arrowdown_middle_holo_light);
-        mRightDrawable = resources.getDrawable(arrowUp
-                ? R.drawable.quickactions_arrowup_right_holo_light
-                : R.drawable.quickactions_arrowdown_right_holo_light);
-
-        mRequestedX = requestedX;
-
-        setChildAlpha();
-        setChildBounds();
-    }
-
     @Override
     protected void onBoundsChange(Rect bounds) {
-        mBoundsSet = true;
-        setChildBounds();
-    }
+        final int requestedX = getLevel();
 
-    private void setChildAlpha() {
-        if (mAlpha == -1) return;
-
-        if (mLeftDrawable != null) mLeftDrawable.setAlpha(mAlpha);
-        if (mMiddleDrawable != null) mMiddleDrawable.setAlpha(mAlpha);
-        if (mRightDrawable != null) mRightDrawable.setAlpha(mAlpha);
-    }
-
-    private void setChildBounds() {
-        if (mRequestedX == Integer.MIN_VALUE) return;
-        if (!mBoundsSet) return;
-
-        final Rect bounds = getBounds();
-        int middleLeft = mRequestedX - mMiddleDrawable.getIntrinsicWidth() / 2;
-        int middleRight = mRequestedX + mMiddleDrawable.getIntrinsicWidth() / 2;
+        int middleLeft = requestedX - mMiddleDrawable.getIntrinsicWidth() / 2;
+        int middleRight = requestedX + mMiddleDrawable.getIntrinsicWidth() / 2;
 
         // ensure left drawable is not smaller than its Intrinsic Width
-        final int leftExtra =  (middleLeft - bounds.left) - mLeftDrawable.getIntrinsicWidth();
+        final int leftExtra = (middleLeft - bounds.left) - mLeftDrawable.getIntrinsicWidth();
         if (leftExtra < 0) {
             middleLeft -= leftExtra;
             middleRight -= leftExtra;
         }
 
         // ensure right drawable is not smaller than its Intrinsic Width
-        final int rightExtra =  (bounds.right - middleRight) - mRightDrawable.getIntrinsicWidth();
+        final int rightExtra = (bounds.right - middleRight) - mRightDrawable.getIntrinsicWidth();
         if (rightExtra < 0) {
             middleLeft += rightExtra;
             middleRight += rightExtra;
diff --git a/src/com/android/contacts/quickcontact/QuickContactRootLayout.java b/src/com/android/contacts/quickcontact/QuickContactRootLayout.java
deleted file mode 100644
index 007783a..0000000
--- a/src/com/android/contacts/quickcontact/QuickContactRootLayout.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * 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.contacts.quickcontact;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.KeyEvent;
-import android.widget.LinearLayout;
-
-/**
- * Custom layout for Quick Contact. It intercepts the BACK key and
- * close QC even when the soft keyboard is open.
- */
-public class QuickContactRootLayout extends LinearLayout {
-    private Listener mListener;
-
-    public QuickContactRootLayout(Context context, AttributeSet attrs) {
-        super(context, attrs);
-    }
-
-    public void setListener(Listener value) {
-        mListener = value;
-    }
-
-    /**
-     * Intercepts the BACK key event and dismisses QuickContact window.
-     */
-    @Override
-    public boolean dispatchKeyEventPreIme(KeyEvent event) {
-        if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
-            if (mListener != null) mListener.onBackPressed();
-            return true;
-        }
-        return super.dispatchKeyEventPreIme(event);
-    }
-
-    public interface Listener {
-        void onBackPressed();
-    }
-}
diff --git a/src/com/android/contacts/quickcontact/QuickContactWindow.java b/src/com/android/contacts/quickcontact/QuickContactWindow.java
index 147e364..5f4bcc9 100644
--- a/src/com/android/contacts/quickcontact/QuickContactWindow.java
+++ b/src/com/android/contacts/quickcontact/QuickContactWindow.java
@@ -20,18 +20,20 @@
 import com.android.contacts.ContactPresenceIconUtil;
 import com.android.contacts.ContactSaveService;
 import com.android.contacts.R;
-import com.android.contacts.model.AccountType.DataKind;
 import com.android.contacts.model.AccountTypeManager;
+import com.android.contacts.model.DataKind;
 import com.android.contacts.util.Constants;
 import com.android.contacts.util.DataStatus;
 import com.android.contacts.util.NotifyingAsyncQueryHandler;
-import com.android.internal.policy.PolicyManager;
 import com.google.android.collect.Lists;
+import com.google.common.base.Preconditions;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
+import android.app.Activity;
 import android.content.ActivityNotFoundException;
+import android.content.ContentUris;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
@@ -41,6 +43,7 @@
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
+import android.os.Bundle;
 import android.os.Handler;
 import android.provider.ContactsContract.CommonDataKinds.Email;
 import android.provider.ContactsContract.CommonDataKinds.Im;
@@ -54,30 +57,16 @@
 import android.provider.ContactsContract.QuickContact;
 import android.provider.ContactsContract.RawContacts;
 import android.text.TextUtils;
-import android.util.Log;
-import android.view.ActionMode;
-import android.view.ContextThemeWrapper;
-import android.view.Gravity;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuItem;
 import android.view.MotionEvent;
 import android.view.View;
-import android.view.View.OnClickListener;
 import android.view.ViewGroup;
 import android.view.ViewStub;
-import android.view.ViewTreeObserver.OnGlobalLayoutListener;
-import android.view.Window;
-import android.view.WindowManager;
-import android.view.accessibility.AccessibilityEvent;
 import android.widget.AbsListView;
 import android.widget.AdapterView;
 import android.widget.BaseAdapter;
 import android.widget.Button;
 import android.widget.CheckBox;
 import android.widget.FrameLayout;
-import android.widget.HorizontalScrollView;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.ListView;
@@ -88,72 +77,44 @@
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.LinkedList;
 import java.util.List;
 import java.util.Set;
 
 /**
- * Window that shows QuickContact dialog for a specific {@link Contacts#_ID}.
+ * Mostly translucent {@link Activity} that shows QuickContact dialog. It loads
+ * data asynchronously, and then shows a popup with details centered around
+ * {@link Intent#getSourceBounds()}.
  */
-public class QuickContactWindow implements Window.Callback,
+public class QuickContactWindow extends Activity implements
         NotifyingAsyncQueryHandler.AsyncQueryListener, View.OnClickListener,
-        AbsListView.OnItemClickListener, KeyEvent.Callback, OnGlobalLayoutListener,
-        QuickContactRootLayout.Listener {
+        AbsListView.OnItemClickListener {
+    private static final String TAG = "QuickContact";
 
-    private static final String TAG = "QuickContactWindow";
+    private static final boolean TRACE_LAUNCH = false;
+    private static final String TRACE_TAG = "quickcontact";
 
-    /**
-     * Interface used to allow the person showing a {@link QuickContactWindow} to
-     * know when the window has been dismissed.
-     */
-    public interface OnDismissListener {
-        public void onDismiss(QuickContactWindow dialog);
-    }
-
-    private final static int ANIMATION_FADE_IN_TIME = 100;
-    private final static int ANIMATION_FADE_OUT_TIME = 100;
-    private final static int ANIMATION_EXPAND_TIME = 100;
-    private final static int ANIMATION_COLLAPSE_TIME = 100;
-
-    /**
-     * If the anchor is wider than (quick contact width * this constant) then
-     * center quick contact.  Otherwise, left-align.
-     */
-    private static final double MIN_RELATIVE_ANCHOR_WIDTH_TO_CENTER = 0.5;
-
-    private final Context mContext;
-    private final LayoutInflater mInflater;
-    private final WindowManager mWindowManager;
-    private Window mWindow;
-    private View mDecor;
-    private final Rect mRect = new Rect();
-
-    private boolean mDismissed = false;
-    private boolean mQuerying = false;
-    private boolean mShowing = false;
+    private static final int ANIMATION_FADE_IN_TIME = 100;
+    private static final int ANIMATION_FADE_OUT_TIME = 100;
+    private static final int ANIMATION_EXPAND_TIME = 100;
+    private static final int ANIMATION_COLLAPSE_TIME = 100;
 
     private NotifyingAsyncQueryHandler mHandler;
-    private OnDismissListener mDismissListener;
 
     private Uri mLookupUri;
-    private Rect mAnchor;
-
-    private int mScreenWidth;
-    private int mUseableScreenHeight;
-    private int mRequestedY;
+    private int mMode;
+    private String[] mExcludeMimes;
 
     private boolean mHasValidSocial = false;
 
-    private int mMode;
-    private QuickContactRootLayout mRootView;
+    private FloatingChildLayout mFloatingLayout;
     private QuickContactBackgroundDrawable mBackground;
-    private View mHeader;
-    private HorizontalScrollView mTrackScroll;
-    private ViewGroup mTrack;
 
+    private View mHeader;
+    private ViewGroup mTrack;
     private FrameLayout mFooter;
     private LinearLayout mFooterDisambig;
     private LinearLayout mFooterClearDefaults;
+
     private ListView mResolveList;
     private CheckableImageView mLastAction;
     private CheckBox mSetPrimaryCheckBox;
@@ -165,9 +126,6 @@
      */
     private HashMap<String, Action> mDefaultsMap = new HashMap<String, Action>();
 
-    private int mWindowRecycled = 0;
-    private int mActionRecycled = 0;
-
     /**
      * Set of {@link Action} that are associated with the aggregate currently
      * displayed by this dialog, represented as a map from {@link String}
@@ -176,14 +134,6 @@
     private ActionMultiMap mActions = new ActionMultiMap();
 
     /**
-     * Pool of unused {@link CheckableImageView} that have previously been
-     * inflated, and are ready to be recycled through {@link #obtainView()}.
-     */
-    private LinkedList<CheckableImageView> mActionPool = new LinkedList<CheckableImageView>();
-
-    private String[] mExcludeMimes;
-
-    /**
      * {@link #PRECEDING_MIMETYPES} and {@link #FOLLOWING_MIMETYPES} are used to sort MIME-types.
      *
      * <p>The MIME-types in {@link #PRECEDING_MIMETYPES} appear in the front of the dialog,
@@ -221,82 +171,48 @@
     });
     private static final int TOKEN_DATA = 1;
 
-    static final boolean TRACE_LAUNCH = false;
-    static final String TRACE_TAG = "quickcontact";
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
 
-    /**
-     * Prepare a dialog to show in the given {@link Context}.
-     */
-    public QuickContactWindow(Context context) {
-        mContext = new ContextThemeWrapper(context, R.style.QuickContact);
-        mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-        mWindowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
+        setContentView(R.layout.quickcontact_activity);
 
-        mWindow = PolicyManager.makeNewWindow(mContext);
-        mWindow.setCallback(this);
-        mWindow.setWindowManager(mWindowManager, null, null);
-        mWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED);
+        mBackground = new QuickContactBackgroundDrawable(getResources());
 
-        mWindow.setContentView(R.layout.quickcontact);
+        mFloatingLayout = findTypedViewById(R.id.floating_layout);
+        mFloatingLayout.getChild().setBackgroundDrawable(mBackground);
+        mFloatingLayout.setOnOutsideTouchListener(mOnOutsideTouchListener);
 
-        mRootView = (QuickContactRootLayout)mWindow.findViewById(R.id.root);
-        mRootView.setListener(this);
-        mRootView.setFocusable(true);
-        mRootView.setFocusableInTouchMode(true);
-        mRootView.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
+        mTrack = findTypedViewById(R.id.quickcontact);
+        mFooter = findTypedViewById(R.id.footer);
+        mFooterDisambig = findTypedViewById(R.id.footer_disambig);
+        mFooterClearDefaults = findTypedViewById(R.id.footer_clear_defaults);
+        mResolveList = findTypedViewById(android.R.id.list);
+        mSetPrimaryCheckBox = findTypedViewById(android.R.id.checkbox);
 
-        mBackground = new QuickContactBackgroundDrawable();
-        mRootView.setBackgroundDrawable(mBackground);
+        mDefaultsListView = findTypedViewById(R.id.defaults_list);
 
-        mScreenWidth = mWindowManager.getDefaultDisplay().getWidth();
-        // Status bar height
-        final int screenMarginBottom = context.getResources().getDimensionPixelSize(
-                com.android.internal.R.dimen.screen_margin_bottom);
-        mUseableScreenHeight = mWindowManager.getDefaultDisplay().getHeight() - screenMarginBottom;
+        mClearDefaultsButton = findTypedViewById(R.id.clear_defaults_button);
+        mClearDefaultsButton.setOnClickListener(mOnClearDefaultsClickListener);
 
-        mTrack = (ViewGroup) mWindow.findViewById(R.id.quickcontact);
-        mTrackScroll = (HorizontalScrollView) mWindow.findViewById(R.id.scroll);
+        mResolveList.setOnItemClickListener(this);
 
-        mFooter = (FrameLayout) mWindow.findViewById(R.id.footer);
-        mFooterDisambig = (LinearLayout) mWindow.findViewById(R.id.footer_disambig);
-        mFooterClearDefaults = (LinearLayout) mWindow.findViewById(R.id.footer_clear_defaults);
-        mResolveList = (ListView) mWindow.findViewById(android.R.id.list);
-        mSetPrimaryCheckBox = (CheckBox) mWindow.findViewById(android.R.id.checkbox);
+        mHandler = new NotifyingAsyncQueryHandler(this, this);
 
-        mDefaultsListView = (ListView) mWindow.findViewById(R.id.defaults_list);
-        mClearDefaultsButton = (Button) mWindow.findViewById(R.id.clear_defaults_button);
-        mClearDefaultsButton.setOnClickListener(new OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                clearDefaults();
-            }
-        });
-
-        mResolveList.setOnItemClickListener(QuickContactWindow.this);
-
-        mHandler = new NotifyingAsyncQueryHandler(mContext, this);
-    }
-
-    /**
-     * Prepare a dialog to show in the given {@link Context}, and notify the
-     * given {@link OnDismissListener} each time this dialog is dismissed.
-     */
-    public QuickContactWindow(Context context, OnDismissListener dismissListener) {
-        this(context);
-        mDismissListener = dismissListener;
+        show();
     }
 
     private View getHeaderView(int mode) {
         View header = null;
         switch (mode) {
             case QuickContact.MODE_SMALL:
-                header = mWindow.findViewById(R.id.header_small);
+                header = findViewById(R.id.header_small);
                 break;
             case QuickContact.MODE_MEDIUM:
-                header = mWindow.findViewById(R.id.header_medium);
+                header = findViewById(R.id.header_medium);
                 break;
             case QuickContact.MODE_LARGE:
-                header = mWindow.findViewById(R.id.header_large);
+                header = findViewById(R.id.header_large);
                 break;
         }
 
@@ -311,60 +227,52 @@
         return header;
     }
 
-    /**
-     * Start showing a dialog for the given {@link Contacts#_ID} pointing
-     * towards the given location.
-     */
-    public synchronized void show(Uri lookupUri, Rect anchor, int mode, String[] excludeMimes) {
-        if (mQuerying || mShowing) {
-            Log.w(TAG, "dismissing before showing");
-            dismissInternal();
-        }
+    private void show() {
 
-        if (TRACE_LAUNCH && !android.os.Debug.isMethodTracingActive()) {
+        if (TRACE_LAUNCH) {
             android.os.Debug.startMethodTracing(TRACE_TAG);
         }
 
-        // Validate incoming parameters
-        final boolean validMode = (mode == QuickContact.MODE_SMALL
-                || mode == QuickContact.MODE_MEDIUM || mode == QuickContact.MODE_LARGE);
-        if (!validMode) {
-            throw new IllegalArgumentException("Invalid mode, expecting MODE_LARGE, "
-                    + "MODE_MEDIUM, or MODE_SMALL");
+        final Intent intent = getIntent();
+
+        Uri lookupUri = intent.getData();
+
+        // Check to see whether it comes from the old version.
+        if (android.provider.Contacts.AUTHORITY.equals(lookupUri.getAuthority())) {
+            final long rawContactId = ContentUris.parseId(lookupUri);
+            lookupUri = RawContacts.getContactLookupUri(getContentResolver(),
+                    ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId));
         }
 
-        if (anchor == null) {
-            throw new IllegalArgumentException("Missing anchor rectangle");
+        mLookupUri = Preconditions.checkNotNull(lookupUri, "missing lookupUri");
+
+        // Read requested parameters for displaying
+        final Rect targetScreen = intent.getSourceBounds();
+        Preconditions.checkNotNull(targetScreen, "missing targetScreen");
+        mFloatingLayout.setChildTargetScreen(targetScreen);
+
+        mMode = intent.getIntExtra(QuickContact.EXTRA_MODE, QuickContact.MODE_MEDIUM);
+        mExcludeMimes = intent.getStringArrayExtra(QuickContact.EXTRA_EXCLUDE_MIMES);
+
+        switch (mMode) {
+            case QuickContact.MODE_SMALL:
+            case QuickContact.MODE_MEDIUM:
+            case QuickContact.MODE_LARGE:
+                break;
+            default:
+                throw new IllegalArgumentException("Unexpected mode: " + mMode);
         }
 
-        // Prepare header view for requested mode
-        mLookupUri = lookupUri;
-        mAnchor = new Rect(anchor);
-        mMode = mode;
-        mExcludeMimes = excludeMimes;
-
-        mHeader = getHeaderView(mode);
-
+        // find and prepare correct header view
+        mHeader = getHeaderView(mMode);
         setHeaderText(R.id.name, R.string.quickcontact_missing_name);
-
         setHeaderText(R.id.status, null);
         setHeaderText(R.id.timestamp, null);
-
         setHeaderImage(R.id.presence, null);
 
-        resetTrack();
-
-        // We need to have a focused view inside the QuickContact window so
-        // that the BACK key event can be intercepted
-        mRootView.requestFocus();
-
-        mHasValidSocial = false;
-        mDismissed = false;
-        mQuerying = true;
-
         // Start background query for data, but only select photo rows when they
         // directly match the super-primary PHOTO_ID.
-        final Uri dataUri = getDataUri(lookupUri);
+        final Uri dataUri = Uri.withAppendedPath(lookupUri, Contacts.Data.CONTENT_DIRECTORY);
         mHandler.cancelOperation(TOKEN_DATA);
 
         // Only request photo data when required by mode
@@ -380,222 +288,85 @@
         }
     }
 
-    /**
-     * Build a {@link Uri} into the {@link Data} table for the requested
-     * {@link Contacts#CONTENT_LOOKUP_URI} style {@link Uri}.
-     */
-    private Uri getDataUri(Uri lookupUri) {
-        return Uri.withAppendedPath(lookupUri, Contacts.Data.CONTENT_DIRECTORY);
+    @SuppressWarnings("unchecked")
+    private <T> T findTypedViewById(int id) {
+        return (T) super.findViewById(id);
     }
 
-    /**
-     * Creates and configures the background resource
-     */
-    private void configureBackground(boolean arrowUp, int requestedX) {
-        mBackground.configure(mContext.getResources(), arrowUp, requestedX);
+    private View.OnTouchListener mOnOutsideTouchListener = new View.OnTouchListener() {
+        /** {@inheritDoc} */
+        public boolean onTouch(View v, MotionEvent event) {
+            hide(true);
+            return true;
+        }
+    };
+
+    private View.OnClickListener mOnClearDefaultsClickListener = new View.OnClickListener() {
+        /** {@inheritDoc} */
+        public void onClick(View v) {
+            clearDefaults();
+        }
+    };
+
+    private void hide(boolean withAnimation) {
+        // cancel any pending queries
+        mHandler.cancelOperation(TOKEN_DATA);
+
+        if (withAnimation) {
+            mFloatingLayout.hideChild(new Runnable() {
+                /** {@inheritDoc} */
+                public void run() {
+                    finish();
+                }
+            });
+        } else {
+            mFloatingLayout.hideChild(null);
+            finish();
+        }
     }
 
-    /**
-     * Actual internal method to show this dialog. Called only by
-     * {@link #considerShowing()} when all data requirements have been met.
-     */
-    private void showInternal() {
-        mDecor = mWindow.getDecorView();
-        mDecor.getViewTreeObserver().addOnGlobalLayoutListener(this);
-        WindowManager.LayoutParams layoutParams = mWindow.getAttributes();
-
-        layoutParams.width = mContext.getResources().getDimensionPixelSize(
-                R.dimen.quick_contact_width);
-        layoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
-
-        // Try to left align with the anchor control or center if the anchor is wide
-        if (mAnchor.left + layoutParams.width <= mScreenWidth) {
-            if (mAnchor.width() > layoutParams.width * MIN_RELATIVE_ANCHOR_WIDTH_TO_CENTER) {
-                layoutParams.x = mAnchor.left + (mAnchor.width() - layoutParams.width) / 2;
-            } else {
-                layoutParams.x = mAnchor.left;
-            }
-        } else {
-            // Not enough space. Try to right align to the anchor
-            if (mAnchor.right - layoutParams.width >= 0) {
-                layoutParams.x = mAnchor.right - layoutParams.width;
-            } else {
-                // Also not enough space. Use the whole screen width available
-                layoutParams.x = 0;
-                layoutParams.width = mScreenWidth;
-            }
-        }
-
-        // Force layout measuring pass so we have baseline numbers
-        mDecor.measure(layoutParams.width, layoutParams.height);
-        final int blockHeight = mDecor.getMeasuredHeight();
-
-        layoutParams.gravity = Gravity.TOP | Gravity.LEFT;
-
-        if (mUseableScreenHeight - mAnchor.bottom > blockHeight) {
-            // Show downwards callout when enough room, aligning block top with bottom of
-            // anchor area, and adjusting to inset arrow.
-            configureBackground(true, mAnchor.centerX() - layoutParams.x);
-            layoutParams.y = mAnchor.bottom;
-            layoutParams.windowAnimations = R.style.QuickContactBelowAnimation;
-        } else {
-            // Show upwards callout, aligning bottom block
-            // edge with top of anchor area, and adjusting to inset arrow.
-            configureBackground(false, mAnchor.centerX() - layoutParams.x);
-            layoutParams.y = mAnchor.top - blockHeight;
-            layoutParams.windowAnimations = R.style.QuickContactAboveAnimation;
-        }
-
-        layoutParams.flags = WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
-                | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
-
-        mRequestedY = layoutParams.y;
-        mWindowManager.addView(mDecor, layoutParams);
-        mShowing = true;
-        mQuerying = false;
-        mDismissed = false;
-
-        if (TRACE_LAUNCH) {
-            android.os.Debug.stopMethodTracing();
-            Log.d(TAG, "Window recycled " + mWindowRecycled + " times, chiclets "
-                    + mActionRecycled + " times");
-        }
+    @Override
+    public void onBackPressed() {
+        hide(true);
     }
 
     /** {@inheritDoc} */
-    @Override
-    public void onGlobalLayout() {
-        layoutInScreen();
-    }
+    public synchronized void onQueryComplete(int token, Object cookie, Cursor cursor) {
+        try {
+            if (isFinishing()) {
+                hide(false);
+                return;
+            } else if (cursor == null || cursor.getCount() == 0) {
+                Toast.makeText(this, R.string.invalidContactMessage, Toast.LENGTH_LONG).show();
+                hide(false);
+                return;
+            }
 
-    /**
-     * Adjust vertical {@link WindowManager.LayoutParams} to fit window as best
-     * as possible, shifting up to display content as needed.
-     */
-    private void layoutInScreen() {
-        if (!mShowing) return;
+            bindData(cursor);
 
-        final WindowManager.LayoutParams l = mWindow.getAttributes();
-        final int originalY = l.y;
-
-        final int blockHeight = mDecor.getHeight();
-
-        l.y = mRequestedY;
-        if (mRequestedY + blockHeight > mUseableScreenHeight) {
-            // Shift up from bottom when overflowing
-            l.y = mUseableScreenHeight - blockHeight;
-        }
-
-        if (originalY != l.y) {
-            // Only update when value is changed
-            mWindow.setAttributes(l);
-        }
-    }
-
-    /**
-     * Dismiss this dialog if showing.
-     */
-    public synchronized void dismiss() {
-        // Notify any listeners that we've been dismissed
-        if (mDismissListener != null) {
-            mDismissListener.onDismiss(this);
-        }
-
-        dismissInternal();
-    }
-
-    private void dismissInternal() {
-        // Remove any attached window decor for recycling
-        boolean hadDecor = mDecor != null;
-        if (hadDecor) {
-            mWindowManager.removeView(mDecor);
-            mWindowRecycled++;
-            mDecor.getViewTreeObserver().removeGlobalOnLayoutListener(this);
-            mDecor = null;
-            mWindow.closeAllPanels();
-        }
-        mShowing = false;
-        mDismissed = true;
-
-        // Cancel any pending queries
-        mHandler.cancelOperation(TOKEN_DATA);
-        mQuerying = false;
-
-        // Completely hide header and reset track
-        mHeader.setVisibility(View.GONE);
-        resetTrack();
-    }
-
-    /**
-     * Reset track to initial state, recycling any chiclets.
-     */
-    private void resetTrack() {
-        // Clear background height-animation override
-        mBackground.clearBottomOverride();
-
-        // Release reference to last chiclet
-        mLastAction = null;
-
-        // Clear track actions and scroll to hard left
-        mActions.clear();
-
-        // Recycle any chiclets in use
-        for (int i = mTrack.getChildCount() - 1; i >= 0; i--) {
-            releaseView((CheckableImageView)mTrack.getChildAt(i));
-            mTrack.removeViewAt(i);
-        }
-
-        mTrackScroll.fullScroll(View.FOCUS_LEFT);
-
-        // Clear any primary requests
-        mSetPrimaryCheckBox.setChecked(false);
-
-        setNewActionViewChecked(null);
-        mFooter.setVisibility(View.GONE);
-    }
-
-    /**
-     * Consider showing this window, which will only call through to
-     * {@link #showInternal()} when all data items are present.
-     */
-    private void considerShowing() {
-        if (!mShowing && !mDismissed) {
             if (mMode == QuickContact.MODE_MEDIUM && !mHasValidSocial) {
                 // Missing valid social, swap medium for small header
                 mHeader.setVisibility(View.GONE);
                 mHeader = getHeaderView(QuickContact.MODE_SMALL);
             }
 
-            // All queries have returned, pull curtain
-            showInternal();
+            if (TRACE_LAUNCH) {
+                android.os.Debug.stopMethodTracing();
+            }
+
+            // data bound and ready, pull curtain to show
+            mFloatingLayout.showChild();
+
+        } finally {
+            if (cursor != null) {
+                cursor.close();
+            }
         }
     }
 
-    /** {@inheritDoc} */
-    @Override
-    public synchronized void onQueryComplete(int token, Object cookie, Cursor cursor) {
-        // Bail early when query is stale
-        if (cookie != mLookupUri) return;
-
-        if (cursor == null) {
-            // Problem while running query, so bail without showing
-            Log.w(TAG, "Missing cursor for token=" + token);
-            this.dismiss();
-            return;
-        }
-
-        handleData(cursor);
-
-        if (!cursor.isClosed()) {
-            cursor.close();
-        }
-
-        considerShowing();
-    }
-
     /** Assign this string to the view, if found in {@link #mHeader}. */
     private void setHeaderText(int id, int resId) {
-        setHeaderText(id, mContext.getResources().getText(resId));
+        setHeaderText(id, getText(resId));
     }
 
     /** Assign this string to the view, if found in {@link #mHeader}. */
@@ -633,26 +404,22 @@
     /**
      * Handle the result from the {@link #TOKEN_DATA} query.
      */
-    private void handleData(Cursor cursor) {
-        final ResolveCache cache = ResolveCache.getInstance(mContext);
-        if (cursor == null) return;
-        if (cursor.getCount() == 0) {
-            Toast.makeText(mContext, R.string.invalidContactMessage, Toast.LENGTH_LONG).show();
-            dismiss();
-            return;
-        }
+    private void bindData(Cursor cursor) {
+        final ResolveCache cache = ResolveCache.getInstance(this);
+        final Context context = this;
 
         if (!isMimeExcluded(Contacts.CONTENT_ITEM_TYPE)) {
             // Add the profile shortcut action
-            final Action action = new ProfileAction(mContext, mLookupUri);
+            final Action action = new ProfileAction(context, mLookupUri);
             mActions.put(Contacts.CONTENT_ITEM_TYPE, action);
         }
 
         mDefaultsMap.clear();
 
         final DataStatus status = new DataStatus();
-        final AccountTypeManager accountTypes = AccountTypeManager.getInstance(mContext);
-        final ImageView photoView = (ImageView)mHeader.findViewById(R.id.photo);
+        final AccountTypeManager accountTypes = AccountTypeManager.getInstance(
+                context.getApplicationContext());
+        final ImageView photoView = (ImageView) mHeader.findViewById(R.id.photo);
 
         Bitmap photoBitmap = null;
         while (cursor.moveToNext()) {
@@ -684,7 +451,7 @@
                 // Build an action for this data entry, find a mapping to a UI
                 // element, build its summary from the cursor, and collect it
                 // along with all others of this MIME-type.
-                final Action action = new DataAction(mContext, mimeType, kind, dataId, cursor);
+                final Action action = new DataAction(context, mimeType, kind, dataId, cursor);
                 final boolean wasAdded = considerAdd(action, cache);
                 if (wasAdded) {
                     // Remember the default
@@ -696,7 +463,7 @@
 
             // If phone number, also insert as text message action
             if (Phone.CONTENT_ITEM_TYPE.equals(mimeType) && kind != null) {
-                final DataAction action = new DataAction(mContext, Constants.MIME_TYPE_SMS_ADDRESS,
+                final DataAction action = new DataAction(context, Constants.MIME_TYPE_SMS_ADDRESS,
                         kind, dataId, cursor);
                 considerAdd(action, cache);
             }
@@ -709,7 +476,7 @@
                 final DataKind imKind = accountTypes.getKindOrFallback(accountType,
                         Im.CONTENT_ITEM_TYPE);
                 if (imKind != null) {
-                    final DataAction action = new DataAction(mContext, Im.CONTENT_ITEM_TYPE, imKind,
+                    final DataAction action = new DataAction(context, Im.CONTENT_ITEM_TYPE, imKind,
                             dataId, cursor);
                     considerAdd(action, cache);
                     isIm = true;
@@ -722,7 +489,7 @@
                     final DataKind imKind = accountTypes.getKindOrFallback(accountType,
                             Im.CONTENT_ITEM_TYPE);
                     if (imKind != null) {
-                        final DataAction chatAction = new DataAction(mContext,
+                        final DataAction chatAction = new DataAction(context,
                                 Constants.MIME_TYPE_VIDEO_CHAT, imKind, dataId, cursor);
                         considerAdd(chatAction, cache);
                     }
@@ -730,6 +497,11 @@
             }
         }
 
+        // Collapse Action Lists (remove e.g. duplicate e-mail addresses from different sources)
+        for (ArrayList<Action> actionChildren : mActions.values()) {
+            Collapser.collapseList(actionChildren);
+        }
+
         // Make sure that we only display the "clear default" action if there
         // are actually several items to chose from
         boolean shouldDisplayClearDefaults = false;
@@ -751,7 +523,7 @@
             final int presence = cursor.getInt(DataQuery.CONTACT_PRESENCE);
             final int chatCapability = cursor.getInt(DataQuery.CONTACT_CHAT_CAPABILITY);
             final Drawable statusIcon = ContactPresenceIconUtil.getChatCapabilityIcon(
-                    mContext, presence, chatCapability);
+                    context, presence, chatCapability);
 
             setHeaderText(R.id.name, name);
             setHeaderImage(R.id.presence, statusIcon);
@@ -767,7 +539,7 @@
         if (mHasValidSocial && mMode != QuickContact.MODE_SMALL) {
             // Update status when valid was found
             setHeaderText(R.id.status, status.getStatus());
-            setHeaderText(R.id.timestamp, status.getTimestampLabel(mContext));
+            setHeaderText(R.id.timestamp, status.getTimestampLabel(context));
         }
 
         // Turn our list of actions into UI elements
@@ -781,7 +553,7 @@
         for (String mimeType : PRECEDING_MIMETYPES) {
             if (containedTypes.contains(mimeType)) {
                 hasData = true;
-                mTrack.addView(inflateAction(mimeType, cache));
+                mTrack.addView(inflateAction(mimeType, cache, mTrack));
                 containedTypes.remove(mimeType);
             }
         }
@@ -793,7 +565,7 @@
         for (String mimeType : FOLLOWING_MIMETYPES) {
             if (containedTypes.contains(mimeType)) {
                 hasData = true;
-                mTrack.addView(inflateAction(mimeType, cache));
+                mTrack.addView(inflateAction(mimeType, cache, mTrack));
                 containedTypes.remove(mimeType);
             }
         }
@@ -802,9 +574,11 @@
         if (containedTypes.contains(ClearDefaultsAction.PSEUDO_MIME_TYPE)) {
             final ClearDefaultsAction action = (ClearDefaultsAction) mActions.get(
                     ClearDefaultsAction.PSEUDO_MIME_TYPE).get(0);
-            final CheckableImageView view = obtainView();
+            final CheckableImageView view = (CheckableImageView) getLayoutInflater().inflate(
+                    R.layout.quickcontact_item, mTrack, false);
+
             view.setChecked(false);
-            final String description = mContext.getResources().getString(
+            final String description = context.getResources().getString(
                     R.string.quickcontact_clear_defaults_description);
             view.setContentDescription(description);
             view.setImageResource(R.drawable.ic_menu_settings_holo_light);
@@ -820,12 +594,13 @@
         if (remainingTypes.length > 0) hasData = true;
         Arrays.sort(remainingTypes);
         for (String mimeType : remainingTypes) {
-            mTrack.addView(inflateAction(mimeType, cache), index++);
+            mTrack.addView(inflateAction(mimeType, cache, mTrack), index++);
         }
 
         if (!hasData) {
             // When there is no data to display, add a TextView to show the user there's no data
-            View view = mInflater.inflate(R.layout.quickcontact_item_nodata, mTrack, false);
+            View view = getLayoutInflater().inflate(
+                    R.layout.quickcontact_item_nodata, mTrack, false);
             mTrack.addView(view, index++);
         }
     }
@@ -834,7 +609,9 @@
      * Clears the defaults currently set on the Contact
      */
     private void clearDefaults() {
+        final Context context = this;
         final Set<String> mimeTypesKeySet = mDefaultsMap.keySet();
+
         // Copy to array so that we can modify the HashMap below
         final String[] mimeTypes = new String[mimeTypesKeySet.size()];
         mimeTypesKeySet.toArray(mimeTypes);
@@ -842,9 +619,9 @@
         // Send clear default Intents, one by one
         for (String mimeType : mimeTypes) {
             final Action action = mDefaultsMap.get(mimeType);
-            final Intent intent =
-                    ContactSaveService.createClearPrimaryIntent(mContext, action.getDataId());
-            mContext.startService(intent);
+            final Intent intent = ContactSaveService.createClearPrimaryIntent(
+                    context, action.getDataId());
+            context.startService(intent);
             mDefaultsMap.remove(mimeType);
         }
 
@@ -855,7 +632,6 @@
                 for (int i = mTrack.getChildCount() - 1; i >= 0; i--) {
                     final CheckableImageView button = (CheckableImageView) mTrack.getChildAt(i);
                     if (button.getTag() instanceof ClearDefaultsAction) {
-                        releaseView(button);
                         mTrack.removeViewAt(i);
                         break;
                     }
@@ -879,41 +655,15 @@
     }
 
     /**
-     * Obtain a new {@link CheckableImageView} for a new chiclet, either by
-     * recycling one from {@link #mActionPool}, or by inflating a new one. When
-     * finished, use {@link #releaseView(CheckableImageView)} to return back into the pool for
-     * later recycling.
-     */
-    private synchronized CheckableImageView obtainView() {
-        CheckableImageView view = mActionPool.poll();
-        if (view == null || QuickContactActivity.FORCE_CREATE) {
-            view = (CheckableImageView) mInflater.inflate(R.layout.quickcontact_item, mTrack,
-                    false);
-        }
-        return view;
-    }
-
-    /**
-     * Return the given {@link CheckableImageView} into our internal pool for
-     * possible recycling during another pass.
-     */
-    private synchronized void releaseView(CheckableImageView view) {
-        mActionPool.offer(view);
-        mActionRecycled++;
-    }
-
-    /**
      * Inflate the in-track view for the action of the given MIME-type, collapsing duplicate values.
      * Will use the icon provided by the {@link DataKind}.
      */
-    private View inflateAction(String mimeType, ResolveCache resolveCache) {
-        final CheckableImageView view = obtainView();
+    private View inflateAction(String mimeType, ResolveCache resolveCache, ViewGroup root) {
+        final CheckableImageView view = (CheckableImageView) getLayoutInflater().inflate(
+                R.layout.quickcontact_item, root, false);
 
         // Add direct intent if single child, otherwise flag for multiple
         List<Action> children = mActions.get(mimeType);
-        if (children.size() > 1) {
-            Collapser.collapseList(children);
-        }
         view.setTag(mimeType);
         final Action firstInfo = children.get(0);
 
@@ -990,6 +740,13 @@
                 expandAnimator.setDuration(ANIMATION_EXPAND_TIME);
                 expandAnimator.start();
 
+                expandAnimator.addListener(new AnimatorListenerAdapter() {
+                    @Override
+                    public void onAnimationEnd(Animator animation) {
+                        mBackground.clearBottomOverride();
+                    }
+                });
+
                 final ObjectAnimator fadeInAnimator = ObjectAnimator.ofFloat(mFooter,
                         "alpha", 0.0f, 1.0f);
                 fadeInAnimator.setDuration(ANIMATION_FADE_IN_TIME);
@@ -1002,9 +759,12 @@
     /** {@inheritDoc} */
     @Override
     public void onClick(View view) {
+        final Context context = this;
+
         final boolean isActionView = (view instanceof CheckableImageView);
         final CheckableImageView actionView = isActionView ? (CheckableImageView)view : null;
         final Object tag = view.getTag();
+
         if (tag instanceof ClearDefaultsAction) {
             // Do nothing if already open
             if (actionView == mLastAction) return;
@@ -1045,29 +805,28 @@
 
                         @Override
                         public View getView(int position, View convertView, ViewGroup parent) {
-                            final View result = convertView != null ? convertView :
-                                    mInflater.inflate(R.layout.quickcontact_default_item,
-                                    parent, false);
+                            if (convertView == null) {
+                                convertView = getLayoutInflater().inflate(
+                                        R.layout.quickcontact_default_item, parent, false);
+                            }
+
                             // Set action title based on summary value
                             final Action defaultAction = actions[position];
 
-                            TextView text1 = (TextView)result.findViewById(android.R.id.text1);
-                            TextView text2 = (TextView)result.findViewById(android.R.id.text2);
+                            final TextView text1 = (TextView) convertView.findViewById(
+                                    android.R.id.text1);
+                            final TextView text2 = (TextView) convertView.findViewById(
+                                    android.R.id.text2);
 
                             text1.setText(defaultAction.getHeader());
                             text2.setText(defaultAction.getBody());
 
-                            result.setTag(defaultAction);
-                            return result;
+                            convertView.setTag(defaultAction);
+                            return convertView;
                         }
                     });
 
                     animateExpand(true);
-                    // Make sure we resize to make room for ListView
-                    if (mDecor != null) {
-                        mDecor.forceLayout();
-                        mDecor.invalidate();
-                    }
                 }
             };
             if (mFooter.getVisibility() == View.VISIBLE) {
@@ -1116,24 +875,24 @@
                 public void run() {
                     // Incoming tag is concrete intent, so try launching
                     try {
-                        mContext.startActivity(action.getIntent());
+                        context.startActivity(action.getIntent());
                     } catch (ActivityNotFoundException e) {
-                        Toast.makeText(mContext, R.string.quickcontact_missing_app,
+                        Toast.makeText(context, R.string.quickcontact_missing_app,
                                 Toast.LENGTH_SHORT).show();
                     }
 
                     // Hide the resolution list, if present
                     setNewActionViewChecked(null);
-                    dismiss();
-                    mFooter.setVisibility(View.GONE);
 
                     // Set default?
                     final long dataId = action.getDataId();
                     if (makePrimary && dataId != -1) {
                         Intent serviceIntent = ContactSaveService.createSetSuperPrimaryIntent(
-                                mContext, dataId);
-                        mContext.startService(serviceIntent);
+                                context, dataId);
+                        context.startService(serviceIntent);
                     }
+
+                    hide(false);
                 }
             };
             if (isActionView && mFooter.getVisibility() == View.VISIBLE) {
@@ -1178,31 +937,31 @@
 
                     @Override
                     public View getView(int position, View convertView, ViewGroup parent) {
-                        final View result = convertView != null ? convertView :
-                                mInflater.inflate(R.layout.quickcontact_resolve_item,
-                                parent, false);
+                        if (convertView == null) {
+                            convertView = getLayoutInflater().inflate(
+                                    R.layout.quickcontact_resolve_item, parent, false);
+                        }
+
                         // Set action title based on summary value
                         final Action listAction = actionList.get(position);
 
-                        TextView text1 = (TextView)result.findViewById(android.R.id.text1);
-                        TextView text2 = (TextView)result.findViewById(android.R.id.text2);
+                        final TextView text1 = (TextView) convertView.findViewById(
+                                android.R.id.text1);
+                        final TextView text2 = (TextView) convertView.findViewById(
+                                android.R.id.text2);
 
                         text1.setText(listAction.getHeader());
                         text2.setText(listAction.getBody());
 
-                        result.setTag(listAction);
-                        return result;
+                        convertView.setTag(listAction);
+                        return convertView;
                     }
                 });
 
                 animateExpand(false);
-                // Make sure we resize to make room for ListView
-                if (mDecor != null) {
-                    mDecor.forceLayout();
-                    mDecor.invalidate();
-                }
             }
         };
+
         if (mFooter.getVisibility() == View.VISIBLE) {
             // If the expansion list is currently opened, animate its collapse and then
             // execute the target app
@@ -1213,191 +972,6 @@
         }
     }
 
-    @Override
-    public void onBackPressed() {
-        dismiss();
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public boolean dispatchKeyEvent(KeyEvent event) {
-        if (mWindow.superDispatchKeyEvent(event)) {
-            return true;
-        }
-        return event.dispatch(this, mDecor != null
-                ? mDecor.getKeyDispatcherState() : null, this);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public boolean onKeyDown(int keyCode, KeyEvent event) {
-        if (keyCode == KeyEvent.KEYCODE_BACK) {
-            event.startTracking();
-            return true;
-        }
-
-        return false;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public boolean onKeyUp(int keyCode, KeyEvent event) {
-        if (keyCode == KeyEvent.KEYCODE_BACK && event.isTracking()
-                && !event.isCanceled()) {
-            onBackPressed();
-            return true;
-        }
-
-        return false;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public boolean onKeyLongPress(int keyCode, KeyEvent event) {
-        return false;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public boolean onKeyMultiple(int keyCode, int count, KeyEvent event) {
-        return false;
-    }
-
-    /** {@inheritDoc} */
-    public boolean dispatchKeyShortcutEvent(KeyEvent event) {
-        return mWindow.superDispatchKeyShortcutEvent(event);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
-        // TODO: make this window accessible
-        return false;
-    }
-
-    /**
-     * Detect if the given {@link MotionEvent} is outside the boundaries of this
-     * window, which usually means we should dismiss.
-     */
-    protected void detectEventOutside(MotionEvent event) {
-        if (event.getAction() == MotionEvent.ACTION_DOWN && mDecor != null) {
-            // Only try detecting outside events on down-press
-            mDecor.getHitRect(mRect);
-            final int x = (int)event.getX();
-            final int y = (int)event.getY();
-            if (!mRect.contains(x, y)) {
-                event.setAction(MotionEvent.ACTION_OUTSIDE);
-            }
-        }
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public boolean dispatchTouchEvent(MotionEvent event) {
-        detectEventOutside(event);
-        if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {
-            dismiss();
-            return true;
-        }
-        return mWindow.superDispatchTouchEvent(event);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public boolean dispatchTrackballEvent(MotionEvent event) {
-        return mWindow.superDispatchTrackballEvent(event);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public boolean dispatchGenericMotionEvent(MotionEvent event) {
-        return mWindow.superDispatchGenericMotionEvent(event);
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public void onContentChanged() {
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public boolean onCreatePanelMenu(int featureId, Menu menu) {
-        return false;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public View onCreatePanelView(int featureId) {
-        return null;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public boolean onMenuItemSelected(int featureId, MenuItem item) {
-        return false;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public boolean onMenuOpened(int featureId, Menu menu) {
-        return false;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public void onPanelClosed(int featureId, Menu menu) {
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public boolean onPreparePanel(int featureId, View view, Menu menu) {
-        return false;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public boolean onSearchRequested() {
-        return false;
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public void onWindowAttributesChanged(android.view.WindowManager.LayoutParams attrs) {
-        if (mDecor != null) {
-            mWindowManager.updateViewLayout(mDecor, attrs);
-        }
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public void onWindowFocusChanged(boolean hasFocus) {
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public void onAttachedToWindow() {
-        // No actions
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public void onDetachedFromWindow() {
-        // No actions
-    }
-
-    /** {@inheritDoc} */
-    @Override
-    public ActionMode onWindowStartingActionMode(ActionMode.Callback callback) {
-        return null;
-    }
-
-    @Override
-    public void onActionModeStarted(ActionMode mode) {
-    }
-
-    @Override
-    public void onActionModeFinished(ActionMode mode) {
-    }
 
     private interface DataQuery {
         final String[] PROJECTION = new String[] {
diff --git a/src/com/android/contacts/util/NotifyingAsyncQueryHandler.java b/src/com/android/contacts/util/NotifyingAsyncQueryHandler.java
index 83fae29..c8cfc8d 100644
--- a/src/com/android/contacts/util/NotifyingAsyncQueryHandler.java
+++ b/src/com/android/contacts/util/NotifyingAsyncQueryHandler.java
@@ -29,8 +29,6 @@
  * <p>
  * This pattern can be used to perform background queries without leaking
  * {@link Context} objects.
- *
- * @hide pending API council review
  */
 public class NotifyingAsyncQueryHandler extends AsyncQueryHandler {
     private WeakReference<AsyncQueryListener> mListener;
diff --git a/src/com/android/contacts/util/PhoneCapabilityTester.java b/src/com/android/contacts/util/PhoneCapabilityTester.java
index 23319aa..d3a8060 100644
--- a/src/com/android/contacts/util/PhoneCapabilityTester.java
+++ b/src/com/android/contacts/util/PhoneCapabilityTester.java
@@ -16,6 +16,8 @@
 
 package com.android.contacts.util;
 
+import com.android.contacts.R;
+
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
@@ -79,4 +81,12 @@
                 Uri.fromParts(Constants.SCHEME_SMSTO, "", null));
         return isIntentRegistered(context, intent);
     }
+
+    /**
+     * True if we are using two-pane layouts ("tablet mode"), false if we are using single views
+     * ("phone mode")
+     */
+    public static boolean isUsingTwoPanes(Context context) {
+        return context.getResources().getBoolean(R.bool.config_use_two_panes);
+    }
 }
diff --git a/src/com/android/contacts/vcard/ExportProcessor.java b/src/com/android/contacts/vcard/ExportProcessor.java
index 67c9c4a..7b5e001 100644
--- a/src/com/android/contacts/vcard/ExportProcessor.java
+++ b/src/com/android/contacts/vcard/ExportProcessor.java
@@ -22,18 +22,22 @@
 
 import android.app.Notification;
 import android.app.NotificationManager;
-import android.app.PendingIntent;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Resources;
 import android.net.Uri;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.RawContactsEntity;
 import android.text.TextUtils;
 import android.util.Log;
-import android.widget.RemoteViews;
 
+import java.io.BufferedWriter;
 import java.io.FileNotFoundException;
+import java.io.IOException;
 import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
 
 /**
  * Class for processing one export request from a user. Dropped after exporting requested Uri(s).
@@ -92,6 +96,7 @@
         if (DEBUG) Log.d(LOG_TAG, String.format("vCard export (id: %d) has started.", mJobId));
         final ExportRequest request = mExportRequest;
         VCardComposer composer = null;
+        Writer writer = null;
         boolean successful = false;
         try {
             if (isCancelled()) {
@@ -129,9 +134,14 @@
             //     VCardConfig.FLAG_USE_QP_TO_PRIMARY_PROPERTIES);
             // composer = new VCardComposer(ExportVCardActivity.this, vcardType, true);
 
-            composer.addHandler(composer.new HandlerForOutputStream(outputStream));
-
-            if (!composer.init()) {
+            writer = new BufferedWriter(new OutputStreamWriter(outputStream));
+            final Uri contentUriForRawContactsEntity = RawContactsEntity.CONTENT_URI.buildUpon()
+                    .appendQueryParameter(RawContactsEntity.FOR_EXPORT_ONLY, "1")
+                    .build();
+            // TODO: should provide better selection.
+            if (!composer.init(Contacts.CONTENT_URI, new String[] {Contacts._ID},
+                    null, null,
+                    null, contentUriForRawContactsEntity)) {
                 final String errorReason = composer.getErrorReason();
                 Log.e(LOG_TAG, "initialization of vCard composer failed: " + errorReason);
                 final String translatedErrorReason =
@@ -157,7 +167,9 @@
                     Log.i(LOG_TAG, "Export request is cancelled during composing vCard");
                     return;
                 }
-                if (!composer.createOneEntry()) {
+                try {
+                    writer.write(composer.createOneEntry());
+                } catch (IOException e) {
                     final String errorReason = composer.getErrorReason();
                     Log.e(LOG_TAG, "Failed to read a contact: " + errorReason);
                     final String translatedErrorReason =
@@ -192,7 +204,13 @@
             if (composer != null) {
                 composer.terminate();
             }
-
+            if (writer != null) {
+                try {
+                    writer.close();
+                } catch (IOException e) {
+                    Log.w(LOG_TAG, "IOException is thrown during close(). Ignored. " + e);
+                }
+            }
             mService.handleFinishExportNotification(mJobId, successful);
         }
     }
diff --git a/src/com/android/contacts/vcard/ImportVCardActivity.java b/src/com/android/contacts/vcard/ImportVCardActivity.java
index b3376e9..17b89c3 100644
--- a/src/com/android/contacts/vcard/ImportVCardActivity.java
+++ b/src/com/android/contacts/vcard/ImportVCardActivity.java
@@ -21,7 +21,6 @@
 import com.android.contacts.model.AccountTypeManager;
 import com.android.contacts.util.AccountSelectionUtil;
 import com.android.vcard.VCardEntryCounter;
-import com.android.vcard.VCardInterpreterCollection;
 import com.android.vcard.VCardParser;
 import com.android.vcard.VCardParser_V21;
 import com.android.vcard.VCardParser_V30;
@@ -399,7 +398,6 @@
             final ContentResolver resolver = ImportVCardActivity.this.getContentResolver();
             VCardEntryCounter counter = null;
             VCardSourceDetector detector = null;
-            VCardInterpreterCollection interpreter = null;
             int vcardVersion = VCARD_VERSION_V21;
             try {
                 boolean shouldUseV30 = false;
@@ -408,9 +406,9 @@
                 try {
                     counter = new VCardEntryCounter();
                     detector = new VCardSourceDetector();
-                    interpreter = new VCardInterpreterCollection(
-                            Arrays.asList(counter, detector));
-                    mVCardParser.parse(is, interpreter);
+                    mVCardParser.addInterpreter(counter);
+                    mVCardParser.addInterpreter(detector);
+                    mVCardParser.parse(is);
                 } catch (VCardVersionException e1) {
                     try {
                         is.close();
@@ -423,9 +421,9 @@
                     try {
                         counter = new VCardEntryCounter();
                         detector = new VCardSourceDetector();
-                        interpreter = new VCardInterpreterCollection(
-                                Arrays.asList(counter, detector));
-                        mVCardParser.parse(is, interpreter);
+                        mVCardParser.addInterpreter(counter);
+                        mVCardParser.addInterpreter(detector);
+                        mVCardParser.parse(is);
                     } catch (VCardVersionException e2) {
                         throw new VCardException("vCard with unspported version.");
                     }
diff --git a/tests/res/values/donottranslate_strings.xml b/tests/res/values/donottranslate_strings.xml
index 8557fd6..bd272c3 100644
--- a/tests/res/values/donottranslate_strings.xml
+++ b/tests/res/values/donottranslate_strings.xml
@@ -32,6 +32,7 @@
         <item>ACTION_PICK: phone (legacy)</item>
         <item>ACTION_PICK: postal</item>
         <item>ACTION_PICK: postal (legacy)</item>
+        <item>ACTION_PICK: e-mail</item>
         <item>ACTION_CREATE_SHORTCUT: contact</item>
         <item>ACTION_CREATE_SHORTCUT: dial</item>
         <item>ACTION_CREATE_SHORTCUT: message</item>
diff --git a/tests/src/com/android/contacts/EntityModifierTests.java b/tests/src/com/android/contacts/EntityModifierTests.java
index 4acaa92..389041a 100644
--- a/tests/src/com/android/contacts/EntityModifierTests.java
+++ b/tests/src/com/android/contacts/EntityModifierTests.java
@@ -21,9 +21,9 @@
 import static android.content.ContentProviderOperation.TYPE_UPDATE;
 
 import com.android.contacts.model.AccountType;
-import com.android.contacts.model.AccountType.DataKind;
 import com.android.contacts.model.AccountType.EditType;
 import com.android.contacts.model.AccountTypeManager;
+import com.android.contacts.model.DataKind;
 import com.android.contacts.model.EntityDelta;
 import com.android.contacts.model.EntityDelta.ValuesDelta;
 import com.android.contacts.model.EntityDeltaList;
@@ -81,45 +81,50 @@
         MockContactsSource() {
             this.accountType = TEST_ACCOUNT_TYPE;
 
+            final DataKind nameKind = new DataKind(StructuredName.CONTENT_ITEM_TYPE,
+                    R.string.nameLabelsGroup, -1, -1, true);
+            nameKind.typeOverallMax = 1;
+            addKind(nameKind);
+
             // Phone allows maximum 2 home, 1 work, and unlimited other, with
             // constraint of 5 numbers maximum.
-            DataKind kind = new DataKind(Phone.CONTENT_ITEM_TYPE, -1, -1, 10, true);
+            final DataKind phoneKind = new DataKind(Phone.CONTENT_ITEM_TYPE, -1, -1, 10, true);
 
-            kind.typeOverallMax = 5;
-            kind.typeColumn = Phone.TYPE;
-            kind.typeList = Lists.newArrayList();
-            kind.typeList.add(new EditType(Phone.TYPE_HOME, -1).setSpecificMax(2));
-            kind.typeList.add(new EditType(Phone.TYPE_WORK, -1).setSpecificMax(1));
-            kind.typeList.add(new EditType(Phone.TYPE_FAX_WORK, -1).setSecondary(true));
-            kind.typeList.add(new EditType(Phone.TYPE_OTHER, -1));
+            phoneKind.typeOverallMax = 5;
+            phoneKind.typeColumn = Phone.TYPE;
+            phoneKind.typeList = Lists.newArrayList();
+            phoneKind.typeList.add(new EditType(Phone.TYPE_HOME, -1).setSpecificMax(2));
+            phoneKind.typeList.add(new EditType(Phone.TYPE_WORK, -1).setSpecificMax(1));
+            phoneKind.typeList.add(new EditType(Phone.TYPE_FAX_WORK, -1).setSecondary(true));
+            phoneKind.typeList.add(new EditType(Phone.TYPE_OTHER, -1));
 
-            kind.fieldList = Lists.newArrayList();
-            kind.fieldList.add(new EditField(Phone.NUMBER, -1, -1));
-            kind.fieldList.add(new EditField(Phone.LABEL, -1, -1));
+            phoneKind.fieldList = Lists.newArrayList();
+            phoneKind.fieldList.add(new EditField(Phone.NUMBER, -1, -1));
+            phoneKind.fieldList.add(new EditField(Phone.LABEL, -1, -1));
 
-            addKind(kind);
+            addKind(phoneKind);
 
             // Email is unlimited
-            kind = new DataKind(Email.CONTENT_ITEM_TYPE, -1, -1, 10, true);
-            kind.typeOverallMax = -1;
-            kind.fieldList = Lists.newArrayList();
-            kind.fieldList.add(new EditField(Email.DATA, -1, -1));
-            addKind(kind);
+            final DataKind emailKind = new DataKind(Email.CONTENT_ITEM_TYPE, -1, -1, 10, true);
+            emailKind.typeOverallMax = -1;
+            emailKind.fieldList = Lists.newArrayList();
+            emailKind.fieldList.add(new EditField(Email.DATA, -1, -1));
+            addKind(emailKind);
 
             // IM is only one
-            kind = new DataKind(Im.CONTENT_ITEM_TYPE, -1, -1, 10, true);
-            kind.typeOverallMax = 1;
-            kind.fieldList = Lists.newArrayList();
-            kind.fieldList.add(new EditField(Im.DATA, -1, -1));
-            addKind(kind);
+            final DataKind imKind = new DataKind(Im.CONTENT_ITEM_TYPE, -1, -1, 10, true);
+            imKind.typeOverallMax = 1;
+            imKind.fieldList = Lists.newArrayList();
+            imKind.fieldList.add(new EditField(Im.DATA, -1, -1));
+            addKind(imKind);
 
             // Organization is only one
-            kind = new DataKind(Organization.CONTENT_ITEM_TYPE, -1, -1, 10, true);
-            kind.typeOverallMax = 1;
-            kind.fieldList = Lists.newArrayList();
-            kind.fieldList.add(new EditField(Organization.COMPANY, -1, -1));
-            kind.fieldList.add(new EditField(Organization.TITLE, -1, -1));
-            addKind(kind);
+            final DataKind orgKind = new DataKind(Organization.CONTENT_ITEM_TYPE, -1, -1, 10, true);
+            orgKind.typeOverallMax = 1;
+            orgKind.fieldList = Lists.newArrayList();
+            orgKind.fieldList.add(new EditField(Organization.COMPANY, -1, -1));
+            orgKind.fieldList.add(new EditField(Organization.TITLE, -1, -1));
+            addKind(orgKind);
         }
 
         @Override
@@ -330,7 +335,7 @@
 
         // Test row that has type values, but core fields are empty
         final EntityDelta state = getEntity(TEST_ID);
-        final ValuesDelta values = EntityModifier.insertChild(state, kindPhone, typeHome);
+        EntityModifier.insertChild(state, kindPhone, typeHome);
 
         // Build diff, expecting insert for data row and update enforcement
         final ArrayList<ContentProviderOperation> diff = Lists.newArrayList();
@@ -420,7 +425,7 @@
     public void testTrimEmptyUntouched() {
         final AccountType source = getAccountType();
         final DataKind kindPhone = source.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
-        final EditType typeHome = EntityModifier.getType(kindPhone, Phone.TYPE_HOME);
+        EntityModifier.getType(kindPhone, Phone.TYPE_HOME);
 
         // Build "before" that has empty row
         final EntityDelta state = getEntity(TEST_ID);
@@ -497,7 +502,7 @@
         final AccountType accountType = getAccountType();
         final AccountTypeManager accountTypes = getAccountTypes(accountType);
         final DataKind kindPhone = accountType.getKindForMimetype(Phone.CONTENT_ITEM_TYPE);
-        final EditType typeHome = EntityModifier.getType(kindPhone, Phone.TYPE_HOME);
+        EntityModifier.getType(kindPhone, Phone.TYPE_HOME);
 
         // Try creating a contact without any child entries
         final EntityDelta state = getEntity(null);
@@ -528,7 +533,7 @@
 
         // Try creating a contact with single empty entry
         final EntityDelta state = getEntity(null);
-        final ValuesDelta values = EntityModifier.insertChild(state, kindPhone, typeHome);
+        EntityModifier.insertChild(state, kindPhone, typeHome);
         final EntityDeltaList set = EntityDeltaList.fromSingle(state);
 
         // Build diff, expecting two insert operations
diff --git a/tests/src/com/android/contacts/activities/ContactBrowserActivityTest.java b/tests/src/com/android/contacts/activities/ContactBrowserActivityTest.java
index 912950f..88da971 100644
--- a/tests/src/com/android/contacts/activities/ContactBrowserActivityTest.java
+++ b/tests/src/com/android/contacts/activities/ContactBrowserActivityTest.java
@@ -16,6 +16,7 @@
 
 package com.android.contacts.activities;
 
+import com.android.contacts.ContactPhotoManager;
 import com.android.contacts.ContactsApplication;
 import com.android.contacts.R;
 import com.android.contacts.detail.ContactDetailFragment;
@@ -26,6 +27,7 @@
 import com.android.contacts.test.InjectedServices;
 import com.android.contacts.tests.mocks.ContactsMockContext;
 import com.android.contacts.tests.mocks.MockAccountTypeManager;
+import com.android.contacts.tests.mocks.MockContactPhotoManager;
 import com.android.contacts.tests.mocks.MockContentProvider;
 import com.android.contacts.tests.mocks.MockContentProvider.Query;
 import com.android.contacts.tests.mocks.MockSharedPreferences;
@@ -85,7 +87,8 @@
         InjectedServices services = new InjectedServices();
         services.setContentResolver(mContext.getContentResolver());
         services.setSharedPreferences(new MockSharedPreferences());
-
+        services.setSystemService(ContactPhotoManager.CONTACT_PHOTO_SERVICE,
+                new MockContactPhotoManager());
         AccountType accountType = new BaseAccountType();
         accountType.accountType = TEST_ACCOUNT_TYPE;
 
diff --git a/tests/src/com/android/contacts/interactions/PhoneNumberInteractionTest.java b/tests/src/com/android/contacts/interactions/PhoneNumberInteractionTest.java
index 43e844e..c401a8c 100644
--- a/tests/src/com/android/contacts/interactions/PhoneNumberInteractionTest.java
+++ b/tests/src/com/android/contacts/interactions/PhoneNumberInteractionTest.java
@@ -124,6 +124,26 @@
         assertEquals("sms:456", interaction.startedIntent.getDataString());
     }
 
+    public void testShouldCollapseWith() {
+        PhoneNumberInteraction.PhoneItem phoneItem1 = new PhoneNumberInteraction.PhoneItem();
+        PhoneNumberInteraction.PhoneItem phoneItem2 = new PhoneNumberInteraction.PhoneItem();
+
+        phoneItem1.phoneNumber = "123";
+        phoneItem2.phoneNumber = "123";
+
+        assertTrue(phoneItem1.shouldCollapseWith(phoneItem2));
+
+        phoneItem1.phoneNumber = "123";
+        phoneItem2.phoneNumber = "456";
+
+        assertFalse(phoneItem1.shouldCollapseWith(phoneItem2));
+
+        phoneItem1.phoneNumber = "123#,123";
+        phoneItem2.phoneNumber = "123#,456";
+
+        assertFalse(phoneItem1.shouldCollapseWith(phoneItem2));
+    }
+
     public void testCallNumberWhenThereAreDuplicates() {
         Uri contactUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, 13);
         expectQuery(contactUri)
diff --git a/tests/src/com/android/contacts/tests/allintents/AllIntentsActivity.java b/tests/src/com/android/contacts/tests/allintents/AllIntentsActivity.java
index 50a1f1f..03b6302 100644
--- a/tests/src/com/android/contacts/tests/allintents/AllIntentsActivity.java
+++ b/tests/src/com/android/contacts/tests/allintents/AllIntentsActivity.java
@@ -73,6 +73,7 @@
         ACTION_PICK_PHONE_LEGACY,
         ACTION_PICK_POSTAL,
         ACTION_PICK_POSTAL_LEGACY,
+        ACTION_PICK_EMAIL,
         ACTION_CREATE_SHORTCUT_CONTACT,
         ACTION_CREATE_SHORTCUT_DIAL,
         ACTION_CREATE_SHORTCUT_MESSAGE,
@@ -195,6 +196,11 @@
                 startContactSelectionActivityForResult(intent);
                 break;
             }
+            case ACTION_PICK_EMAIL: {
+                startContactSelectionActivityForResult(
+                        new Intent(Intent.ACTION_PICK, Email.CONTENT_URI));
+                break;
+            }
             case ACTION_CREATE_SHORTCUT_CONTACT: {
                 Intent intent = new Intent(Intent.ACTION_CREATE_SHORTCUT);
                 startContactSelectionActivityForResult(intent);
diff --git a/tests/src/com/android/contacts/tests/mocks/MockContactPhotoManager.java b/tests/src/com/android/contacts/tests/mocks/MockContactPhotoManager.java
new file mode 100644
index 0000000..6da205b
--- /dev/null
+++ b/tests/src/com/android/contacts/tests/mocks/MockContactPhotoManager.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.contacts.tests.mocks;
+
+import com.android.contacts.ContactPhotoManager;
+
+import android.net.Uri;
+import android.widget.ImageView;
+
+/**
+ * A photo preloader that always uses the "no contact" picture and never executes any real
+ * db queries
+ */
+public class MockContactPhotoManager extends ContactPhotoManager {
+    @Override
+    public void loadPhoto(ImageView view, long photoId) {
+        view.setImageResource(mDefaultResourceId);
+    }
+
+    @Override
+    public void loadPhoto(ImageView view, Uri photoUri) {
+        view.setImageResource(mDefaultResourceId);
+    }
+
+    @Override
+    public void pause() {
+    }
+
+    @Override
+    public void resume() {
+    }
+
+    @Override
+    public void refreshCache() {
+    }
+
+    @Override
+    public void preloadPhotosInBackground() {
+    }
+}