Merge "Fixed favorites layout in phone app."
diff --git a/proguard.flags b/proguard.flags
index 577144b..5a08b9f 100644
--- a/proguard.flags
+++ b/proguard.flags
@@ -2,6 +2,13 @@
   public <init>(...);
 }
 
+# Xml files containing onClick (menus and layouts) require that proguard not
+# remove their handlers.
+-keepclassmembers class * extends android.app.Activity {
+  public void *(android.view.View);
+  public void *(android.view.MenuItem);
+}
+
 # TODO: Instead of keeping the following two functions we could as well just remove them completely
 # as they are only used in test code
 
@@ -16,4 +23,4 @@
 # Any methods whose name is '*ForTest' are preserved.
 -keep class ** {
   *** *ForTest(...);
-}
\ No newline at end of file
+}
diff --git a/res/drawable-hdpi/ic_add_contact_holo_dark.png b/res/drawable-hdpi/ic_add_contact_holo_dark.png
new file mode 100644
index 0000000..1190bf6
--- /dev/null
+++ b/res/drawable-hdpi/ic_add_contact_holo_dark.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_add_contact_holo_light.png b/res/drawable-hdpi/ic_add_contact_holo_light.png
new file mode 100644
index 0000000..c0c201e
--- /dev/null
+++ b/res/drawable-hdpi/ic_add_contact_holo_light.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_fav_quickcontact_holo_dark.png b/res/drawable-hdpi/ic_contacts_holo_dark.png
similarity index 100%
rename from res/drawable-hdpi/ic_fav_quickcontact_holo_dark.png
rename to res/drawable-hdpi/ic_contacts_holo_dark.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_share_holo_dark.png b/res/drawable-hdpi/ic_share_holo_dark.png
new file mode 100644
index 0000000..686da4c
--- /dev/null
+++ b/res/drawable-hdpi/ic_share_holo_dark.png
Binary files differ
diff --git a/res/drawable-hdpi/sym_action_add.png b/res/drawable-hdpi/sym_action_add.png
deleted file mode 100755
index 45a9ec5..0000000
--- a/res/drawable-hdpi/sym_action_add.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/sym_action_view_contact.png b/res/drawable-hdpi/sym_action_view_contact.png
deleted file mode 100755
index 3a016ff..0000000
--- a/res/drawable-hdpi/sym_action_view_contact.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/ic_add_contact_holo_dark.png b/res/drawable-mdpi/ic_add_contact_holo_dark.png
new file mode 100644
index 0000000..9aadd04
--- /dev/null
+++ b/res/drawable-mdpi/ic_add_contact_holo_dark.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_add_contact_holo_light.png b/res/drawable-mdpi/ic_add_contact_holo_light.png
new file mode 100644
index 0000000..84ec510
--- /dev/null
+++ b/res/drawable-mdpi/ic_add_contact_holo_light.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_fav_quickcontact_holo_dark.png b/res/drawable-mdpi/ic_contacts_holo_dark.png
similarity index 100%
rename from res/drawable-mdpi/ic_fav_quickcontact_holo_dark.png
rename to res/drawable-mdpi/ic_contacts_holo_dark.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_share_holo_dark.png b/res/drawable-mdpi/ic_share_holo_dark.png
new file mode 100644
index 0000000..5c33eac
--- /dev/null
+++ b/res/drawable-mdpi/ic_share_holo_dark.png
Binary files differ
diff --git a/res/drawable-mdpi/sym_action_add.png b/res/drawable-mdpi/sym_action_add.png
deleted file mode 100644
index af637b3..0000000
--- a/res/drawable-mdpi/sym_action_add.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi/sym_action_view_contact.png b/res/drawable-mdpi/sym_action_view_contact.png
deleted file mode 100644
index 118d8b3..0000000
--- a/res/drawable-mdpi/sym_action_view_contact.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_add_contact_holo_dark.png b/res/drawable-xhdpi/ic_add_contact_holo_dark.png
new file mode 100644
index 0000000..2eac542
--- /dev/null
+++ b/res/drawable-xhdpi/ic_add_contact_holo_dark.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_add_contact_holo_light.png b/res/drawable-xhdpi/ic_add_contact_holo_light.png
new file mode 100644
index 0000000..578df30
--- /dev/null
+++ b/res/drawable-xhdpi/ic_add_contact_holo_light.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_fav_quickcontact_holo_dark.png b/res/drawable-xhdpi/ic_contacts_holo_dark.png
similarity index 100%
rename from res/drawable-xhdpi/ic_fav_quickcontact_holo_dark.png
rename to res/drawable-xhdpi/ic_contacts_holo_dark.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_share_holo_dark.png b/res/drawable-xhdpi/ic_share_holo_dark.png
new file mode 100644
index 0000000..b3e2f80
--- /dev/null
+++ b/res/drawable-xhdpi/ic_share_holo_dark.png
Binary files differ
diff --git a/res/drawable-xhdpi/sym_action_add.png b/res/drawable-xhdpi/sym_action_add.png
deleted file mode 100644
index 32f8e22..0000000
--- a/res/drawable-xhdpi/sym_action_add.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/sym_action_view_contact.png b/res/drawable-xhdpi/sym_action_view_contact.png
deleted file mode 100644
index 2c14e56..0000000
--- a/res/drawable-xhdpi/sym_action_view_contact.png
+++ /dev/null
Binary files differ
diff --git a/res/layout-sw580dp-w1000dp/contact_detail_fragment.xml b/res/layout-sw580dp-w1000dp/contact_detail_fragment.xml
index f4c95f8..b8328ef 100644
--- a/res/layout-sw580dp-w1000dp/contact_detail_fragment.xml
+++ b/res/layout-sw580dp-w1000dp/contact_detail_fragment.xml
@@ -21,7 +21,8 @@
     android:orientation="vertical"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:background="@drawable/panel_content">
+    android:background="@color/background_primary"
+    android:padding="16dip">
 
     <!-- Placeholder for empty list -->
     <include
@@ -40,10 +41,7 @@
             android:scaleType="centerCrop"
             android:layout_width="@dimen/detail_contact_photo_size"
             android:layout_height="@dimen/detail_contact_photo_size"
-            android:layout_marginLeft="@dimen/detail_contact_photo_margin"
-            android:layout_marginRight="@dimen/detail_contact_photo_margin"
-            android:layout_marginTop="@dimen/detail_contact_photo_margin"
-            android:layout_marginBottom="@dimen/detail_contact_photo_margin"/>
+            android:layout_marginRight="@dimen/detail_contact_photo_margin"/>
 
         <ListView android:id="@android:id/list"
             android:layout_width="0dip"
diff --git a/res/layout-sw580dp-w1000dp/detail_header_contact_with_updates.xml b/res/layout-sw580dp-w1000dp/detail_header_contact_with_updates.xml
index 1a1a3bb..dce00ac 100644
--- a/res/layout-sw580dp-w1000dp/detail_header_contact_with_updates.xml
+++ b/res/layout-sw580dp-w1000dp/detail_header_contact_with_updates.xml
@@ -24,8 +24,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:orientation="horizontal"
-    android:padding="20dip">
+    android:orientation="horizontal">
 
     <ImageView
         android:id="@+id/photo"
@@ -37,8 +36,8 @@
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:orientation="vertical"
-        android:paddingLeft="10dip"
-        android:paddingRight="10dip">
+        android:paddingLeft="16dip"
+        android:paddingRight="16dip">
 
         <TextView
             android:id="@+id/name"
diff --git a/res/layout-sw580dp-w1000dp/detail_header_contact_without_updates.xml b/res/layout-sw580dp-w1000dp/detail_header_contact_without_updates.xml
index 415bbbf..486b7c2 100644
--- a/res/layout-sw580dp-w1000dp/detail_header_contact_without_updates.xml
+++ b/res/layout-sw580dp-w1000dp/detail_header_contact_without_updates.xml
@@ -23,8 +23,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:orientation="vertical"
-    android:paddingTop="20dip">
+    android:orientation="vertical">
 
     <TextView
         android:id="@+id/name"
diff --git a/res/layout-sw580dp/contact_detail_fragment.xml b/res/layout-sw580dp/contact_detail_fragment.xml
index cd559fe..c9dad2a 100644
--- a/res/layout-sw580dp/contact_detail_fragment.xml
+++ b/res/layout-sw580dp/contact_detail_fragment.xml
@@ -20,8 +20,7 @@
     android:id="@+id/contact_detail"
     android:orientation="vertical"
     android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:background="@drawable/panel_content">
+    android:layout_height="match_parent">
 
     <!-- Placeholder for empty list -->
     <include
@@ -30,23 +29,12 @@
         android:visibility="gone" />
 
     <!-- Real list -->
-    <com.android.contacts.widget.InterpolatingLayout
+    <ListView android:id="@android:id/list"
         android:layout_width="match_parent"
-        android:layout_height="0px"
-        android:layout_weight="1">
-        <ListView android:id="@android:id/list"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            ex:layout_wideParentWidth="800dip"
-            ex:layout_wideMarginLeft="64dip"
-            ex:layout_widePaddingRight="48dip"
-            ex:layout_narrowParentWidth="300dip"
-            ex:layout_narrowMarginLeft="5dip"
-            ex:layout_narrowPaddingRight="16dip"
-            android:cacheColorHint="#00000000"
-            android:divider="@null"
-        />
-    </com.android.contacts.widget.InterpolatingLayout>
+        android:layout_height="match_parent"
+        android:cacheColorHint="#00000000"
+        android:divider="@null"
+    />
 
     <!-- "QuickFix"- button (Copy to local contact, add to group) -->
     <Button
diff --git a/res/layout-sw580dp/detail_header_contact_without_updates.xml b/res/layout-sw580dp/detail_header_contact_without_updates.xml
index 4ae31c8..04fbad9 100644
--- a/res/layout-sw580dp/detail_header_contact_without_updates.xml
+++ b/res/layout-sw580dp/detail_header_contact_without_updates.xml
@@ -22,8 +22,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:orientation="vertical"
-    android:paddingTop="20dip">
+    android:orientation="vertical">
 
     <ImageView
         android:id="@+id/photo"
diff --git a/res/layout-sw580dp/people_activity.xml b/res/layout-sw580dp/people_activity.xml
index 87bb3b5..13adfa9 100644
--- a/res/layout-sw580dp/people_activity.xml
+++ b/res/layout-sw580dp/people_activity.xml
@@ -67,8 +67,10 @@
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             ex:layout_narrowParentWidth="800dip"
+            ex:layout_narrowMarginLeft="0dip"
             ex:layout_narrowMarginRight="0dip"
             ex:layout_wideParentWidth="1280dip"
+            ex:layout_wideMarginLeft="0dip"
             ex:layout_wideMarginRight="0dip"
             ex:clipMarginLeft="0dip"
             ex:clipMarginTop="3dip"
diff --git a/res/layout/call_detail.xml b/res/layout/call_detail.xml
index 83d3e20..a4de03f 100644
--- a/res/layout/call_detail.xml
+++ b/res/layout/call_detail.xml
@@ -57,49 +57,48 @@
         android:layout_height="wrap_content"
         android:layout_below="@id/contact_background_sizer"
     >
-        <fragment
-            class="com.android.contacts.voicemail.VoicemailPlaybackFragment"
-            android:id="@+id/voicemail_playback_fragment"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-        />
+        <!-- The voicemail fragment will be put here. -->
     </LinearLayout>
-    <LinearLayout
+    <View
+        android:id="@+id/photo_text_bar"
         android:layout_width="match_parent"
-        android:layout_height="@dimen/call_detail_contact_background_overlay_height"
-        android:background="#3F000000"
+        android:layout_height="42dip"
+        android:background="#7F000000"
         android:layout_alignParentLeft="true"
         android:layout_alignBottom="@id/contact_background_sizer"
     />
+    <ImageView
+        android:id="@+id/main_action"
+        android:layout_width="wrap_content"
+        android:layout_height="0dip"
+        android:scaleType="center"
+        android:layout_alignRight="@id/photo_text_bar"
+        android:layout_alignBottom="@id/photo_text_bar"
+        android:layout_alignTop="@id/photo_text_bar"
+        android:layout_marginRight="@dimen/call_log_outer_margin"
+    />
     <RelativeLayout
-        android:id="@+id/contact_text"
-        android:layout_width="match_parent"
-        android:layout_height="@dimen/call_detail_contact_background_overlay_height"
-        android:layout_alignParentLeft="true"
-        android:layout_alignBottom="@id/contact_background_sizer"
-        android:paddingLeft="@dimen/call_detail_contact_name_margin"
+        android:layout_width="wrap_content"
+        android:layout_height="0dip"
+        android:layout_alignLeft="@id/photo_text_bar"
+        android:layout_alignTop="@id/photo_text_bar"
+        android:layout_toLeftOf="@id/main_action"
+        android:layout_alignBottom="@id/photo_text_bar"
+        android:layout_marginRight="@dimen/call_log_inner_margin"
+        android:layout_marginLeft="@dimen/call_detail_contact_name_margin"
     >
-        <ImageView
-            android:id="@+id/main_action"
-            android:layout_width="@dimen/call_log_call_action_size"
-            android:layout_height="match_parent"
-            android:gravity="center_vertical"
-            android:scaleType="center"
-            android:layout_alignParentRight="true"
-            android:layout_alignParentBottom="true"
-            android:layout_marginRight="@dimen/call_log_outer_margin"
-            android:layout_marginLeft="@dimen/call_log_inner_margin"
-        />
-        <RelativeLayout
-            android:layout_width="wrap_content"
-            android:layout_height="match_parent"
-            android:layout_alignParentLeft="true"
-            android:layout_toLeftOf="@id/main_action"
-            android:layout_alignParentBottom="true"
-        >
-            <include layout="@layout/call_log_phone_call_details" />
-        </RelativeLayout>
+        <include layout="@layout/call_log_phone_call_details" />
     </RelativeLayout>
+    <ImageButton
+        android:id="@+id/main_action_push_layer"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_alignLeft="@id/contact_background_sizer"
+        android:layout_alignTop="@id/contact_background_sizer"
+        android:layout_alignRight="@id/contact_background_sizer"
+        android:layout_alignBottom="@id/contact_background_sizer"
+        android:background="?android:attr/selectableItemBackground"
+    />
     <ListView
         android:id="@android:id/list"
         android:layout_width="match_parent"
diff --git a/res/layout/call_detail_history_item.xml b/res/layout/call_detail_history_item.xml
index 069ade9..b225369 100644
--- a/res/layout/call_detail_history_item.xml
+++ b/res/layout/call_detail_history_item.xml
@@ -22,7 +22,8 @@
     android:background="?attr/call_log_secondary_background_color"
     android:padding="@dimen/call_log_indent_margin"
 >
-    <FrameLayout
+    <view
+        class="com.android.contacts.calllog.CallTypeIconsView"
         android:id="@+id/call_type_icon"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
diff --git a/res/layout/call_log_list_item.xml b/res/layout/call_log_list_item.xml
index a86d839..3b5601f 100644
--- a/res/layout/call_log_list_item.xml
+++ b/res/layout/call_log_list_item.xml
@@ -14,60 +14,41 @@
      limitations under the License.
 -->
 
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
+    android:padding="@dimen/call_log_inner_margin"
 >
     <!--
-        We have a nested FrameLayout because the margin attributes out the outer
-        layout are not used when this layout is inflated within a list.
+        This layout may represent either a call log item or one of the
+        headers in the call log.
 
-        TODO: Can we find a way to avoid the extra layer?
-     -->
-    <FrameLayout
+        The former will make the @id/call_log_item visible and the
+        @id/call_log_header gone.
+
+        The latter will make the @id/call_log_header visible and the
+        @id/call_log_item gone
+    -->
+
+    <RelativeLayout
+        android:id="@+id/call_log_item"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:gravity="center_vertical"
+    >
+        <include layout="@layout/call_log_contact_photo"/>
+        <include layout="@layout/call_log_action_call"/>
+        <include layout="@layout/call_log_list_item_layout"/>
+    </RelativeLayout>
+
+    <TextView
+        android:id="@+id/call_log_header_text"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_marginLeft="@dimen/call_log_inner_margin"
-        android:layout_marginRight="@dimen/call_log_inner_margin"
-        android:layout_marginTop="@dimen/call_log_inner_margin"
-        android:layout_marginBottom="@dimen/call_log_inner_margin"
-    >
-        <!--
-            This layout may represent either a call log item or one of the
-            headers in the call log.
-
-            The former will make the @id/call_log_item visible and the
-            @id/call_log_header gone.
-
-            The latter will make the @id/call_log_header visible and the
-            @id/call_log_item gone
-        -->
-
-        <RelativeLayout
-            android:id="@+id/call_log_item"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:gravity="center_vertical"
-        >
-            <include layout="@layout/call_log_contact_photo"/>
-            <include layout="@layout/call_log_action_call"/>
-            <include layout="@layout/call_log_list_item_layout"/>
-        </RelativeLayout>
-
-        <LinearLayout
-            android:id="@+id/call_log_header"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-        >
-            <TextView
-                android:id="@+id/call_log_header_text"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_marginLeft="@dimen/call_log_inner_margin"
-                android:textSize="14sp"
-                android:textStyle="bold"
-                android:textColor="?attr/call_log_header_color"
-            />
-        </LinearLayout>
-    </FrameLayout>
-</LinearLayout>
+        android:textSize="14sp"
+        android:textStyle="bold"
+        android:textColor="?attr/call_log_header_color"
+    />
+</FrameLayout>
diff --git a/res/layout/call_log_phone_call_details.xml b/res/layout/call_log_phone_call_details.xml
index 5a4131e..4d12a1d 100644
--- a/res/layout/call_log_phone_call_details.xml
+++ b/res/layout/call_log_phone_call_details.xml
@@ -45,13 +45,13 @@
             android:layout_height="wrap_content"
             android:orientation="horizontal"
         >
-            <LinearLayout
+            <view
+                class="com.android.contacts.calllog.CallTypeIconsView"
                 android:id="@+id/call_type_icons"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:layout_marginRight="@dimen/call_log_icon_margin"
                 android:layout_gravity="center_vertical"
-                android:orientation="horizontal"
             />
             <TextView
                 android:id="@+id/call_type_name"
diff --git a/res/layout/contact_detail_container.xml b/res/layout/contact_detail_container.xml
index 0b5b85a..3991e5c 100644
--- a/res/layout/contact_detail_container.xml
+++ b/res/layout/contact_detail_container.xml
@@ -26,13 +26,14 @@
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:orientation="vertical">
+    android:orientation="vertical"
+    android:background="@color/background_primary"
+    android:padding="16dip">
 
     <android.support.v4.view.ViewPager
         android:id="@+id/pager"
         android:layout_alignParentTop="true"
         android:layout_alignParentLeft="true"
-        android:paddingTop="20dip"
         android:layout_width="match_parent"
         android:layout_height="match_parent" />
 
@@ -42,10 +43,7 @@
         android:layout_alignParentTop="true"
         android:layout_alignParentLeft="true"
         android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:paddingTop="20dip"
-        android:paddingLeft="10dip"
-        android:paddingRight="10dip"/>
+        android:layout_height="wrap_content"/>
 
     <fragment
         android:id="@+id/contact_detail_fragment"
diff --git a/res/layout/create_new_contact.xml b/res/layout/create_new_contact.xml
index 2c36017..2edaf3e 100644
--- a/res/layout/create_new_contact.xml
+++ b/res/layout/create_new_contact.xml
@@ -31,7 +31,7 @@
             android:layout_marginLeft="5dip"
             android:layout_marginRight="11dip"
             android:focusable="false"
-            android:src="@*android:drawable/sym_action_add"
+            android:src="@drawable/ic_add_contact_holo_light"
             android:scaleType="fitCenter"
             />
     <TextView android:id="@+id/title"
diff --git a/res/layout/group_browse_list_item.xml b/res/layout/group_browse_list_item.xml
index ecdc132..b9b272c 100644
--- a/res/layout/group_browse_list_item.xml
+++ b/res/layout/group_browse_list_item.xml
@@ -19,6 +19,8 @@
     android:orientation="vertical"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
+    android:minHeight="@dimen/detail_min_line_item_height"
+    android:paddingRight="20dip"
     android:paddingBottom="10dip"
     style="@style/GroupBrowseListItem">
 
@@ -37,25 +39,76 @@
         layout="@layout/group_browse_list_account_header"
         android:visibility="gone" />
 
-    <TextView
-        android:id="@+id/label"
-        android:layout_height="wrap_content"
-        android:layout_width="wrap_content"
-        android:paddingLeft="10dip"
-        android:paddingRight="10dip"
-        android:textAppearance="?android:attr/textAppearanceMedium"
-        android:ellipsize="end"
-        android:singleLine="true" />
+    <RelativeLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content">
 
-    <TextView
-        android:id="@+id/count"
-        android:layout_height="wrap_content"
-        android:layout_width="wrap_content"
-        android:paddingLeft="10dip"
-        android:paddingRight="10dip"
-        android:textAppearance="?android:attr/textAppearanceSmall"
-        android:textColor="?android:attr/textColorTertiary"
-        android:ellipsize="end"
-        android:singleLine="true" />
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical"
+            android:layout_toLeftOf="@+id/icons"
+            android:layout_alignParentLeft="true"
+            android:layout_centerVertical="true">
 
+            <TextView
+                android:id="@+id/label"
+                android:layout_height="wrap_content"
+                android:layout_width="wrap_content"
+                android:paddingLeft="10dip"
+                android:paddingRight="10dip"
+                android:textAppearance="?android:attr/textAppearanceMedium"
+                android:ellipsize="end"
+                android:singleLine="true" />
+
+            <TextView
+                android:id="@+id/count"
+                android:layout_height="wrap_content"
+                android:layout_width="wrap_content"
+                android:paddingLeft="10dip"
+                android:paddingRight="10dip"
+                android:textAppearance="?android:attr/textAppearanceSmall"
+                android:textColor="?android:attr/textColorTertiary"
+                android:ellipsize="end"
+                android:singleLine="true" />
+
+        </LinearLayout>
+
+        <TableLayout
+            android:id="@+id/icons"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignParentRight="true"
+            android:layout_centerVertical="true">
+            <TableRow
+                android:layout_marginBottom="1dip">
+                <ImageView
+                    android:id="@+id/icon_1"
+                    android:layout_width="@dimen/group_list_icon_size"
+                    android:layout_height="@dimen/group_list_icon_size"
+                    android:layout_marginRight="1dip"
+                    android:src="@drawable/ic_contact_picture" />
+                <ImageView
+                    android:id="@+id/icon_2"
+                    android:layout_width="@dimen/group_list_icon_size"
+                    android:layout_height="@dimen/group_list_icon_size"
+                    android:src="@drawable/ic_contact_picture" />
+            </TableRow>
+            <TableRow>
+                <ImageView
+                    android:id="@+id/icon_3"
+                    android:layout_width="@dimen/group_list_icon_size"
+                    android:layout_height="@dimen/group_list_icon_size"
+                    android:layout_marginRight="1dip"
+                    android:src="@drawable/ic_contact_picture" />
+                <ImageView
+                    android:id="@+id/icon_4"
+                    android:layout_width="@dimen/group_list_icon_size"
+                    android:layout_height="@dimen/group_list_icon_size"
+                    android:src="@drawable/ic_contact_picture" />
+            </TableRow>
+
+        </TableLayout>
+    </RelativeLayout>
 </LinearLayout>
+
diff --git a/res/layout/playback_layout.xml b/res/layout/playback_layout.xml
index 1fb36be..020c017 100644
--- a/res/layout/playback_layout.xml
+++ b/res/layout/playback_layout.xml
@@ -40,18 +40,6 @@
                 android:src="@drawable/ic_hold_pause_holo_dark"
                 android:layout_weight="1"
             />
-            <ImageButton
-                android:id="@+id/playback_trash"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:padding="5px"
-                android:layout_marginTop="4dip"
-                android:layout_marginLeft="4dip"
-                android:layout_marginRight="4dip"
-                android:background="@drawable/dialpad_background"
-                android:src="@drawable/ic_trash_holo_dark"
-                android:layout_weight="1"
-            />
         </LinearLayout>
         <SeekBar
             android:id="@+id/playback_seek"
diff --git a/res/layout/quickcontact_photo_container.xml b/res/layout/quickcontact_photo_container.xml
index b18fddc..7df54d9 100644
--- a/res/layout/quickcontact_photo_container.xml
+++ b/res/layout/quickcontact_photo_container.xml
@@ -32,11 +32,10 @@
             android:layout_alignBottom="@id/photo"
             android:layout_alignLeft="@id/photo"
             android:layout_alignRight="@id/photo"
-            android:alpha="0.5"
-            android:background="@android:color/black" />
+            android:background="#7F000000" />
         <ImageButton
             android:id="@+id/open_details_button"
-            android:src="@drawable/ic_fav_quickcontact_holo_dark"
+            android:src="@drawable/ic_contacts_holo_dark"
             android:background="?android:attr/selectableItemBackground"
             android:layout_height="wrap_content"
             android:layout_width="wrap_content"
diff --git a/res/menu/call_details_options.xml b/res/menu/call_details_options.xml
index 68e265c..0db32a4 100644
--- a/res/menu/call_details_options.xml
+++ b/res/menu/call_details_options.xml
@@ -15,15 +15,26 @@
 -->
 <menu xmlns:android="http://schemas.android.com/apk/res/android">
     <item
-        android:id="@+id/remove_from_call_log"
+        android:id="@+id/menu_share_voicemail"
+        android:icon="@drawable/ic_share_holo_dark"
+        android:showAsAction="ifRoom"
+        android:onClick="onMenuShareVoicemail"
+    />
+    <item
+        android:id="@+id/menu_trash"
+        android:icon="@drawable/ic_trash_holo_dark"
+        android:showAsAction="ifRoom"
+        android:onClick="onMenuTrashVoicemail"
+    />
+    <item
+        android:id="@+id/menu_remove_from_call_log"
         android:icon="@android:drawable/ic_menu_close_clear_cancel"
         android:title="@string/recentCalls_removeFromRecentList"
-        android:showAsAction="withText"
+        android:onClick="onMenuRemoveFromCallLog"
     />
-
     <item
-        android:id="@+id/edit_number_before_call"
+        android:id="@+id/menu_edit_number_before_call"
         android:title="@string/recentCalls_editNumberBeforeCall"
-        android:showAsAction="withText"
+        android:onClick="onMenuEditNumberBeforeCall"
     />
 </menu>
diff --git a/res/values-sw580dp/dimens.xml b/res/values-sw580dp/dimens.xml
index 4de6bb7..a10d234 100644
--- a/res/values-sw580dp/dimens.xml
+++ b/res/values-sw580dp/dimens.xml
@@ -22,7 +22,7 @@
     <dimen name="editor_round_button_padding_right">8dip</dimen>
     <dimen name="editor_field_top_padding">12dip</dimen>
     <dimen name="editor_field_bottom_padding">12dip</dimen>
-    <dimen name="detail_item_side_margin">19dip</dimen>
+    <dimen name="detail_item_side_margin">0dip</dimen>
     <dimen name="contact_name_text_size">26sp</dimen>
     <dimen name="action_bar_filter_min_width">120dip</dimen>
     <dimen name="action_bar_filter_max_width">120dip</dimen>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 2ca8512..79d12f9 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -97,11 +97,6 @@
         <attr name="list_item_header_underline_color" format="color" />
     </declare-styleable>
 
-    <declare-styleable name="CallDetailActivity">
-        <attr name="call_detail_transparent_background" format="color" />
-        <attr name="call_detail_contact_background_overlay_alpha" format="float" />
-    </declare-styleable>
-
     <declare-styleable name="CallLog">
         <attr name="call_log_primary_text_color" format="color" />
         <attr name="call_log_primary_background_color" format="color" />
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index cbac941..a4a6112 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -116,7 +116,7 @@
     <dimen name="detail_update_section_internal_padding">16dip</dimen>
 
     <!-- Margin around the contact's photo on the contact card -->
-    <dimen name="detail_contact_photo_margin">15dip</dimen>
+    <dimen name="detail_contact_photo_margin">16dip</dimen>
 
     <!-- Width and height of the contact photo on the contact detail page -->
     <dimen name="detail_contact_photo_size">256dip</dimen>
@@ -173,6 +173,9 @@
     <!-- Border padding for the group list header for each account -->
     <dimen name="group_list_header_padding">5dip</dimen>
 
+    <!-- Size of group list icons -->
+    <dimen name="group_list_icon_size">32dip</dimen>
+
     <!-- Border padding for the group detail fragment header -->
     <dimen name="group_detail_border_padding">20dip</dimen>
 
@@ -219,7 +222,6 @@
     <dimen name="call_log_indent_margin">24dip</dimen>
     <dimen name="call_log_list_contact_photo_size">64dip</dimen>
     <dimen name="call_detail_contact_background_height">174dip</dimen>
-    <dimen name="call_detail_contact_background_overlay_height">42dip</dimen>
     <dimen name="call_detail_contact_name_margin">24dip</dimen>
     <dimen name="call_detail_action_bar_height">60dip</dimen>
 
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 6bc5582..6f1e84b 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -58,11 +58,9 @@
         <item name="favorites_padding_bottom">?android:attr/actionBarSize</item>
     </style>
 
-    <style name="CallDetailActivityTheme" parent="android:Theme.Holo.SplitActionBarWhenNarrow">
+    <style name="CallDetailActivityTheme" parent="android:Theme.Holo">
         <item name="android:windowBackground">@android:color/black</item>
         <item name="android:gravity">top</item>
-        <item name="call_detail_transparent_background">#CC000000</item>
-        <item name="call_detail_contact_background_overlay_alpha">0.25</item>
         <!-- CallLog -->
         <item name="call_log_primary_text_color">#FFFFFF</item>
         <item name="call_log_primary_background_color">#000000</item>
@@ -250,7 +248,6 @@
     </style>
 
     <style name="GroupBrowseListItem">
-        <item name="android:paddingRight">20dip</item>
     </style>
 
     <style name="DialtactsDigitsTextAppearance">
@@ -292,8 +289,7 @@
     </style>
 
     <style name="ContactTileStarredShadowBox">
-        <item name="android:alpha">0.5</item>
-        <item name="android:background">@android:color/black</item>
+        <item name="android:background">#7F000000</item>
     </style>
 
     <style name="DialtactsActionBarStyle" parent="android:Widget.Holo.ActionBar">
diff --git a/src/com/android/contacts/CallDetailActivity.java b/src/com/android/contacts/CallDetailActivity.java
index 813ebb1..d0eb817 100644
--- a/src/com/android/contacts/CallDetailActivity.java
+++ b/src/com/android/contacts/CallDetailActivity.java
@@ -25,7 +25,6 @@
 import com.android.contacts.voicemail.VoicemailStatusHelperImpl;
 
 import android.app.ActionBar;
-import android.app.FragmentManager;
 import android.app.ListActivity;
 import android.content.ContentResolver;
 import android.content.ContentUris;
@@ -52,6 +51,7 @@
 import android.view.ViewGroup;
 import android.widget.AdapterView;
 import android.widget.BaseAdapter;
+import android.widget.ImageButton;
 import android.widget.ImageView;
 import android.widget.ListView;
 import android.widget.TextView;
@@ -83,6 +83,7 @@
     private PhoneNumberHelper mPhoneNumberHelper;
     private PhoneCallDetailsHelper mPhoneCallDetailsHelper;
     private ImageView mMainActionView;
+    private ImageButton mMainActionPushLayerView;
     private ImageView mContactBackgroundView;
 
     private String mNumber = null;
@@ -101,8 +102,6 @@
     private TextView mStatusMessageText;
     private TextView mStatusMessageAction;
 
-    /** Whether we should show "remove from call log" in the options menu. */
-    private boolean mHasRemoveFromCallLog;
     /** Whether we should show "edit number before call" in the options menu. */
     private boolean mHasEditNumberBeforeCall;
 
@@ -147,7 +146,7 @@
         mResources = getResources();
 
         mPhoneCallDetailsViews = PhoneCallDetailsViews.fromView(getWindow().getDecorView());
-        mCallTypeHelper = new CallTypeHelper(getResources(), mInflater);
+        mCallTypeHelper = new CallTypeHelper(getResources());
         mPhoneNumberHelper = new PhoneNumberHelper(mResources, getVoicemailNumber());
         mPhoneCallDetailsHelper = new PhoneCallDetailsHelper(mResources, mCallTypeHelper,
                 mPhoneNumberHelper);
@@ -157,6 +156,7 @@
         mStatusMessageText = (TextView) findViewById(R.id.voicemail_status_message);
         mStatusMessageAction = (TextView) findViewById(R.id.voicemail_status_action);
         mMainActionView = (ImageView) findViewById(R.id.main_action);
+        mMainActionPushLayerView = (ImageButton) findViewById(R.id.main_action_push_layer);
         mContactBackgroundView = (ImageView) findViewById(R.id.contact_background);
         mDefaultCountryIso = ContactsUtils.getCurrentCountryIso(this);
         mContactPhotoManager = ContactPhotoManager.getInstance(this);
@@ -179,16 +179,22 @@
      */
     private void optionallyHandleVoicemail() {
         if (hasVoicemail()) {
-            // Has voicemail: leave the fragment visible.  Optionally start the playback.
+            // Has voicemail: add the voicemail fragment.  Add suitable arguments to set the uri
+            // to play and optionally start the playback.
             // Do a query to fetch the voicemail status messages.
-            boolean startPlayback = getIntent().getBooleanExtra(
-                    EXTRA_VOICEMAIL_START_PLAYBACK, false);
+            VoicemailPlaybackFragment playbackFragment = new VoicemailPlaybackFragment();
+            Bundle fragmentArguments = new Bundle();
             Uri voicemailUri = getIntent().getParcelableExtra(EXTRA_VOICEMAIL_URI);
-            getVoicemailPlaybackFragment().setVoicemailUri(voicemailUri, startPlayback);
+            fragmentArguments.putParcelable(EXTRA_VOICEMAIL_URI, voicemailUri);
+            if (getIntent().getBooleanExtra(EXTRA_VOICEMAIL_START_PLAYBACK, false)) {
+                fragmentArguments.putBoolean(EXTRA_VOICEMAIL_START_PLAYBACK, true);
+            }
+            playbackFragment.setArguments(fragmentArguments);
+            getFragmentManager().beginTransaction()
+                    .add(R.id.voicemail_container, playbackFragment).commit();
             mAsyncQueryHandler.startVoicemailStatusQuery(voicemailUri);
         } else {
-            // No voicemail uri: hide the voicemail fragment and the status view.
-            getFragmentManager().beginTransaction().hide(getVoicemailPlaybackFragment()).commit();
+            // No voicemail uri: hide the status view.
             mStatusMessageView.setVisibility(View.GONE);
         }
     }
@@ -197,12 +203,6 @@
         return getIntent().getParcelableExtra(EXTRA_VOICEMAIL_URI) != null;
     }
 
-    private VoicemailPlaybackFragment getVoicemailPlaybackFragment() {
-        FragmentManager manager = getFragmentManager();
-        return (VoicemailPlaybackFragment) manager.findFragmentById(
-                R.id.voicemail_playback_fragment);
-    }
-
     /**
      * Returns the list of URIs to show.
      * <p>
@@ -290,7 +290,7 @@
         if (details[0].personId != -1) {
             Uri personUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, personId);
             mainActionIntent = new Intent(Intent.ACTION_VIEW, personUri);
-            mainActionIcon = R.drawable.sym_action_view_contact;
+            mainActionIcon = R.drawable.ic_contacts_holo_dark;
         } else if (isVoicemailNumber) {
             mainActionIntent = null;
             mainActionIcon = 0;
@@ -310,7 +310,7 @@
             mainActionIntent = new Intent(Intent.ACTION_INSERT_OR_EDIT);
             mainActionIntent.setType(Contacts.CONTENT_ITEM_TYPE);
             mainActionIntent.putExtra(Insert.PHONE, mNumber);
-            mainActionIcon = R.drawable.sym_action_add;
+            mainActionIcon = R.drawable.ic_add_contact_holo_dark;
         } else {
             // If we cannot call the number, when we probably cannot add it as a contact either.
             // This is usually the case of private, unknown, or payphone numbers.
@@ -320,10 +320,12 @@
 
         if (mainActionIntent == null) {
             mMainActionView.setVisibility(View.INVISIBLE);
+            mMainActionPushLayerView.setVisibility(View.GONE);
         } else {
             mMainActionView.setVisibility(View.VISIBLE);
             mMainActionView.setImageResource(mainActionIcon);
-            mMainActionView.setOnClickListener(new View.OnClickListener() {
+            mMainActionPushLayerView.setVisibility(View.VISIBLE);
+            mMainActionPushLayerView.setOnClickListener(new View.OnClickListener() {
                 @Override
                 public void onClick(View v) {
                     startActivity(mainActionIntent);
@@ -349,9 +351,6 @@
                     getString(R.string.menu_sendTextMessage), smsIntent));
         }
 
-        // This action deletes all elements in the group from the call log.
-        // We don't have this action for voicemails, because you can just use the trash button.
-        mHasRemoveFromCallLog = !hasVoicemail();
         mHasEditNumberBeforeCall = canPlaceCallsTo && !isSipNumber && !isVoicemailNumber;
 
         if (actions.size() != 0) {
@@ -610,58 +609,65 @@
     @Override
     public boolean onCreateOptionsMenu(Menu menu) {
         getMenuInflater().inflate(R.menu.call_details_options, menu);
-        return true;
+        return super.onCreateOptionsMenu(menu);
     }
 
     @Override
     public boolean onPrepareOptionsMenu(Menu menu) {
         // This action deletes all elements in the group from the call log.
         // We don't have this action for voicemails, because you can just use the trash button.
-        menu.findItem(R.id.remove_from_call_log).setVisible(mHasRemoveFromCallLog);
-        menu.findItem(R.id.edit_number_before_call).setVisible(mHasEditNumberBeforeCall);
-        return mHasRemoveFromCallLog || mHasEditNumberBeforeCall;
+        menu.findItem(R.id.menu_remove_from_call_log).setVisible(!hasVoicemail());
+        menu.findItem(R.id.menu_edit_number_before_call).setVisible(mHasEditNumberBeforeCall);
+        menu.findItem(R.id.menu_trash).setVisible(hasVoicemail());
+        menu.findItem(R.id.menu_share_voicemail).setVisible(hasVoicemail());
+        return super.onPrepareOptionsMenu(menu);
     }
 
     @Override
     public boolean onMenuItemSelected(int featureId, MenuItem item) {
         switch (item.getItemId()) {
-            case R.id.remove_from_call_log: {
-                StringBuilder callIds = new StringBuilder();
-                for (Uri callUri : getCallLogEntryUris()) {
-                    if (callIds.length() != 0) {
-                        callIds.append(",");
-                    }
-                    callIds.append(ContentUris.parseId(callUri));
-                }
-
-                getContentResolver().delete(Calls.CONTENT_URI_WITH_VOICEMAIL,
-                        Calls._ID + " IN (" + callIds + ")", null);
-                // Also close the activity.
-                finish();
-                return true;
-            }
-
-            case R.id.edit_number_before_call:
-                startActivity(
-                        new Intent(Intent.ACTION_DIAL, mPhoneNumberHelper.getCallUri(mNumber)));
-                return true;
-
             case android.R.id.home: {
                 onHomeSelected();
                 return true;
             }
 
+            // All the options menu items are handled by onMenu... methods.
             default:
                 throw new IllegalArgumentException();
         }
     }
 
+    public void onMenuRemoveFromCallLog(MenuItem menuItem) {
+        StringBuilder callIds = new StringBuilder();
+        for (Uri callUri : getCallLogEntryUris()) {
+            if (callIds.length() != 0) {
+                callIds.append(",");
+            }
+            callIds.append(ContentUris.parseId(callUri));
+        }
+
+        getContentResolver().delete(Calls.CONTENT_URI_WITH_VOICEMAIL,
+                Calls._ID + " IN (" + callIds + ")", null);
+        // Also close the activity.
+        finish();
+    }
+
+    public void onMenuEditNumberBeforeCall(MenuItem menuItem) {
+        startActivity(new Intent(Intent.ACTION_DIAL, mPhoneNumberHelper.getCallUri(mNumber)));
+    }
+
+    public void onMenuShareVoicemail(MenuItem menuItem) {
+        Log.w(TAG, "onMenuShareVoicemail not yet implemented");
+    }
+
+    public void onMenuTrashVoicemail(MenuItem menuItem) {
+        Log.w(TAG, "onMenuTrashVoicemail not yet implemented");
+    }
+
     private void configureActionBar() {
         ActionBar actionBar = getActionBar();
         if (actionBar != null) {
-            actionBar.setDisplayOptions(ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME,
-                    ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_TITLE
-                    | ActionBar.DISPLAY_SHOW_HOME);
+            actionBar.setDisplayOptions(ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_HOME);
             actionBar.setIcon(R.drawable.ic_ab_dialer_holo_dark);
         }
     }
diff --git a/src/com/android/contacts/PhoneCallDetailsHelper.java b/src/com/android/contacts/PhoneCallDetailsHelper.java
index f312a5d..8cdd0d0 100644
--- a/src/com/android/contacts/PhoneCallDetailsHelper.java
+++ b/src/com/android/contacts/PhoneCallDetailsHelper.java
@@ -61,10 +61,10 @@
     public void setPhoneCallDetails(PhoneCallDetailsViews views, PhoneCallDetails details,
             boolean useIcons, boolean isHighlighted, boolean nameOnly) {
         if (useIcons) {
-            views.callTypeIcons.removeAllViews();
+            views.callTypeIcons.clear();
             int count = details.callTypes.length;
             for (int index = 0; index < count && index < MAX_CALL_TYPE_ICONS; ++index) {
-                mCallTypeHelper.inflateCallTypeIcon(details.callTypes[index], views.callTypeIcons);
+                views.callTypeIcons.add(details.callTypes[index]);
             }
             views.callTypeIcons.setVisibility(View.VISIBLE);
             if (count > MAX_CALL_TYPE_ICONS) {
@@ -77,14 +77,13 @@
                 views.callTypeSeparator.setVisibility(View.GONE);
             }
         } else {
-            String callTypeName;
             // Use the name of the first call type.
             // TODO: We should update this to handle the text for multiple calls as well.
             int callType = details.callTypes[0];
             views.callTypeText.setText(
                     isHighlighted ? mCallTypeHelper.getHighlightedCallTypeText(callType)
                             : mCallTypeHelper.getCallTypeText(callType));
-            views.callTypeIcons.removeAllViews();
+            views.callTypeIcons.clear();
 
             views.callTypeText.setVisibility(View.VISIBLE);
             views.callTypeSeparator.setVisibility(View.VISIBLE);
diff --git a/src/com/android/contacts/PhoneCallDetailsViews.java b/src/com/android/contacts/PhoneCallDetailsViews.java
index 19e931f..c07e337 100644
--- a/src/com/android/contacts/PhoneCallDetailsViews.java
+++ b/src/com/android/contacts/PhoneCallDetailsViews.java
@@ -16,9 +16,10 @@
 
 package com.android.contacts;
 
+import com.android.contacts.calllog.CallTypeIconsView;
+
 import android.content.Context;
 import android.view.View;
-import android.widget.LinearLayout;
 import android.widget.TextView;
 
 /**
@@ -27,14 +28,15 @@
 public final class PhoneCallDetailsViews {
     public final TextView nameView;
     public final View callTypeView;
-    public final LinearLayout callTypeIcons;
+    public final CallTypeIconsView callTypeIcons;
     public final TextView callTypeText;
     public final View callTypeSeparator;
     public final TextView dateView;
     public final TextView numberView;
 
-    private PhoneCallDetailsViews(TextView nameView, View callTypeView, LinearLayout callTypeIcons,
-            TextView callTypeText, View callTypeSeparator, TextView dateView, TextView numberView) {
+    private PhoneCallDetailsViews(TextView nameView, View callTypeView,
+            CallTypeIconsView callTypeIcons, TextView callTypeText, View callTypeSeparator,
+            TextView dateView, TextView numberView) {
         this.nameView = nameView;
         this.callTypeView = callTypeView;
         this.callTypeIcons = callTypeIcons;
@@ -54,7 +56,7 @@
     public static PhoneCallDetailsViews fromView(View view) {
         return new PhoneCallDetailsViews((TextView) view.findViewById(R.id.name),
                 view.findViewById(R.id.call_type),
-                (LinearLayout) view.findViewById(R.id.call_type_icons),
+                (CallTypeIconsView) view.findViewById(R.id.call_type_icons),
                 (TextView) view.findViewById(R.id.call_type_name),
                 view.findViewById(R.id.call_type_separator),
                 (TextView) view.findViewById(R.id.date),
@@ -65,7 +67,7 @@
         return new PhoneCallDetailsViews(
                 new TextView(context),
                 new View(context),
-                new LinearLayout(context),
+                new CallTypeIconsView(context),
                 new TextView(context),
                 new View(context),
                 new TextView(context),
diff --git a/src/com/android/contacts/calllog/CallDetailHistoryAdapter.java b/src/com/android/contacts/calllog/CallDetailHistoryAdapter.java
index e55020c..3e3ba36 100644
--- a/src/com/android/contacts/calllog/CallDetailHistoryAdapter.java
+++ b/src/com/android/contacts/calllog/CallDetailHistoryAdapter.java
@@ -64,19 +64,20 @@
     @Override
     public View getView(int position, View convertView, ViewGroup parent) {
         // Make sure we have a valid convertView to start with
-        if (convertView == null) {
-            convertView = mLayoutInflater.inflate(R.layout.call_detail_history_item, parent, false);
-        }
+        final View result  = convertView == null
+                ? mLayoutInflater.inflate(R.layout.call_detail_history_item, parent, false)
+                : convertView;
 
         PhoneCallDetails details = mPhoneCallDetails[position];
-        FrameLayout callTypeIconView = (FrameLayout) convertView.findViewById(R.id.call_type_icon);
-        TextView callTypeTextView = (TextView) convertView.findViewById(R.id.call_type_text);
-        TextView dateView = (TextView) convertView.findViewById(R.id.date);
-        TextView durationView = (TextView) convertView.findViewById(R.id.duration);
+        CallTypeIconsView callTypeIconView =
+                (CallTypeIconsView) result.findViewById(R.id.call_type_icon);
+        TextView callTypeTextView = (TextView) result.findViewById(R.id.call_type_text);
+        TextView dateView = (TextView) result.findViewById(R.id.date);
+        TextView durationView = (TextView) result.findViewById(R.id.duration);
 
         int callType = details.callTypes[0];
-        callTypeIconView.removeAllViews();
-        mCallTypeHelper.inflateCallTypeIcon(callType, callTypeIconView);
+        callTypeIconView.clear();
+        callTypeIconView.add(callType);
         callTypeTextView.setText(mCallTypeHelper.getCallTypeText(callType));
         // Set the date.
         CharSequence dateValue = DateUtils.formatDateRange(mContext, details.date, details.date,
@@ -84,14 +85,14 @@
                 DateUtils.FORMAT_SHOW_WEEKDAY | DateUtils.FORMAT_SHOW_YEAR);
         dateView.setText(dateValue);
         // Set the duration
-        if (callType == Calls.MISSED_TYPE) {
+        if (callType == Calls.MISSED_TYPE || callType == Calls.VOICEMAIL_TYPE) {
             durationView.setVisibility(View.GONE);
         } else {
             durationView.setVisibility(View.VISIBLE);
             durationView.setText(formatDuration(details.duration));
         }
 
-        return convertView;
+        return result;
     }
 
     private String formatDuration(long elapsedSeconds) {
diff --git a/src/com/android/contacts/calllog/CallLogFragment.java b/src/com/android/contacts/calllog/CallLogFragment.java
index abc9adf..0999b44 100644
--- a/src/com/android/contacts/calllog/CallLogFragment.java
+++ b/src/com/android/contacts/calllog/CallLogFragment.java
@@ -313,11 +313,7 @@
             mPreDrawListener = null;
 
             Resources resources = getResources();
-            LayoutInflater layoutInflater = getActivity().getLayoutInflater();
-            CallTypeHelper callTypeHelper = new CallTypeHelper(resources, layoutInflater);
-            Drawable callDrawable = resources.getDrawable(R.drawable.ic_dial_action_call);
-            Drawable playDrawable = resources.getDrawable(
-                    R.drawable.ic_call_log_list_action_play);
+            CallTypeHelper callTypeHelper = new CallTypeHelper(resources);
 
             mContactPhotoManager = ContactPhotoManager.getInstance(getActivity());
             mPhoneNumberHelper = new PhoneNumberHelper(getResources(), mVoiceMailNumber);
@@ -678,7 +674,7 @@
             if (section == CallLogQuery.SECTION_NEW_HEADER
                     || section == CallLogQuery.SECTION_OLD_HEADER) {
                 views.listItemView.setVisibility(View.GONE);
-                views.listHeaderView.setVisibility(View.VISIBLE);
+                views.listHeaderTextView.setVisibility(View.VISIBLE);
                 views.listHeaderTextView.setText(
                         section == CallLogQuery.SECTION_NEW_HEADER
                                 ? R.string.call_log_new_header
@@ -688,7 +684,7 @@
             }
             // Default case: an item in the call log.
             views.listItemView.setVisibility(View.VISIBLE);
-            views.listHeaderView.setVisibility(View.GONE);
+            views.listHeaderTextView.setVisibility(View.GONE);
 
             final String number = c.getString(CallLogQuery.NUMBER);
             final long date = c.getLong(CallLogQuery.DATE);
diff --git a/src/com/android/contacts/calllog/CallLogListItemViews.java b/src/com/android/contacts/calllog/CallLogListItemViews.java
index 90f78f7..368a868 100644
--- a/src/com/android/contacts/calllog/CallLogListItemViews.java
+++ b/src/com/android/contacts/calllog/CallLogListItemViews.java
@@ -45,14 +45,12 @@
     public final PhoneCallDetailsViews phoneCallDetailsViews;
     /** The item view for a stand-alone row, or null for other types of rows. */
     public final View listItemView;
-    /** The header view for a stand-alone row, or null for other types of rows. */
-    public final View listHeaderView;
     /** The text of the header in a stand-alone row, or null for other types of rows. */
     public final TextView listHeaderTextView;
 
     private CallLogListItemViews(QuickContactBadge quickContactView, ImageView photoView,
             View callView, View playView, View unheardView, View dividerView,
-            PhoneCallDetailsViews phoneCallDetailsViews, View listItemView, View listHeaderView,
+            PhoneCallDetailsViews phoneCallDetailsViews, View listItemView,
             TextView listHeaderTextView) {
         this.quickContactView = quickContactView;
         this.plainPhotoView = photoView;
@@ -62,7 +60,6 @@
         this.dividerView = dividerView;
         this.phoneCallDetailsViews = phoneCallDetailsViews;
         this.listItemView = listItemView;
-        this.listHeaderView = listHeaderView;
         this.listHeaderTextView = listHeaderTextView;
     }
 
@@ -76,7 +73,6 @@
                 view.findViewById(R.id.divider),
                 PhoneCallDetailsViews.fromView(view),
                 view.findViewById(R.id.call_log_item),
-                view.findViewById(R.id.call_log_header),
                 (TextView) view.findViewById(R.id.call_log_header_text));
     }
 
@@ -90,7 +86,6 @@
                 new View(context),
                 PhoneCallDetailsViews.createForTest(context),
                 new View(context),
-                new View(context),
                 new TextView(context));
     }
 }
diff --git a/src/com/android/contacts/calllog/CallTypeHelper.java b/src/com/android/contacts/calllog/CallTypeHelper.java
index 465e2bf..d27d4f9 100644
--- a/src/com/android/contacts/calllog/CallTypeHelper.java
+++ b/src/com/android/contacts/calllog/CallTypeHelper.java
@@ -25,16 +25,11 @@
 import android.text.Spanned;
 import android.text.style.ForegroundColorSpan;
 import android.text.style.StyleSpan;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
 
 /**
  * Helper class to perform operations related to call types.
  */
 public class CallTypeHelper {
-    /** Used to create the views for the call types. */
-    private final LayoutInflater mLayoutInflater;
     /** Name used to identify incoming calls. */
     private final CharSequence mIncomingName;
     /** Name used to identify outgoing calls. */
@@ -48,8 +43,7 @@
     /** Name used to identify new voicemail calls. */
     private final CharSequence mNewVoicemailName;
 
-    public CallTypeHelper(Resources resources, LayoutInflater layoutInflater) {
-        mLayoutInflater = layoutInflater;
+    public CallTypeHelper(Resources resources) {
         // Cache these values so that we do not need to look them up each time.
         mIncomingName = resources.getString(R.string.type_incoming);
         mOutgoingName = resources.getString(R.string.type_outgoing);
@@ -103,26 +97,6 @@
         }
     }
 
-    /** Returns a new view for the icon to be used to represent a given call type. */
-    public View inflateCallTypeIcon(int callType, ViewGroup root) {
-        switch (callType) {
-            case Calls.INCOMING_TYPE:
-                return mLayoutInflater.inflate(R.layout.call_log_incoming_call_icon, root);
-
-            case Calls.OUTGOING_TYPE:
-                return mLayoutInflater.inflate(R.layout.call_log_outgoing_call_icon, root);
-
-            case Calls.MISSED_TYPE:
-                return mLayoutInflater.inflate(R.layout.call_log_missed_call_icon, root);
-
-            case Calls.VOICEMAIL_TYPE:
-                return mLayoutInflater.inflate(R.layout.call_log_voicemail_icon, root);
-
-            default:
-                throw new IllegalArgumentException("invalid call type: " + callType);
-        }
-    }
-
     /** Creates a SpannableString for the given text which is bold and in the given color. */
     private CharSequence addBoldAndColor(CharSequence text, int color) {
         int flags = Spanned.SPAN_INCLUSIVE_INCLUSIVE;
diff --git a/src/com/android/contacts/calllog/CallTypeIconsView.java b/src/com/android/contacts/calllog/CallTypeIconsView.java
new file mode 100644
index 0000000..4fbe7d7
--- /dev/null
+++ b/src/com/android/contacts/calllog/CallTypeIconsView.java
@@ -0,0 +1,123 @@
+/*
+ * 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.calllog;
+
+import com.android.contacts.R;
+import com.google.common.collect.Lists;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+import android.provider.CallLog.Calls;
+import android.util.AttributeSet;
+import android.view.View;
+
+import java.util.List;
+
+/**
+ * View that draws one or more symbols for different types of calls (missed calls, outgoing etc).
+ * The symbols are set up horizontally. As this view doesn't create subviews, it is better suited
+ * for ListView-recycling that a regular LinearLayout using ImageViews.
+ */
+public class CallTypeIconsView extends View {
+    private List<Integer> mCallTypes = Lists.newArrayListWithCapacity(3);
+    private Resources mResources;
+    private int mWidth;
+    private int mHeight;
+
+    public CallTypeIconsView(Context context) {
+        this(context, null);
+    }
+
+    public CallTypeIconsView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        mResources = new Resources(context);
+    }
+
+    public void clear() {
+        mCallTypes.clear();
+        mWidth = 0;
+        mHeight = 0;
+        invalidate();
+    }
+
+    public void add(int callType) {
+        mCallTypes.add(callType);
+
+        final Drawable drawable = getCallTypeDrawable(callType);
+        mWidth += drawable.getIntrinsicWidth() + mResources.iconMargin;
+        mHeight = Math.max(mHeight, drawable.getIntrinsicHeight());
+        invalidate();
+    }
+
+    public int getCount() {
+        return mCallTypes.size();
+    }
+
+    public int getCallType(int index) {
+        return mCallTypes.get(index);
+    }
+
+    private Drawable getCallTypeDrawable(int callType) {
+        switch (callType) {
+            case Calls.INCOMING_TYPE:
+                return mResources.incoming;
+            case Calls.OUTGOING_TYPE:
+                return mResources.outgoing;
+            case Calls.MISSED_TYPE:
+                return mResources.missed;
+            case Calls.VOICEMAIL_TYPE:
+                return mResources.voicemail;
+            default:
+                throw new IllegalArgumentException("invalid call type: " + callType);
+        }
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        setMeasuredDimension(mWidth, mHeight);
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        int left = 0;
+        for (Integer callType : mCallTypes) {
+            final Drawable drawable = getCallTypeDrawable(callType);
+            final int right = left + drawable.getIntrinsicWidth();
+            drawable.setBounds(left, 0, right, drawable.getIntrinsicHeight());
+            drawable.draw(canvas);
+            left = right + mResources.iconMargin;
+        }
+    }
+
+    private static class Resources {
+        public final Drawable incoming;
+        public final Drawable outgoing;
+        public final Drawable missed;
+        public final Drawable voicemail;
+        public final int iconMargin;
+
+        public Resources(Context context) {
+            final android.content.res.Resources r = context.getResources();
+            incoming = r.getDrawable(R.drawable.ic_call_incoming_holo_dark);
+            outgoing = r.getDrawable(R.drawable.ic_call_outgoing_holo_dark);
+            missed = r.getDrawable(R.drawable.ic_call_missed_holo_dark);
+            voicemail = r.getDrawable(R.drawable.ic_call_voicemail_holo_dark);
+            iconMargin = r.getDimensionPixelSize(R.dimen.call_log_icon_margin);
+        }
+    }
+}
diff --git a/src/com/android/contacts/group/GroupBrowseListAdapter.java b/src/com/android/contacts/group/GroupBrowseListAdapter.java
index 630a397..1f06029 100644
--- a/src/com/android/contacts/group/GroupBrowseListAdapter.java
+++ b/src/com/android/contacts/group/GroupBrowseListAdapter.java
@@ -16,33 +16,159 @@
 
 package com.android.contacts.group;
 
+import com.android.contacts.ContactPhotoManager;
 import com.android.contacts.GroupListLoader;
 import com.android.contacts.R;
 import com.android.contacts.model.AccountType;
 import com.android.contacts.model.AccountTypeManager;
-import com.android.contacts.model.AccountWithDataSet;
 import com.android.internal.util.Objects;
 
+import android.content.ContentResolver;
 import android.content.ContentUris;
 import android.content.Context;
 import android.database.Cursor;
 import android.net.Uri;
+import android.os.AsyncTask;
+import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
+import android.provider.ContactsContract.Data;
 import android.provider.ContactsContract.Groups;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.BaseAdapter;
+import android.widget.ImageView;
 import android.widget.TextView;
 
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
 /**
  * Adapter to populate the list of groups.
  */
 public class GroupBrowseListAdapter extends BaseAdapter {
 
+    private static final int MAX_ICONS_PER_GROUP_ROW = 4;
+
+    private static final String[] PROJECTION_GROUP_MEMBERSHIP_INFO = new String[] {
+        GroupMembership._ID,
+        GroupMembership.PHOTO_ID
+    };
+    private static final int GROUP_MEMBERSHIP_COLUMN_PHOTO_ID = 1;
+
+    /**
+     * Arguments for asynchronous photo ID loading. See {@link AsyncPhotoIdLoadTask}
+     */
+    private static class AsyncPhotoIdLoadArg {
+        public final View icons;
+        public final long groupId;
+        public final Map<Long, ArrayList<Long>> groupPhotoIdMap;
+        public final ContentResolver contentResolver;
+        public final ContactPhotoManager contactPhotoManager;
+
+        public AsyncPhotoIdLoadArg(
+                View icons, long groupId, Map<Long, ArrayList<Long>> groupPhotoIdMap,
+                ContentResolver contentResolver, ContactPhotoManager contactPhotoManager) {
+            this.icons = icons;
+            this.groupId = groupId;
+            this.groupPhotoIdMap = groupPhotoIdMap;
+            this.contentResolver = contentResolver;
+            this.contactPhotoManager = contactPhotoManager;
+        }
+    }
+
+    /**
+     * Loads photo IDs associated with a group ID supplied from {@link AsyncPhotoIdLoadArg#groupId},
+     * storing them in {@link GroupBrowseListAdapter#mGroupPhotoIdMap}.
+     *
+     * This AsyncTask also remembers a View which is associated with the group ID at the moment it
+     * is initiated (we use {@link View#setTag(Object) and View#getTag() to associate them}. If the
+     * View is still associated with the group ID after the asynchronous photo ID load, this class
+     * also asks {@link ContactPhotoManager} to load actual photo contents. Its parent (typically
+     * ListView) may reuse Views for different group IDs, so the photo content load often don't
+     * occur.
+     */
+    private static class AsyncPhotoIdLoadTask extends
+            AsyncTask<AsyncPhotoIdLoadArg, Void, ArrayList<Long>> {
+
+        private View mIcons;
+        private long mGroupId;
+        private Map<Long, ArrayList<Long>> mGroupPhotoIdMap;
+        private ContentResolver mContentResolver;
+        private ContactPhotoManager mContactPhotoManager;
+
+        @Override
+        protected ArrayList<Long> doInBackground(AsyncPhotoIdLoadArg... params) {
+            final AsyncPhotoIdLoadArg arg = params[0];
+            mIcons = arg.icons;
+            mGroupId = arg.groupId;
+            mGroupPhotoIdMap = arg.groupPhotoIdMap;
+            mContentResolver = arg.contentResolver;
+            mContactPhotoManager = arg.contactPhotoManager;
+
+            // Multiple requests for one group ID is possible. We just ignore duplicates,
+            // assuming query results won't change.
+            if (mGroupPhotoIdMap.containsKey(mGroupId)) {
+                return null;
+            }
+
+            final ArrayList<Long> photoIds = new ArrayList<Long>(MAX_ICONS_PER_GROUP_ROW);
+            Cursor cursor = null;
+            try {
+                cursor = mContentResolver.query(Data.CONTENT_URI,
+                        PROJECTION_GROUP_MEMBERSHIP_INFO,
+                        GroupMembership.MIMETYPE + "=? AND "
+                                + GroupMembership.PHOTO_ID + " IS NOT NULL AND "
+                                + GroupMembership.GROUP_ROW_ID + "=?",
+                        new String[] { GroupMembership.CONTENT_ITEM_TYPE,
+                                String.valueOf(mGroupId) }, null);
+                if (cursor != null) {
+                    int count = 0;
+                    while (cursor.moveToNext() && count < MAX_ICONS_PER_GROUP_ROW) {
+                        photoIds.add(cursor.getLong(GROUP_MEMBERSHIP_COLUMN_PHOTO_ID));
+                        count++;
+                    }
+                }
+            } finally {
+                if (cursor != null) {
+                    cursor.close();
+                }
+            }
+            return photoIds;
+        }
+
+        @Override
+        protected void onPostExecute(ArrayList<Long> photoIds) {
+            if (photoIds == null) {
+                return;
+            }
+
+            mGroupPhotoIdMap.put(mGroupId, photoIds);
+
+            final View icons = mIcons;
+            // If the original group ID, which was supplied when this AsyncTask was executed, is
+            // consistent with the ID inside mArgs, it means the View isn't reused by the
+            // other groups, and thus we can assume these Views are available for the group ID.
+            final Long currentGroupId = (Long) icons.getTag();
+            if (currentGroupId == mGroupId) {
+                final ImageView[] children = getIconViewsSordedByFillOrder(icons);
+                for (int i = 0; i < children.length; i++) {
+                    final long photoId = i < photoIds.size() ? photoIds.get(i) : 0;
+                    mContactPhotoManager.loadPhoto(children[i], photoId);
+                }
+            }
+        }
+    }
+
     private final Context mContext;
     private final LayoutInflater mLayoutInflater;
     private final AccountTypeManager mAccountTypeManager;
 
+    private final Map<Long, ArrayList<Long>> mGroupPhotoIdMap =
+            new ConcurrentHashMap<Long, ArrayList<Long>>();
+
+    private final ContactPhotoManager mContactPhotoManager;
+
     private Cursor mCursor;
 
     private boolean mSelectionVisible;
@@ -52,6 +178,7 @@
         mContext = context;
         mLayoutInflater = LayoutInflater.from(context);
         mAccountTypeManager = AccountTypeManager.getInstance(mContext);
+        mContactPhotoManager = ContactPhotoManager.getInstance(mContext);
     }
 
     public void setCursor(Cursor cursor) {
@@ -179,6 +306,32 @@
         viewCache.groupTitle.setText(entry.getTitle());
         viewCache.groupMemberCount.setText(memberCountString);
 
+        final View icons = result.findViewById(R.id.icons);
+        final ImageView[] children = getIconViewsSordedByFillOrder(icons);
+        final ArrayList<Long> photoIds = mGroupPhotoIdMap.get(entry.getGroupId());
+
+        // Let the icon holder remember its associated group ID.
+        // Each AsyncTask loading photo IDs will compare this ID with the AsyncTask's argument, and
+        // check if the bound View is reused by the other list items or not. If the View is reused,
+        // the group ID set here will be overridden by the new owner, thus ID inconsistency happens.
+        icons.setTag(entry.getGroupId());
+        if (photoIds != null) {
+            // Cache is available. Let the photo manager load those IDs.
+            for (int i = 0; i < children.length; i++) {
+                final long photoId = i < photoIds.size() ? photoIds.get(i) : 0;
+                mContactPhotoManager.loadPhoto(children[i], photoId);
+            }
+        } else {
+            // Cache is not available. Load photo IDs asynchronously.
+            for (ImageView child : children) {
+                mContactPhotoManager.loadPhoto(child, 0);
+            }
+            new AsyncPhotoIdLoadTask().execute(
+                    new AsyncPhotoIdLoadArg(icons, entry.getGroupId(),
+                            mGroupPhotoIdMap, mContext.getContentResolver(),
+                            mContactPhotoManager));
+        }
+
         if (mSelectionVisible) {
             result.setActivated(isSelectedGroup(groupUri));
         }
@@ -201,6 +354,19 @@
     }
 
     /**
+     * Get ImageView objects inside the given View, sorted by the order photos should be filled.
+     */
+    private static ImageView[] getIconViewsSordedByFillOrder(View icons) {
+        final ImageView[] children = new ImageView[] {
+                (ImageView) icons.findViewById(R.id.icon_4),
+                (ImageView) icons.findViewById(R.id.icon_2),
+                (ImageView) icons.findViewById(R.id.icon_3),
+                (ImageView) icons.findViewById(R.id.icon_1)
+        };
+        return children;
+    }
+
+    /**
      * Cache of the children views of a contact detail entry represented by a
      * {@link GroupListItem}
      */
diff --git a/src/com/android/contacts/list/ContactTileAdapter.java b/src/com/android/contacts/list/ContactTileAdapter.java
index 2c64d8f..5850a4a 100644
--- a/src/com/android/contacts/list/ContactTileAdapter.java
+++ b/src/com/android/contacts/list/ContactTileAdapter.java
@@ -236,7 +236,7 @@
 
     @Override
     public int getCount() {
-        if (mContactCursor == null || mContactCursor.getCount() == 0) {
+        if (mContactCursor == null) {
             return 0;
         }
 
@@ -458,30 +458,15 @@
             for (int columnCounter = 0; columnCounter < columnCount; columnCounter++) {
                 ContactEntry entry =
                         columnCounter < list.size() ? list.get(columnCounter) : null;
-                        addTileFromEntry(entry, columnCounter);
-                }
+                addTileFromEntry(entry, columnCounter);
             }
+        }
 
         private void addTileFromEntry(ContactEntry entry, int tileIndex) {
             final ContactTileView contactTile;
 
             if (getChildCount() <= tileIndex) {
-                switch (mItemViewType) {
-                    case ViewTypes.STARRED_WITH_SECONDARY_ACTION:
-                        contactTile = (ContactTileSecondaryTargetView)
-                                inflate(mContext, mLayoutResId, null);
-                        break;
-                    case ViewTypes.STARRED:
-                        contactTile =
-                                (ContactTileStarredView) inflate(mContext, mLayoutResId, null);
-                        break;
-                    case ViewTypes.FREQUENT:
-                        contactTile = (ContactTileView) inflate(mContext, mLayoutResId, null);
-                        break;
-                    default:
-                        throw new IllegalStateException(
-                                "Unrecognized ViewType " + mItemViewType);
-                }
+                contactTile = (ContactTileView) inflate(mContext, mLayoutResId, null);
                 contactTile.setLayoutParams(new LinearLayout.LayoutParams(0,
                         LinearLayout.LayoutParams.WRAP_CONTENT, 1.0f));
                 contactTile.setPhotoManager(mPhotoManager);
diff --git a/src/com/android/contacts/list/ContactTileView.java b/src/com/android/contacts/list/ContactTileView.java
index aee34c9..4dfa876 100644
--- a/src/com/android/contacts/list/ContactTileView.java
+++ b/src/com/android/contacts/list/ContactTileView.java
@@ -52,7 +52,6 @@
 
     public ContactTileView(Context context, AttributeSet attrs) {
         super(context, attrs);
-        setLayerType(View.LAYER_TYPE_HARDWARE, null);
     }
 
     @Override
diff --git a/src/com/android/contacts/model/ExternalAccountType.java b/src/com/android/contacts/model/ExternalAccountType.java
index caf311b..e5af8f8 100644
--- a/src/com/android/contacts/model/ExternalAccountType.java
+++ b/src/com/android/contacts/model/ExternalAccountType.java
@@ -23,6 +23,7 @@
 
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
@@ -74,6 +75,7 @@
     private int mInviteActionLabelResId;
     private String mAccountTypeLabelAttribute;
     private String mAccountTypeIconAttribute;
+    private boolean mInitSuccessful;
 
     public ExternalAccountType(Context context, String resPackageName) {
         this.resPackageName = resPackageName;
@@ -81,17 +83,18 @@
 
         // Handle unknown sources by searching their package
         final PackageManager pm = context.getPackageManager();
-        final Intent syncAdapter = new Intent(ACTION_SYNC_ADAPTER);
-        final List<ResolveInfo> matches = pm.queryIntentServices(syncAdapter,
-                PackageManager.GET_META_DATA);
-        for (ResolveInfo info : matches) {
-            ServiceInfo serviceInfo = info.serviceInfo;
-            if (serviceInfo.packageName.equals(resPackageName)) {
+        try {
+            PackageInfo packageInfo = pm.getPackageInfo(resPackageName,
+                    PackageManager.GET_SERVICES|PackageManager.GET_META_DATA);
+            for (ServiceInfo serviceInfo : packageInfo.services) {
                 final XmlResourceParser parser = serviceInfo.loadXmlMetaData(pm,
                         METADATA_CONTACTS);
                 if (parser == null) continue;
                 inflate(context, parser);
             }
+        } catch (NameNotFoundException nnfe) {
+            // If the package name is not found, we can't initialize this account type.
+            return;
         }
 
         mExtensionPackageNames = new ArrayList<String>();
@@ -107,6 +110,9 @@
         addDataKindDisplayName(context);
         addDataKindPhoneticName(context);
         addDataKindPhoto(context);
+
+        // If we reach this point, the account type has been successfully initialized.
+        mInitSuccessful = true;
     }
 
     @Override
@@ -114,6 +120,14 @@
         return true;
     }
 
+    /**
+     * Whether this account type was able to be fully initialized.  This may be false if
+     * (for example) the package name associated with the account type could not be found.
+     */
+    public boolean isInitialized() {
+        return mInitSuccessful;
+    }
+
     @Override
     public String getEditContactActivityClassName() {
         return mEditContactActivityClassName;
diff --git a/src/com/android/contacts/model/GoogleAccountType.java b/src/com/android/contacts/model/GoogleAccountType.java
index c3dbd79..a5fab96 100644
--- a/src/com/android/contacts/model/GoogleAccountType.java
+++ b/src/com/android/contacts/model/GoogleAccountType.java
@@ -35,6 +35,9 @@
     protected static final int FLAGS_RELATION = EditorInfo.TYPE_CLASS_TEXT
     | EditorInfo.TYPE_TEXT_FLAG_CAP_WORDS | EditorInfo.TYPE_TEXT_VARIATION_PERSON_NAME;
 
+    private static final List<String> mExtensionPackages =
+            Lists.newArrayList("com.google.android.apps.plus");
+
     public GoogleAccountType(Context context, String resPackageName) {
         this.accountType = ACCOUNT_TYPE;
         this.resPackageName = null;
@@ -60,8 +63,7 @@
 
     @Override
     public List<String> getExtensionPackageNames() {
-        // TODO: Return the Google+ package name once it has the XML for an ExternalAccountType.
-        return super.getExtensionPackageNames();
+        return mExtensionPackages;
     }
 
     @Override
diff --git a/src/com/android/contacts/quickcontact/FloatingChildLayout.java b/src/com/android/contacts/quickcontact/FloatingChildLayout.java
index 62b4f1a..5358aca 100644
--- a/src/com/android/contacts/quickcontact/FloatingChildLayout.java
+++ b/src/com/android/contacts/quickcontact/FloatingChildLayout.java
@@ -158,7 +158,7 @@
         final int scaleInterpolator = isExitAnimation ? android.R.interpolator.accelerate_quint
                 : android.R.interpolator.decelerate_quint;
         animator.setInterpolator(AnimationUtils.loadInterpolator(getContext(), scaleInterpolator));
-        final float scaleTarget = isExitAnimation ? 0.7f : 1.0f;
+        final float scaleTarget = isExitAnimation ? 0.5f : 1.0f;
         animator.scaleX(scaleTarget);
         animator.scaleY(scaleTarget);
         animator.alpha(isExitAnimation ? 0.0f : 1.0f);
diff --git a/src/com/android/contacts/quickcontact/QuickContactActivity.java b/src/com/android/contacts/quickcontact/QuickContactActivity.java
index d236e01..1ef40db 100644
--- a/src/com/android/contacts/quickcontact/QuickContactActivity.java
+++ b/src/com/android/contacts/quickcontact/QuickContactActivity.java
@@ -68,6 +68,7 @@
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.view.ViewGroup;
+import android.view.WindowManager;
 import android.widget.HorizontalScrollView;
 import android.widget.ImageButton;
 import android.widget.ImageView;
@@ -163,6 +164,10 @@
     protected void onCreate(Bundle icicle) {
         super.onCreate(icicle);
 
+        // Show QuickContact in front of soft input
+        getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
+                WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
+
         setContentView(R.layout.quickcontact_activity);
 
         mFloatingLayout = (FloatingChildLayout) findViewById(R.id.floating_layout);
diff --git a/src/com/android/contacts/socialwidget/SocialWidgetProvider.java b/src/com/android/contacts/socialwidget/SocialWidgetProvider.java
index 4686c81..ee41332 100644
--- a/src/com/android/contacts/socialwidget/SocialWidgetProvider.java
+++ b/src/com/android/contacts/socialwidget/SocialWidgetProvider.java
@@ -202,7 +202,7 @@
         sb.setSpan(sizeSpan, 0, name.length(), 0);
         sb.setSpan(styleSpan, 0, name.length(), 0);
 
-        if (streamItems.isEmpty()) {
+        if (streamItems == null || streamItems.isEmpty()) {
             views.setTextViewText(R.id.name, sb);
             views.setViewVisibility(R.id.name, View.VISIBLE);
             views.setViewVisibility(R.id.name_and_snippet, View.GONE);
diff --git a/src/com/android/contacts/voicemail/VoicemailPlaybackFragment.java b/src/com/android/contacts/voicemail/VoicemailPlaybackFragment.java
index b1da1a1..d306209 100644
--- a/src/com/android/contacts/voicemail/VoicemailPlaybackFragment.java
+++ b/src/com/android/contacts/voicemail/VoicemailPlaybackFragment.java
@@ -16,9 +16,13 @@
 
 package com.android.contacts.voicemail;
 
+import static com.android.contacts.CallDetailActivity.EXTRA_VOICEMAIL_START_PLAYBACK;
+import static com.android.contacts.CallDetailActivity.EXTRA_VOICEMAIL_URI;
+
 import com.android.contacts.R;
 import com.android.ex.variablespeed.MediaPlayerProxy;
 import com.android.ex.variablespeed.VariableSpeed;
+import com.google.common.base.Preconditions;
 
 import android.app.Fragment;
 import android.content.Context;
@@ -62,7 +66,6 @@
     private SeekBar mPlaybackSeek;
     private ImageButton mStartStopButton;
     private ImageButton mPlaybackSpeakerphone;
-    private ImageButton mPlaybackTrashButton;
     private TextView mPlaybackPositionText;
     private ImageButton mRateDecreaseButton;
     private ImageButton mRateIncreaseButton;
@@ -71,12 +74,11 @@
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container,
             Bundle savedInstanceState) {
-        View view = inflater.inflate(R.layout.playback_layout, container);
+        View view = inflater.inflate(R.layout.playback_layout, null);
         mPlaybackSeek = (SeekBar) view.findViewById(R.id.playback_seek);
         mPlaybackSeek = (SeekBar) view.findViewById(R.id.playback_seek);
         mStartStopButton = (ImageButton) view.findViewById(R.id.playback_start_stop);
         mPlaybackSpeakerphone = (ImageButton) view.findViewById(R.id.playback_speakerphone);
-        mPlaybackTrashButton = (ImageButton) view.findViewById(R.id.playback_trash);
         mPlaybackPositionText = (TextView) view.findViewById(R.id.playback_position_text);
         mRateDecreaseButton = (ImageButton) view.findViewById(R.id.rate_decrease_button);
         mRateIncreaseButton = (ImageButton) view.findViewById(R.id.rate_increase_button);
@@ -88,8 +90,14 @@
     public void onActivityCreated(Bundle savedInstanceState) {
         super.onActivityCreated(savedInstanceState);
         mScheduledExecutorService = createScheduledExecutorService();
+        Bundle arguments = getArguments();
+        Preconditions.checkNotNull(arguments, "fragment must be started with arguments");
+        Uri voicemailUri = arguments.getParcelable(EXTRA_VOICEMAIL_URI);
+        Preconditions.checkNotNull(voicemailUri, "fragment must contain EXTRA_VOICEMAIL_URI");
+        boolean startPlayback = arguments.getBoolean(EXTRA_VOICEMAIL_START_PLAYBACK, false);
         mPresenter = new VoicemailPlaybackPresenter(new PlaybackViewImpl(),
-                createMediaPlayer(mScheduledExecutorService), mScheduledExecutorService);
+                createMediaPlayer(mScheduledExecutorService), voicemailUri,
+                mScheduledExecutorService, startPlayback);
         mPresenter.onCreate(savedInstanceState);
     }
 
@@ -106,11 +114,6 @@
         super.onDestroy();
     }
 
-    /** Call this from the Activity containing this fragment to set the voicemail to play. */
-    public void setVoicemailUri(Uri voicemailUri, boolean startPlaying) {
-        mPresenter.setVoicemailUri(voicemailUri, startPlaying);
-    }
-
     private MediaPlayerProxy createMediaPlayer(ExecutorService executorService) {
         return VariableSpeed.createVariableSpeed(executorService);
     }
@@ -183,11 +186,6 @@
         }
 
         @Override
-        public void setDeleteButtonListener(View.OnClickListener listener) {
-            mPlaybackTrashButton.setOnClickListener(listener);
-        }
-
-        @Override
         public void setPositionSeekListener(SeekBar.OnSeekBarChangeListener listener) {
             mPlaybackSeek.setOnSeekBarChangeListener(listener);
         }
diff --git a/src/com/android/contacts/voicemail/VoicemailPlaybackPresenter.java b/src/com/android/contacts/voicemail/VoicemailPlaybackPresenter.java
index 5e7b707..eac502d 100644
--- a/src/com/android/contacts/voicemail/VoicemailPlaybackPresenter.java
+++ b/src/com/android/contacts/voicemail/VoicemailPlaybackPresenter.java
@@ -56,7 +56,6 @@
         void setStartStopListener(View.OnClickListener listener);
         void setPositionSeekListener(SeekBar.OnSeekBarChangeListener listener);
         void setSpeakerphoneListener(View.OnClickListener listener);
-        void setDeleteButtonListener(View.OnClickListener listener);
         void setClipPosition(int clipPositionInMillis, int clipLengthInMillis);
         int getDesiredClipPosition();
         void playbackStarted();
@@ -119,13 +118,18 @@
     private final MediaPlayerProxy mPlayer;
     private final PositionUpdater mPositionUpdater;
 
-    /** Voicemail uri to play, will be set with a call to {@link #setVoicemailUri(Uri, boolean)}. */
-    private Uri mVoicemailUri;
+    /** Voicemail uri to play. */
+    private final Uri mVoicemailUri;
+    /** Start playing in onCreate iff this is true. */
+    private final boolean mStartPlayingImmediately;
 
     public VoicemailPlaybackPresenter(PlaybackView view, MediaPlayerProxy player,
-            ScheduledExecutorService executorService) {
+            Uri voicemailUri, ScheduledExecutorService executorService,
+            boolean startPlayingImmediately) {
         mView = view;
         mPlayer = player;
+        mVoicemailUri = voicemailUri;
+        mStartPlayingImmediately = startPlayingImmediately;
         mPositionUpdater = new PositionUpdater(executorService, SLIDER_UPDATE_PERIOD_MILLIS);
     }
 
@@ -133,7 +137,6 @@
         mView.setPositionSeekListener(new PlaybackPositionListener());
         mView.setStartStopListener(new StartStopButtonListener());
         mView.setSpeakerphoneListener(new SpeakerphoneListener());
-        mView.setDeleteButtonListener(new DeleteButtonListener());
         mPlayer.setOnErrorListener(new MediaPlayerErrorListener());
         mPlayer.setOnCompletionListener(new MediaPlayerCompletionListener());
         mView.setSpeakerPhoneOn(mView.isSpeakerPhoneOn());
@@ -141,6 +144,9 @@
         mView.setRateIncreaseButtonListener(createRateIncreaseListener());
         mView.setClipPosition(0, 0);
         mView.playbackStopped();
+        if (mStartPlayingImmediately) {
+            resetPrepareStartPlaying(0);
+        }
         // TODO: Now I'm ignoring the bundle, when previously I was checking for contains against
         // the PAUSED_STATE_KEY, and CLIP_POSITION_KEY.
     }
@@ -157,13 +163,6 @@
         mPlayer.release();
     }
 
-    public void setVoicemailUri(Uri voicemailUri, boolean startPlaying) {
-        mVoicemailUri = voicemailUri;
-        if (startPlaying) {
-            resetPrepareStartPlaying(0);
-        }
-    }
-
     private class MediaPlayerErrorListener implements MediaPlayer.OnErrorListener {
         @Override
         public boolean onError(MediaPlayer mp, int what, int extra) {
@@ -302,15 +301,6 @@
         }
     }
 
-    private class DeleteButtonListener implements View.OnClickListener {
-        @Override
-        public void onClick(View v) {
-            // TODO: Temporarily removed this whilst the team discuss the merits of porting
-            // the VoicemailHelper class across vs just hard-coding the delete via cursor.
-            mView.finish();
-        }
-    }
-
     private class StartStopButtonListener implements View.OnClickListener {
         @Override
         public void onClick(View arg0) {
@@ -334,7 +324,13 @@
         private final Runnable mSetClipPostitionRunnable = new Runnable() {
             @Override
             public void run() {
-                mView.setClipPosition(mPlayer.getCurrentPosition(), mDuration.get());
+                int currentPosition = 0;
+                synchronized (mLock) {
+                    if (mScheduledFuture != null) {
+                        currentPosition = mPlayer.getCurrentPosition();
+                    }
+                }
+                mView.setClipPosition(currentPosition, mDuration.get());
             }
         };
 
@@ -345,11 +341,7 @@
 
         @Override
         public void run() {
-            synchronized (mLock) {
-                if (mScheduledFuture != null) {
-                    mView.runOnUiThread(mSetClipPostitionRunnable);
-                }
-            }
+            mView.runOnUiThread(mSetClipPostitionRunnable);
         }
 
         public void startUpdating(int beginPosition, int endPosition) {
diff --git a/tests/src/com/android/contacts/CallDetailActivityTest.java b/tests/src/com/android/contacts/CallDetailActivityTest.java
index c1efa3f..cdb6e44 100644
--- a/tests/src/com/android/contacts/CallDetailActivityTest.java
+++ b/tests/src/com/android/contacts/CallDetailActivityTest.java
@@ -103,7 +103,7 @@
         Menu menu = new ContextMenuBuilder(activity);
         activity.onCreateOptionsMenu(menu);
         activity.onPrepareOptionsMenu(menu);
-        assertFalse(menu.findItem(R.id.remove_from_call_log).isVisible());
+        assertFalse(menu.findItem(R.id.menu_remove_from_call_log).isVisible());
     }
 
     /** Test to check that I haven't broken the remove-from-call-log entry from regular calls. */
@@ -113,7 +113,7 @@
         Menu menu = new ContextMenuBuilder(activity);
         activity.onCreateOptionsMenu(menu);
         activity.onPrepareOptionsMenu(menu);
-        assertTrue(menu.findItem(R.id.remove_from_call_log).isVisible());
+        assertTrue(menu.findItem(R.id.menu_remove_from_call_log).isVisible());
     }
 
     /**
diff --git a/tests/src/com/android/contacts/PhoneCallDetailsHelperTest.java b/tests/src/com/android/contacts/PhoneCallDetailsHelperTest.java
index 8feca19..1e5d879 100644
--- a/tests/src/com/android/contacts/PhoneCallDetailsHelperTest.java
+++ b/tests/src/com/android/contacts/PhoneCallDetailsHelperTest.java
@@ -25,7 +25,6 @@
 import android.content.res.Resources;
 import android.provider.CallLog.Calls;
 import android.test.AndroidTestCase;
-import android.view.LayoutInflater;
 import android.view.View;
 
 import java.util.GregorianCalendar;
@@ -59,9 +58,7 @@
         super.setUp();
         Context context = getContext();
         Resources resources = context.getResources();
-        LayoutInflater layoutInflater =
-                (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-        CallTypeHelper callTypeHelper = new CallTypeHelper(resources, layoutInflater);
+        CallTypeHelper callTypeHelper = new CallTypeHelper(resources);
         mPhoneNumberHelper = new PhoneNumberHelper(resources, TEST_VOICEMAIL_NUMBER);
         mHelper = new PhoneCallDetailsHelper(resources, callTypeHelper, mPhoneNumberHelper);
         mViews = PhoneCallDetailsViews.createForTest(context);
@@ -128,25 +125,30 @@
 
     public void testSetPhoneCallDetails_CallTypeIcons() {
         setPhoneCallDetailsWithCallTypeIcons(Calls.INCOMING_TYPE);
-        assertCallTypeIconsEquals(R.id.call_log_incoming_call_icon);
+        assertCallTypeIconsEquals(Calls.INCOMING_TYPE);
 
         setPhoneCallDetailsWithCallTypeIcons(Calls.OUTGOING_TYPE);
-        assertCallTypeIconsEquals(R.id.call_log_outgoing_call_icon);
+        assertCallTypeIconsEquals(Calls.OUTGOING_TYPE);
 
         setPhoneCallDetailsWithCallTypeIcons(Calls.MISSED_TYPE);
-        assertCallTypeIconsEquals(R.id.call_log_missed_call_icon);
+        assertCallTypeIconsEquals(Calls.MISSED_TYPE);
 
         setPhoneCallDetailsWithCallTypeIcons(Calls.VOICEMAIL_TYPE);
-        assertCallTypeIconsEquals(R.id.call_log_voicemail_icon);
+        assertCallTypeIconsEquals(Calls.VOICEMAIL_TYPE);
     }
 
     public void testSetPhoneCallDetails_MultipleCallTypeIcons() {
         setPhoneCallDetailsWithCallTypeIcons(Calls.INCOMING_TYPE, Calls.OUTGOING_TYPE);
-        assertCallTypeIconsEquals(R.id.call_log_incoming_call_icon,
-                R.id.call_log_outgoing_call_icon);
+        assertCallTypeIconsEquals(Calls.INCOMING_TYPE, Calls.OUTGOING_TYPE);
 
         setPhoneCallDetailsWithCallTypeIcons(Calls.MISSED_TYPE, Calls.MISSED_TYPE);
-        assertCallTypeIconsEquals(R.id.call_log_missed_call_icon, R.id.call_log_missed_call_icon);
+        assertCallTypeIconsEquals(Calls.MISSED_TYPE, Calls.MISSED_TYPE);
+    }
+
+    public void testSetPhoneCallDetails_MultipleCallTypeIconsLastOneDropped() {
+        setPhoneCallDetailsWithCallTypeIcons(Calls.MISSED_TYPE, Calls.MISSED_TYPE,
+                Calls.INCOMING_TYPE, Calls.OUTGOING_TYPE);
+        assertCallTypeIconsEquals(Calls.MISSED_TYPE, Calls.MISSED_TYPE, Calls.INCOMING_TYPE);
     }
 
     public void testSetPhoneCallDetails_CallTypeText() {
@@ -222,10 +224,10 @@
 
     /** Asserts that the call type contains the images with the given drawables. */
     private void assertCallTypeIconsEquals(int... ids) {
-        assertEquals(ids.length, mViews.callTypeIcons.getChildCount());
+        assertEquals(ids.length, mViews.callTypeIcons.getCount());
         for (int index = 0; index < ids.length; ++index) {
             int id = ids[index];
-            assertEquals(id, mViews.callTypeIcons.getChildAt(index).getId());
+            assertEquals(id, mViews.callTypeIcons.getCallType(index));
         }
         assertEquals(View.VISIBLE, mViews.callTypeIcons.getVisibility());
         assertEquals(View.GONE, mViews.callTypeText.getVisibility());
diff --git a/tests/src/com/android/contacts/calllog/CallLogListItemHelperTest.java b/tests/src/com/android/contacts/calllog/CallLogListItemHelperTest.java
index 79ebf4d..4628b8e 100644
--- a/tests/src/com/android/contacts/calllog/CallLogListItemHelperTest.java
+++ b/tests/src/com/android/contacts/calllog/CallLogListItemHelperTest.java
@@ -24,7 +24,6 @@
 import android.content.res.Resources;
 import android.provider.CallLog.Calls;
 import android.test.AndroidTestCase;
-import android.view.LayoutInflater;
 import android.view.View;
 
 /**
@@ -56,9 +55,7 @@
         super.setUp();
         Context context = getContext();
         Resources resources = context.getResources();
-        LayoutInflater layoutInflater =
-                (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-        CallTypeHelper callTypeHelper = new CallTypeHelper(resources, layoutInflater);
+        CallTypeHelper callTypeHelper = new CallTypeHelper(resources);
         mPhoneNumberHelper = new PhoneNumberHelper(resources, TEST_VOICEMAIL_NUMBER);
         PhoneCallDetailsHelper phoneCallDetailsHelper = new PhoneCallDetailsHelper(
                 resources, callTypeHelper, mPhoneNumberHelper);