Merge "Replace the is_profile hack by a worse hack, which is at least way faster"
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index aeec2b2..e255fd2 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -117,7 +117,9 @@
             </intent-filter>
         </activity>
 
-        <!-- Tab container for all tabs -->
+        <!-- The entrance point for Phone UI.
+             stateAlwaysHidden is set to suppress keyboard show up on
+             dialpad screen. -->
         <activity android:name=".activities.DialtactsActivity"
             android:label="@string/launcherDialer"
             android:theme="@style/DialtactsTheme"
@@ -128,7 +130,7 @@
             android:screenOrientation="nosensor"
             android:enabled="@*android:bool/config_voice_capable"
             android:taskAffinity="android.task.contacts.phone"
-        >
+            android:windowSoftInputMode="stateAlwaysHidden">
             <intent-filter>
                 <action android:name="android.intent.action.DIAL" />
                 <category android:name="android.intent.category.DEFAULT" />
diff --git a/res/drawable-hdpi/list_pressed_holo_light.9.png b/res/drawable-hdpi/list_pressed_holo_light.9.png
new file mode 100644
index 0000000..cf5ff8e
--- /dev/null
+++ b/res/drawable-hdpi/list_pressed_holo_light.9.png
Binary files differ
diff --git a/res/drawable-mdpi/list_pressed_holo_light.9.png b/res/drawable-mdpi/list_pressed_holo_light.9.png
new file mode 100644
index 0000000..3a9686d
--- /dev/null
+++ b/res/drawable-mdpi/list_pressed_holo_light.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/list_pressed_holo_light.9.png b/res/drawable-xhdpi/list_pressed_holo_light.9.png
new file mode 100644
index 0000000..8ff9dca
--- /dev/null
+++ b/res/drawable-xhdpi/list_pressed_holo_light.9.png
Binary files differ
diff --git a/res/layout/contact_detail_container_without_updates.xml b/res/drawable/action_bar_item_background.xml
similarity index 62%
rename from res/layout/contact_detail_container_without_updates.xml
rename to res/drawable/action_bar_item_background.xml
index 884f280..1fd4614 100644
--- a/res/layout/contact_detail_container_without_updates.xml
+++ b/res/drawable/action_bar_item_background.xml
@@ -14,15 +14,8 @@
      limitations under the License.
 -->
 
-<FrameLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent">
-
-    <fragment
-        android:id="@+id/contact_detail_fragment"
-        class="com.android.contacts.detail.ContactDetailFragment"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"/>
-
-</FrameLayout>
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+          android:exitFadeDuration="@android:integer/config_mediumAnimTime">
+    <item android:state_pressed="true" android:drawable="@drawable/list_pressed_holo_light"/>
+    <item android:drawable="@android:color/transparent" />
+</selector>
\ No newline at end of file
diff --git a/res/layout/contact_detail_container_with_updates.xml b/res/layout-sw580dp/contact_detail_container.xml
similarity index 86%
rename from res/layout/contact_detail_container_with_updates.xml
rename to res/layout-sw580dp/contact_detail_container.xml
index 48f1800..62c4081 100644
--- a/res/layout/contact_detail_container_with_updates.xml
+++ b/res/layout-sw580dp/contact_detail_container.xml
@@ -17,7 +17,9 @@
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:orientation="vertical">
+    android:orientation="vertical"
+    android:background="@color/background_primary"
+    android:padding="16dip">
 
     <android.support.v4.view.ViewPager
         android:id="@+id/pager"
@@ -32,6 +34,7 @@
         android:layout_alignParentTop="true"
         android:layout_alignParentLeft="true"
         android:layout_width="match_parent"
-        android:layout_height="wrap_content"/>
+        android:layout_height="wrap_content"
+        android:visibility="gone"/>
 
-</RelativeLayout>
+</RelativeLayout>
\ No newline at end of file
diff --git a/res/layout-w470dp/contact_detail_container_with_updates.xml b/res/layout-w470dp/contact_detail_container.xml
similarity index 100%
rename from res/layout-w470dp/contact_detail_container_with_updates.xml
rename to res/layout-w470dp/contact_detail_container.xml
diff --git a/res/layout-w470dp/contact_detail_fragment.xml b/res/layout-w470dp/contact_detail_fragment.xml
index 982abbb..4f26cc5 100644
--- a/res/layout-w470dp/contact_detail_fragment.xml
+++ b/res/layout-w470dp/contact_detail_fragment.xml
@@ -75,8 +75,7 @@
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:layout_alignParentLeft="true"
-        android:layout_alignParentTop="true"
-        android:visibility="gone"/>
+        android:layout_alignParentTop="true"/>
 
     <View
         android:id="@+id/touch_intercept_overlay"
diff --git a/res/layout-w470dp/contact_detail_updates_fragment.xml b/res/layout-w470dp/contact_detail_updates_fragment.xml
index ccb7123..6081cfd 100644
--- a/res/layout-w470dp/contact_detail_updates_fragment.xml
+++ b/res/layout-w470dp/contact_detail_updates_fragment.xml
@@ -31,8 +31,7 @@
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:layout_alignParentLeft="true"
-        android:layout_alignParentTop="true"
-        android:visibility="gone"/>
+        android:layout_alignParentTop="true"/>
 
     <View
         android:id="@+id/touch_intercept_overlay"
diff --git a/res/layout/carousel_about_tab.xml b/res/layout/carousel_about_tab.xml
index c7c4394..c5d4114 100644
--- a/res/layout/carousel_about_tab.xml
+++ b/res/layout/carousel_about_tab.xml
@@ -43,8 +43,7 @@
         android:layout_height="match_parent"
         android:layout_alignParentLeft="true"
         android:layout_alignParentTop="true"
-        android:layout_marginBottom="@dimen/detail_tab_carousel_tab_label_height"
-        android:visibility="gone"/>
+        android:layout_marginBottom="@dimen/detail_tab_carousel_tab_label_height"/>
 
     <TextView
         android:id="@+id/label"
diff --git a/res/layout/carousel_updates_tab.xml b/res/layout/carousel_updates_tab.xml
index 9637023..3f633fc 100644
--- a/res/layout/carousel_updates_tab.xml
+++ b/res/layout/carousel_updates_tab.xml
@@ -63,8 +63,7 @@
         android:layout_height="match_parent"
         android:layout_alignParentLeft="true"
         android:layout_alignParentTop="true"
-        android:layout_marginBottom="@dimen/detail_tab_carousel_tab_label_height"
-        android:visibility="gone"/>
+        android:layout_marginBottom="@dimen/detail_tab_carousel_tab_label_height"/>
 
     <TextView
         android:id="@+id/label"
diff --git a/res/layout/contact_detail_activity.xml b/res/layout/contact_detail_activity.xml
index 3ab40c3..1e63aa7 100644
--- a/res/layout/contact_detail_activity.xml
+++ b/res/layout/contact_detail_activity.xml
@@ -27,4 +27,11 @@
         android:layout_width="0dip"
         android:visibility="gone"/>
 
+      <!-- This layout includes all possible views needed for a contact detail page -->
+      <include
+          android:id="@+id/contact_detail_container"
+          layout="@layout/contact_detail_container"
+          android:layout_width="match_parent"
+          android:layout_height="match_parent"/>
+
 </FrameLayout>
diff --git a/res/layout/contact_detail_container.xml b/res/layout/contact_detail_container.xml
index 9204b62..ff2eab1 100644
--- a/res/layout/contact_detail_container.xml
+++ b/res/layout/contact_detail_container.xml
@@ -26,9 +26,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:padding="16dip">
+    android:orientation="vertical">
 
     <android.support.v4.view.ViewPager
         android:id="@+id/pager"
diff --git a/res/layout/contact_detail_fragment_carousel.xml b/res/layout/contact_detail_fragment_carousel.xml
index 07c8d1c..4f65549 100644
--- a/res/layout/contact_detail_fragment_carousel.xml
+++ b/res/layout/contact_detail_fragment_carousel.xml
@@ -28,8 +28,9 @@
     -->
     <FrameLayout
         android:id="@+id/about_fragment_container"
-        android:layout_width="@dimen/detail_fragment_carousel_fragment_width"
-        android:layout_height="match_parent" />
+        android:layout_width="0dip"
+        android:layout_height="match_parent"
+        android:layout_weight="1" />
 
     <!--
       Container for the "Updates" page fragment on the contact card for a contact
@@ -38,7 +39,9 @@
     -->
     <FrameLayout
         android:id="@+id/updates_fragment_container"
-        android:layout_width="@dimen/detail_fragment_carousel_fragment_width"
-        android:layout_height="match_parent" />
+        android:layout_width="0dip"
+        android:layout_height="match_parent"
+        android:layout_weight="1"
+        android:visibility="gone" />
 
 </LinearLayout>
\ No newline at end of file
diff --git a/res/layout/dialpad_fragment.xml b/res/layout/dialpad_fragment.xml
index 90d2593..9c5099f 100644
--- a/res/layout/dialpad_fragment.xml
+++ b/res/layout/dialpad_fragment.xml
@@ -35,7 +35,8 @@
              in the java code.
 
              Background drawable can be controlled programatically. -->
-        <EditText android:id="@+id/digits"
+        <com.android.contacts.dialpad.DigitsEditText
+            android:id="@+id/digits"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             android:layout_alignParentLeft="true"
diff --git a/res/values-sw580dp-w720dp/styles.xml b/res/values-sw580dp-w720dp/styles.xml
index f3a3759..69548c5 100644
--- a/res/values-sw580dp-w720dp/styles.xml
+++ b/res/values-sw580dp-w720dp/styles.xml
@@ -16,6 +16,7 @@
 <resources>
     <style name="PeopleTheme" parent="@android:style/Theme.Holo.Light.DarkActionBar">
         <item name="android:actionBarStyle">@style/ContactsActionBarStyle</item>
+        <item name="android:actionBarItemBackground">@drawable/action_bar_item_background</item>
         <item name="android:actionBarTabStyle">@style/ContactsActionBarTabView</item>
         <item name="android:textColorPrimary">@color/primary_text_color</item>
         <item name="android:textColorSecondary">@color/secondary_text_color</item>
diff --git a/res/values-sw580dp/styles.xml b/res/values-sw580dp/styles.xml
index 5a28bf6..0a62db2 100644
--- a/res/values-sw580dp/styles.xml
+++ b/res/values-sw580dp/styles.xml
@@ -16,6 +16,7 @@
 <resources>
     <style name="PeopleTheme" parent="@android:style/Theme.Holo.Light.DarkActionBar">
         <item name="android:actionBarStyle">@style/ContactsActionBarStyle</item>
+        <item name="android:actionBarItemBackground">@drawable/action_bar_item_background</item>
         <item name="android:actionBarTabStyle">@style/ContactsActionBarTabView</item>
         <item name="android:textColorPrimary">@color/primary_text_color</item>
         <item name="android:textColorSecondary">@color/secondary_text_color</item>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index dc675b3..418d632 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -79,12 +79,14 @@
 
     <style name="ContactDetailActivityTheme" parent="@android:style/Theme.Holo.Light.DarkActionBar">
         <item name="android:actionBarStyle">@style/ContactsActionBarStyle</item>
+        <item name="android:actionBarItemBackground">@drawable/action_bar_item_background</item>
         <item name="android:textColorPrimary">@color/primary_text_color</item>
         <item name="android:textColorSecondary">@color/secondary_text_color</item>
     </style>
 
     <style name="EditorActivityTheme" parent="@android:style/Theme.Holo.Light.DarkActionBar">
         <item name="android:actionBarStyle">@style/ContactsActionBarStyle</item>
+        <item name="android:actionBarItemBackground">@drawable/action_bar_item_background</item>
         <item name="android:windowContentOverlay">@null</item>
         <item name="android:textColorPrimary">@color/primary_text_color</item>
         <item name="android:textColorSecondary">@color/secondary_text_color</item>
@@ -125,6 +127,7 @@
 
     <style name="PeopleTheme" parent="@android:style/Theme.Holo.Light.DarkActionBar">
         <item name="android:actionBarStyle">@style/ContactsActionBarStyle</item>
+        <item name="android:actionBarItemBackground">@drawable/action_bar_item_background</item>
         <item name="android:actionBarTabStyle">@style/ContactsActionBarTabView</item>
         <item name="android:textColorPrimary">@color/primary_text_color</item>
         <item name="android:textColorSecondary">@color/secondary_text_color</item>
@@ -174,6 +177,7 @@
     <!-- TODO: Clean up this file so themes aren't copied. -->
     <style name="GroupDetailTheme" parent="@android:style/Theme.Holo.Light.DarkActionBar">
         <item name="android:actionBarStyle">@style/ContactsActionBarStyle</item>
+        <item name="android:actionBarItemBackground">@drawable/action_bar_item_background</item>
         <item name="android:textColorPrimary">@color/primary_text_color</item>
         <item name="android:textColorSecondary">@color/secondary_text_color</item>
         <item name="list_item_height">?android:attr/listPreferredItemHeight</item>
diff --git a/src/com/android/contacts/ContactTileLoaderFactory.java b/src/com/android/contacts/ContactTileLoaderFactory.java
index 30bd7e4..28f2164 100644
--- a/src/com/android/contacts/ContactTileLoaderFactory.java
+++ b/src/com/android/contacts/ContactTileLoaderFactory.java
@@ -23,7 +23,6 @@
 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
diff --git a/src/com/android/contacts/activities/ContactDetailActivity.java b/src/com/android/contacts/activities/ContactDetailActivity.java
index c863b23..c3dc593 100644
--- a/src/com/android/contacts/activities/ContactDetailActivity.java
+++ b/src/com/android/contacts/activities/ContactDetailActivity.java
@@ -22,34 +22,23 @@
 import com.android.contacts.R;
 import com.android.contacts.detail.ContactDetailDisplayUtils;
 import com.android.contacts.detail.ContactDetailFragment;
-import com.android.contacts.detail.ContactDetailFragmentCarousel;
-import com.android.contacts.detail.ContactDetailTabCarousel;
-import com.android.contacts.detail.ContactDetailUpdatesFragment;
-import com.android.contacts.detail.ContactDetailViewPagerAdapter;
+import com.android.contacts.detail.ContactDetailLayoutController;
 import com.android.contacts.detail.ContactLoaderFragment;
 import com.android.contacts.detail.ContactLoaderFragment.ContactLoaderFragmentListener;
-import com.android.contacts.detail.TabCarouselScrollManager;
 import com.android.contacts.interactions.ContactDeletionInteraction;
 import com.android.contacts.model.AccountWithDataSet;
 import com.android.contacts.util.PhoneCapabilityTester;
 
 import android.app.ActionBar;
 import android.app.Fragment;
-import android.app.FragmentManager;
-import android.app.FragmentTransaction;
 import android.content.ActivityNotFoundException;
 import android.content.ContentValues;
-import android.content.Context;
 import android.content.Intent;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
-import android.support.v13.app.FragmentPagerAdapter;
-import android.support.v4.view.ViewPager;
-import android.support.v4.view.ViewPager.OnPageChangeListener;
 import android.util.Log;
 import android.view.KeyEvent;
-import android.view.LayoutInflater;
 import android.view.Menu;
 import android.view.MenuInflater;
 import android.view.MenuItem;
@@ -61,7 +50,6 @@
 
 import java.util.ArrayList;
 
-// TODO: Use {@link ContactDetailLayoutController} so there isn't duplicated code
 public class ContactDetailActivity extends ContactsActivity {
     private static final String TAG = "ContactDetailActivity";
 
@@ -72,38 +60,15 @@
      */
     public static final String INTENT_KEY_IGNORE_DEFAULT_UP_BEHAVIOR = "ignoreDefaultUpBehavior";
 
-    private static final String KEY_CONTACT_HAS_UPDATES = "contactHasUpdates";
-    private static final String KEY_CURRENT_PAGE_INDEX = "currentPageIndex";
-
-    public static final int FRAGMENT_COUNT = 2;
-
     private ContactLoader.Result mContactData;
     private Uri mLookupUri;
     private boolean mIgnoreDefaultUpBehavior;
 
+    private ContactDetailLayoutController mContactDetailLayoutController;
     private ContactLoaderFragment mLoaderFragment;
-    private ContactDetailFragment mDetailFragment;
-    private ContactDetailUpdatesFragment mUpdatesFragment;
-
-    private ContactDetailTabCarousel mTabCarousel;
-    private ViewPager mViewPager;
-
-    private ContactDetailFragmentCarousel mFragmentCarousel;
-
-    private boolean mFragmentsAddedToFragmentManager;
-
-    private ViewGroup mRootView;
-    private ViewGroup mContentView;
-    private LayoutInflater mInflater;
 
     private Handler mHandler = new Handler();
 
-    /**
-     * Whether or not the contact has updates, which dictates whether the
-     * {@link ContactDetailUpdatesFragment} will be shown.
-     */
-    private boolean mContactHasUpdates;
-
     @Override
     public void onCreate(Bundle savedState) {
         super.onCreate(savedState);
@@ -128,41 +93,10 @@
                 INTENT_KEY_IGNORE_DEFAULT_UP_BEHAVIOR, false);
 
         setContentView(R.layout.contact_detail_activity);
-        mRootView = (ViewGroup) findViewById(R.id.contact_detail_view);
-        mInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
 
-        FragmentManager fragmentManager = getFragmentManager();
-        mDetailFragment = (ContactDetailFragment)
-                fragmentManager.findFragmentByTag(
-                ContactDetailViewPagerAdapter.ABOUT_FRAGMENT_TAG);
-        mUpdatesFragment = (ContactDetailUpdatesFragment)
-                fragmentManager.findFragmentByTag(
-                ContactDetailViewPagerAdapter.UPDTES_FRAGMENT_TAG);
-
-        // If the fragment were found in the {@link FragmentManager} then we don't need to add
-        // it again.
-        if (mDetailFragment != null) {
-            mFragmentsAddedToFragmentManager = true;
-        } else {
-            // Otherwise, create the fragments dynamically and remember to add them to the
-            // {@link FragmentManager}.
-            mDetailFragment = new ContactDetailFragment();
-            mUpdatesFragment = new ContactDetailUpdatesFragment();
-            mFragmentsAddedToFragmentManager = false;
-        }
-
-        mDetailFragment.setListener(mFragmentListener);
-        mDetailFragment.setData(mLookupUri, mContactData);
-        mUpdatesFragment.setData(mLookupUri, mContactData);
-
-        if (savedState != null) {
-            mContactHasUpdates = savedState.getBoolean(KEY_CONTACT_HAS_UPDATES);
-            if (mContactHasUpdates) {
-                setupContactWithUpdates(savedState.getInt(KEY_CURRENT_PAGE_INDEX, 0));
-            } else {
-                setupContactWithoutUpdates();
-            }
-        }
+        mContactDetailLayoutController = new ContactDetailLayoutController(this, savedState,
+                getFragmentManager(), findViewById(R.id.contact_detail_container),
+                mContactDetailFragmentListener);
 
         // We want the UP affordance but no app icon.
         // Setting HOME_AS_UP, SHOW_TITLE and clearing SHOW_HOME does the trick.
@@ -232,43 +166,19 @@
         if (mLoaderFragment != null && mLoaderFragment.handleKeyDown(keyCode)) return true;
 
         // Otherwise find the correct fragment to handle the event
-        FragmentKeyListener mCurrentFragment;
-        switch (getCurrentPage()) {
-            case 0:
-                mCurrentFragment = mDetailFragment;
-                break;
-            case 1:
-                mCurrentFragment = mUpdatesFragment;
-                break;
-            default:
-                throw new IllegalStateException("Invalid current item for ViewPager");
-        }
+        FragmentKeyListener mCurrentFragment = mContactDetailLayoutController.getCurrentPage();
         if (mCurrentFragment != null && mCurrentFragment.handleKeyDown(keyCode)) return true;
 
         // In the last case, give the key event to the superclass.
         return super.onKeyDown(keyCode, event);
     }
 
-    private int getCurrentPage() {
-        // If the contact doesn't have any social updates, there is only 1 page (detail fragment).
-        if (!mContactHasUpdates) {
-            return 0;
-        }
-        // Otherwise find the current page based on the {@link ViewPager} or fragment carousel.
-        if (mViewPager != null) {
-            return mViewPager.getCurrentItem();
-        } else if (mFragmentCarousel != null) {
-            return mFragmentCarousel.getCurrentPage();
-        }
-        throw new IllegalStateException("Can't figure out the currently selected page. If the " +
-                "contact has social updates, there must be a ViewPager or fragment carousel");
-    }
-
     @Override
     protected void onSaveInstanceState(Bundle outState) {
         super.onSaveInstanceState(outState);
-        outState.putBoolean(KEY_CONTACT_HAS_UPDATES, mContactHasUpdates);
-        outState.putInt(KEY_CURRENT_PAGE_INDEX, getCurrentPage());
+        if (mContactDetailLayoutController != null) {
+            mContactDetailLayoutController.onSaveInstanceState(outState);
+        }
     }
 
     private final ContactLoaderFragmentListener mLoaderFragmentListener =
@@ -295,14 +205,9 @@
                     }
                     mContactData = result;
                     mLookupUri = result.getLookupUri();
-                    mContactHasUpdates = !result.getStreamItems().isEmpty();
                     invalidateOptionsMenu();
                     setupTitle();
-                    if (mContactHasUpdates) {
-                        setupContactWithUpdates(null /* Don't change the current page */);
-                    } else {
-                        setupContactWithoutUpdates();
-                    }
+                    mContactDetailLayoutController.setContactData(mContactData);
                 }
             });
         }
@@ -331,117 +236,7 @@
         actionBar.setSubtitle(company);
     }
 
-    /**
-     * Setup the layout for the contact with updates. Pass in the index of the current page to
-     * select or null if the current selection should be left as is.
-     */
-    private void setupContactWithUpdates(Integer currentPageIndex) {
-        if (mContentView == null) {
-            mContentView = (ViewGroup) mInflater.inflate(
-                    R.layout.contact_detail_container_with_updates, mRootView, false);
-            mRootView.addView(mContentView);
-
-            // Make sure all needed views are retrieved. Note that narrow width screens have a
-            // {@link ViewPager} and {@link ContactDetailTabCarousel}, while wide width screens have
-            // a {@link ContactDetailFragmentCarousel}.
-            mTabCarousel = (ContactDetailTabCarousel) findViewById(R.id.tab_carousel);
-            if (mTabCarousel != null) {
-                mTabCarousel.setListener(mTabCarouselListener);
-                TabCarouselScrollManager.bind(mTabCarousel, mDetailFragment, mUpdatesFragment);
-            }
-
-            mViewPager = (ViewPager) findViewById(R.id.pager);
-            if (mViewPager != null) {
-                // Inflate 2 view containers to pass in as children to the {@link ViewPager},
-                // which will in turn be the parents to the mDetailFragment and mUpdatesFragment
-                // since the fragments must have the same parent view IDs in both landscape and
-                // portrait layouts.
-                ViewGroup detailContainer = (ViewGroup) mInflater.inflate(
-                        R.layout.contact_detail_about_fragment_container, mViewPager, false);
-                ViewGroup updatesContainer = (ViewGroup) mInflater.inflate(
-                        R.layout.contact_detail_updates_fragment_container, mViewPager, false);
-
-                ContactDetailViewPagerAdapter adapter = new ContactDetailViewPagerAdapter();
-                adapter.setAboutFragmentView(detailContainer);
-                adapter.setUpdatesFragmentView(updatesContainer);
-
-                mViewPager.addView(detailContainer);
-                mViewPager.addView(updatesContainer);
-                mViewPager.setAdapter(adapter);
-                mViewPager.setOnPageChangeListener(mOnPageChangeListener);
-
-                if (!mFragmentsAddedToFragmentManager) {
-                    FragmentManager fragmentManager = getFragmentManager();
-                    FragmentTransaction transaction = fragmentManager.beginTransaction();
-                    transaction.add(R.id.about_fragment_container, mDetailFragment,
-                            ContactDetailViewPagerAdapter.ABOUT_FRAGMENT_TAG);
-                    transaction.add(R.id.updates_fragment_container, mUpdatesFragment,
-                            ContactDetailViewPagerAdapter.UPDTES_FRAGMENT_TAG);
-                    transaction.commit();
-                    fragmentManager.executePendingTransactions();
-                }
-
-                // Select page if applicable
-                if (currentPageIndex != null) {
-                    mViewPager.setCurrentItem(currentPageIndex);
-                }
-            }
-
-            mFragmentCarousel = (ContactDetailFragmentCarousel)
-                    findViewById(R.id.fragment_carousel);
-            // Add the fragments to the fragment containers in the carousel using a
-            // {@link FragmentTransaction} if they haven't already been added to the
-            // {@link FragmentManager}.
-            if (mFragmentCarousel != null) {
-                if (!mFragmentsAddedToFragmentManager) {
-                    FragmentManager fragmentManager = getFragmentManager();
-                    FragmentTransaction transaction = fragmentManager.beginTransaction();
-                    transaction.add(R.id.about_fragment_container, mDetailFragment,
-                            ContactDetailViewPagerAdapter.ABOUT_FRAGMENT_TAG);
-                    transaction.add(R.id.updates_fragment_container, mUpdatesFragment,
-                            ContactDetailViewPagerAdapter.UPDTES_FRAGMENT_TAG);
-                    transaction.commit();
-                    fragmentManager.executePendingTransactions();
-                }
-
-                // Select page if applicable
-                if (currentPageIndex != null) {
-                    mFragmentCarousel.setCurrentPage(currentPageIndex);
-                }
-            }
-        }
-
-        // Then reset the contact data to the appropriate views
-        if (mTabCarousel != null) {
-            mTabCarousel.loadData(mContactData);
-        }
-        if (mFragmentCarousel != null && mDetailFragment != null && mUpdatesFragment != null) {
-            mFragmentCarousel.setFragments(mDetailFragment, mUpdatesFragment);
-        }
-        if (mDetailFragment != null) {
-            mDetailFragment.setData(mLookupUri, mContactData);
-        }
-        if (mUpdatesFragment != null) {
-            mUpdatesFragment.setData(mLookupUri, mContactData);
-        }
-    }
-
-    private void setupContactWithoutUpdates() {
-        if (mContentView == null) {
-            mContentView = (ViewGroup) mInflater.inflate(
-                    R.layout.contact_detail_container_without_updates, mRootView, false);
-            mRootView.addView(mContentView);
-            mDetailFragment = (ContactDetailFragment) getFragmentManager().findFragmentById(
-                    R.id.contact_detail_fragment);
-            mDetailFragment.setListener(mFragmentListener);
-        }
-        // Reset contact data
-        if (mDetailFragment != null) {
-            mDetailFragment.setData(mLookupUri, mContactData);
-        }
-    }
-
-    private final ContactDetailFragment.Listener mFragmentListener =
+    private final ContactDetailFragment.Listener mContactDetailFragmentListener =
             new ContactDetailFragment.Listener() {
         @Override
         public void onItemClicked(Intent intent) {
@@ -465,95 +260,6 @@
         }
     };
 
-    public class ViewPagerAdapter extends FragmentPagerAdapter{
-
-        public ViewPagerAdapter(FragmentManager fm) {
-            super(fm);
-        }
-
-        @Override
-        public Fragment getItem(int position) {
-            switch (position) {
-                case 0:
-                    return new ContactDetailFragment();
-                case 1:
-                    return new ContactDetailUpdatesFragment();
-            }
-            throw new IllegalStateException("No fragment at position " + position);
-        }
-
-        @Override
-        public int getCount() {
-            return FRAGMENT_COUNT;
-        }
-    }
-
-    private OnPageChangeListener mOnPageChangeListener = new OnPageChangeListener() {
-
-        @Override
-        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
-            // The user is horizontally dragging the {@link ViewPager}, so send
-            // these scroll changes to the tab carousel. Ignore these events though if the carousel
-            // is actually controlling the {@link ViewPager} scrolls because it will already be
-            // in the correct position.
-            if (mViewPager.isFakeDragging()) {
-                return;
-            }
-            int x = (int) ((position + positionOffset) *
-                    mTabCarousel.getAllowedHorizontalScrollLength());
-            mTabCarousel.scrollTo(x, 0);
-        }
-
-        @Override
-        public void onPageSelected(int position) {
-            // Since a new page has been selected by the {@link ViewPager},
-            // update the tab selection in the carousel.
-            mTabCarousel.setCurrentTab(position);
-        }
-
-        @Override
-        public void onPageScrollStateChanged(int state) {}
-
-    };
-
-    private ContactDetailTabCarousel.Listener mTabCarouselListener =
-            new ContactDetailTabCarousel.Listener() {
-
-        @Override
-        public void onTouchDown() {
-            // The user just started scrolling the carousel, so begin "fake dragging" the
-            // {@link ViewPager} if it's not already doing so.
-            if (mViewPager.isFakeDragging()) {
-                return;
-            }
-            mViewPager.beginFakeDrag();
-        }
-
-        @Override
-        public void onTouchUp() {
-            // The user just stopped scrolling the carousel, so stop "fake dragging" the
-            // {@link ViewPager} if was doing so before.
-            if (mViewPager.isFakeDragging()) {
-                mViewPager.endFakeDrag();
-            }
-        }
-
-        @Override
-        public void onScrollChanged(int l, int t, int oldl, int oldt) {
-            // The user is scrolling the carousel, so send the scroll deltas to the
-            // {@link ViewPager} so it can move in sync.
-            if (mViewPager.isFakeDragging()) {
-                mViewPager.fakeDragBy(oldl-l);
-            }
-        }
-
-        @Override
-        public void onTabSelected(int position) {
-            // The user selected a tab, so update the {@link ViewPager}
-            mViewPager.setCurrentItem(position);
-        }
-    };
-
     /**
      * This interface should be implemented by {@link Fragment}s within this
      * activity so that the activity can determine whether the currently
diff --git a/src/com/android/contacts/activities/DialtactsActivity.java b/src/com/android/contacts/activities/DialtactsActivity.java
index b6dfbfa..12709c8 100644
--- a/src/com/android/contacts/activities/DialtactsActivity.java
+++ b/src/com/android/contacts/activities/DialtactsActivity.java
@@ -568,13 +568,14 @@
         } else {
             tabIndex = mLastManuallySelectedFragment;
         }
+
+        final int previousItemIndex = mViewPager.getCurrentItem();
         mViewPager.setCurrentItem(tabIndex, false /* smoothScroll */);
-        if (mViewPager.getCurrentItem() == tabIndex) {
-            mPageChangeListener.setCurrentPosition(tabIndex);
-            sendFragmentVisibilityChange(tabIndex, true);
-        } else {
-            getActionBar().selectTab(getActionBar().getTabAt(tabIndex));
+        if (previousItemIndex != tabIndex) {
+            sendFragmentVisibilityChange(previousItemIndex, false);
         }
+        mPageChangeListener.setCurrentPosition(tabIndex);
+        sendFragmentVisibilityChange(tabIndex, true);
 
         // Restore to the previous manual selection
         mLastManuallySelectedFragment = savedTabIndex;
diff --git a/src/com/android/contacts/activities/GroupEditorActivity.java b/src/com/android/contacts/activities/GroupEditorActivity.java
index b397c19..544cd16 100644
--- a/src/com/android/contacts/activities/GroupEditorActivity.java
+++ b/src/com/android/contacts/activities/GroupEditorActivity.java
@@ -147,6 +147,11 @@
         }
 
         @Override
+        public void onAccountsNotFound() {
+            finish();
+        }
+
+        @Override
         public void onSaveFinished(int resultCode, Intent resultIntent) {
             // TODO: Collapse these 2 cases into 1 that will just launch an intent with the VIEW
             // action to see the group URI (when group URIs are supported)
diff --git a/src/com/android/contacts/detail/CarouselTab.java b/src/com/android/contacts/detail/CarouselTab.java
index 26397ff..677f0ad 100644
--- a/src/com/android/contacts/detail/CarouselTab.java
+++ b/src/com/android/contacts/detail/CarouselTab.java
@@ -78,13 +78,6 @@
     }
 
     @Override
-    public void enableAlphaLayer() {
-        if (mAlphaLayer != null) {
-            mAlphaLayer.setVisibility(View.VISIBLE);
-        }
-    }
-
-    @Override
     public void enableTouchInterceptor(OnClickListener clickListener) {
         if (mTouchInterceptLayer != null) {
             mTouchInterceptLayer.setVisibility(View.VISIBLE);
diff --git a/src/com/android/contacts/detail/ContactDetailFragment.java b/src/com/android/contacts/detail/ContactDetailFragment.java
index bbf9d5b..ca99c79 100644
--- a/src/com/android/contacts/detail/ContactDetailFragment.java
+++ b/src/com/android/contacts/detail/ContactDetailFragment.java
@@ -183,6 +183,11 @@
     private View mEmptyView;
 
     /**
+     * Initial alpha value to set on the alpha layer.
+     */
+    private float mInitialAlphaValue;
+
+    /**
      * This optional view adds an alpha layer over the entire fragment.
      */
     private View mAlphaLayer;
@@ -285,8 +290,9 @@
         // Don't set it to mListView yet.  We do so later when we bind the adapter.
         mEmptyView = mView.findViewById(android.R.id.empty);
 
-        mAlphaLayer = mView.findViewById(R.id.alpha_overlay);
         mTouchInterceptLayer = mView.findViewById(R.id.touch_intercept_overlay);
+        mAlphaLayer = mView.findViewById(R.id.alpha_overlay);
+        ContactDetailDisplayUtils.setAlphaOnViewBackground(mAlphaLayer, mInitialAlphaValue);
 
         mQuickFixButton = (Button) mView.findViewById(R.id.contact_quick_fix);
         mQuickFixButton.setOnClickListener(new OnClickListener() {
@@ -315,13 +321,12 @@
 
     @Override
     public void setAlphaLayerValue(float alpha) {
-        ContactDetailDisplayUtils.setAlphaOnViewBackground(mAlphaLayer, alpha);
-    }
-
-    @Override
-    public void enableAlphaLayer() {
-        if (mAlphaLayer != null) {
-            mAlphaLayer.setVisibility(View.VISIBLE);
+        // If the alpha layer is not ready yet, store it for later when the view is initialized
+        if (mAlphaLayer == null) {
+            mInitialAlphaValue = alpha;
+        } else {
+            // Otherwise set the value immediately
+            ContactDetailDisplayUtils.setAlphaOnViewBackground(mAlphaLayer, alpha);
         }
     }
 
diff --git a/src/com/android/contacts/detail/ContactDetailFragmentCarousel.java b/src/com/android/contacts/detail/ContactDetailFragmentCarousel.java
index 7efcc51..106ff0e 100644
--- a/src/com/android/contacts/detail/ContactDetailFragmentCarousel.java
+++ b/src/com/android/contacts/detail/ContactDetailFragmentCarousel.java
@@ -54,16 +54,39 @@
      */
     private int mUpperThreshold = Integer.MIN_VALUE;
 
+    /**
+     * Minimum width of a fragment (if there is more than 1 fragment in the carousel, then this is
+     * the width of one of the fragments).
+     */
+    private int mMinFragmentWidth = Integer.MIN_VALUE;
+
+    /**
+     * Maximum alpha value of the overlay on the fragment that is not currently selected
+     * (if there are 1+ fragments in the carousel).
+     */
+    private static final float MAX_ALPHA = 0.5f;
+
+    /**
+     * Fragment width (if there are 1+ fragments in the carousel) as defined as a fraction of the
+     * screen width.
+     */
+    private static final float FRAGMENT_WIDTH_SCREEN_WIDTH_FRACTION = 0.85f;
+
     private static final int ABOUT_PAGE = 0;
     private static final int UPDATES_PAGE = 1;
 
+    private static final int MAX_FRAGMENT_VIEW_COUNT = 2;
+
+    private boolean mEnableSwipe;
+
     private int mCurrentPage = ABOUT_PAGE;
     private int mLastScrollPosition;
 
     private ViewOverlay mAboutFragment;
     private ViewOverlay mUpdatesFragment;
 
-    private static final float MAX_ALPHA = 0.5f;
+    private View mDetailFragmentView;
+    private View mUpdatesFragmentView;
 
     private final Handler mHandler = new Handler();
 
@@ -87,42 +110,86 @@
 
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        int screenWidth = MeasureSpec.getSize(widthMeasureSpec);
+        int screenHeight = MeasureSpec.getSize(heightMeasureSpec);
 
         // Take the width of this view as the width of the screen and compute necessary thresholds.
         // Only do this computation 1x.
         if (mAllowedHorizontalScrollLength == Integer.MIN_VALUE) {
-            int screenWidth = MeasureSpec.getSize(widthMeasureSpec);
-            int fragmentWidth = mContext.getResources().getDimensionPixelSize(
-                    R.dimen.detail_fragment_carousel_fragment_width);
-            mAllowedHorizontalScrollLength = (2 * fragmentWidth) - screenWidth;
-            mLowerThreshold = (screenWidth - fragmentWidth) / 2;
+            mMinFragmentWidth = (int) (FRAGMENT_WIDTH_SCREEN_WIDTH_FRACTION * screenWidth);
+            mAllowedHorizontalScrollLength = (MAX_FRAGMENT_VIEW_COUNT * mMinFragmentWidth) -
+                    screenWidth;
+            mLowerThreshold = (screenWidth - mMinFragmentWidth) / MAX_FRAGMENT_VIEW_COUNT;
             mUpperThreshold = mAllowedHorizontalScrollLength - mLowerThreshold;
         }
+
+        if (getChildCount() > 0) {
+            View child = getChildAt(0);
+            // If we enable swipe, then the {@link LinearLayout} child width must be the sum of the
+            // width of all its children fragments.
+            if (mEnableSwipe) {
+                child.measure(MeasureSpec.makeMeasureSpec(
+                        mMinFragmentWidth * MAX_FRAGMENT_VIEW_COUNT, MeasureSpec.EXACTLY),
+                        MeasureSpec.makeMeasureSpec(screenHeight, MeasureSpec.EXACTLY));
+            } else {
+                // Otherwise, the {@link LinearLayout} child width will just be the screen width
+                // because it will only have 1 child fragment.
+                child.measure(MeasureSpec.makeMeasureSpec(screenWidth, MeasureSpec.EXACTLY),
+                        MeasureSpec.makeMeasureSpec(screenHeight, MeasureSpec.EXACTLY));
+            }
+        }
+
+        setMeasuredDimension(
+                resolveSize(screenWidth, widthMeasureSpec),
+                resolveSize(screenHeight, heightMeasureSpec));
     }
 
+    /**
+     * Set the current page. This auto-scrolls the carousel to the current page and dims out
+     * the non-selected page.
+     */
     public void setCurrentPage(int pageIndex) {
-        if (mCurrentPage != pageIndex) {
-            mCurrentPage = pageIndex;
+        mCurrentPage = pageIndex;
 
-            // This method could have been called before the view has been measured, so snap to edge
-            // only after the view is ready.
-            postRunnableToSnapToEdge();
+        if (mAboutFragment != null && mUpdatesFragment != null) {
+            mAboutFragment.setAlphaLayerValue(mCurrentPage == ABOUT_PAGE ? 0 : MAX_ALPHA);
+            mUpdatesFragment.setAlphaLayerValue(mCurrentPage == UPDATES_PAGE ? 0 : MAX_ALPHA);
+            snapToEdge();
         }
     }
 
+    /**
+     * Set the view containers for the detail and updates fragment.
+     */
+    public void setFragmentViews(View detailFragmentView, View updatesFragmentView) {
+        mDetailFragmentView = detailFragmentView;
+        mUpdatesFragmentView = updatesFragmentView;
+    }
+
+    /**
+     * Set the detail and updates fragment.
+     */
     public void setFragments(ViewOverlay aboutFragment, ViewOverlay updatesFragment) {
         mAboutFragment = aboutFragment;
-        mAboutFragment.enableAlphaLayer();
-        mAboutFragment.setAlphaLayerValue(mCurrentPage == ABOUT_PAGE ? 0 : MAX_ALPHA);
-
         mUpdatesFragment = updatesFragment;
-        mUpdatesFragment.enableAlphaLayer();
-        mUpdatesFragment.setAlphaLayerValue(mCurrentPage == UPDATES_PAGE ? 0 : MAX_ALPHA);
+    }
 
-        // This method could have been called before the view has been measured, so snap to edge
-        // only after the view is ready.
-        postRunnableToSnapToEdge();
+    /**
+     * Enable swiping if the detail and update fragments should be showing. Otherwise disable
+     * swiping if only the detail fragment should be showing.
+     */
+    public void enableSwipe(boolean enable) {
+        if (mEnableSwipe != enable) {
+            mEnableSwipe = enable;
+            if (mUpdatesFragmentView != null) {
+                mUpdatesFragmentView.setVisibility(enable ? View.VISIBLE : View.GONE);
+                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();
+        }
     }
 
     /**
@@ -134,8 +201,7 @@
         mHandler.post(new Runnable() {
             @Override
             public void run() {
-                if (isAttachedToWindow() && mAboutFragment != null &&
-                        mUpdatesFragment != null) {
+                if (isAttachedToWindow() && mAboutFragment != null && mUpdatesFragment != null) {
                     snapToEdge();
                 }
             }
@@ -187,6 +253,9 @@
     @Override
     protected void onScrollChanged(int l, int t, int oldl, int oldt) {
         super.onScrollChanged(l, t, oldl, oldt);
+        if (!mEnableSwipe) {
+            return;
+        }
         mLastScrollPosition= l;
         updateAlphaLayers();
     }
@@ -223,6 +292,9 @@
 
     @Override
     public boolean onTouch(View v, MotionEvent event) {
+        if (!mEnableSwipe) {
+            return false;
+        }
         if (event.getAction() == MotionEvent.ACTION_UP) {
             mCurrentPage = getDesiredPage();
             snapToEdge();
diff --git a/src/com/android/contacts/detail/ContactDetailLayoutController.java b/src/com/android/contacts/detail/ContactDetailLayoutController.java
index f3cc016..a10431b 100644
--- a/src/com/android/contacts/detail/ContactDetailLayoutController.java
+++ b/src/com/android/contacts/detail/ContactDetailLayoutController.java
@@ -18,7 +18,7 @@
 
 import com.android.contacts.ContactLoader;
 import com.android.contacts.R;
-import com.android.contacts.activities.PeopleActivity.ContactDetailFragmentListener;
+import com.android.contacts.activities.ContactDetailActivity.FragmentKeyListener;
 
 import android.app.FragmentManager;
 import android.app.FragmentTransaction;
@@ -35,12 +35,17 @@
  */
 public class ContactDetailLayoutController {
 
-    public static final int FRAGMENT_COUNT = 2;
-
     private static final String KEY_CONTACT_HAS_UPDATES = "contactHasUpdates";
+    private static final String KEY_CURRENT_PAGE_INDEX = "currentPageIndex";
 
+    /**
+     * There are 3 possible layouts for the contact detail screen:
+     * 1. TWO_COLUMN - Tall and wide screen so the 2 pages can be shown side-by-side
+     * 2. VIEW_PAGER_AND_TAB_CAROUSEL - Tall and narrow screen to allow swipe between the 2 pages
+     * 3. FRAGMENT_CAROUSEL- Short and wide screen to allow half of the other page to show at a time
+     */
     private enum LayoutMode {
-        TWO_COLUMN, VIEW_PAGER_AND_CAROUSEL,
+        TWO_COLUMN, VIEW_PAGER_AND_TAB_CAROUSEL, FRAGMENT_CAROUSEL,
     }
 
     private final LayoutInflater mLayoutInflater;
@@ -56,7 +61,9 @@
     private final ContactDetailTabCarousel mTabCarousel;
     private ContactDetailViewPagerAdapter mViewPagerAdapter;
 
-    private ContactDetailFragmentListener mContactDetailFragmentListener;
+    private ContactDetailFragmentCarousel mFragmentCarousel;
+
+    private ContactDetailFragment.Listener mContactDetailFragmentListener;
 
     private ContactLoader.Result mContactData;
 
@@ -65,7 +72,7 @@
     private LayoutMode mLayoutMode;
 
     public ContactDetailLayoutController(Context context, Bundle savedState,
-            FragmentManager fragmentManager, View viewContainer, ContactDetailFragmentListener
+            FragmentManager fragmentManager, View viewContainer, ContactDetailFragment.Listener
             contactDetailFragmentListener) {
 
         if (fragmentManager == null) {
@@ -82,16 +89,21 @@
         mViewPager = (ViewPager) viewContainer.findViewById(R.id.pager);
         mTabCarousel = (ContactDetailTabCarousel) viewContainer.findViewById(R.id.tab_carousel);
 
-        // Retrieve views in case this is 2-column layout mode
+        // Retrieve view in case this is in fragment carousel mode
+        mFragmentCarousel = (ContactDetailFragmentCarousel) viewContainer.findViewById(
+                R.id.fragment_carousel);
+
+        // Retrieve container views in case they are already in the XML layout
         mDetailFragmentView = viewContainer.findViewById(R.id.about_fragment_container);
         mUpdatesFragmentView = viewContainer.findViewById(R.id.updates_fragment_container);
 
-        // Determine the layout mode based on whether the {@link ViewPager} is null or not. If the
-        // {@link ViewPager} is null, then this is a wide screen and the content can be displayed
-        // in 2 columns side by side. If the {@link ViewPager} is non-null, then this is a narrow
-        // screen and the user will need to swipe to see all the data.
-        mLayoutMode = (mViewPager == null) ? LayoutMode.TWO_COLUMN :
-                LayoutMode.VIEW_PAGER_AND_CAROUSEL;
+        // Determine the layout mode based on the presence of certain views in the layout XML.
+        if (mViewPager != null) {
+            mLayoutMode = LayoutMode.VIEW_PAGER_AND_TAB_CAROUSEL;
+        } else {
+            mLayoutMode = (mFragmentCarousel != null) ? LayoutMode.FRAGMENT_CAROUSEL :
+                    LayoutMode.TWO_COLUMN;
+        }
 
         initialize(savedState);
     }
@@ -114,9 +126,15 @@
 
         mDetailFragment.setListener(mContactDetailFragmentListener);
 
+        // Read from savedState if possible
+        int currentPageIndex = 0;
+        if (savedState != null) {
+            mContactHasUpdates = savedState.getBoolean(KEY_CONTACT_HAS_UPDATES);
+            currentPageIndex = savedState.getInt(KEY_CURRENT_PAGE_INDEX, 0);
+        }
+
         switch (mLayoutMode) {
-            case VIEW_PAGER_AND_CAROUSEL: {
-                mTabCarousel.setListener(mTabCarouselListener);
+            case VIEW_PAGER_AND_TAB_CAROUSEL: {
                 // Inflate 2 view containers to pass in as children to the {@link ViewPager},
                 // which will in turn be the parents to the mDetailFragment and mUpdatesFragment
                 // since the fragments must have the same parent view IDs in both landscape and
@@ -135,19 +153,19 @@
                 mViewPager.setAdapter(mViewPagerAdapter);
                 mViewPager.setOnPageChangeListener(mOnPageChangeListener);
 
-                FragmentTransaction transaction = mFragmentManager.beginTransaction();
                 if (!fragmentsAddedToFragmentManager) {
+                    FragmentTransaction transaction = mFragmentManager.beginTransaction();
                     transaction.add(R.id.about_fragment_container, mDetailFragment,
                             ContactDetailViewPagerAdapter.ABOUT_FRAGMENT_TAG);
                     transaction.add(R.id.updates_fragment_container, mUpdatesFragment,
                             ContactDetailViewPagerAdapter.UPDTES_FRAGMENT_TAG);
-                } else {
-                    transaction.show(mDetailFragment);
-                    transaction.show(mUpdatesFragment);
+                    transaction.commit();
+                    mFragmentManager.executePendingTransactions();
                 }
-                transaction.commit();
-                mFragmentManager.executePendingTransactions();
+
+                mTabCarousel.setListener(mTabCarouselListener);
                 TabCarouselScrollManager.bind(mTabCarousel, mDetailFragment, mUpdatesFragment);
+                mViewPager.setCurrentItem(currentPageIndex);
                 break;
             }
             case TWO_COLUMN: {
@@ -160,11 +178,32 @@
                     transaction.commit();
                     mFragmentManager.executePendingTransactions();
                 }
+                break;
+            }
+            case FRAGMENT_CAROUSEL: {
+                // Add the fragments to the fragment containers in the carousel using a
+                // {@link FragmentTransaction} if they haven't already been added to the
+                // {@link FragmentManager}.
+                if (!fragmentsAddedToFragmentManager) {
+                    FragmentTransaction transaction = mFragmentManager.beginTransaction();
+                    transaction.add(R.id.about_fragment_container, mDetailFragment,
+                            ContactDetailViewPagerAdapter.ABOUT_FRAGMENT_TAG);
+                    transaction.add(R.id.updates_fragment_container, mUpdatesFragment,
+                            ContactDetailViewPagerAdapter.UPDTES_FRAGMENT_TAG);
+                    transaction.commit();
+                    mFragmentManager.executePendingTransactions();
+                }
+
+                mFragmentCarousel.setFragmentViews(mDetailFragmentView, mUpdatesFragmentView);
+                mFragmentCarousel.setFragments(mDetailFragment, mUpdatesFragment);
+                mFragmentCarousel.setCurrentPage(currentPageIndex);
+                break;
             }
         }
 
+        // Setup the layout if we already have a saved state
         if (savedState != null) {
-            if (savedState.getBoolean(KEY_CONTACT_HAS_UPDATES)) {
+            if (mContactHasUpdates) {
                 showContactWithUpdates();
             } else {
                 showContactWithoutUpdates();
@@ -182,7 +221,14 @@
         }
     }
 
+    /**
+     * Setup the layout for the contact with updates. Pass in the index of the current page to
+     * select or null if the current selection should be left as is.
+     */
     private void showContactWithUpdates() {
+        if (mContactData == null) {
+            return;
+        }
         switch (mLayoutMode) {
             case TWO_COLUMN: {
                 // Set the contact data (hide the static photo because the photo will already be in
@@ -192,25 +238,31 @@
                 mUpdatesFragmentView.setVisibility(View.VISIBLE);
                 break;
             }
-            case VIEW_PAGER_AND_CAROUSEL: {
+            case VIEW_PAGER_AND_TAB_CAROUSEL: {
                 // Update and show the tab carousel
                 mTabCarousel.loadData(mContactData);
                 mTabCarousel.setVisibility(View.VISIBLE);
-                // Update ViewPager so that it has the max # of tabs (to show updates)
-                mViewPagerAdapter.setFragmentViewCount(FRAGMENT_COUNT);
+                // Update ViewPager to allow swipe between all the fragments (to see updates)
+                mViewPagerAdapter.enableSwipe(true);
+                break;
+            }
+            case FRAGMENT_CAROUSEL: {
+                // Allow swiping between all fragments
+                mFragmentCarousel.enableSwipe(true);
                 break;
             }
             default:
                 throw new IllegalStateException("Invalid LayoutMode " + mLayoutMode);
         }
 
-        if (mContactData != null) {
-            mDetailFragment.setData(mContactData.getLookupUri(), mContactData);
-            mUpdatesFragment.setData(mContactData.getLookupUri(), mContactData);
-        }
+        mDetailFragment.setData(mContactData.getLookupUri(), mContactData);
+        mUpdatesFragment.setData(mContactData.getLookupUri(), mContactData);
     }
 
     private void showContactWithoutUpdates() {
+        if (mContactData == null) {
+            return;
+        }
         switch (mLayoutMode) {
             case TWO_COLUMN:
                 // Show the static photo which is next to the list of scrolling contact details
@@ -218,24 +270,54 @@
                 // Hide the updates fragment
                 mUpdatesFragmentView.setVisibility(View.GONE);
                 break;
-            case VIEW_PAGER_AND_CAROUSEL:
+            case VIEW_PAGER_AND_TAB_CAROUSEL:
                 // Hide the tab carousel
                 mTabCarousel.setVisibility(View.GONE);
-                // Update ViewPager so that it only has 1 tab and switch to the first indexed tab
-                mViewPagerAdapter.setFragmentViewCount(1);
+                // Update ViewPager to disable swipe so that it only shows the detail fragment
+                // and switch to the detail fragment
+                mViewPagerAdapter.enableSwipe(false);
                 mViewPager.setCurrentItem(0);
                 break;
+            case FRAGMENT_CAROUSEL: {
+                // Disable swipe so only the detail fragment shows
+                mFragmentCarousel.enableSwipe(false);
+                break;
+            }
             default:
                 throw new IllegalStateException("Invalid LayoutMode " + mLayoutMode);
         }
 
-        if (mContactData != null) {
-            mDetailFragment.setData(mContactData.getLookupUri(), mContactData);
+        mDetailFragment.setData(mContactData.getLookupUri(), mContactData);
+    }
+
+    public FragmentKeyListener getCurrentPage() {
+        switch (getCurrentPageIndex()) {
+            case 0:
+                return mDetailFragment;
+            case 1:
+                return mUpdatesFragment;
+            default:
+                throw new IllegalStateException("Invalid current item for ViewPager");
         }
     }
 
+    private int getCurrentPageIndex() {
+        // If the contact has social updates, then retrieve the current page based on the
+        // {@link ViewPager} or fragment carousel.
+        if (mContactHasUpdates) {
+            if (mViewPager != null) {
+                return mViewPager.getCurrentItem();
+            } else if (mFragmentCarousel != null) {
+                return mFragmentCarousel.getCurrentPage();
+            }
+        }
+        // Otherwise return the default page (detail fragment).
+        return 0;
+    }
+
     public void onSaveInstanceState(Bundle outState) {
         outState.putBoolean(KEY_CONTACT_HAS_UPDATES, mContactHasUpdates);
+        outState.putInt(KEY_CURRENT_PAGE_INDEX, getCurrentPageIndex());
     }
 
     private OnPageChangeListener mOnPageChangeListener = new OnPageChangeListener() {
diff --git a/src/com/android/contacts/detail/ContactDetailTabCarousel.java b/src/com/android/contacts/detail/ContactDetailTabCarousel.java
index 5daca05..bb30f7e 100644
--- a/src/com/android/contacts/detail/ContactDetailTabCarousel.java
+++ b/src/com/android/contacts/detail/ContactDetailTabCarousel.java
@@ -103,11 +103,9 @@
 
         // TODO: We can't always assume the "about" page will be the current page.
         mAboutTab.showSelectedState();
-        mAboutTab.enableAlphaLayer();
         mAboutTab.setAlphaLayerValue(0);
         mAboutTab.enableTouchInterceptor(mAboutTabTouchInterceptListener);
 
-        mUpdatesTab.enableAlphaLayer();
         mUpdatesTab.setAlphaLayerValue(MAX_ALPHA);
         mUpdatesTab.enableTouchInterceptor(mUpdatesTabTouchInterceptListener);
 
diff --git a/src/com/android/contacts/detail/ContactDetailUpdatesFragment.java b/src/com/android/contacts/detail/ContactDetailUpdatesFragment.java
index ba86f9f..846a957 100644
--- a/src/com/android/contacts/detail/ContactDetailUpdatesFragment.java
+++ b/src/com/android/contacts/detail/ContactDetailUpdatesFragment.java
@@ -47,6 +47,8 @@
     private LayoutInflater mInflater;
     private StreamItemAdapter mStreamItemAdapter;
 
+    private float mInitialAlphaValue;
+
     /**
      * This optional view adds an alpha layer over the entire fragment.
      */
@@ -96,8 +98,9 @@
         View rootView = mInflater.inflate(R.layout.contact_detail_updates_fragment, container,
                 false);
 
-        mAlphaLayer = rootView.findViewById(R.id.alpha_overlay);
         mTouchInterceptLayer = rootView.findViewById(R.id.touch_intercept_overlay);
+        mAlphaLayer = rootView.findViewById(R.id.alpha_overlay);
+        ContactDetailDisplayUtils.setAlphaOnViewBackground(mAlphaLayer, mInitialAlphaValue);
 
         return rootView;
     }
@@ -135,13 +138,12 @@
 
     @Override
     public void setAlphaLayerValue(float alpha) {
-        ContactDetailDisplayUtils.setAlphaOnViewBackground(mAlphaLayer, alpha);
-    }
-
-    @Override
-    public void enableAlphaLayer() {
-        if (mAlphaLayer != null) {
-            mAlphaLayer.setVisibility(View.VISIBLE);
+        // If the alpha layer is not ready yet, store it for later when the view is initialized
+        if (mAlphaLayer == null) {
+            mInitialAlphaValue = alpha;
+        } else {
+            // Otherwise set the value immediately
+            ContactDetailDisplayUtils.setAlphaOnViewBackground(mAlphaLayer, alpha);
         }
     }
 
diff --git a/src/com/android/contacts/detail/ContactDetailViewPagerAdapter.java b/src/com/android/contacts/detail/ContactDetailViewPagerAdapter.java
index d7f2743..40e391d 100644
--- a/src/com/android/contacts/detail/ContactDetailViewPagerAdapter.java
+++ b/src/com/android/contacts/detail/ContactDetailViewPagerAdapter.java
@@ -50,12 +50,12 @@
         mUpdatesFragmentView = view;
     }
 
-    public void setFragmentViewCount(int viewCount) {
-        if (viewCount < 0 || viewCount > MAX_FRAGMENT_VIEW_COUNT) {
-            throw new IllegalStateException("The view count in the ViewPager adapter must not be"
-                    + "less than 0 or exceed " + MAX_FRAGMENT_VIEW_COUNT);
-        }
-        mFragmentViewCount = viewCount;
+    /**
+     * Enable swiping if the detail and update fragments should be showing. Otherwise diable
+     * swiping if only the detail fragment should be showing.
+     */
+    public void enableSwipe(boolean enable) {
+        mFragmentViewCount = enable ? MAX_FRAGMENT_VIEW_COUNT : 1;
         notifyDataSetChanged();
     }
 
diff --git a/src/com/android/contacts/detail/ViewOverlay.java b/src/com/android/contacts/detail/ViewOverlay.java
index 4c14460..58428b8 100644
--- a/src/com/android/contacts/detail/ViewOverlay.java
+++ b/src/com/android/contacts/detail/ViewOverlay.java
@@ -32,11 +32,6 @@
     public void setAlphaLayerValue(float alpha);
 
     /**
-     * Makes the alpha layer on this fragment visible (if there is one).
-     */
-    public void enableAlphaLayer();
-
-    /**
      * Makes the touch intercept layer on this fragment visible (if there is one). Also adds a click
      * listener which is called when there is a touch event on the layer.
      */
diff --git a/src/com/android/contacts/dialpad/DialpadFragment.java b/src/com/android/contacts/dialpad/DialpadFragment.java
index 93bd3e9..188c546 100644
--- a/src/com/android/contacts/dialpad/DialpadFragment.java
+++ b/src/com/android/contacts/dialpad/DialpadFragment.java
@@ -33,7 +33,6 @@
 import android.database.Cursor;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
-import android.graphics.drawable.Drawable;
 import android.media.AudioManager;
 import android.media.ToneGenerator;
 import android.net.Uri;
@@ -298,12 +297,10 @@
         mDialpad = fragmentView.findViewById(R.id.dialpad);  // This is null in landscape mode.
 
         // In landscape we put the keyboard in phone mode.
-        // In portrait we prevent the soft keyboard to show since the
-        // dialpad acts as one already.
         if (null == mDialpad) {
             mDigits.setInputType(android.text.InputType.TYPE_CLASS_PHONE);
         } else {
-            mDigits.setInputType(android.text.InputType.TYPE_NULL);
+            mDigits.setCursorVisible(false);
         }
 
         // Set up the "dialpad chooser" UI; see showDialpadChooser().
diff --git a/src/com/android/contacts/dialpad/DigitsEditText.java b/src/com/android/contacts/dialpad/DigitsEditText.java
new file mode 100644
index 0000000..930717a
--- /dev/null
+++ b/src/com/android/contacts/dialpad/DigitsEditText.java
@@ -0,0 +1,56 @@
+/*
+ * 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.dialpad;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.EditText;
+
+/**
+ * EditText which suppresses IME show up.
+ */
+public class DigitsEditText extends EditText {
+    public DigitsEditText(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        setSuggestionsEnabled(false);
+    }
+
+    @Override
+    protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
+        super.onFocusChanged(focused, direction, previouslyFocusedRect);
+        final InputMethodManager imm = ((InputMethodManager) getContext()
+                .getSystemService(Context.INPUT_METHOD_SERVICE));
+        if (imm != null && imm.isActive(this)) {
+            imm.hideSoftInputFromWindow(getApplicationWindowToken(), 0);
+        }
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        final boolean ret = super.onTouchEvent(event);
+        // Must be done after super.onTouchEvent()
+        final InputMethodManager imm = ((InputMethodManager) getContext()
+                .getSystemService(Context.INPUT_METHOD_SERVICE));
+        if (imm != null && imm.isActive(this)) {
+            imm.hideSoftInputFromWindow(getApplicationWindowToken(), 0);
+        }
+        return ret;
+    }
+}
\ No newline at end of file
diff --git a/src/com/android/contacts/group/GroupEditorFragment.java b/src/com/android/contacts/group/GroupEditorFragment.java
index 4712871..2287557 100644
--- a/src/com/android/contacts/group/GroupEditorFragment.java
+++ b/src/com/android/contacts/group/GroupEditorFragment.java
@@ -107,6 +107,11 @@
          * Contact was saved and the Fragment can now be closed safely.
          */
         void onSaveFinished(int resultCode, Intent resultIntent);
+
+        /**
+         * Fragment is created but there's no accounts set up.
+         */
+        void onAccountsNotFound();
     }
 
     private static final int LOADER_GROUP_METADATA = 1;
@@ -308,7 +313,11 @@
                 AccountTypeManager.getInstance(mContext).getAccounts(true /* writeable */);
         // No Accounts available
         if (accounts.isEmpty()) {
-            throw new IllegalStateException("No accounts were found.");
+            Log.e(TAG, "No accounts were found.");
+            if (mListener != null) {
+                mListener.onAccountsNotFound();
+            }
+            return;
         }
 
         // In the common case of a single account being writable, auto-select
diff --git a/src/com/android/contacts/list/ContactListAdapter.java b/src/com/android/contacts/list/ContactListAdapter.java
index 51cc965..2e511bc 100644
--- a/src/com/android/contacts/list/ContactListAdapter.java
+++ b/src/com/android/contacts/list/ContactListAdapter.java
@@ -45,14 +45,13 @@
         Contacts.SORT_KEY_PRIMARY,              // 3
         Contacts.STARRED,                       // 4
         Contacts.CONTACT_PRESENCE,              // 5
-        Contacts.CONTACT_CHAT_CAPABILITY,       // 6
-        Contacts.CONTACT_STATUS,                // 7
-        Contacts.PHOTO_ID,                      // 8
-        Contacts.PHOTO_THUMBNAIL_URI,           // 9
-        Contacts.LOOKUP_KEY,                    // 10
-        Contacts.PHONETIC_NAME,                 // 11
-        Contacts.HAS_PHONE_NUMBER,              // 12
-        Contacts.IS_USER_PROFILE,               // 13
+        Contacts.CONTACT_STATUS,                // 6
+        Contacts.PHOTO_ID,                      // 7
+        Contacts.PHOTO_THUMBNAIL_URI,           // 8
+        Contacts.LOOKUP_KEY,                    // 9
+        Contacts.PHONETIC_NAME,                 // 10
+        Contacts.HAS_PHONE_NUMBER,              // 11
+        Contacts.IS_USER_PROFILE,               // 12
     };
 
     protected static final String[] PROJECTION_DATA = new String[] {
@@ -62,13 +61,12 @@
         Data.SORT_KEY_PRIMARY,                  // 3
         Data.STARRED,                           // 4
         Data.CONTACT_PRESENCE,                  // 5
-        Data.CONTACT_CHAT_CAPABILITY,           // 6
-        Data.CONTACT_STATUS,                    // 7
-        Data.PHOTO_ID,                          // 8
-        Data.PHOTO_THUMBNAIL_URI,               // 9
-        Data.LOOKUP_KEY,                        // 10
-        Data.PHONETIC_NAME,                     // 11
-        Data.HAS_PHONE_NUMBER,                  // 12
+        Data.CONTACT_STATUS,                    // 6
+        Data.PHOTO_ID,                          // 7
+        Data.PHOTO_THUMBNAIL_URI,               // 8
+        Data.LOOKUP_KEY,                        // 9
+        Data.PHONETIC_NAME,                     // 10
+        Data.HAS_PHONE_NUMBER,                  // 11
     };
 
     protected static final String[] FILTER_PROJECTION = new String[] {
@@ -78,15 +76,14 @@
         Contacts.SORT_KEY_PRIMARY,              // 3
         Contacts.STARRED,                       // 4
         Contacts.CONTACT_PRESENCE,              // 5
-        Contacts.CONTACT_CHAT_CAPABILITY,       // 6
-        Contacts.CONTACT_STATUS,                // 7
-        Contacts.PHOTO_ID,                      // 8
-        Contacts.PHOTO_THUMBNAIL_URI,           // 9
-        Contacts.LOOKUP_KEY,                    // 10
-        Contacts.PHONETIC_NAME,                 // 11
-        Contacts.HAS_PHONE_NUMBER,              // 12
-        Contacts.IS_USER_PROFILE,               // 13
-        SearchSnippetColumns.SNIPPET,           // 14
+        Contacts.CONTACT_STATUS,                // 6
+        Contacts.PHOTO_ID,                      // 7
+        Contacts.PHOTO_THUMBNAIL_URI,           // 8
+        Contacts.LOOKUP_KEY,                    // 9
+        Contacts.PHONETIC_NAME,                 // 10
+        Contacts.HAS_PHONE_NUMBER,              // 11
+        Contacts.IS_USER_PROFILE,               // 12
+        SearchSnippetColumns.SNIPPET,           // 13
     };
 
     protected static final int CONTACT_ID_COLUMN_INDEX = 0;
@@ -95,15 +92,14 @@
     protected static final int CONTACT_SORT_KEY_PRIMARY_COLUMN_INDEX = 3;
     protected static final int CONTACT_STARRED_COLUMN_INDEX = 4;
     protected static final int CONTACT_PRESENCE_STATUS_COLUMN_INDEX = 5;
-    protected static final int CONTACT_CHAT_CAPABILITY_COLUMN_INDEX = 6;
-    protected static final int CONTACT_CONTACT_STATUS_COLUMN_INDEX = 7;
-    protected static final int CONTACT_PHOTO_ID_COLUMN_INDEX = 8;
-    protected static final int CONTACT_PHOTO_URI_COLUMN_INDEX = 9;
-    protected static final int CONTACT_LOOKUP_KEY_COLUMN_INDEX = 10;
-    protected static final int CONTACT_PHONETIC_NAME_COLUMN_INDEX = 11;
-    protected static final int CONTACT_HAS_PHONE_COLUMN_INDEX = 12;
-    protected static final int CONTACT_IS_USER_PROFILE = 13;
-    protected static final int CONTACT_SNIPPET_COLUMN_INDEX = 14;
+    protected static final int CONTACT_CONTACT_STATUS_COLUMN_INDEX = 6;
+    protected static final int CONTACT_PHOTO_ID_COLUMN_INDEX = 7;
+    protected static final int CONTACT_PHOTO_URI_COLUMN_INDEX = 8;
+    protected static final int CONTACT_LOOKUP_KEY_COLUMN_INDEX = 9;
+    protected static final int CONTACT_PHONETIC_NAME_COLUMN_INDEX = 10;
+    protected static final int CONTACT_HAS_PHONE_COLUMN_INDEX = 11;
+    protected static final int CONTACT_IS_USER_PROFILE = 12;
+    protected static final int CONTACT_SNIPPET_COLUMN_INDEX = 13;
 
     private CharSequence mUnknownNameText;
     private int mDisplayNameColumnIndex;
@@ -281,7 +277,7 @@
 
     protected void bindPresenceAndStatusMessage(final ContactListItemView view, Cursor cursor) {
         view.showPresenceAndStatusMessage(cursor, CONTACT_PRESENCE_STATUS_COLUMN_INDEX,
-                CONTACT_CHAT_CAPABILITY_COLUMN_INDEX, CONTACT_CONTACT_STATUS_COLUMN_INDEX);
+                CONTACT_CONTACT_STATUS_COLUMN_INDEX);
     }
 
     protected void bindSearchSnippet(final ContactListItemView view, Cursor cursor) {
diff --git a/src/com/android/contacts/list/ContactListItemView.java b/src/com/android/contacts/list/ContactListItemView.java
index 4c4b780..ce1b119 100644
--- a/src/com/android/contacts/list/ContactListItemView.java
+++ b/src/com/android/contacts/list/ContactListItemView.java
@@ -1050,17 +1050,12 @@
      * Sets the proper icon (star or presence or nothing) and/or status message.
      */
     public void showPresenceAndStatusMessage(Cursor cursor, int presenceColumnIndex,
-            int capabilityColumnIndex, int contactStatusColumnIndex) {
+            int contactStatusColumnIndex) {
         Drawable icon = null;
         int presence = 0;
-        int chatCapability = 0;
         if (!cursor.isNull(presenceColumnIndex)) {
             presence = cursor.getInt(presenceColumnIndex);
-            if (capabilityColumnIndex != 0 && !cursor.isNull(presenceColumnIndex)) {
-                chatCapability = cursor.getInt(capabilityColumnIndex);
-            }
-            icon = ContactPresenceIconUtil.getChatCapabilityIcon(
-                    getContext(), presence, chatCapability);
+            icon = ContactPresenceIconUtil.getPresenceIcon(getContext(), presence);
         }
         setPresence(icon);
 
diff --git a/src/com/android/contacts/list/ContactTileAdapter.java b/src/com/android/contacts/list/ContactTileAdapter.java
index 63d44be..b7434b1 100644
--- a/src/com/android/contacts/list/ContactTileAdapter.java
+++ b/src/com/android/contacts/list/ContactTileAdapter.java
@@ -16,6 +16,8 @@
 package com.android.contacts.list;
 
 import com.android.contacts.ContactPhotoManager;
+import com.android.contacts.ContactPresenceIconUtil;
+import com.android.contacts.ContactStatusUtil;
 import com.android.contacts.ContactTileLoaderFactory;
 import com.android.contacts.GroupMemberLoader;
 import com.android.contacts.R;
@@ -25,6 +27,7 @@
 import android.content.Context;
 import android.content.res.Resources;
 import android.database.Cursor;
+import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.provider.ContactsContract.CommonDataKinds.Phone;
 import android.provider.ContactsContract.Contacts;
@@ -238,8 +241,8 @@
         contact.photoUri = (photoUri != null ? Uri.parse(photoUri) : null);
         contact.lookupKey = ContentUris.withAppendedId(
                 Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, lookupKey), id);
-        contact.presence = cursor.isNull(mPresenceIndex) ? null : cursor.getInt(mPresenceIndex);
 
+        // Set phone number and label
         if (mDisplayType == DisplayType.STREQUENT_PHONE_ONLY) {
             int phoneNumberType = cursor.getInt(mPhoneNumberTypeIndex);
             String phoneNumberCustomLabel = cursor.getString(mPhoneNumberLabelIndex);
@@ -247,8 +250,25 @@
                     phoneNumberCustomLabel);
             contact.phoneNumber = cursor.getString(mPhoneNumberIndex);
         } else {
-            contact.status = cursor.getString(mStatusIndex);
-            contact.presence = cursor.isNull(mPresenceIndex) ? null : cursor.getInt(mPresenceIndex);
+            // Set presence icon and status message
+            Drawable icon = null;
+            int presence = 0;
+            if (!cursor.isNull(mPresenceIndex)) {
+                presence = cursor.getInt(mPresenceIndex);
+                icon = ContactPresenceIconUtil.getPresenceIcon(mContext, presence);
+            }
+            contact.presenceIcon = icon;
+
+            String statusMessage = null;
+            if (mStatusIndex != 0 && !cursor.isNull(mStatusIndex)) {
+                statusMessage = cursor.getString(mStatusIndex);
+            }
+            // If there is no status message from the contact, but there was a presence value,
+            // then use the default status message string
+            if (statusMessage == null && presence != 0) {
+                statusMessage = ContactStatusUtil.getStatusString(mContext, presence);
+            }
+            contact.status = statusMessage;
         }
 
         return contact;
@@ -530,7 +550,7 @@
         public String phoneNumber;
         public Uri photoUri;
         public Uri lookupKey;
-        public Integer presence;
+        public Drawable presenceIcon;
     }
 
     private static class ViewTypes {
diff --git a/src/com/android/contacts/list/ContactTileView.java b/src/com/android/contacts/list/ContactTileView.java
index 25edd7f..bfc4a2e 100644
--- a/src/com/android/contacts/list/ContactTileView.java
+++ b/src/com/android/contacts/list/ContactTileView.java
@@ -96,22 +96,12 @@
             mLookupUri = entry.lookupKey;
 
             if (mStatus != null) {
-                String statusText;
-                if (entry.presence == null) {
+                if (entry.status == null) {
                     mStatus.setVisibility(View.GONE);
                 } else {
-                    statusText =
-                          (entry.status != null ? entry.status :
-                          ContactStatusUtil.getStatusString(mContext, entry.presence));
-                    mStatus.setText(statusText);
-                    int presenceDrawableResId = (entry.presence == null ? 0 :
-                            StatusUpdates.getPresenceIconResourceId(entry.presence));
-                    if (presenceDrawableResId != 0) {
-                        Log.i(TAG, "iconId = " + presenceDrawableResId);
-                        mStatus.setCompoundDrawablesWithIntrinsicBounds(
-                                getResources().getDrawable(presenceDrawableResId),
-                                null, null, null);
-                    }
+                    mStatus.setText(entry.status);
+                    mStatus.setCompoundDrawablesWithIntrinsicBounds(entry.presenceIcon,
+                            null, null, null);
                     mStatus.setVisibility(View.VISIBLE);
                 }
             }
diff --git a/src/com/android/contacts/list/LegacyContactListAdapter.java b/src/com/android/contacts/list/LegacyContactListAdapter.java
index b3ab2af..b21d484 100644
--- a/src/com/android/contacts/list/LegacyContactListAdapter.java
+++ b/src/com/android/contacts/list/LegacyContactListAdapter.java
@@ -91,6 +91,6 @@
     }
 
     protected void bindPresence(final ContactListItemView view, Cursor cursor) {
-        view.showPresenceAndStatusMessage(cursor, PERSON_PRESENCE_STATUS_COLUMN_INDEX, 0, 0);
+        view.showPresenceAndStatusMessage(cursor, PERSON_PRESENCE_STATUS_COLUMN_INDEX, 0);
     }
 }
diff --git a/src/com/android/contacts/util/ContactBadgeUtil.java b/src/com/android/contacts/util/ContactBadgeUtil.java
index 806264d..a89177a 100644
--- a/src/com/android/contacts/util/ContactBadgeUtil.java
+++ b/src/com/android/contacts/util/ContactBadgeUtil.java
@@ -57,10 +57,15 @@
 
         final String statusLabelRes = streamItem.getLabelRes();
         final String statusResPackage = streamItem.getResPackage();
+
+        // Package name used for resources.getIdentifier()
+        String identiferPackage = statusResPackage;
         if (statusLabelRes  != null) {
             Resources resources;
             if (TextUtils.isEmpty(statusResPackage)) {
                 resources = context.getResources();
+                // In this case, we're using the framework resources.
+                identiferPackage = "android";
             } else {
                 PackageManager pm = context.getPackageManager();
                 try {
@@ -74,7 +79,7 @@
 
             if (resources != null) {
                 final int resId = resources.getIdentifier(statusLabelRes, "string",
-                        statusResPackage);
+                        identiferPackage);
                 if (resId == 0) {
                     Log.w(TAG, "Contact status update resource not found: " + statusLabelRes +
                             " in " + statusResPackage);