Merge "Implement new QuickContact design"
diff --git a/res/layout-sw580dp-w1000dp/contact_detail_fragment.xml b/res/layout-sw580dp-w1000dp/contact_detail_fragment.xml
index 9dd3690..f4c95f8 100644
--- a/res/layout-sw580dp-w1000dp/contact_detail_fragment.xml
+++ b/res/layout-sw580dp-w1000dp/contact_detail_fragment.xml
@@ -32,8 +32,9 @@
     <!-- Real list -->
     <LinearLayout
         android:orientation="horizontal"
+        android:layout_weight="1"
         android:layout_width="match_parent"
-        android:layout_height="match_parent">
+        android:layout_height="0dip">
 
         <ImageView android:id="@+id/photo"
             android:scaleType="centerCrop"
diff --git a/res/layout-sw580dp-w1000dp/contact_detail_list_item.xml b/res/layout-sw580dp-w1000dp/contact_detail_list_item.xml
index 2de488d..22f0412 100644
--- a/res/layout-sw580dp-w1000dp/contact_detail_list_item.xml
+++ b/res/layout-sw580dp-w1000dp/contact_detail_list_item.xml
@@ -47,9 +47,24 @@
                     android:layout_height="wrap_content"
                     android:visibility="gone" />
 
-                <TextView
-                    android:id="@+id/type"
-                    style="@style/ContactDetailItemType" />
+                <LinearLayout
+                    android:layout_width="wrap_content"
+                    android:layout_height="match_parent"
+                    android:orientation="horizontal">
+
+                    <TextView
+                        android:id="@+id/type"
+                        style="@style/ContactDetailItemType" />
+
+                    <View
+                        android:id="@+id/primary_indicator"
+                        android:layout_width="16dip"
+                        android:layout_height="16dip"
+                        android:visibility="gone"
+                        android:layout_gravity="center_vertical"
+                        android:background="@drawable/ic_menu_mark" />
+
+                </LinearLayout>
 
             </FrameLayout>
 
diff --git a/res/layout-w470dp/contact_detail_fragment.xml b/res/layout-w470dp/contact_detail_fragment.xml
index 42266d5..17cbc2d 100644
--- a/res/layout-w470dp/contact_detail_fragment.xml
+++ b/res/layout-w470dp/contact_detail_fragment.xml
@@ -14,15 +14,17 @@
      limitations under the License.
 -->
 
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/contact_detail"
+    android:orientation="vertical"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
 
     <LinearLayout
         android:orientation="horizontal"
         android:layout_width="match_parent"
-        android:layout_height="match_parent">
+        android:layout_height="0px"
+        android:layout_weight="1" >
 
         <ImageView android:id="@+id/photo"
             android:scaleType="centerCrop"
@@ -87,5 +89,5 @@
         android:layout_alignParentTop="true"
         android:background="@android:color/transparent"
         android:visibility="gone"/>
-</RelativeLayout>
+</LinearLayout>
 
diff --git a/res/layout/call_log_fragment.xml b/res/layout/call_log_fragment.xml
index 2d0b9b5..ff7dd4b 100644
--- a/res/layout/call_log_fragment.xml
+++ b/res/layout/call_log_fragment.xml
@@ -18,7 +18,8 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:orientation="vertical"
->
+    android:paddingBottom="?android:attr/actionBarSize">
+
     <FrameLayout
         android:id="@+id/voicemail_status"
         android:layout_width="match_parent"
diff --git a/res/layout/carousel_about_tab.xml b/res/layout/carousel_about_tab.xml
index dfcf0da..e902c8e 100644
--- a/res/layout/carousel_about_tab.xml
+++ b/res/layout/carousel_about_tab.xml
@@ -14,8 +14,9 @@
      limitations under the License.
 -->
 
-<RelativeLayout
+<view
     xmlns:android="http://schemas.android.com/apk/res/android"
+    class="com.android.contacts.detail.CarouselTab"
     android:layout_width="0dip"
     android:layout_height="match_parent"
     android:layout_weight="1"
@@ -51,4 +52,22 @@
         android:textColor="@color/detail_tab_carousel_tab_label_color"
         style="@android:style/Widget.Holo.ActionBar.TabView" />
 
-</RelativeLayout>
+    <View
+        android:id="@+id/alpha_overlay"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_alignParentLeft="true"
+        android:layout_alignParentTop="true"
+        android:background="@android:color/black"
+        android:alpha="0"
+        android:visibility="gone"/>
+
+    <View
+        android:id="@+id/touch_intercept_overlay"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_alignParentLeft="true"
+        android:layout_alignParentTop="true"
+        android:background="?android:attr/selectableItemBackground"
+        android:visibility="gone"/>
+</view>
diff --git a/res/layout/carousel_updates_tab.xml b/res/layout/carousel_updates_tab.xml
index b036523..689e17b 100644
--- a/res/layout/carousel_updates_tab.xml
+++ b/res/layout/carousel_updates_tab.xml
@@ -14,8 +14,13 @@
      limitations under the License.
 -->
 
-<RelativeLayout
+<!--
+  TODO: Collapse carousel_about_tab with carousel_updates_tab into 1 XML that
+  handles all cases when updates fragment is more finalized.
+-->
+<view
     xmlns:android="http://schemas.android.com/apk/res/android"
+    class="com.android.contacts.detail.CarouselTab"
     android:layout_width="0dip"
     android:layout_height="match_parent"
     android:layout_weight="1"
@@ -68,4 +73,23 @@
         android:textStyle="bold"
         android:maxLines="3"/>
 
-</RelativeLayout>
+    <View
+        android:id="@+id/alpha_overlay"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_alignParentLeft="true"
+        android:layout_alignParentTop="true"
+        android:background="@android:color/black"
+        android:alpha="0"
+        android:visibility="gone"/>
+
+    <View
+        android:id="@+id/touch_intercept_overlay"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_alignParentLeft="true"
+        android:layout_alignParentTop="true"
+        android:background="?android:attr/selectableItemBackground"
+        android:visibility="gone"/>
+
+</view>
diff --git a/res/layout/contact_detail_list_item.xml b/res/layout/contact_detail_list_item.xml
index 4fcd881..e96b7f0 100644
--- a/res/layout/contact_detail_list_item.xml
+++ b/res/layout/contact_detail_list_item.xml
@@ -45,9 +45,24 @@
             android:layout_gravity="center_vertical"
             android:textAppearance="?android:attr/textAppearanceMedium" />
 
-        <TextView
-            android:id="@+id/type"
-            style="@style/ContactDetailItemType" />
+        <LinearLayout
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal">
+
+            <TextView
+                android:id="@+id/type"
+                style="@style/ContactDetailItemType" />
+
+            <View
+                android:id="@+id/primary_indicator"
+                android:layout_width="16dip"
+                android:layout_height="16dip"
+                android:visibility="gone"
+                android:layout_gravity="center_vertical"
+                android:background="@drawable/ic_menu_mark" />
+
+        </LinearLayout>
 
         <TextView
             android:id="@+id/footer"
diff --git a/res/layout/contact_tile_frequent_phone.xml b/res/layout/contact_tile_frequent_phone.xml
new file mode 100644
index 0000000..e0ea0fb
--- /dev/null
+++ b/res/layout/contact_tile_frequent_phone.xml
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<view
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    class="com.android.contacts.list.ContactTileView"
+    android:focusable="true"
+    android:background="@drawable/list_selector"
+    android:paddingRight="16dip"
+    android:paddingLeft="16dip" >
+
+    <RelativeLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent" >
+
+        <QuickContactBadge
+            android:id="@+id/contact_tile_quick"
+            android:layout_width="64dip"
+            android:layout_height="64dip"
+            android:scaleType="centerCrop"
+            android:layout_alignParentLeft="true" />
+
+        <TextView
+            android:id="@+id/contact_tile_name"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:singleLine="true"
+            android:ellipsize="end"
+            android:layout_marginLeft="8dip"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:layout_marginTop="8dip"
+            android:layout_toRightOf="@id/contact_tile_quick" />
+
+        <TextView
+            android:id="@+id/contact_tile_phone_number"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textSize="12sp"
+            android:ellipsize="end"
+            android:singleLine="true"
+            android:textColor="#cccccc"
+            android:layout_marginLeft="12dip"
+            android:layout_toRightOf="@id/contact_tile_quick"
+            android:layout_below="@id/contact_tile_name" />
+
+        <TextView
+            android:id="@+id/contact_tile_phone_type"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textSize="12sp"
+            android:ellipsize="end"
+            android:singleLine="true"
+            android:textColor="#cccccc"
+            android:layout_marginLeft="12dip"
+            android:layout_alignParentRight="true"
+            android:layout_alignTop="@id/contact_tile_phone_number" />
+
+    </RelativeLayout>
+
+</view>
diff --git a/res/layout/contact_tile_list.xml b/res/layout/contact_tile_list.xml
index c72386e..2047b13 100644
--- a/res/layout/contact_tile_list.xml
+++ b/res/layout/contact_tile_list.xml
@@ -17,7 +17,8 @@
 <FrameLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
-    android:layout_height="match_parent">
+    android:layout_height="match_parent"
+    android:paddingBottom="?attr/favorites_padding_bottom">
 
     <ListView
         android:id="@+id/contact_tile_list"
diff --git a/res/layout/contact_tile_starred_secondary_target.xml b/res/layout/contact_tile_starred_secondary_target.xml
index 5d4e55e..f7b8673 100644
--- a/res/layout/contact_tile_starred_secondary_target.xml
+++ b/res/layout/contact_tile_starred_secondary_target.xml
@@ -35,29 +35,24 @@
             android:layout_alignParentBottom="true"
             style="@style/ContactTileStarredShadowBox" />
 
-        <LinearLayout
+        <TextView
+            android:id="@+id/contact_tile_name"
             android:layout_width="match_parent"
-            android:layout_height="48dip"
+            android:layout_height="wrap_content"
             android:layout_alignParentBottom="true"
-            android:orientation="horizontal" >
+            android:layout_alignParentLeft="true"
+            android:layout_marginLeft="8dip"
+            android:layout_marginBottom="20dip"
+            android:textColor="@android:color/white"
+            stlye="@style/ContactTileStarredName" />
 
-            <TextView
-                android:id="@+id/contact_tile_name"
-                android:layout_width="0dip"
-                android:layout_height="match_parent"
-                android:layout_weight="1"
-                android:gravity="center_vertical"
-                android:layout_marginLeft="8dip"
-                android:textColor="@android:color/white"
-                stlye="@style/ContactTileStarredName" />
-
-            <ImageButton
-                android:id="@+id/contact_tile_secondary_button"
-                android:src="@drawable/ic_tab_unselected_contacts"
-                android:layout_height="match_parent"
-                android:layout_width="wrap_content" />
-
-        </LinearLayout>
+        <ImageButton
+            android:id="@+id/contact_tile_secondary_button"
+            android:src="@drawable/ic_tab_unselected_contacts"
+            android:layout_height="@dimen/contact_tile_shadowbox_height"
+            android:layout_width="wrap_content"
+            android:layout_alignParentBottom="true"
+            android:layout_alignParentRight="true" />
 
     </RelativeLayout>
 
diff --git a/res/layout/dialtacts_activity.xml b/res/layout/dialtacts_activity.xml
index 14fb137..6484d87 100644
--- a/res/layout/dialtacts_activity.xml
+++ b/res/layout/dialtacts_activity.xml
@@ -16,7 +16,8 @@
 
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
-    android:layout_height="match_parent">
+    android:layout_height="match_parent"
+    android:layout_marginTop="?android:attr/actionBarSize">
 
     <android.support.v4.view.ViewPager
         android:id="@+id/pager"
diff --git a/res/layout/contact_editor_custom_action_bar.xml b/res/layout/editor_custom_action_bar.xml
similarity index 97%
rename from res/layout/contact_editor_custom_action_bar.xml
rename to res/layout/editor_custom_action_bar.xml
index ba09929..0f42213 100644
--- a/res/layout/contact_editor_custom_action_bar.xml
+++ b/res/layout/editor_custom_action_bar.xml
@@ -49,6 +49,7 @@
                 android:layout_gravity="center_vertical"
                 android:layout_marginRight="20dip"
                 android:textAppearance="?android:attr/textAppearanceMedium"
+                android:textColor="@android:color/white"
                 android:text="@string/menu_done"
                 style="@android:style/Widget.Holo.ActionBar.TabText" />
 
diff --git a/res/menu/edit_group.xml b/res/menu/edit_group.xml
index d207317..a3387ca 100644
--- a/res/menu/edit_group.xml
+++ b/res/menu/edit_group.xml
@@ -16,15 +16,8 @@
 
 <menu xmlns:android="http://schemas.android.com/apk/res/android">
     <item
-        android:id="@+id/menu_done"
-        android:alphabeticShortcut="\n"
-        android:icon="@drawable/ic_menu_done_holo_light"
-        android:title="@string/menu_done"
-        android:showAsAction="always|withText" />
-
-    <item
         android:id="@+id/menu_discard"
         android:alphabeticShortcut="q"
-        android:title="@string/menu_doNotSave"
-        android:showAsAction="always|withText" />
+        android:title="@string/menu_discard"
+        android:showAsAction="withText" />
 </menu>
diff --git a/res/values-sw580dp-w720dp/styles.xml b/res/values-sw580dp-w720dp/styles.xml
index 045aeab..d4487b2 100644
--- a/res/values-sw580dp-w720dp/styles.xml
+++ b/res/values-sw580dp-w720dp/styles.xml
@@ -39,6 +39,8 @@
         <item name="list_item_header_text_size">14sp</item>
         <item name="list_item_header_underline_color">@color/people_app_theme_color</item>
         <item name="contact_filter_popup_width">320dip</item>
+        <!-- Favorites -->
+        <item name="favorites_padding_bottom">0dip</item>
     </style>
 
     <style name="ContactDetailHeaderTextView">
@@ -47,4 +49,4 @@
         <item name="android:singleLine">true</item>
         <item name="android:ellipsize">end</item>
     </style>
-</resources>
\ No newline at end of file
+</resources>
diff --git a/res/values-sw580dp/styles.xml b/res/values-sw580dp/styles.xml
index df77fc6..cf4c4ee 100644
--- a/res/values-sw580dp/styles.xml
+++ b/res/values-sw580dp/styles.xml
@@ -39,6 +39,8 @@
         <item name="list_item_header_height">26dip</item>
         <item name="list_item_header_underline_color">@color/people_app_theme_color</item>
         <item name="contact_filter_popup_width">320dip</item>
+        <!-- Favorites -->
+        <item name="favorites_padding_bottom">0dip</item>
     </style>
 
     <style name="ContactPickerTheme" parent="@android:Theme.Holo.Light.Dialog">
@@ -83,15 +85,6 @@
         <item name="android:windowContentOverlay">@null</item>
     </style>
 
-    <style name="ContactEditorActivityTheme" parent="@android:Theme.Holo.Light">
-        <item name="android:actionBarStyle">@style/TransparentActionBarStyle</item>
-        <item name="android:windowContentOverlay">@null</item>
-    </style>
-
-    <style name="TransparentActionBarStyle" parent="android:Widget.Holo.Light.ActionBar">
-        <item name="android:background">@null</item>
-    </style>
-
     <style name="DirectoryHeader" parent="PeopleTheme">
         <item name="android:background">@drawable/directory_bg_holo</item>
     </style>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 20326ef..999531e 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -203,7 +203,7 @@
     <!-- Menu item to indicate you are done editing a contact and want to save the changes you've made -->
     <string name="menu_done">Done</string>
 
-    <!-- Menu item to indicate you want to stop editing a group and NOT save the changes you've made [CHAR LIMIT=12] -->
+    <!-- Menu item to indicate you want to cancel the current editing process and NOT save the changes you've made [CHAR LIMIT=12] -->
     <string name="menu_doNotSave">Cancel</string>
 
     <!-- Menu item to indicate you want to stop editing a contact and NOT save the changes you've made [CHAR LIMIT=12] -->
@@ -1562,6 +1562,15 @@
     <!-- Joined contact indicator displayed in the contact detail [CHAR LIMIT=64] -->
     <string name="indicator_joined_contact">Joined contact</string>
 
+    <!-- Option displayed in context menu to copy long pressed item to clipboard [CHAR LIMIT=64] -->
+    <string name="copy_text">Copy to clipboard</string>
+
+    <!-- Option displayed in context menu to set long pressed item as default contact method [CHAR LIMIT=64] -->
+    <string name="set_default">Set default</string>
+
+    <!-- Option displayed in context menu to clear long pressed item as default contact method [CHAR LIMIT=64] -->
+    <string name="clear_default">Clear default</string>
+
     <!-- Toast shown when text is copied to the clipboard [CHAR LIMIT=64] -->
     <string name="toast_text_copied">Text copied</string>
 
diff --git a/res/values/styles.xml b/res/values/styles.xml
index b58706e..785c887 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -14,7 +14,9 @@
      limitations under the License.
 -->
 <resources>
-    <style name="DialtactsTheme" parent="android:Theme.Holo.SplitActionBarWhenNarrow">
+    <style name="DialtactsTheme"
+           parent="android:Theme.Holo.SolidActionBar.SplitActionBarWhenNarrow">
+        <item name="android:windowActionBarOverlay">true</item>
         <item name="android:windowContentOverlay">@null</item>
         <item name="android:windowBackground">@android:color/black</item>
         <item name="activated_background">@drawable/list_item_activated_background</item>
@@ -51,6 +53,8 @@
         <item name="call_log_voicemail_status_height">40dip</item>
         <item name="call_log_voicemail_status_background_color">#FFFFE0</item>
         <item name="call_log_voicemail_status_text_color">#000000</item>
+        <!-- Favorites -->
+        <item name="favorites_padding_bottom">?android:attr/actionBarSize</item>
     </style>
 
     <style name="CallDetailActivityTheme" parent="android:Theme.Holo.SplitActionBarWhenNarrow">
@@ -69,7 +73,7 @@
         <item name="call_log_voicemail_status_text_color">#000000</item>
     </style>
 
-    <style name="ContactDetailActivityTheme" parent="@android:style/Theme.Holo.Light.SolidActionBar.Inverse.SplitActionBarWhenNarrow">
+    <style name="ContactDetailActivityTheme" parent="@android:style/Theme.Holo.Light.SolidActionBar.Inverse">
         <item name="android:actionBarStyle">@style/ContactsActionBarStyle</item>
         <item name="android:windowContentOverlay">@null</item>
     </style>
@@ -161,6 +165,10 @@
         <attr name="call_log_voicemail_status_text_color" format="color" />
     </declare-styleable>
 
+    <declare-styleable name="Favorites">
+        <attr name="favorites_padding_bottom" format="dimension" />
+    </declare-styleable>
+
     <style name="PeopleTheme" parent="@android:style/Theme.Holo.Light.SolidActionBar.Inverse.SplitActionBarWhenNarrow">
         <item name="android:actionBarStyle">@style/ContactsActionBarStyle</item>
         <item name="list_item_height">?android:attr/listPreferredItemHeight</item>
@@ -188,6 +196,8 @@
         <item name="list_item_header_underline_height">1px</item>
         <item name="list_item_header_underline_color">@color/people_app_theme_color</item>
         <item name="contact_filter_popup_width">320dip</item>
+        <!-- Favorites -->
+        <item name="favorites_padding_bottom">0dip</item>
     </style>
 
     <style name="ContactsActionBarStyle" parent="@android:style/Widget.Holo.Light.ActionBar.Solid.Inverse">
diff --git a/src/com/android/contacts/ContactTileLoaderFactory.java b/src/com/android/contacts/ContactTileLoaderFactory.java
index 41532c2..30bd7e4 100644
--- a/src/com/android/contacts/ContactTileLoaderFactory.java
+++ b/src/com/android/contacts/ContactTileLoaderFactory.java
@@ -21,7 +21,9 @@
 import android.content.CursorLoader;
 import android.net.Uri;
 import android.provider.ContactsContract;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
 import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.Contacts.Data;
 
 /**
  * Used to create {@link CursorLoader}s to load different groups of {@link ContactTileView}s
@@ -36,14 +38,36 @@
     public final static int CONTACT_PRESENCE = 5;
     public final static int CONTACT_STATUS = 6;
 
+    // Only used for StrequentPhoneOnlyLoader
+    public final static int PHONE_NUMBER = 5;
+    public final static int PHONE_NUMBER_TYPE = 6;
+    public final static int PHONE_NUMBER_LABEL = 7;
+
     private static final String[] COLUMNS = new String[] {
-        Contacts._ID,
-        Contacts.DISPLAY_NAME,
-        Contacts.STARRED,
-        Contacts.PHOTO_URI,
-        Contacts.LOOKUP_KEY,
-        Contacts.CONTACT_PRESENCE,
-        Contacts.CONTACT_STATUS,
+        Contacts._ID, // ..........................................0
+        Contacts.DISPLAY_NAME, // .................................1
+        Contacts.STARRED, // ......................................2
+        Contacts.PHOTO_URI, // ....................................3
+        Contacts.LOOKUP_KEY, // ...................................4
+        Contacts.CONTACT_PRESENCE, // .............................5
+        Contacts.CONTACT_STATUS, // ...............................6
+    };
+
+    /**
+     * Projection used for the {@link Contacts#CONTENT_STREQUENT_URI}
+     * query when {@link ContactsContract#STREQUENT_PHONE_ONLY} flag
+     * is set to true. The main difference is the lack of presence
+     * and status data and the addition of phone number and label.
+     */
+    private static final String[] COLUMNS_PHONE_ONLY = new String[] {
+        Contacts._ID, // ..........................................0
+        Contacts.DISPLAY_NAME, // .................................1
+        Contacts.STARRED, // ......................................2
+        Contacts.PHOTO_URI, // ....................................3
+        Contacts.LOOKUP_KEY, // ...................................4
+        Phone.NUMBER, // ..........................................5
+        Phone.TYPE, // ............................................6
+        Phone.LABEL // ............................................7
     };
 
     public static CursorLoader createStrequentLoader(Context context) {
@@ -54,7 +78,7 @@
         Uri uri = Contacts.CONTENT_STREQUENT_URI.buildUpon()
                 .appendQueryParameter(ContactsContract.STREQUENT_PHONE_ONLY, "true").build();
 
-        return new CursorLoader(context, uri, COLUMNS, null, null, null);
+        return new CursorLoader(context, uri, COLUMNS_PHONE_ONLY, null, null, null);
     }
 
     public static CursorLoader createStarredLoader(Context context) {
diff --git a/src/com/android/contacts/activities/ContactEditorActivity.java b/src/com/android/contacts/activities/ContactEditorActivity.java
index 10be943..a5b3aab 100644
--- a/src/com/android/contacts/activities/ContactEditorActivity.java
+++ b/src/com/android/contacts/activities/ContactEditorActivity.java
@@ -84,8 +84,7 @@
             // to the contact
             LayoutInflater inflater = (LayoutInflater) getSystemService
                     (Context.LAYOUT_INFLATER_SERVICE);
-            View customActionBarView = inflater.inflate(R.layout.contact_editor_custom_action_bar,
-                    null);
+            View customActionBarView = inflater.inflate(R.layout.editor_custom_action_bar, null);
             View saveMenuItem = customActionBarView.findViewById(R.id.save_menu_item);
             saveMenuItem.setOnClickListener(new OnClickListener() {
                 @Override
diff --git a/src/com/android/contacts/activities/DialtactsActivity.java b/src/com/android/contacts/activities/DialtactsActivity.java
index 7e41a5c..01212f5 100644
--- a/src/com/android/contacts/activities/DialtactsActivity.java
+++ b/src/com/android/contacts/activities/DialtactsActivity.java
@@ -122,7 +122,12 @@
     }
 
     private class PageChangeListener implements OnPageChangeListener {
-        private int mPreviousPosition = -1;  // Invalid at first
+        private int mCurrentPosition = -1;
+        /**
+         * Used during page migration, to remember the next position {@link #onPageSelected(int)}
+         * specified.
+         */
+        private int mNextPosition = -1;
 
         @Override
         public void onPageScrolled(
@@ -132,34 +137,38 @@
         @Override
         public void onPageSelected(int position) {
             final ActionBar actionBar = getActionBar();
-            if (mPreviousPosition == position) {
+            if (mCurrentPosition == position) {
                 Log.w(TAG, "Previous position and next position became same (" + position + ")");
             }
 
-            if (mPreviousPosition >= 0) {
-                sendFragmentVisibilityChange(mPreviousPosition, false);
-            }
-            sendFragmentVisibilityChange(position, true);
-
             actionBar.selectTab(actionBar.getTabAt(position));
-
-            // Activity#onPrepareOptionsMenu() may not be called when Fragment has it's own
-            // options menu. We force this Activity to call it to hide/show bottom bar. Also
-            // we don't want to do so when it is unnecessary (buttons may flicker).
-            if (mPreviousPosition == TAB_INDEX_DIALER || position == TAB_INDEX_DIALER) {
-                // Force this Activity to prepare Menu again.
-                invalidateOptionsMenu();
-            }
-
-            mPreviousPosition = position;
+            mNextPosition = position;
         }
 
         public void setCurrentPosition(int position) {
-            mPreviousPosition = position;
+            mCurrentPosition = position;
         }
 
         @Override
         public void onPageScrollStateChanged(int state) {
+            switch (state) {
+                case ViewPager.SCROLL_STATE_IDLE: {
+                    if (mCurrentPosition >= 0) {
+                        sendFragmentVisibilityChange(mCurrentPosition, false);
+                    }
+                    if (mNextPosition >= 0) {
+                        sendFragmentVisibilityChange(mNextPosition, true);
+                    }
+                    invalidateOptionsMenu();
+
+                    mCurrentPosition = mNextPosition;
+                    break;
+                }
+                case ViewPager.SCROLL_STATE_DRAGGING:
+                case ViewPager.SCROLL_STATE_SETTLING:
+                default:
+                    break;
+            }
         }
     }
 
@@ -246,7 +255,11 @@
             new OnQueryTextListener() {
                 @Override
                 public boolean onQueryTextSubmit(String query) {
-                    // Ignore.
+                    View view = getCurrentFocus();
+                    if (view != null) {
+                        hideInputMethod(view);
+                        view.clearFocus();
+                    }
                     return true;
                 }
 
@@ -265,16 +278,12 @@
      * the search UI and let users go back to usual Phone UI.
      *
      * This does _not_ handle back button.
-     *
-     * TODO: need "up" button instead of close button
      */
     private final OnCloseListener mPhoneSearchCloseListener =
             new OnCloseListener() {
                 @Override
                 public boolean onClose() {
-                    if (TextUtils.isEmpty(mSearchView.getQuery())) {
-                        exitSearchUi();
-                    } else {
+                    if (!TextUtils.isEmpty(mSearchView.getQuery())) {
                         mSearchView.setQuery(null, true);
                     }
                     return true;
@@ -636,13 +645,20 @@
 
         // Instantiate or reset SearchView in ActionBar.
         if (mSearchView == null) {
-            // TODO: layout is not what we want. Need "up" button instead of "close" button, etc.
             final View searchViewLayout =
                     getLayoutInflater().inflate(R.layout.custom_action_bar, null);
             mSearchView = (SearchView) searchViewLayout.findViewById(R.id.search_view);
-            mSearchView.setQueryHint(getString(R.string.hint_findContacts));
             mSearchView.setOnQueryTextListener(mPhoneSearchQueryTextListener);
             mSearchView.setOnCloseListener(mPhoneSearchCloseListener);
+            // Since we're using a custom layout for showing SearchView instead of letting the
+            // search menu icon do that job, we need to manually configure the View so it looks
+            // "shown via search menu".
+            // - it should be iconified by default
+            // - it should not be iconified at this time
+            // See also comments for onActionViewExpanded()/onActionViewCollapsed()
+            mSearchView.setIconifiedByDefault(true);
+            mSearchView.setQueryHint(getString(R.string.hint_findContacts));
+            mSearchView.setIconified(false);
             mSearchView.requestFocus();
             // Show soft keyboard when SearchView has a focus. Need to delay the request in order
             // to let InputMethodManager handle it correctly.
@@ -681,6 +697,9 @@
         transaction.commit();
         mViewPager.setVisibility(View.GONE);
 
+        // We need to call this and onActionViewCollapsed() manually, since we are using a custom
+        // layout instead of asking the search menu item to take care of SearchView.
+        mSearchView.onActionViewExpanded();
         mInSearchUi = true;
     }
 
@@ -723,6 +742,8 @@
         // Request to update option menu.
         invalidateOptionsMenu();
 
+        // See comments in onActionViewExpanded()
+        mSearchView.onActionViewCollapsed();
         mInSearchUi = false;
     }
 
diff --git a/src/com/android/contacts/activities/GroupDetailActivity.java b/src/com/android/contacts/activities/GroupDetailActivity.java
index c7cf47c..b56f182 100644
--- a/src/com/android/contacts/activities/GroupDetailActivity.java
+++ b/src/com/android/contacts/activities/GroupDetailActivity.java
@@ -61,9 +61,12 @@
         fragment.loadGroup(getIntent().getData());
         fragment.closeActivityAfterDelete(true);
 
-        ActionBar actionBar =  getActionBar();
+        // We want the UP affordance but no app icon.
+        ActionBar actionBar = getActionBar();
         if (actionBar != null) {
-            actionBar.setDisplayHomeAsUpEnabled(true);
+            actionBar.setDisplayOptions(ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_TITLE,
+                    ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_TITLE
+                    | ActionBar.DISPLAY_SHOW_HOME);
         }
     }
 
diff --git a/src/com/android/contacts/activities/GroupEditorActivity.java b/src/com/android/contacts/activities/GroupEditorActivity.java
index 814595c..d61b6c3 100644
--- a/src/com/android/contacts/activities/GroupEditorActivity.java
+++ b/src/com/android/contacts/activities/GroupEditorActivity.java
@@ -17,7 +17,6 @@
 package com.android.contacts.activities;
 
 import com.android.contacts.ContactsActivity;
-import com.android.contacts.ContactsSearchManager;
 import com.android.contacts.R;
 import com.android.contacts.editor.ContactEditorFragment.SaveMode;
 import com.android.contacts.group.GroupEditorFragment;
@@ -26,11 +25,14 @@
 
 import android.app.ActionBar;
 import android.app.Dialog;
+import android.content.Context;
 import android.content.Intent;
 import android.net.Uri;
 import android.os.Bundle;
 import android.util.Log;
-import android.view.MenuItem;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
 
 public class GroupEditorActivity extends ContactsActivity
         implements DialogManager.DialogShowingViewActivity {
@@ -57,11 +59,26 @@
 
         setContentView(R.layout.group_editor_activity);
 
-        // This Activity will always fall back to the "top" Contacts screen when touched on the
-        // app up icon, regardless of launch context.
         ActionBar actionBar = getActionBar();
         if (actionBar != null) {
-            actionBar.setDisplayOptions(ActionBar.DISPLAY_HOME_AS_UP, ActionBar.DISPLAY_HOME_AS_UP);
+            // Inflate a custom action bar that contains the "done" button for saving changes
+            // to the group
+            LayoutInflater inflater = (LayoutInflater) getSystemService
+                    (Context.LAYOUT_INFLATER_SERVICE);
+            View customActionBarView = inflater.inflate(R.layout.editor_custom_action_bar,
+                    null);
+            View saveMenuItem = customActionBarView.findViewById(R.id.save_menu_item);
+            saveMenuItem.setOnClickListener(new OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    mFragment.doSaveAction();
+                }
+            });
+            // Show the custom action bar but hide the home icon and title
+            actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM,
+                    ActionBar.DISPLAY_SHOW_CUSTOM | ActionBar.DISPLAY_SHOW_HOME |
+                    ActionBar.DISPLAY_SHOW_TITLE);
+            actionBar.setCustomView(customActionBarView);
         }
 
         mFragment = (GroupEditorFragment) getFragmentManager().findFragmentById(
@@ -109,17 +126,6 @@
         }
     }
 
-    @Override
-    public boolean onOptionsItemSelected(MenuItem item) {
-        switch (item.getItemId()) {
-            case android.R.id.home: {
-                mFragment.save(SaveMode.HOME);
-                return true;
-            }
-        }
-        return false;
-    }
-
     private final GroupEditorFragment.Listener mFragmentListener =
             new GroupEditorFragment.Listener() {
         @Override
diff --git a/src/com/android/contacts/calllog/CallLogFragment.java b/src/com/android/contacts/calllog/CallLogFragment.java
index 8f7cfa8..abc9adf 100644
--- a/src/com/android/contacts/calllog/CallLogFragment.java
+++ b/src/com/android/contacts/calllog/CallLogFragment.java
@@ -989,19 +989,16 @@
     @Override
     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
         super.onCreateOptionsMenu(menu, inflater);
-        inflater.inflate(R.menu.call_log_options, menu);
+        if (mShowOptionsMenu) {
+            inflater.inflate(R.menu.call_log_options, menu);
+        }
     }
 
     @Override
     public void onPrepareOptionsMenu(Menu menu) {
-        menu.findItem(R.id.delete_all).setVisible(mShowOptionsMenu);
-        menu.findItem(R.id.show_voicemails_only).setVisible(mShowOptionsMenu);
-        final MenuItem callSettingsMenuItem = menu.findItem(R.id.menu_call_settings_call_log);
         if (mShowOptionsMenu) {
-            callSettingsMenuItem.setVisible(true);
-            callSettingsMenuItem.setIntent(DialtactsActivity.getCallSettingsIntent());
-        } else {
-            callSettingsMenuItem.setVisible(false);
+            menu.findItem(R.id.menu_call_settings_call_log)
+                .setIntent(DialtactsActivity.getCallSettingsIntent());
         }
     }
 
diff --git a/src/com/android/contacts/detail/CarouselTab.java b/src/com/android/contacts/detail/CarouselTab.java
new file mode 100644
index 0000000..9b8efd5
--- /dev/null
+++ b/src/com/android/contacts/detail/CarouselTab.java
@@ -0,0 +1,101 @@
+/*
+ * 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.detail;
+
+import com.android.contacts.R;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+/**
+ * This is a tab in the {@link ContactDetailTabCarousel}.
+ */
+public class CarouselTab extends RelativeLayout implements ViewOverlay {
+
+    private static final String TAG = CarouselTab.class.getSimpleName();
+
+    private TextView mLabelView;
+
+    /**
+     * This view adds an alpha layer over the entire tab.
+     */
+    private View mAlphaLayer;
+
+    /**
+     * This view adds a layer over the entire tab so that when visible, it intercepts all touch
+     * events on the tab.
+     */
+    private View mTouchInterceptLayer;
+
+    public CarouselTab(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+
+        mLabelView = (TextView) findViewById(R.id.label);
+        mLabelView.setClickable(true);
+
+        mAlphaLayer = findViewById(R.id.alpha_overlay);
+        mTouchInterceptLayer = findViewById(R.id.touch_intercept_overlay);
+    }
+
+    public void setLabel(String label) {
+        mLabelView.setText(label);
+    }
+
+    public void showSelectedState() {
+        mLabelView.setSelected(true);
+    }
+
+    public void showDeselectedState() {
+        mLabelView.setSelected(false);
+    }
+
+    @Override
+    public void disableTouchInterceptor() {
+        // This shouldn't be called because there is no need to disable the touch interceptor if
+        // there is no content within the tab that needs to be clicked.
+    }
+
+    @Override
+    public void enableAlphaLayer() {
+        if (mAlphaLayer != null) {
+            mAlphaLayer.setVisibility(View.VISIBLE);
+        }
+    }
+
+    @Override
+    public void enableTouchInterceptor(OnClickListener clickListener) {
+        if (mTouchInterceptLayer != null) {
+            mTouchInterceptLayer.setVisibility(View.VISIBLE);
+            mTouchInterceptLayer.setOnClickListener(clickListener);
+        }
+    }
+
+    @Override
+    public void setAlphaLayerValue(float alpha) {
+        if (mAlphaLayer != null) {
+            mAlphaLayer.setAlpha(alpha);
+        }
+    }
+}
diff --git a/src/com/android/contacts/detail/ContactDetailFragment.java b/src/com/android/contacts/detail/ContactDetailFragment.java
index a6ba6b0..41324f8 100644
--- a/src/com/android/contacts/detail/ContactDetailFragment.java
+++ b/src/com/android/contacts/detail/ContactDetailFragment.java
@@ -47,6 +47,7 @@
 import android.app.Activity;
 import android.app.Fragment;
 import android.app.SearchManager;
+import android.content.ClipData;
 import android.content.ClipboardManager;
 import android.content.ContentUris;
 import android.content.ContentValues;
@@ -87,15 +88,18 @@
 import android.telephony.PhoneNumberUtils;
 import android.text.TextUtils;
 import android.util.Log;
+import android.view.ContextMenu;
+import android.view.ContextMenu.ContextMenuInfo;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
+import android.view.MenuItem;
 import android.view.View;
 import android.view.View.OnClickListener;
 import android.view.ViewGroup;
 import android.widget.AbsListView.OnScrollListener;
 import android.widget.AdapterView;
+import android.widget.AdapterView.AdapterContextMenuInfo;
 import android.widget.AdapterView.OnItemClickListener;
-import android.widget.AdapterView.OnItemLongClickListener;
 import android.widget.BaseAdapter;
 import android.widget.Button;
 import android.widget.CheckBox;
@@ -112,13 +116,19 @@
 import java.util.List;
 import java.util.Map;
 
-public class ContactDetailFragment extends Fragment implements FragmentKeyListener, FragmentOverlay,
-        OnItemClickListener, OnItemLongClickListener, SelectAccountDialogFragment.Listener {
+public class ContactDetailFragment extends Fragment implements FragmentKeyListener, ViewOverlay,
+        OnItemClickListener, SelectAccountDialogFragment.Listener {
 
     private static final String TAG = "ContactDetailFragment";
 
     private static final int LOADER_DETAILS = 1;
 
+    private interface ContextMenuIds {
+        static final int COPY_TEXT = 0;
+        static final int CLEAR_DEFAULT = 1;
+        static final int SET_DEFAULT = 2;
+    }
+
     private static final String KEY_CONTACT_URI = "contactUri";
     private static final String LOADER_ARG_CONTACT_URI = "contactUri";
 
@@ -255,7 +265,7 @@
         mListView = (ListView) mView.findViewById(android.R.id.list);
         mListView.setScrollBarStyle(ListView.SCROLLBARS_OUTSIDE_OVERLAY);
         mListView.setOnItemClickListener(this);
-        mListView.setOnItemLongClickListener(this);
+        registerForContextMenu(mListView);
         mListView.setOnScrollListener(mVerticalScrollListener);
 
         // Don't set it to mListView yet.  We do so later when we bind the adapter.
@@ -1328,12 +1338,14 @@
         public ImageView secondaryActionButton;
         public View secondaryActionButtonContainer;
         public View secondaryActionDivider;
+        public View primaryIndicator;
 
         public DetailViewCache(View view, OnClickListener secondaryActionClickListener) {
             kind = (TextView) view.findViewById(R.id.kind);
             type = (TextView) view.findViewById(R.id.type);
             data = (TextView) view.findViewById(R.id.data);
             footer = (TextView) view.findViewById(R.id.footer);
+            primaryIndicator = view.findViewById(R.id.primary_indicator);
             presenceIcon = (ImageView) view.findViewById(R.id.presence_icon);
             secondaryActionButton = (ImageView) view.findViewById(
                     R.id.secondary_action_button);
@@ -1511,6 +1523,9 @@
                 views.footer.setVisibility(View.GONE);
             }
 
+            // Set the default contact method
+            views.primaryIndicator.setVisibility(entry.isPrimary ? View.VISIBLE : View.GONE);
+
             // Set the presence icon
             final Drawable presenceIcon = ContactPresenceIconUtil.getPresenceIcon(
                     mContext, entry.presence);
@@ -1642,18 +1657,105 @@
     }
 
     @Override
-    public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
-        if (mListener == null) return false;
-        final DetailViewCache cache = (DetailViewCache) view.getTag();
-        if (cache == null) return false;
-        CharSequence text = cache.data.getText();
-        if (TextUtils.isEmpty(text)) return false;
+    public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo menuInfo) {
+        super.onCreateContextMenu(menu, view, menuInfo);
 
-        ClipboardManager cm = (ClipboardManager) getActivity().getSystemService(
+        AdapterView.AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
+        DetailViewEntry selectedEntry = (DetailViewEntry) mAllEntries.get(info.position);
+
+        menu.setHeaderTitle(selectedEntry.data);
+        menu.add(ContextMenu.NONE, ContextMenuIds.COPY_TEXT,
+                ContextMenu.NONE, getString(R.string.copy_text));
+
+        String selectedMimeType = selectedEntry.mimetype;
+
+        // Only allow primary support for Phone and Email content types
+        if (Phone.CONTENT_ITEM_TYPE.equals(selectedMimeType) ||
+                Email.CONTENT_ITEM_TYPE.equals(selectedMimeType)) {
+
+            // Used to determine if entry is the only mime type of its kind
+            boolean isUniqueMimeType = true;
+
+            // Checking for unique mime type
+            for (int positionCounter = 0; positionCounter < mAllEntries.size(); positionCounter++) {
+                final ViewEntry entry = mAllEntries.get(positionCounter);
+
+                // Ignoring cases where entry is not a detail entry
+                if (entry.getViewType() != ViewAdapter.VIEW_TYPE_DETAIL_ENTRY) continue;
+
+                final DetailViewEntry checkEntry = (DetailViewEntry) entry;
+                if (positionCounter != info.position &&
+                        checkEntry.mimetype.equalsIgnoreCase(selectedMimeType)) {
+                    isUniqueMimeType = false;
+                    break;
+                }
+            }
+
+            // Checking for previously set default
+            if (selectedEntry.isPrimary) {
+                menu.add(ContextMenu.NONE, ContextMenuIds.CLEAR_DEFAULT,
+                        ContextMenu.NONE, getString(R.string.clear_default));
+            } else if (!isUniqueMimeType) {
+                menu.add(ContextMenu.NONE, ContextMenuIds.SET_DEFAULT,
+                        ContextMenu.NONE, getString(R.string.set_default));
+            }
+        }
+    }
+
+    @Override
+    public boolean onContextItemSelected(MenuItem item) {
+        AdapterView.AdapterContextMenuInfo menuInfo;
+        try {
+            menuInfo = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
+        } catch (ClassCastException e) {
+            Log.e(TAG, "bad menuInfo", e);
+            return false;
+        }
+
+        switch (item.getItemId()) {
+            case ContextMenuIds.COPY_TEXT:
+                copyToClipboard(menuInfo.position);
+                return true;
+            case ContextMenuIds.SET_DEFAULT:
+                setDefaultContactMethod(mListView.getItemIdAtPosition(menuInfo.position));
+                return true;
+            case ContextMenuIds.CLEAR_DEFAULT:
+                clearDefaultContactMethod(mListView.getItemIdAtPosition(menuInfo.position));
+                return true;
+            default:
+                throw new IllegalArgumentException("Unknown menu option " + item.getItemId());
+        }
+    }
+
+    private void setDefaultContactMethod(long id) {
+        Intent setIntent = ContactSaveService.createSetSuperPrimaryIntent(mContext, id);
+        mContext.startService(setIntent);
+    }
+
+    private void clearDefaultContactMethod(long id) {
+        Intent clearIntent = ContactSaveService.createClearPrimaryIntent(mContext, id);
+        mContext.startService(clearIntent);
+    }
+
+    private void copyToClipboard(int viewEntryPosition) {
+        // Getting the text to copied
+        DetailViewEntry detailViewEntry = (DetailViewEntry) mAllEntries.get(viewEntryPosition);
+        CharSequence textToCopy = detailViewEntry.data;
+
+        // Checking for empty string
+        if (TextUtils.isEmpty(textToCopy)) return;
+
+        // Adding item to clipboard
+        ClipboardManager clipboardManager = (ClipboardManager) getActivity().getSystemService(
                 Context.CLIPBOARD_SERVICE);
-        cm.setText(text);
-        Toast.makeText(getActivity(), R.string.toast_text_copied, Toast.LENGTH_SHORT).show();
-        return true;
+        String[] mimeTypes = new String[]{detailViewEntry.mimetype};
+        ClipData.Item clipDataItem = new ClipData.Item(textToCopy);
+        ClipData cd = new ClipData(detailViewEntry.typeString, mimeTypes, clipDataItem);
+        clipboardManager.setPrimaryClip(cd);
+
+        // Display Confirmation Toast
+        String toastText = getString(R.string.toast_text_copied);
+        Toast.makeText(getActivity(), toastText, Toast.LENGTH_SHORT).show();
     }
 
     @Override
diff --git a/src/com/android/contacts/detail/ContactDetailFragmentCarousel.java b/src/com/android/contacts/detail/ContactDetailFragmentCarousel.java
index da64c34..95cf055 100644
--- a/src/com/android/contacts/detail/ContactDetailFragmentCarousel.java
+++ b/src/com/android/contacts/detail/ContactDetailFragmentCarousel.java
@@ -46,8 +46,8 @@
     private int mCurrentPage = ABOUT_PAGE;
     private int mLastScrollPosition;
 
-    private FragmentOverlay mAboutFragment;
-    private FragmentOverlay mUpdatesFragment;
+    private ViewOverlay mAboutFragment;
+    private ViewOverlay mUpdatesFragment;
 
     private static final float MAX_ALPHA = 0.5f;
 
@@ -69,7 +69,7 @@
         setOnTouchListener(this);
     }
 
-    public void setAboutFragment(FragmentOverlay fragment) {
+    public void setAboutFragment(ViewOverlay fragment) {
         // TODO: We can't always assume the "about" page will be the current page.
         mAboutFragment = fragment;
         mAboutFragment.enableAlphaLayer();
@@ -77,7 +77,7 @@
         mAboutFragment.disableTouchInterceptor();
     }
 
-    public void setUpdatesFragment(FragmentOverlay fragment) {
+    public void setUpdatesFragment(ViewOverlay fragment) {
         mUpdatesFragment = fragment;
         mUpdatesFragment.enableAlphaLayer();
         mUpdatesFragment.setAlphaLayerValue(MAX_ALPHA);
diff --git a/src/com/android/contacts/detail/ContactDetailTabCarousel.java b/src/com/android/contacts/detail/ContactDetailTabCarousel.java
index 26987f6..79ac5fb 100644
--- a/src/com/android/contacts/detail/ContactDetailTabCarousel.java
+++ b/src/com/android/contacts/detail/ContactDetailTabCarousel.java
@@ -24,6 +24,7 @@
 import android.util.AttributeSet;
 import android.view.MotionEvent;
 import android.view.View;
+import android.view.View.OnClickListener;
 import android.view.View.OnTouchListener;
 import android.widget.HorizontalScrollView;
 import android.widget.ImageView;
@@ -49,15 +50,22 @@
 
     private Listener mListener;
 
-    private final View[] mTabs = new View[TAB_COUNT];
+    private int mCurrentTab = TAB_INDEX_ABOUT;
+
+    private CarouselTab mAboutTab;
+    private CarouselTab mUpdatesTab;
 
     private int mTabWidth;
     private int mTabHeight;
     private int mTabDisplayLabelHeight;
 
+    private int mLastScrollPosition;
+
     private int mAllowedHorizontalScrollLength = Integer.MIN_VALUE;
     private int mAllowedVerticalScrollLength = Integer.MIN_VALUE;
 
+    private static final float MAX_ALPHA = 0.5f;
+
     /**
      * Interface for callbacks invoked when the user interacts with the carousel.
      */
@@ -83,40 +91,28 @@
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
-        View aboutView = findViewById(R.id.tab_about);
-        View updateView = findViewById(R.id.tab_update);
+        mAboutTab = (CarouselTab) findViewById(R.id.tab_about);
+        mAboutTab.setLabel(mContext.getString(R.string.contactDetailAbout));
 
-        TextView aboutTab = (TextView) aboutView.findViewById(R.id.label);
-        aboutTab.setText(mContext.getString(R.string.contactDetailAbout));
-        aboutTab.setClickable(true);
-        aboutTab.setSelected(true);
+        mUpdatesTab = (CarouselTab) findViewById(R.id.tab_update);
+        mUpdatesTab.setLabel(mContext.getString(R.string.contactDetailUpdates));
 
-        TextView updatesTab = (TextView) updateView.findViewById(R.id.label);
-        updatesTab.setText(mContext.getString(R.string.contactDetailUpdates));
-        updatesTab.setClickable(true);
+        // TODO: We can't always assume the "about" page will be the current page.
+        mAboutTab.showSelectedState();
+        mAboutTab.enableAlphaLayer();
+        mAboutTab.setAlphaLayerValue(0);
+        mAboutTab.enableTouchInterceptor(mAboutTabTouchInterceptListener);
 
-        aboutTab.setOnClickListener(new OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                mListener.onTabSelected(TAB_INDEX_ABOUT);
-            }
-        });
-        updatesTab.setOnClickListener(new OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                mListener.onTabSelected(TAB_INDEX_ABOUT);
-            }
-        });
-
-        mTabs[TAB_INDEX_ABOUT] = aboutTab;
-        mTabs[TAB_INDEX_UPDATES] = updatesTab;
+        mUpdatesTab.enableAlphaLayer();
+        mUpdatesTab.setAlphaLayerValue(MAX_ALPHA);
+        mUpdatesTab.enableTouchInterceptor(mUpdatesTabTouchInterceptListener);
 
         // Retrieve the photo view for the "about" tab
-        mPhotoView = (ImageView) aboutView.findViewById(R.id.photo);
+        mPhotoView = (ImageView) mAboutTab.findViewById(R.id.photo);
 
         // Retrieve the social update views for the "updates" tab
-        mStatusView = (TextView) updateView.findViewById(R.id.status);
-        mStatusPhotoView = (ImageView) updateView.findViewById(R.id.status_photo);
+        mStatusView = (TextView) mUpdatesTab.findViewById(R.id.status);
+        mStatusPhotoView = (ImageView) mUpdatesTab.findViewById(R.id.status_photo);
     }
 
     @Override
@@ -143,10 +139,33 @@
         }
     }
 
+    private final OnClickListener mAboutTabTouchInterceptListener = new OnClickListener() {
+        @Override
+        public void onClick(View v) {
+            mListener.onTabSelected(TAB_INDEX_ABOUT);
+        }
+    };
+
+    private final OnClickListener mUpdatesTabTouchInterceptListener = new OnClickListener() {
+        @Override
+        public void onClick(View v) {
+            mListener.onTabSelected(TAB_INDEX_UPDATES);
+        }
+    };
+
+    private void updateAlphaLayers() {
+        mAboutTab.setAlphaLayerValue(mLastScrollPosition * MAX_ALPHA /
+                mAllowedHorizontalScrollLength);
+        mUpdatesTab.setAlphaLayerValue(MAX_ALPHA - mLastScrollPosition * MAX_ALPHA /
+                mAllowedVerticalScrollLength);
+    }
+
     @Override
     protected void onScrollChanged(int l, int t, int oldl, int oldt) {
         super.onScrollChanged(l, t, oldl, oldt);
         mListener.onScrollChanged(l, t, oldl, oldt);
+        mLastScrollPosition = l;
+        updateAlphaLayers();
     }
 
     /**
@@ -168,24 +187,21 @@
      * Updates the tab selection.
      */
     public void setCurrentTab(int position) {
-        if (position < 0 || position > mTabs.length) {
-            throw new IllegalStateException("Invalid position in array of tabs: " + position);
-        }
         // TODO: Handle device rotation (saving and restoring state of the selected tab)
         // This will take more work because there is no tab carousel in phone landscape
-        if (mTabs[position] == null) {
-            return;
+        switch (position) {
+            case TAB_INDEX_ABOUT:
+                mAboutTab.showSelectedState();
+                mUpdatesTab.showDeselectedState();
+                break;
+            case TAB_INDEX_UPDATES:
+                mUpdatesTab.showSelectedState();
+                mAboutTab.showDeselectedState();
+                break;
+            default:
+                throw new IllegalStateException("Invalid tab position " + position);
         }
-        mTabs[position].setSelected(true);
-        unselectAllOtherTabs(position);
-    }
-
-    private void unselectAllOtherTabs(int position) {
-        for (int i = 0; i < mTabs.length; i++) {
-            if (position != i) {
-                mTabs[i].setSelected(false);
-            }
-        }
+        mCurrentTab = position;
     }
 
     /**
@@ -197,6 +213,8 @@
             return;
         }
 
+        // TODO: Move this into the {@link CarouselTab} class when the updates fragment code is more
+        // finalized
         ContactDetailDisplayUtils.setPhoto(mContext, contactData, mPhotoView);
         ContactDetailDisplayUtils.setSocialSnippet(mContext, contactData, mStatusView,
                 mStatusPhotoView);
diff --git a/src/com/android/contacts/detail/ContactDetailUpdatesFragment.java b/src/com/android/contacts/detail/ContactDetailUpdatesFragment.java
index daeae00..602958d 100644
--- a/src/com/android/contacts/detail/ContactDetailUpdatesFragment.java
+++ b/src/com/android/contacts/detail/ContactDetailUpdatesFragment.java
@@ -31,7 +31,7 @@
 import android.widget.TextView;
 
 public class ContactDetailUpdatesFragment extends Fragment
-        implements FragmentKeyListener, FragmentOverlay {
+        implements FragmentKeyListener, ViewOverlay {
 
     private static final String TAG = "ContactDetailUpdatesFragment";
 
diff --git a/src/com/android/contacts/detail/FragmentOverlay.java b/src/com/android/contacts/detail/ViewOverlay.java
similarity index 88%
rename from src/com/android/contacts/detail/FragmentOverlay.java
rename to src/com/android/contacts/detail/ViewOverlay.java
index 6ef0846..4c14460 100644
--- a/src/com/android/contacts/detail/FragmentOverlay.java
+++ b/src/com/android/contacts/detail/ViewOverlay.java
@@ -19,12 +19,12 @@
 import android.view.View.OnClickListener;
 
 /**
- * This is implemented by {@link Fragment}s that contain an alpha layer and touch interceptor layer.
+ * This is implemented by {@link View}s that contain an alpha layer and touch interceptor layer.
  * The alpha layer covers the entire fragment and has an alpha value which makes the fragment
  * contents appear "dimmed" out. The touch interceptor layer covers the entire fragment so that
- * when visible, it intercepts all touch events on the {@link Fragment}.
+ * when visible, it intercepts all touch events on the {@link View}.
  */
-public interface FragmentOverlay {
+public interface ViewOverlay {
 
     /**
      * Sets the alpha value on the alpha layer (if there is one).
diff --git a/src/com/android/contacts/dialpad/DialpadFragment.java b/src/com/android/contacts/dialpad/DialpadFragment.java
index 6acbc85..add6b80 100644
--- a/src/com/android/contacts/dialpad/DialpadFragment.java
+++ b/src/com/android/contacts/dialpad/DialpadFragment.java
@@ -538,10 +538,8 @@
     @Override
     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
         super.onCreateOptionsMenu(menu, inflater);
-
-        // If the hardware doesn't have a hardware menu key, we'll show soft menu button on the
-        // right side of digits EditText.
-        if (ViewConfiguration.get(getActivity()).hasPermanentMenuKey()) {
+        if (mShowOptionsMenu && ViewConfiguration.get(getActivity()).hasPermanentMenuKey() &&
+                mDialpadChooser != null && mDigits != null) {
             inflater.inflate(R.menu.dialpad_options, menu);
         }
     }
@@ -549,16 +547,9 @@
     @Override
     public void onPrepareOptionsMenu(Menu menu) {
         // Hardware menu key should be available and Views should already be ready.
-        if (ViewConfiguration.get(getActivity()).hasPermanentMenuKey() &&
+        if (mShowOptionsMenu && ViewConfiguration.get(getActivity()).hasPermanentMenuKey() &&
                 mDialpadChooser != null && mDigits != null) {
-            if (mShowOptionsMenu) {
-                setupMenuItems(menu);
-            } else {
-                menu.findItem(R.id.menu_call_settings_dialpad).setVisible(false);
-                menu.findItem(R.id.menu_add_contacts).setVisible(false);
-                menu.findItem(R.id.menu_2s_pause).setVisible(false);
-                menu.findItem(R.id.menu_add_wait).setVisible(false);
-            }
+             setupMenuItems(menu);
         }
     }
 
diff --git a/src/com/android/contacts/group/GroupEditorFragment.java b/src/com/android/contacts/group/GroupEditorFragment.java
index f17ac60..bc9e5ba 100644
--- a/src/com/android/contacts/group/GroupEditorFragment.java
+++ b/src/com/android/contacts/group/GroupEditorFragment.java
@@ -388,6 +388,10 @@
         mListener = value;
     }
 
+    public void doSaveAction() {
+        save(SaveMode.CLOSE);
+    }
+
     @Override
     public void onCreateOptionsMenu(Menu menu, final MenuInflater inflater) {
         inflater.inflate(R.menu.edit_group, menu);
@@ -396,8 +400,6 @@
     @Override
     public boolean onOptionsItemSelected(MenuItem item) {
         switch (item.getItemId()) {
-            case R.id.menu_done:
-                return save(SaveMode.CLOSE);
             case R.id.menu_discard:
                 return revert();
         }
diff --git a/src/com/android/contacts/list/ContactTileAdapter.java b/src/com/android/contacts/list/ContactTileAdapter.java
index 7691587..ceabbd9 100644
--- a/src/com/android/contacts/list/ContactTileAdapter.java
+++ b/src/com/android/contacts/list/ContactTileAdapter.java
@@ -19,11 +19,16 @@
 import com.android.contacts.ContactTileLoaderFactory;
 import com.android.contacts.GroupMemberLoader;
 import com.android.contacts.R;
+import com.android.contacts.model.AccountTypeManager;
+import com.android.contacts.model.DataKind;
 
 import android.content.ContentUris;
 import android.content.Context;
 import android.database.Cursor;
 import android.net.Uri;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
 import android.provider.ContactsContract.Contacts;
 import android.view.View;
 import android.view.View.OnClickListener;
@@ -62,6 +67,13 @@
     private int mPresenceIndex;
     private int mStatusIndex;
 
+    /**
+     * Only valid when {@link DisplayType#STREQUENT_PHONE_ONLY} is true
+     */
+    private int mPhoneNumberIndex;
+    private int mPhoneNumberTypeIndex;
+    private int mPhoneNumberLabelIndex;
+
     private boolean mIsQuickContactEnabled = false;
 
     /**
@@ -151,6 +163,10 @@
             mStarredIndex = ContactTileLoaderFactory.STARRED;
             mPresenceIndex = ContactTileLoaderFactory.CONTACT_PRESENCE;
             mStatusIndex = ContactTileLoaderFactory.CONTACT_STATUS;
+
+            mPhoneNumberIndex = ContactTileLoaderFactory.PHONE_NUMBER;
+            mPhoneNumberTypeIndex = ContactTileLoaderFactory.PHONE_NUMBER_TYPE;
+            mPhoneNumberLabelIndex = ContactTileLoaderFactory.PHONE_NUMBER_LABEL;
         }
     }
 
@@ -168,7 +184,7 @@
     /**
      * Iterates over the {@link Cursor}
      * Returns position of the first NON Starred Contact
-     * Returns -1 if not {@link DisplayType#}
+     * Returns -1 if not {@link DisplayType#STREQUENT} or {@link DisplayType#STREQUENT_PHONE_ONLY}
      */
     private int getDividerPosition(Cursor cursor) {
         if (cursor == null || cursor.isClosed() || (mDisplayType != DisplayType.STREQUENT
@@ -204,6 +220,17 @@
                 Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, lookupKey), id);
         contact.presence = cursor.isNull(mPresenceIndex) ? null : cursor.getInt(mPresenceIndex);
 
+        if (mDisplayType == DisplayType.STREQUENT_PHONE_ONLY) {
+            int phoneNumberType = cursor.getInt(mPhoneNumberTypeIndex);
+            String phoneNumberCustomLabel = cursor.getString(mPhoneNumberLabelIndex);
+            contact.phoneLabel = (String) Phone.getTypeLabel(mContext.getResources(),
+                    phoneNumberType, phoneNumberCustomLabel);
+            contact.phoneNumber = cursor.getString(mPhoneNumberIndex);
+        } else {
+            contact.status = cursor.getString(mStatusIndex);
+            contact.presence = cursor.isNull(mPresenceIndex) ? null : cursor.getInt(mPresenceIndex);
+        }
+
         return contact;
     }
 
@@ -343,7 +370,8 @@
                 return mIsQuickContactEnabled ?
                         R.layout.contact_tile_starred_quick_contact : R.layout.contact_tile_starred;
             case ViewTypes.FREQUENT:
-                return R.layout.contact_tile_frequent;
+                return mDisplayType == DisplayType.STREQUENT_PHONE_ONLY ?
+                        R.layout.contact_tile_frequent_phone : R.layout.contact_tile_frequent;
             case ViewTypes.STARRED_WITH_SECONDARY_ACTION:
                 return R.layout.contact_tile_starred_secondary_target;
             default:
@@ -464,6 +492,8 @@
     public static class ContactEntry {
         public String name;
         public String status;
+        public String phoneLabel;
+        public String phoneNumber;
         public Uri photoUri;
         public Uri lookupKey;
         public Integer presence;
diff --git a/src/com/android/contacts/list/ContactTileView.java b/src/com/android/contacts/list/ContactTileView.java
index 6374c23..3839573 100644
--- a/src/com/android/contacts/list/ContactTileView.java
+++ b/src/com/android/contacts/list/ContactTileView.java
@@ -21,9 +21,8 @@
 import com.android.contacts.list.ContactTileAdapter.ContactEntry;
 
 import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.drawable.Drawable;
 import android.net.Uri;
+import android.provider.ContactsContract.StatusUpdates;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.view.View;
@@ -32,9 +31,6 @@
 import android.widget.QuickContactBadge;
 import android.widget.TextView;
 
-import android.provider.ContactsContract.StatusUpdates;
-
-
 /**
  * A ContactTile displays the contact's picture overlayed with their name
  */
@@ -47,6 +43,8 @@
     private QuickContactBadge mQuickContact;
     private TextView mName;
     private TextView mStatus;
+    private TextView mPhoneLabel;
+    private TextView mPhoneNumber;
     private ContactPhotoManager mPhotoManager = null;
 
     public ContactTileView(Context context, AttributeSet attrs) {
@@ -63,6 +61,8 @@
         mPhoto = (ImageView) findViewById(R.id.contact_tile_image);
         mPresence = (ImageView) findViewById(R.id.contact_tile_presence);
         mStatus = (TextView) findViewById(R.id.contact_tile_status);
+        mPhoneLabel = (TextView) findViewById(R.id.contact_tile_phone_type);
+        mPhoneNumber = (TextView) findViewById(R.id.contact_tile_phone_number);
     }
 
     public void setPhotoManager(ContactPhotoManager photoManager) {
@@ -97,6 +97,15 @@
                 mStatus.setText(statusText);
             }
 
+            if (mPhoneLabel != null) {
+                mPhoneLabel.setText(entry.phoneLabel);
+            }
+
+            if (mPhoneNumber != null) {
+                // TODO: Format number correctly
+                mPhoneNumber.setText(entry.phoneNumber);
+            }
+
             if (mQuickContact != null) {
                 mQuickContact.assignContactUri(mLookupUri);
                 mQuickContact.setImageBitmap(null);
diff --git a/tests/src/com/android/contacts/ContactLoaderTest.java b/tests/src/com/android/contacts/ContactLoaderTest.java
index 1d3fb20..3d0ddb4 100644
--- a/tests/src/com/android/contacts/ContactLoaderTest.java
+++ b/tests/src/com/android/contacts/ContactLoaderTest.java
@@ -297,6 +297,9 @@
                         Data.STATUS_LABEL, Data.STATUS_TIMESTAMP,
 
                         Contacts.PHOTO_URI,
+
+                        Contacts.SEND_TO_VOICEMAIL,
+                        Contacts.CUSTOM_RINGTONE,
                     })
                     .withSortOrder(Contacts.Entity.RAW_CONTACT_ID)
                     .returnRow(
@@ -330,7 +333,10 @@
                         "Having dinner", "mockPkg3", 0,
                         20, 0,
 
-                        "content:some.photo.uri"
+                        "content:some.photo.uri",
+
+                        0,
+                        null
                     );
         }