Merge "Re-introduce appropriate "activated" background"
diff --git a/res/color/list_secondary_text_color.xml b/res/color/list_secondary_text_color.xml
deleted file mode 100644
index edf8678..0000000
--- a/res/color/list_secondary_text_color.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-
-    <item android:state_activated="true" android:color="@color/secondary_text_color_activated" />
-    <item android:color="@color/secondary_text_color" /> <!-- not selected -->
-
-</selector>
diff --git a/res/color/list_primary_text_color.xml b/res/color/primary_text_color.xml
similarity index 81%
copy from res/color/list_primary_text_color.xml
copy to res/color/primary_text_color.xml
index 7c185fc..acc2fb7 100644
--- a/res/color/list_primary_text_color.xml
+++ b/res/color/primary_text_color.xml
@@ -16,7 +16,7 @@
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
 
-    <item android:state_activated="true" android:color="@color/primary_text_color_activated"/>
-    <item android:color="@color/primary_text_color" /> <!-- not selected -->
+    <item android:state_activated="true" android:color="#FFFFFF" />
+    <item android:color="#333333" /> <!-- not selected -->
 
 </selector>
diff --git a/res/color/list_primary_text_color.xml b/res/color/secondary_text_color.xml
similarity index 81%
rename from res/color/list_primary_text_color.xml
rename to res/color/secondary_text_color.xml
index 7c185fc..1c62458 100644
--- a/res/color/list_primary_text_color.xml
+++ b/res/color/secondary_text_color.xml
@@ -16,7 +16,7 @@
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
 
-    <item android:state_activated="true" android:color="@color/primary_text_color_activated"/>
-    <item android:color="@color/primary_text_color" /> <!-- not selected -->
+    <item android:state_activated="true" android:color="#FFFFFF" />
+    <item android:color="#777777" /> <!-- not selected -->
 
 </selector>
diff --git a/res/drawable-hdpi/ab_solid_custom_blue_inverse_holo.9.png b/res/drawable-hdpi/ab_solid_custom_blue_inverse_holo.9.png
index 80fb400..956d61b 100644
--- a/res/drawable-hdpi/ab_solid_custom_blue_inverse_holo.9.png
+++ b/res/drawable-hdpi/ab_solid_custom_blue_inverse_holo.9.png
Binary files differ
diff --git a/res/drawable-hdpi/account_spinner_icon.png b/res/drawable-hdpi/account_spinner_icon.png
index 3e82e51..9566386 100644
--- a/res/drawable-hdpi/account_spinner_icon.png
+++ b/res/drawable-hdpi/account_spinner_icon.png
Binary files differ
diff --git a/res/drawable-hdpi/list_section_divider_holo_custom.9.png b/res/drawable-hdpi/list_section_divider_holo_custom.9.png
index 6c0d251..1e3e778 100644
--- a/res/drawable-hdpi/list_section_divider_holo_custom.9.png
+++ b/res/drawable-hdpi/list_section_divider_holo_custom.9.png
Binary files differ
diff --git a/res/drawable-mdpi/ab_solid_custom_blue_inverse_holo.9.png b/res/drawable-mdpi/ab_solid_custom_blue_inverse_holo.9.png
index f3c0a90..3e9f167 100644
--- a/res/drawable-mdpi/ab_solid_custom_blue_inverse_holo.9.png
+++ b/res/drawable-mdpi/ab_solid_custom_blue_inverse_holo.9.png
Binary files differ
diff --git a/res/drawable-mdpi/account_spinner_icon.png b/res/drawable-mdpi/account_spinner_icon.png
index d9aaf02..e159d59 100644
--- a/res/drawable-mdpi/account_spinner_icon.png
+++ b/res/drawable-mdpi/account_spinner_icon.png
Binary files differ
diff --git a/res/drawable-mdpi/list_section_divider_holo_custom.9.png b/res/drawable-mdpi/list_section_divider_holo_custom.9.png
index cfc57ee..1d8fd09 100644
--- a/res/drawable-mdpi/list_section_divider_holo_custom.9.png
+++ b/res/drawable-mdpi/list_section_divider_holo_custom.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/ab_solid_custom_blue_inverse_holo.9.png b/res/drawable-xhdpi/ab_solid_custom_blue_inverse_holo.9.png
index 3c97b20..31fea59 100644
--- a/res/drawable-xhdpi/ab_solid_custom_blue_inverse_holo.9.png
+++ b/res/drawable-xhdpi/ab_solid_custom_blue_inverse_holo.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/account_spinner_icon.png b/res/drawable-xhdpi/account_spinner_icon.png
index 8b888cb..d3d3cac 100644
--- a/res/drawable-xhdpi/account_spinner_icon.png
+++ b/res/drawable-xhdpi/account_spinner_icon.png
Binary files differ
diff --git a/res/drawable-xhdpi/list_section_divider_holo_custom.9.png b/res/drawable-xhdpi/list_section_divider_holo_custom.9.png
index 32e79e1..0bd8a0f 100644
--- a/res/drawable-xhdpi/list_section_divider_holo_custom.9.png
+++ b/res/drawable-xhdpi/list_section_divider_holo_custom.9.png
Binary files differ
diff --git a/res/layout-sw580dp/contact_detail_container.xml b/res/layout-sw580dp/contact_detail_container.xml
index 58a6eb3..cdb789f 100644
--- a/res/layout-sw580dp/contact_detail_container.xml
+++ b/res/layout-sw580dp/contact_detail_container.xml
@@ -17,8 +17,7 @@
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:orientation="vertical"
-    android:background="@color/background_primary">
+    android:orientation="vertical">
 
     <android.support.v4.view.ViewPager
         android:id="@+id/pager"
diff --git a/res/layout-sw580dp/group_detail_fragment.xml b/res/layout-sw580dp/group_detail_fragment.xml
index 90ca03a..438a987 100644
--- a/res/layout-sw580dp/group_detail_fragment.xml
+++ b/res/layout-sw580dp/group_detail_fragment.xml
@@ -22,8 +22,7 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:paddingLeft="@dimen/group_detail_border_padding"
-    android:paddingRight="@dimen/group_detail_border_padding"
-    android:background="@drawable/panel_content">
+    android:paddingRight="@dimen/group_detail_border_padding">
 
     <TextView
         android:id="@+id/group_title"
diff --git a/res/layout-sw580dp/people_activity.xml b/res/layout-sw580dp/people_activity.xml
index e15c079..fecb848 100644
--- a/res/layout-sw580dp/people_activity.xml
+++ b/res/layout-sw580dp/people_activity.xml
@@ -58,6 +58,7 @@
             android:layout_width="0dip"
             android:layout_height="match_parent"
             android:layout_weight="1"
+            android:background="@color/background_primary"
             ex:clipMarginLeft="0dip"
             ex:clipMarginTop="3dip"
             ex:clipMarginRight="3dip"
@@ -72,7 +73,10 @@
                 android:id="@+id/contact_detail_container"
                 layout="@layout/contact_detail_container"
                 android:layout_width="match_parent"
-                android:layout_height="match_parent"/>
+                android:layout_height="match_parent"
+                android:layout_marginTop="16dip"
+                android:layout_marginLeft="16dip"
+                android:layout_marginRight="16dip"/>
 
             <!-- This invisible worker fragment loads the contact's details -->
             <fragment
diff --git a/res/layout/editor_account_header.xml b/res/layout/editor_account_header.xml
index b6b19db..ff33cf1 100644
--- a/res/layout/editor_account_header.xml
+++ b/res/layout/editor_account_header.xml
@@ -24,6 +24,7 @@
     android:orientation="horizontal"
     android:paddingTop="8dip"
     android:paddingBottom="8dip"
+    android:gravity="center_vertical"
     android:paddingLeft="@dimen/account_container_left_padding"
     android:paddingRight="32dip">
 
diff --git a/res/layout/editor_account_header_with_dropdown.xml b/res/layout/editor_account_header_with_dropdown.xml
index 74abee9..001eaae 100644
--- a/res/layout/editor_account_header_with_dropdown.xml
+++ b/res/layout/editor_account_header_with_dropdown.xml
@@ -22,6 +22,7 @@
     android:minHeight="48dip"
     android:background="#EEEEEE"
     android:orientation="horizontal"
+    android:gravity="center_vertical"
     android:paddingLeft="@dimen/account_container_left_padding"
     android:paddingRight="32dip">
 
diff --git a/res/layout/group_browse_list_item.xml b/res/layout/group_browse_list_item.xml
index b213754..45f444f 100644
--- a/res/layout/group_browse_list_item.xml
+++ b/res/layout/group_browse_list_item.xml
@@ -71,7 +71,6 @@
                 android:layout_height="wrap_content"
                 android:layout_width="wrap_content"
                 android:textAppearance="?android:attr/textAppearanceMedium"
-                android:textColor="@color/list_primary_text_color"
                 android:ellipsize="end"
                 android:singleLine="true" />
 
@@ -80,7 +79,7 @@
                 android:layout_height="wrap_content"
                 android:layout_width="wrap_content"
                 android:textAppearance="?android:attr/textAppearanceSmall"
-                android:textColor="@color/list_secondary_text_color"
+                android:textColor="?android:attr/textColorSecondary"
                 android:ellipsize="end"
                 android:singleLine="true" />
 
diff --git a/res/layout/item_read_only_field.xml b/res/layout/item_read_only_field.xml
index 03778cc..5f8367f 100644
--- a/res/layout/item_read_only_field.xml
+++ b/res/layout/item_read_only_field.xml
@@ -14,7 +14,8 @@
      limitations under the License.
 -->
 
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:orientation="vertical">
@@ -23,13 +24,29 @@
         android:id="@+id/kind_title_layout"
         layout="@layout/edit_kind_title" />
 
-    <TextView android:id="@+id/data"
-        android:layout_width="wrap_content"
-        android:layout_height="0px"
-        android:layout_weight="1"
-        android:layout_marginLeft="16dip"
-        android:textAppearance="?android:attr/textAppearanceMedium"
-        android:textColor="?android:attr/textColorSecondary"
-        android:singleLine="true"/>
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:minHeight="@dimen/editor_min_line_item_height"
+        android:orientation="horizontal">
+        <TextView
+            android:id="@+id/data"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_vertical"
+            android:layout_marginLeft="16dip"
+            android:textAppearance="?android:attr/textAppearanceMedium"
+            android:textColor="?android:attr/textColorPrimary"
+            android:singleLine="true"/>
+        <TextView
+            android:id="@+id/type"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_vertical"
+            android:layout_marginLeft="8dip"
+            android:textAppearance="?android:attr/textAppearanceSmall"
+            android:textColor="?android:attr/textColorSecondary"
+            android:singleLine="true"/>
+    </LinearLayout>
 
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>
diff --git a/res/layout/stream_item_container.xml b/res/layout/stream_item_container.xml
index 308c5f5..de4f87d 100644
--- a/res/layout/stream_item_container.xml
+++ b/res/layout/stream_item_container.xml
@@ -21,7 +21,7 @@
     android:paddingLeft="@dimen/detail_update_section_side_padding"
     android:paddingRight="@dimen/detail_update_section_side_padding">
 
-    <TableLayout
+    <LinearLayout
         android:id="@+id/stream_item_content"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
@@ -31,6 +31,7 @@
         android:paddingBottom="@dimen/detail_update_section_item_vertical_padding"
         android:background="?android:attr/selectableItemBackground"
         android:layout_gravity="center_vertical"
+        android:orientation="vertical"
         />
 
     <View
diff --git a/res/layout/stream_item_row_image_and_text.xml b/res/layout/stream_item_row_image_and_text.xml
index 882a23b..c5699f4 100644
--- a/res/layout/stream_item_row_image_and_text.xml
+++ b/res/layout/stream_item_row_image_and_text.xml
@@ -14,68 +14,41 @@
      limitations under the License.
 -->
 
-<TableRow
+<LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:ex="http://schemas.android.com/apk/res/com.android.contacts">
+    xmlns:ex="http://schemas.android.com/apk/res/com.android.contacts"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical">
 
-    <view
-        class="com.android.contacts.widget.ProportionalLayout"
-        android:layout_width="0dip"
+    <LinearLayout
+        android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_marginRight="@dimen/detail_update_section_between_items_horizontal_padding"
-        android:layout_weight="1"
-        ex:ratio="1"
-        ex:direction="widthToHeight">
-        <include
-            android:id="@+id/stream_item_first_image"
-            layout="@layout/stream_item_photo"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"/>
-    </view>
+        android:layout_marginBottom="8dip"
+        android:orientation="horizontal"
+        android:weightSum="2">
 
-    <view
-        class="com.android.contacts.widget.ProportionalLayout"
-        android:layout_width="0dip"
-        android:layout_height="wrap_content"
-        android:layout_weight="1"
-        ex:ratio="1"
-        ex:direction="widthToHeight">
-        <LinearLayout
-            android:id="@+id/stream_item_second_text"
-            android:orientation="vertical"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content">
+        <view
+            class="com.android.contacts.widget.ProportionalLayout"
+            android:layout_width="0dip"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:layout_marginRight="@dimen/detail_update_section_between_items_horizontal_padding"
+            ex:ratio="1"
+            ex:direction="widthToHeight">
 
-            <TextView android:id="@+id/stream_item_html"
+            <include
+                android:id="@+id/stream_item_first_image"
+                layout="@layout/stream_item_photo"
                 android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:textSize="16sp"
-                android:textColor="?android:attr/textColorPrimary" />
+                android:layout_height="match_parent"/>
 
-            <LinearLayout
-                android:orientation="horizontal"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content">
-                <TextView android:id="@+id/stream_item_attribution"
-                    android:layout_width="0dip"
-                    android:layout_height="wrap_content"
-                    android:textAppearance="?android:attr/textAppearanceSmall"
-                    android:textColor="?android:attr/textColorSecondary"
-                    android:maxLines="1"
-                    android:ellipsize="end"
-                    android:layout_weight="1" />
+        </view>
 
-                <TextView android:id="@+id/stream_item_comments"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_marginLeft="@dimen/detail_update_section_attribution_comments_padding"
-                    android:textAppearance="?android:attr/textAppearanceSmall"
-                    android:textColor="?android:attr/textColorSecondary"
-                    android:visibility="gone"
-                    android:maxLines="1" />
-            </LinearLayout>
+    </LinearLayout>
 
-        </LinearLayout>
-    </view>
+    <include
+        android:id="@+id/stream_item_second_text"
+        layout="@layout/stream_item_row_text_only"/>
 
-</TableRow>
+</LinearLayout>
diff --git a/res/layout/stream_item_row_two_images.xml b/res/layout/stream_item_row_two_images.xml
index f10b7d8..3a524bf 100644
--- a/res/layout/stream_item_row_two_images.xml
+++ b/res/layout/stream_item_row_two_images.xml
@@ -14,9 +14,11 @@
      limitations under the License.
 -->
 
-<TableRow
+<LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:ex="http://schemas.android.com/apk/res/com.android.contacts">
+    xmlns:ex="http://schemas.android.com/apk/res/com.android.contacts"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content">
 
     <view
         class="com.android.contacts.widget.ProportionalLayout"
@@ -47,4 +49,4 @@
             android:layout_height="match_parent"/>
     </view>
 
-</TableRow>
+</LinearLayout>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 5e8bd70..1a8ee23 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -80,19 +80,9 @@
     <!-- Color of the theme of the People app -->
     <color name="people_app_theme_color">#33B5E5</color>
 
-    <!-- Primary text color in the People app -->
-    <color name="primary_text_color">#333333</color>
-
-    <!-- Activated primary text color in the People app -->
-    <color name="primary_text_color_activated">#FFFFFF</color>
-
-    <!-- Secondary text color in the People app -->
-    <color name="secondary_text_color">#777777</color>
+    <!-- Secondary text color in the Phone app -->
     <color name="dialtacts_secondary_text_color">#888888</color>
 
-    <!-- Activated secondary text color in the People app -->
-    <color name="secondary_text_color_activated">#FFFFFF</color>
-
     <!-- Colors in the contact browser list -->
     <color name="contact_count_text_color">#AAAAAA</color>
 
diff --git a/src/com/android/contacts/detail/ContactDetailDisplayUtils.java b/src/com/android/contacts/detail/ContactDetailDisplayUtils.java
index 5d6c7d5..cd4add6 100644
--- a/src/com/android/contacts/detail/ContactDetailDisplayUtils.java
+++ b/src/com/android/contacts/detail/ContactDetailDisplayUtils.java
@@ -237,8 +237,6 @@
         if (!contactData.getStreamItems().isEmpty()) {
             StreamItemEntry firstEntry = contactData.getStreamItems().get(0);
             snippet = Html.fromHtml(firstEntry.getText());
-            // Add quotes around the text
-            snippet = context.getString(R.string.recent_updates_tab_text, snippet);
             if (!firstEntry.getPhotos().isEmpty()) {
                 StreamItemPhotoEntry firstPhoto = firstEntry.getPhotos().get(0);
                 photoUri = firstPhoto.getPhotoUri();
diff --git a/src/com/android/contacts/detail/ContactDetailFragmentCarousel.java b/src/com/android/contacts/detail/ContactDetailFragmentCarousel.java
index 106ff0e..b01316b 100644
--- a/src/com/android/contacts/detail/ContactDetailFragmentCarousel.java
+++ b/src/com/android/contacts/detail/ContactDetailFragmentCarousel.java
@@ -88,7 +88,7 @@
     private View mDetailFragmentView;
     private View mUpdatesFragmentView;
 
-    private final Handler mHandler = new Handler();
+    private boolean mScrollToCurrentPage = false;
 
     public ContactDetailFragmentCarousel(Context context) {
         this(context, null);
@@ -144,6 +144,28 @@
                 resolveSize(screenHeight, heightMeasureSpec));
     }
 
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        super.onLayout(changed, l, t, r, b);
+        if (mScrollToCurrentPage) {
+            mScrollToCurrentPage = false;
+            // Use scrollTo() instead of smoothScrollTo() to prevent a visible flicker to the user
+            scrollTo(mCurrentPage == ABOUT_PAGE ? 0 : mAllowedHorizontalScrollLength, 0);
+            updateTouchInterceptors();
+        }
+    }
+
+    /**
+     * Set the current page that should be restored when the view is first laid out.
+     */
+    public void restoreCurrentPage(int pageIndex) {
+        setCurrentPage(pageIndex);
+        // It is only possible to scroll the view after onMeasure() has been called (where the
+        // allowed horizontal scroll length is determined). Hence, set a flag that will be read
+        // in onLayout() after the children and this view have finished being laid out.
+        mScrollToCurrentPage = true;
+    }
+
     /**
      * Set the current page. This auto-scrolls the carousel to the current page and dims out
      * the non-selected page.
@@ -183,31 +205,13 @@
             mEnableSwipe = enable;
             if (mUpdatesFragmentView != null) {
                 mUpdatesFragmentView.setVisibility(enable ? View.VISIBLE : View.GONE);
+                mScrollToCurrentPage = true;
                 requestLayout();
                 invalidate();
             }
-            // This method could have been called before the view has been measured (i.e.
-            // immediately after a rotation), so snap to edge only after the view is ready.
-            postRunnableToSnapToEdge();
         }
     }
 
-    /**
-     * Snap to the currently selected page only once all the view setup and measurement has
-     * completed (i.e. we need to know the allowed horizontal scroll width in order to
-     * snap to the correct page).
-     */
-    private void postRunnableToSnapToEdge() {
-        mHandler.post(new Runnable() {
-            @Override
-            public void run() {
-                if (isAttachedToWindow() && mAboutFragment != null && mUpdatesFragment != null) {
-                    snapToEdge();
-                }
-            }
-        });
-    }
-
     public int getCurrentPage() {
         return mCurrentPage;
     }
@@ -302,8 +306,4 @@
         }
         return false;
     }
-
-    private boolean isAttachedToWindow() {
-        return getWindowToken() != null;
-    }
 }
diff --git a/src/com/android/contacts/detail/ContactDetailLayoutController.java b/src/com/android/contacts/detail/ContactDetailLayoutController.java
index 6b8829e..7a7f400 100644
--- a/src/com/android/contacts/detail/ContactDetailLayoutController.java
+++ b/src/com/android/contacts/detail/ContactDetailLayoutController.java
@@ -21,6 +21,8 @@
 import com.android.contacts.R;
 import com.android.contacts.activities.ContactDetailActivity.FragmentKeyListener;
 
+import android.animation.Animator;
+import android.animation.Animator.AnimatorListener;
 import android.animation.ObjectAnimator;
 import android.app.Activity;
 import android.app.FragmentManager;
@@ -77,6 +79,7 @@
 
     private ContactLoader.Result mContactData;
 
+    private boolean mTabCarouselIsAnimating;
     private boolean mContactHasUpdates;
 
     private LayoutMode mLayoutMode;
@@ -176,6 +179,7 @@
                 }
 
                 mTabCarousel.setListener(mTabCarouselListener);
+                mTabCarousel.restoreCurrentTab(currentPageIndex);
                 mDetailFragment.setVerticalScrollListener(
                         new VerticalScrollListener(TAB_INDEX_DETAIL));
                 mUpdatesFragment.setVerticalScrollListener(
@@ -211,7 +215,7 @@
 
                 mFragmentCarousel.setFragmentViews(mDetailFragmentView, mUpdatesFragmentView);
                 mFragmentCarousel.setFragments(mDetailFragment, mUpdatesFragment);
-                mFragmentCarousel.setCurrentPage(currentPageIndex);
+                mFragmentCarousel.restoreCurrentPage(currentPageIndex);
                 break;
             }
         }
@@ -239,6 +243,7 @@
     public void showEmptyState() {
         switch (mLayoutMode) {
             case FRAGMENT_CAROUSEL: {
+                mFragmentCarousel.setCurrentPage(0);
                 mFragmentCarousel.enableSwipe(false);
                 mDetailFragment.showEmptyState();
                 break;
@@ -323,6 +328,7 @@
                 break;
             case FRAGMENT_CAROUSEL: {
                 // Disable swipe so only the detail fragment shows
+                mFragmentCarousel.setCurrentPage(0);
                 mFragmentCarousel.enableSwipe(false);
                 break;
             }
@@ -449,12 +455,14 @@
                     mTabCarousel, "y", desiredValue).setDuration(75);
             mTabCarouselAnimator.setInterpolator(AnimationUtils.loadInterpolator(
                     mActivity, android.R.anim.accelerate_decelerate_interpolator));
+            mTabCarouselAnimator.addListener(mTabCarouselAnimatorListener);
         }
 
         private void cancelTabCarouselAnimator() {
             if (mTabCarouselAnimator != null) {
                 mTabCarouselAnimator.cancel();
                 mTabCarouselAnimator = null;
+                mTabCarouselIsAnimating = false;
             }
         }
     };
@@ -478,6 +486,34 @@
         }
     }
 
+    /**
+     * This listener keeps track of whether the tab carousel animation is currently going on or not,
+     * in order to prevent other simultaneous changes to the Y position of the tab carousel which
+     * can cause flicker.
+     */
+    private final AnimatorListener mTabCarouselAnimatorListener = new AnimatorListener() {
+
+        @Override
+        public void onAnimationCancel(Animator animation) {
+            mTabCarouselIsAnimating = false;
+        }
+
+        @Override
+        public void onAnimationEnd(Animator animation) {
+            mTabCarouselIsAnimating = false;
+        }
+
+        @Override
+        public void onAnimationRepeat(Animator animation) {
+            mTabCarouselIsAnimating = true;
+        }
+
+        @Override
+        public void onAnimationStart(Animator animation) {
+            mTabCarouselIsAnimating = true;
+        }
+    };
+
     private final ContactDetailTabCarousel.Listener mTabCarouselListener =
             new ContactDetailTabCarousel.Listener() {
 
@@ -529,10 +565,11 @@
                 int totalItemCount) {
             int currentPageIndex = mViewPager.getCurrentItem();
             // Don't move the carousel if: 1) the contact does not have social updates because then
-            // tab carousel must not be visible, 2) if the view pager is still being scrolled, or
-            // 3) if the current page being viewed is not this one.
+            // tab carousel must not be visible, 2) if the view pager is still being scrolled,
+            // 3) if the current page being viewed is not this one, or 4) if the tab carousel
+            // is already being animated vertically.
             if (!mContactHasUpdates || mViewPagerState != ViewPager.SCROLL_STATE_IDLE ||
-                    mPageIndex != currentPageIndex) {
+                    mPageIndex != currentPageIndex || mTabCarouselIsAnimating) {
                 return;
             }
             // If the FIRST item is not visible on the screen, then the carousel must be pinned
diff --git a/src/com/android/contacts/detail/ContactDetailTabCarousel.java b/src/com/android/contacts/detail/ContactDetailTabCarousel.java
index 8a51d81..9300b54 100644
--- a/src/com/android/contacts/detail/ContactDetailTabCarousel.java
+++ b/src/com/android/contacts/detail/ContactDetailTabCarousel.java
@@ -63,6 +63,7 @@
 
     private int mTabDisplayLabelHeight;
 
+    private boolean mScrollToCurrentTab = false;
     private int mLastScrollPosition;
 
     private int mAllowedHorizontalScrollLength = Integer.MIN_VALUE;
@@ -103,12 +104,7 @@
         mUpdatesTab = (CarouselTab) findViewById(R.id.tab_update);
         mUpdatesTab.setLabel(mContext.getString(R.string.contactDetailUpdates));
 
-        // TODO: We can't always assume the "about" page will be the current page.
-        mAboutTab.showSelectedState();
-        mAboutTab.setAlphaLayerValue(0);
         mAboutTab.enableTouchInterceptor(mAboutTabTouchInterceptListener);
-
-        mUpdatesTab.setAlphaLayerValue(MAX_ALPHA);
         mUpdatesTab.enableTouchInterceptor(mUpdatesTabTouchInterceptListener);
 
         // Retrieve the photo view for the "about" tab
@@ -144,6 +140,15 @@
                 resolveSize(tabHeight, heightMeasureSpec));
     }
 
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        super.onLayout(changed, l, t, r, b);
+        if (mScrollToCurrentTab) {
+            mScrollToCurrentTab = false;
+            scrollTo(mCurrentTab == TAB_INDEX_ABOUT ? 0 : mAllowedHorizontalScrollLength, 0);
+        }
+    }
+
     private final OnClickListener mAboutTabTouchInterceptListener = new OnClickListener() {
         @Override
         public void onClick(View v) {
@@ -174,6 +179,17 @@
     }
 
     /**
+     * Set the current tab that should be restored when the view is first laid out.
+     */
+    public void restoreCurrentTab(int position) {
+        setCurrentTab(position);
+        // It is only possible to scroll the view after onMeasure() has been called (where the
+        // allowed horizontal scroll length is determined). Hence, set a flag that will be read
+        // in onLayout() after the children and this view have finished being laid out.
+        mScrollToCurrentTab = true;
+    }
+
+    /**
      * Restore the Y position of this view to the last manually requested value. This can be done
      * after the parent has been re-laid out again, where this view's position could have been
      * lost if the view laid outside its parent's bounds.
@@ -225,8 +241,6 @@
      * Updates the tab selection.
      */
     public void setCurrentTab(int 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
         switch (position) {
             case TAB_INDEX_ABOUT:
                 mAboutTab.showSelectedState();
@@ -270,10 +284,10 @@
         switch (event.getAction()) {
             case MotionEvent.ACTION_DOWN:
                 mListener.onTouchDown();
-                return false;
+                return true;
             case MotionEvent.ACTION_UP:
                 mListener.onTouchUp();
-                return false;
+                return true;
         }
         return super.onTouchEvent(event);
     }
diff --git a/src/com/android/contacts/editor/ExternalRawContactEditorView.java b/src/com/android/contacts/editor/ExternalRawContactEditorView.java
index 8a18114..0a1ae74 100644
--- a/src/com/android/contacts/editor/ExternalRawContactEditorView.java
+++ b/src/com/android/contacts/editor/ExternalRawContactEditorView.java
@@ -27,6 +27,7 @@
 
 import android.content.ContentUris;
 import android.content.Context;
+import android.content.res.Resources;
 import android.net.Uri;
 import android.provider.ContactsContract.CommonDataKinds.Email;
 import android.provider.ContactsContract.CommonDataKinds.Phone;
@@ -132,12 +133,14 @@
         mDataSet = values.getAsString(RawContacts.DATA_SET);
 
         if (isProfile) {
-            mAccountNameTextView.setVisibility(View.GONE);
             if (TextUtils.isEmpty(mAccountName)) {
+                mAccountNameTextView.setVisibility(View.GONE);
                 mAccountTypeTextView.setText(R.string.local_profile_title);
             } else {
-                mAccountTypeTextView.setText(
-                        mContext.getString(R.string.external_profile_title, mAccountName));
+                CharSequence accountType = type.getDisplayLabel(mContext);
+                mAccountTypeTextView.setText(mContext.getString(R.string.external_profile_title,
+                        accountType));
+                mAccountNameTextView.setText(mAccountName);
             }
         } else {
             CharSequence accountType = type.getDisplayLabel(mContext);
@@ -199,35 +202,42 @@
             mEditExternallyButton.setVisibility(View.VISIBLE);
         }
 
+        final Resources res = mContext.getResources();
         // Phones
         ArrayList<ValuesDelta> phones = state.getMimeEntries(Phone.CONTENT_ITEM_TYPE);
         if (phones != null) {
-            for (ValuesDelta phone : phones) {
-                View field = mInflater.inflate(
-                        R.layout.item_read_only_field, mGeneral, false);
-                TextView v;
-                v = (TextView) field.findViewById(R.id.kind_title);
-                v.setText(mContext.getText(R.string.phoneLabelsGroup));
-                v = (TextView) field.findViewById(R.id.data);
-                v.setText(PhoneNumberUtils.formatNumber(phone.getAsString(Phone.NUMBER),
+            for (int i = 0; i < phones.size(); i++) {
+                ValuesDelta phone = phones.get(i);
+                final String phoneNumber = PhoneNumberUtils.formatNumber(
+                        phone.getAsString(Phone.NUMBER),
                         phone.getAsString(Phone.NORMALIZED_NUMBER),
-                        ContactsUtils.getCurrentCountryIso(getContext())));
-                mGeneral.addView(field);
+                        ContactsUtils.getCurrentCountryIso(getContext()));
+                final CharSequence phoneType;
+                if (phone.containsKey(Phone.TYPE)) {
+                    phoneType = Phone.getTypeLabel(
+                            res, phone.getAsInteger(Phone.TYPE), phone.getAsString(Phone.LABEL));
+                } else {
+                    phoneType = null;
+                }
+                bindData(mContext.getText(R.string.phoneLabelsGroup),
+                        phoneNumber, phoneType, i == 0);
             }
         }
 
         // Emails
         ArrayList<ValuesDelta> emails = state.getMimeEntries(Email.CONTENT_ITEM_TYPE);
         if (emails != null) {
-            for (ValuesDelta email : emails) {
-                View field = mInflater.inflate(
-                        R.layout.item_read_only_field, mGeneral, false);
-                TextView v;
-                v = (TextView) field.findViewById(R.id.kind_title);
-                v.setText(mContext.getText(R.string.emailLabelsGroup));
-                v = (TextView) field.findViewById(R.id.data);
-                v.setText(email.getAsString(Email.DATA));
-                mGeneral.addView(field);
+            for (int i = 0; i < emails.size(); i++) {
+                ValuesDelta email = emails.get(i);
+                final String emailAddress = email.getAsString(Email.DATA);
+                final CharSequence emailType;
+                if (email.containsKey(Email.TYPE)) {
+                    emailType = Email.getTypeLabel(
+                            res, email.getAsInteger(Email.TYPE), email.getAsString(Email.LABEL));
+                } else {
+                    emailType = null;
+                }
+                bindData(mContext.getText(R.string.emailLabelsGroup), emailAddress, null, i == 0);
             }
         }
 
@@ -239,6 +249,28 @@
         }
     }
 
+    private void bindData(
+            CharSequence titleText, CharSequence data, CharSequence type, boolean isFirstEntry) {
+        final View field = mInflater.inflate(R.layout.item_read_only_field, mGeneral, false);
+        if (isFirstEntry) {
+            final TextView titleView = (TextView) field.findViewById(R.id.kind_title);
+            titleView.setText(titleText);
+        } else {
+            View titleContainer = field.findViewById(R.id.kind_title_layout);
+            titleContainer.setVisibility(View.GONE);
+        }
+        final TextView dataView = (TextView) field.findViewById(R.id.data);
+        dataView.setText(data);
+        final TextView typeView = (TextView) field.findViewById(R.id.type);
+        if (!TextUtils.isEmpty(type)) {
+            typeView.setText(type);
+        } else {
+            typeView.setVisibility(View.GONE);
+        }
+
+        mGeneral.addView(field);
+    }
+
     @Override
     public long getRawContactId() {
         return mRawContactId;
diff --git a/src/com/android/contacts/editor/RawContactEditorView.java b/src/com/android/contacts/editor/RawContactEditorView.java
index bac6217..118ca26 100644
--- a/src/com/android/contacts/editor/RawContactEditorView.java
+++ b/src/com/android/contacts/editor/RawContactEditorView.java
@@ -178,13 +178,15 @@
 
         // Fill in the account info
         if (isProfile) {
-            mAccountNameTextView.setVisibility(View.GONE);
             String accountName = values.getAsString(RawContacts.ACCOUNT_NAME);
             if (TextUtils.isEmpty(accountName)) {
+                mAccountNameTextView.setVisibility(View.GONE);
                 mAccountTypeTextView.setText(R.string.local_profile_title);
             } else {
-                mAccountTypeTextView.setText(
-                        mContext.getString(R.string.external_profile_title, accountName));
+                CharSequence accountType = type.getDisplayLabel(mContext);
+                mAccountTypeTextView.setText(mContext.getString(R.string.external_profile_title,
+                        accountType));
+                mAccountNameTextView.setText(accountName);
             }
         } else {
             String accountName = values.getAsString(RawContacts.ACCOUNT_NAME);
diff --git a/src/com/android/contacts/interactions/ImportExportDialogFragment.java b/src/com/android/contacts/interactions/ImportExportDialogFragment.java
index a6a37ef..078f63e 100644
--- a/src/com/android/contacts/interactions/ImportExportDialogFragment.java
+++ b/src/com/android/contacts/interactions/ImportExportDialogFragment.java
@@ -136,30 +136,32 @@
         // TODO move the query into a loader and do this in a background thread
         final Cursor cursor = getActivity().getContentResolver().query(Contacts.CONTENT_URI,
                 LOOKUP_PROJECTION, Contacts.IN_VISIBLE_GROUP + "!=0", null, null);
-        try {
-            if (!cursor.moveToFirst()) {
-                Toast.makeText(getActivity(), R.string.share_error, Toast.LENGTH_SHORT).show();
-                return;
-            }
+        if (cursor != null) {
+            try {
+                if (!cursor.moveToFirst()) {
+                    Toast.makeText(getActivity(), R.string.share_error, Toast.LENGTH_SHORT).show();
+                    return;
+                }
 
-            StringBuilder uriListBuilder = new StringBuilder();
-            int index = 0;
-            while (cursor.moveToNext()) {
-                if (index != 0)
-                    uriListBuilder.append(':');
-                uriListBuilder.append(cursor.getString(0));
-                index++;
-            }
-            Uri uri = Uri.withAppendedPath(
-                    Contacts.CONTENT_MULTI_VCARD_URI,
-                    Uri.encode(uriListBuilder.toString()));
+                StringBuilder uriListBuilder = new StringBuilder();
+                int index = 0;
+                do {
+                    if (index != 0)
+                        uriListBuilder.append(':');
+                    uriListBuilder.append(cursor.getString(0));
+                    index++;
+                } while (cursor.moveToNext());
+                Uri uri = Uri.withAppendedPath(
+                        Contacts.CONTENT_MULTI_VCARD_URI,
+                        Uri.encode(uriListBuilder.toString()));
 
-            final Intent intent = new Intent(Intent.ACTION_SEND);
-            intent.setType(Contacts.CONTENT_VCARD_TYPE);
-            intent.putExtra(Intent.EXTRA_STREAM, uri);
-            getActivity().startActivity(intent);
-        } finally {
-            cursor.close();
+                final Intent intent = new Intent(Intent.ACTION_SEND);
+                intent.setType(Contacts.CONTENT_VCARD_TYPE);
+                intent.putExtra(Intent.EXTRA_STREAM, uri);
+                getActivity().startActivity(intent);
+            } finally {
+                cursor.close();
+            }
         }
     }
 
diff --git a/src/com/android/contacts/list/ContactListItemView.java b/src/com/android/contacts/list/ContactListItemView.java
index 4b86295..7e0940f 100644
--- a/src/com/android/contacts/list/ContactListItemView.java
+++ b/src/com/android/contacts/list/ContactListItemView.java
@@ -121,7 +121,6 @@
     private TextView mCountView;
     private ImageView mPresenceIcon;
 
-    private ColorStateList mPrimaryTextColor;
     private ColorStateList mSecondaryTextColor;
 
     private char[] mHighlightedPrefix;
@@ -252,8 +251,9 @@
                         Color.GREEN));
         a.recycle();
 
-        mPrimaryTextColor = getResources().getColorStateList(R.color.list_primary_text_color);
-        mSecondaryTextColor = getResources().getColorStateList(R.color.list_secondary_text_color);
+        a = getContext().obtainStyledAttributes(android.R.styleable.Theme);
+        mSecondaryTextColor = a.getColorStateList(android.R.styleable.Theme_textColorSecondary);
+        a.recycle();
 
         mHorizontalDividerHeight = mHorizontalDividerDrawable.getIntrinsicHeight();
 
@@ -766,7 +766,6 @@
             mNameTextView.setSingleLine(true);
             mNameTextView.setEllipsize(getTextEllipsis());
             mNameTextView.setTextAppearance(mContext, android.R.style.TextAppearance_Medium);
-            mNameTextView.setTextColor(mPrimaryTextColor);
             // Manually call setActivated() since this view may be added after the first
             // setActivated() call toward this whole item view.
             mNameTextView.setActivated(isActivated());
@@ -826,7 +825,6 @@
             mPhoneticNameTextView.setEllipsize(getTextEllipsis());
             mPhoneticNameTextView.setTextAppearance(mContext, android.R.style.TextAppearance_Small);
             mPhoneticNameTextView.setTypeface(mPhoneticNameTextView.getTypeface(), Typeface.BOLD);
-            mPhoneticNameTextView.setTextColor(mPrimaryTextColor);
             mPhoneticNameTextView.setActivated(isActivated());
             addView(mPhoneticNameTextView);
         }
@@ -873,7 +871,6 @@
             mLabelView.setEllipsize(getTextEllipsis());
             mLabelView.setTextAppearance(mContext, android.R.style.TextAppearance_Small);
             mLabelView.setTypeface(mLabelView.getTypeface(), Typeface.BOLD);
-            mLabelView.setTextColor(mPrimaryTextColor);
             mLabelView.setActivated(isActivated());
             addView(mLabelView);
         }
@@ -905,7 +902,6 @@
             mDataView.setSingleLine(true);
             mDataView.setEllipsize(getTextEllipsis());
             mDataView.setTextAppearance(mContext, android.R.style.TextAppearance_Small);
-            mDataView.setTextColor(mPrimaryTextColor);
             mDataView.setActivated(isActivated());
             addView(mDataView);
         }
@@ -936,7 +932,6 @@
             mSnippetView.setEllipsize(getTextEllipsis());
             mSnippetView.setTextAppearance(mContext, android.R.style.TextAppearance_Small);
             mSnippetView.setTypeface(mSnippetView.getTypeface(), Typeface.BOLD);
-            mSnippetView.setTextColor(mPrimaryTextColor);
             mSnippetView.setActivated(isActivated());
             addView(mSnippetView);
         }
diff --git a/src/com/android/contacts/model/BaseAccountType.java b/src/com/android/contacts/model/BaseAccountType.java
index eee7241..dae09b2 100644
--- a/src/com/android/contacts/model/BaseAccountType.java
+++ b/src/com/android/contacts/model/BaseAccountType.java
@@ -65,7 +65,7 @@
     public BaseAccountType() {
         this.accountType = null;
         this.dataSet = null;
-        this.titleRes = R.string.local_profile_title;
+        this.titleRes = R.string.account_phone;
         this.iconRes = R.mipmap.ic_launcher_contacts;
     }
 
diff --git a/src/com/android/contacts/model/EntityDelta.java b/src/com/android/contacts/model/EntityDelta.java
index 97ab347..a045eb4 100644
--- a/src/com/android/contacts/model/EntityDelta.java
+++ b/src/com/android/contacts/model/EntityDelta.java
@@ -561,6 +561,11 @@
             return mAfter;
         }
 
+        public boolean containsKey(String key) {
+            return ((mAfter != null && mAfter.containsKey(key)) ||
+                    (mBefore != null && mBefore.containsKey(key)));
+        }
+
         public String getAsString(String key) {
             if (mAfter != null && mAfter.containsKey(key)) {
                 return mAfter.getAsString(key);
diff --git a/src/com/android/contacts/model/FallbackAccountType.java b/src/com/android/contacts/model/FallbackAccountType.java
index a40828e..8bb3992 100644
--- a/src/com/android/contacts/model/FallbackAccountType.java
+++ b/src/com/android/contacts/model/FallbackAccountType.java
@@ -25,7 +25,7 @@
     public FallbackAccountType(Context context) {
         this.accountType = null;
         this.dataSet = null;
-        this.titleRes = R.string.local_profile_title;
+        this.titleRes = R.string.account_phone;
         this.iconRes = R.mipmap.ic_launcher_contacts;
 
         this.resPackageName = null;
diff --git a/src/com/android/contacts/voicemail/VoicemailPlaybackFragment.java b/src/com/android/contacts/voicemail/VoicemailPlaybackFragment.java
index 80f7862..8d549a7 100644
--- a/src/com/android/contacts/voicemail/VoicemailPlaybackFragment.java
+++ b/src/com/android/contacts/voicemail/VoicemailPlaybackFragment.java
@@ -395,7 +395,6 @@
 
         @Override
         public void setSpeakerPhoneOn(boolean on) {
-            getAudioManager().setMode(AudioManager.MODE_IN_CALL);
             getAudioManager().setSpeakerphoneOn(on);
             if (on) {
                 mPlaybackSpeakerphone.setImageResource(R.drawable.ic_sound_holo_dark);
@@ -403,6 +402,14 @@
                 mPlaybackSpeakerphone.setImageResource(R.drawable.ic_sound_holo_dark);
             }
         }
+
+        @Override
+        public void setVolumeControlStream(int streamType) {
+            Activity activity = mActivityReference.get();
+            if (activity != null) {
+                activity.setVolumeControlStream(streamType);
+            }
+        }
     }
 
     /**
diff --git a/src/com/android/contacts/voicemail/VoicemailPlaybackPresenter.java b/src/com/android/contacts/voicemail/VoicemailPlaybackPresenter.java
index 6eb541d..f8e497d 100644
--- a/src/com/android/contacts/voicemail/VoicemailPlaybackPresenter.java
+++ b/src/com/android/contacts/voicemail/VoicemailPlaybackPresenter.java
@@ -27,6 +27,7 @@
 
 import android.content.Context;
 import android.database.ContentObserver;
+import android.media.AudioManager;
 import android.media.MediaPlayer;
 import android.net.Uri;
 import android.os.AsyncTask;
@@ -60,6 +61,9 @@
 @NotThreadSafe
 @VisibleForTesting
 public class VoicemailPlaybackPresenter {
+    /** The stream used to playback voicemail. */
+    private static final int PLAYBACK_STREAM = AudioManager.STREAM_VOICE_CALL;
+
     /** Contract describing the behaviour we need from the ui we are controlling. */
     public interface PlaybackView {
         Context getDataSourceContext();
@@ -89,6 +93,7 @@
         void unregisterContentObserver(ContentObserver observer);
         void enableProximitySensor();
         void disableProximitySensor();
+        void setVolumeControlStream(int streamType);
     }
 
     /** The enumeration of {@link AsyncTask} objects we use in this class. */
@@ -179,6 +184,7 @@
     }
 
     public void onCreate(Bundle bundle) {
+        mView.setVolumeControlStream(PLAYBACK_STREAM);
         checkThatWeHaveContent();
     }
 
@@ -304,6 +310,7 @@
                         try {
                             mPlayer.reset();
                             mPlayer.setDataSource(mView.getDataSourceContext(), mVoicemailUri);
+                            mPlayer.setAudioStreamType(PLAYBACK_STREAM);
                             mPlayer.prepare();
                             return null;
                         } catch (IOException e) {
@@ -428,6 +435,7 @@
         try {
             mPlayer.reset();
             mPlayer.setDataSource(mView.getDataSourceContext(), mVoicemailUri);
+            mPlayer.setAudioStreamType(PLAYBACK_STREAM);
             mPlayer.prepare();
             mDuration.set(mPlayer.getDuration());
             int startPosition = constrain(clipPositionInMillis, 0, mDuration.get());
diff --git a/src/com/android/contacts/voicemail/VoicemailStatusHelperImpl.java b/src/com/android/contacts/voicemail/VoicemailStatusHelperImpl.java
index 9e481f8..d88b5d3 100644
--- a/src/com/android/contacts/voicemail/VoicemailStatusHelperImpl.java
+++ b/src/com/android/contacts/voicemail/VoicemailStatusHelperImpl.java
@@ -221,8 +221,13 @@
         Uri actionUri = null;
         if (action == Action.CALL_VOICEMAIL) {
             actionUri = UriUtils.parseUriOrNull(cursor.getString(VOICEMAIL_ACCESS_URI_INDEX));
+            // Even if actionUri is null, it is still be useful to show the notification.
         } else if (action == Action.CONFIGURE_VOICEMAIL) {
             actionUri = UriUtils.parseUriOrNull(cursor.getString(SETTINGS_URI_INDEX));
+            // If there is no settings URI, there is no point in showing the notification.
+            if (actionUri == null) {
+                return null;
+            }
         }
         return new MessageStatusWithPriority(
                 new StatusMessage(sourcePackage, overallState.getCallLogMessageId(),