Merge "Put OK button on the right"
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 5a645a0..9d5381a 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -40,9 +40,6 @@
     <uses-permission android:name="android.permission.VIBRATE" />
     <uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
     <uses-permission android:name="com.android.voicemail.permission.ADD_VOICEMAIL" />
-    <!-- TODO: get rid of READ_WRITE_OWN_VOICEMAIL permission when voicemail provider has been
-    modified to support ADD_VOICEMAIL -->
-    <uses-permission android:name="com.android.voicemail.permission.READ_WRITE_OWN_VOICEMAIL" />
     <uses-permission android:name="com.android.voicemail.permission.READ_WRITE_ALL_VOICEMAIL" />
     <!-- allow broadcasting secret code intents that reboot the phone -->
     <uses-permission android:name="android.permission.REBOOT" />
@@ -476,7 +473,6 @@
         <activity android:name="CallDetailActivity"
             android:label="@string/callDetailTitle"
             android:theme="@style/CallDetailActivityTheme"
-            android:uiOptions="splitActionBarWhenNarrow"
             android:screenOrientation="nosensor"
             android:icon="@mipmap/ic_launcher_phone"
             android:taskAffinity="android.task.contacts.phone"
diff --git a/res/drawable/seek_bar_thumb.xml b/res/drawable/seek_bar_thumb.xml
index 04ba0fa..61884bb 100644
--- a/res/drawable/seek_bar_thumb.xml
+++ b/res/drawable/seek_bar_thumb.xml
@@ -6,8 +6,8 @@
             android:shape="oval"
         >
             <size
-                android:width="15dip"
-                android:height="15dip"
+                android:width="16dip"
+                android:height="16dip"
             />
             <solid
                 android:color="@color/voicemail_playback_seek_bar_yet_to_play"
diff --git a/res/layout-sw580dp-w1000dp/contact_detail_container.xml b/res/layout-sw580dp-w1000dp/contact_detail_container.xml
index be91296..1d4ea35 100644
--- a/res/layout-sw580dp-w1000dp/contact_detail_container.xml
+++ b/res/layout-sw580dp-w1000dp/contact_detail_container.xml
@@ -16,7 +16,7 @@
 
 <!--
   Two-column layout for a contact with social updates. If the contact does not
-  have social updates, then the second fragment view will just be hidden.
+  have social updates, then the second fragment container will just be hidden.
 -->
 
 <LinearLayout
@@ -26,14 +26,24 @@
     android:scrollbars="none"
     android:orientation="horizontal">
 
-    <fragment class="com.android.contacts.detail.ContactDetailFragment"
-        android:id="@+id/about_fragment"
+    <!--
+      Container for the "About" fragment on the contact card for a contact
+      with social updates. This view ID must match with a view ID in the layout
+      that is used after an orientation change.
+    -->
+    <FrameLayout
+        android:id="@+id/about_fragment_container"
         android:layout_width="0dip"
         android:layout_height="match_parent"
         android:layout_weight="1" />
 
-    <fragment class="com.android.contacts.detail.ContactDetailUpdatesFragment"
-        android:id="@+id/updates_fragment"
+    <!--
+      Container for the "Updates" fragment on the contact card for a contact
+      with social updates. This view ID must match with a view ID in the layout
+      that is used after an orientation change.
+    -->
+    <FrameLayout
+        android:id="@+id/updates_fragment_container"
         android:layout_width="306dip"
         android:layout_height="match_parent" />
 
diff --git a/res/layout-sw580dp/people_activity.xml b/res/layout-sw580dp/people_activity.xml
index 13adfa9..1d02042 100644
--- a/res/layout-sw580dp/people_activity.xml
+++ b/res/layout-sw580dp/people_activity.xml
@@ -83,6 +83,7 @@
 
             <!-- 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"/>
diff --git a/res/layout/call_detail.xml b/res/layout/call_detail.xml
index 441cc6c..ece2f64 100644
--- a/res/layout/call_detail.xml
+++ b/res/layout/call_detail.xml
@@ -52,10 +52,17 @@
         />
     </view>
     <LinearLayout
+        android:id="@+id/blue_separator"
+        android:layout_width="match_parent"
+        android:layout_height="1dip"
+        android:background="@android:color/holo_blue_light"
+        android:layout_below="@+id/contact_background_sizer"
+    />
+    <LinearLayout
         android:id="@+id/voicemail_container"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_below="@id/contact_background_sizer"
+        android:layout_below="@id/blue_separator"
     >
         <!-- The voicemail fragment will be put here. -->
     </LinearLayout>
diff --git a/res/layout/contact_detail_container.xml b/res/layout/contact_detail_container.xml
index 3991e5c..9204b62 100644
--- a/res/layout/contact_detail_container.xml
+++ b/res/layout/contact_detail_container.xml
@@ -43,12 +43,7 @@
         android:layout_alignParentTop="true"
         android:layout_alignParentLeft="true"
         android:layout_width="match_parent"
-        android:layout_height="wrap_content"/>
-
-    <fragment
-        android:id="@+id/contact_detail_fragment"
-        class="com.android.contacts.detail.ContactDetailFragment"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"/>
+        android:layout_height="wrap_content"
+        android:visibility="gone"/>
 
 </RelativeLayout>
\ No newline at end of file
diff --git a/res/layout/playback_layout.xml b/res/layout/playback_layout.xml
index 020c017..45e7ad9 100644
--- a/res/layout/playback_layout.xml
+++ b/res/layout/playback_layout.xml
@@ -19,75 +19,90 @@
             android:layout_alignParentTop="true"
         >
             <ImageButton
-                android:id="@+id/playback_speakerphone"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:padding="5px"
-                android:layout_marginTop="4dip"
-                android:layout_marginLeft="4dip"
-                android:background="@drawable/dialpad_background"
-                android:src="@drawable/ic_sound_holo_dark"
-                android:layout_weight="1"
-            />
-            <ImageButton
                 android:id="@+id/playback_start_stop"
                 android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:padding="5px"
-                android:layout_marginTop="4dip"
-                android:layout_marginLeft="4dip"
+                android:layout_height="58dip"
+                android:layout_marginRight="2dip"
                 android:background="@drawable/dialpad_background"
                 android:src="@drawable/ic_hold_pause_holo_dark"
                 android:layout_weight="1"
             />
+            <ImageButton
+                android:id="@+id/playback_speakerphone"
+                android:layout_width="wrap_content"
+                android:layout_height="58dip"
+                android:layout_marginLeft="2dip"
+                android:background="@drawable/dialpad_background"
+                android:src="@drawable/ic_sound_holo_dark"
+                android:layout_weight="1"
+            />
         </LinearLayout>
-        <SeekBar
-            android:id="@+id/playback_seek"
+        <RelativeLayout
+            android:id="@+id/seek_container"
             android:layout_width="fill_parent"
-            android:layout_height="wrap_content"
-            android:progressDrawable="@drawable/seekbar_drawable"
-            android:thumb="@drawable/seek_bar_thumb"
-            android:thumbOffset="0dip"
+            android:layout_height="80dip"
             android:background="@drawable/dialpad_background"
-            android:paddingLeft="50dip"
-            android:paddingRight="50dip"
-            android:paddingTop="10dip"
-            android:paddingBottom="20dip"
-            android:layout_margin="4dip"
-            android:progress="20"
-            android:max="50"
             android:layout_below="@id/buttons_linear_layout"
-        />
-        <TextView
-            android:id="@+id/playback_position_text"
-            android:text="@string/voicemail_initial_time"
-            android:layout_height="wrap_content"
-            android:layout_width="wrap_content"
-            android:paddingBottom="5dip"
-            android:layout_alignBottom="@id/playback_seek"
-            android:layout_centerHorizontal="true"
-        />
-        <ImageButton
-            android:id="@+id/rate_decrease_button"
-            android:src="@drawable/ic_minus_holo_dark"
-            android:layout_width="30dip"
-            android:layout_height="wrap_content"
-            android:background="@android:color/transparent"
-            android:paddingTop="10dip"
-            android:paddingBottom="15dip"
-            android:layout_alignLeft="@id/playback_seek"
-            android:layout_alignBottom="@id/playback_seek"
-        />
-        <ImageButton
-            android:id="@+id/rate_increase_button"
-            android:src="@drawable/ic_plus_holo_dark"
-            android:layout_width="30dip"
-            android:layout_height="wrap_content"
-            android:background="@android:color/transparent"
-            android:paddingTop="10dip"
-            android:paddingBottom="15dip"
-            android:layout_alignRight="@id/playback_seek"
-            android:layout_alignBottom="@id/playback_seek"
-        />
+            android:layout_marginTop="4dip"
+        >
+            <!-- SeekBar left-right margin decreased from redlines 72dip by 8dip to account for
+                 half thumb width (thumb is 16dip).
+                 Vertically, SeekBar and rate buttons should be below centre, position achieved by
+                 making them centred but giving a difference between top and bottom padding,
+                 difference is currently 10dip. -->
+            <SeekBar
+                android:id="@+id/playback_seek"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:progressDrawable="@drawable/seekbar_drawable"
+                android:thumb="@drawable/seek_bar_thumb"
+                android:thumbOffset="8dip"
+                android:progress="20"
+                android:paddingLeft="8dip"
+                android:paddingRight="8dip"
+                android:paddingTop="30dip"
+                android:paddingBottom="20dip"
+                android:layout_marginRight="64dip"
+                android:layout_marginLeft="64dip"
+                android:max="50"
+                android:layout_centerVertical="true"
+            />
+            <TextView
+                android:id="@+id/playback_position_text"
+                android:text="@string/voicemail_initial_time"
+                android:layout_height="wrap_content"
+                android:layout_width="wrap_content"
+                android:textSize="14sp"
+                android:layout_alignParentTop="true"
+                android:layout_centerHorizontal="true"
+                android:layout_marginTop="10dip"
+            />
+            <ImageButton
+                android:id="@+id/rate_decrease_button"
+                android:src="@drawable/ic_minus_holo_dark"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:background="@android:color/transparent"
+                android:paddingLeft="16dip"
+                android:paddingRight="16dip"
+                android:paddingBottom="16dip"
+                android:paddingTop="26dip"
+                android:layout_alignParentLeft="true"
+                android:layout_centerVertical="true"
+            />
+            <ImageButton
+                android:id="@+id/rate_increase_button"
+                android:src="@drawable/ic_plus_holo_dark"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:background="@android:color/transparent"
+                android:paddingLeft="16dip"
+                android:paddingRight="16dip"
+                android:paddingBottom="16dip"
+                android:paddingTop="26dip"
+                android:layout_alignParentRight="true"
+                android:layout_centerVertical="true"
+            />
+        </RelativeLayout>
     </RelativeLayout>
 </LinearLayout>
diff --git a/src/com/android/contacts/activities/ContactDetailActivity.java b/src/com/android/contacts/activities/ContactDetailActivity.java
index 3dffd71..d888dbe 100644
--- a/src/com/android/contacts/activities/ContactDetailActivity.java
+++ b/src/com/android/contacts/activities/ContactDetailActivity.java
@@ -75,8 +75,6 @@
 
     private static final String KEY_CONTACT_HAS_UPDATES = "contactHasUpdates";
     private static final String KEY_CURRENT_PAGE_INDEX = "currentPageIndex";
-    private static final String KEY_DETAIL_FRAGMENT_TAG = "detailFragTag";
-    private static final String KEY_UPDATES_FRAGMENT_TAG = "updatesFragTag";
 
     public static final int FRAGMENT_COUNT = 2;
 
@@ -273,11 +271,6 @@
         super.onSaveInstanceState(outState);
         outState.putBoolean(KEY_CONTACT_HAS_UPDATES, mContactHasUpdates);
         outState.putInt(KEY_CURRENT_PAGE_INDEX, getCurrentPage());
-        if (mViewPager != null) {
-            outState.putString(KEY_DETAIL_FRAGMENT_TAG, mDetailFragment.getTag());
-            outState.putString(KEY_UPDATES_FRAGMENT_TAG, mUpdatesFragment.getTag());
-            return;
-        }
     }
 
     private final ContactLoaderFragmentListener mLoaderFragmentListener =
diff --git a/src/com/android/contacts/activities/PeopleActivity.java b/src/com/android/contacts/activities/PeopleActivity.java
index 48fd49d..282e0b3 100644
--- a/src/com/android/contacts/activities/PeopleActivity.java
+++ b/src/com/android/contacts/activities/PeopleActivity.java
@@ -122,8 +122,6 @@
 
     private ContactDetailFragment mContactDetailFragment;
     private ContactDetailUpdatesFragment mContactDetailUpdatesFragment;
-    private final ContactDetailFragmentListener mContactDetailFragmentListener =
-            new ContactDetailFragmentListener();
 
     private ContactLoaderFragment mContactDetailLoaderFragment;
     private final ContactDetailLoaderFragmentListener mContactDetailLoaderFragmentListener =
@@ -226,7 +224,6 @@
     public void onAttachFragment(Fragment fragment) {
         if (fragment instanceof ContactDetailFragment) {
             mContactDetailFragment = (ContactDetailFragment) fragment;
-            mContactDetailFragment.setListener(mContactDetailFragmentListener);
         } else if (fragment instanceof ContactDetailUpdatesFragment) {
             mContactDetailUpdatesFragment = (ContactDetailUpdatesFragment) fragment;
         } else if (fragment instanceof ContactsUnavailableFragment) {
@@ -379,21 +376,21 @@
 
             mContactDetailLoaderFragment = getFragment(R.id.contact_detail_loader_fragment);
             mContactDetailLoaderFragment.setListener(mContactDetailLoaderFragmentListener);
+            mContactDetailLoaderFragment.setRetainInstance(true);
 
             mGroupDetailFragment = getFragment(R.id.group_detail_fragment);
             mGroupDetailFragment.setListener(mGroupDetailFragmentListener);
             mGroupDetailFragment.setQuickContact(true);
 
-            transaction.hide(mContactDetailFragment);
+            if (mContactDetailFragment != null) {
+                transaction.hide(mContactDetailFragment);
+            }
             transaction.hide(mGroupDetailFragment);
 
             // Configure contact details
-            ViewPager viewPager = (ViewPager) findViewById(R.id.pager);
-            ContactDetailTabCarousel tabCarousel = (ContactDetailTabCarousel)
-                    findViewById(R.id.tab_carousel);
-            mContactDetailLayoutController = new ContactDetailLayoutController(
-                    getFragmentManager(), viewPager, tabCarousel,
-                    mContactDetailFragmentListener);
+            mContactDetailLayoutController = new ContactDetailLayoutController(this, savedState,
+                    getFragmentManager(), findViewById(R.id.contact_detail_container),
+                    new ContactDetailFragmentListener());
         }
         transaction.commit();
         fragmentManager.executePendingTransactions();
@@ -1066,13 +1063,6 @@
                     if (isFinishing()) {
                         return;
                     }
-                    if (!mContactDetailLayoutController.isInitialized()) {
-                        mContactDetailLayoutController.setContactDetailFragment(
-                                mContactDetailFragment);
-                        mContactDetailLayoutController.setContactDetailUpdatesFragment(
-                                mContactDetailUpdatesFragment);
-                        mContactDetailLayoutController.initialize();
-                    }
                     mContactDetailLayoutController.setContactData(result);
                 }
             });
@@ -1570,14 +1560,6 @@
     }
 
     @Override
-    protected void onRestoreInstanceState(Bundle inState) {
-        super.onRestoreInstanceState(inState);
-        if (mContactDetailLayoutController != null) {
-            mContactDetailLayoutController.onRestoreInstanceState(inState);
-        }
-    }
-
-    @Override
     public DialogManager getDialogManager() {
         return mDialogManager;
     }
diff --git a/src/com/android/contacts/detail/ContactDetailFragmentCarousel.java b/src/com/android/contacts/detail/ContactDetailFragmentCarousel.java
index eb1d1f0..561d44e 100644
--- a/src/com/android/contacts/detail/ContactDetailFragmentCarousel.java
+++ b/src/com/android/contacts/detail/ContactDetailFragmentCarousel.java
@@ -66,7 +66,6 @@
     private static final float MAX_ALPHA = 0.5f;
 
     private final Handler mHandler = new Handler();
-    private boolean mAttachedToWindow;
 
     public ContactDetailFragmentCarousel(Context context) {
         this(context, null);
@@ -105,7 +104,8 @@
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
-                    if (mAttachedToWindow && mAboutFragment != null && mUpdatesFragment != null) {
+                    if (isAttachedToWindow() && mAboutFragment != null &&
+                            mUpdatesFragment != null) {
                         snapToEdge();
                     }
                 }
@@ -116,7 +116,7 @@
     public void setCurrentPage(int pageIndex) {
         if (mCurrentPage != pageIndex) {
             mCurrentPage = pageIndex;
-            if (mAttachedToWindow && mAboutFragment != null && mUpdatesFragment != null) {
+            if (isAttachedToWindow() && mAboutFragment != null && mUpdatesFragment != null) {
                 snapToEdge();
             }
         }
@@ -223,15 +223,7 @@
         return false;
     }
 
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        mAttachedToWindow = true;
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        mAttachedToWindow = 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 9b56dde..3fc4c31 100644
--- a/src/com/android/contacts/detail/ContactDetailLayoutController.java
+++ b/src/com/android/contacts/detail/ContactDetailLayoutController.java
@@ -17,16 +17,18 @@
 package com.android.contacts.detail;
 
 import com.android.contacts.ContactLoader;
+import com.android.contacts.R;
 import com.android.contacts.activities.PeopleActivity.ContactDetailFragmentListener;
 
-import android.app.Fragment;
 import android.app.FragmentManager;
 import android.app.FragmentTransaction;
+import android.content.Context;
 import android.os.Bundle;
-import android.support.v13.app.FragmentPagerAdapter;
 import android.support.v4.view.ViewPager;
 import android.support.v4.view.ViewPager.OnPageChangeListener;
+import android.view.LayoutInflater;
 import android.view.View;
+import android.view.ViewGroup;
 import android.widget.AbsListView;
 import android.widget.AbsListView.OnScrollListener;
 
@@ -37,94 +39,145 @@
 
     public static final int FRAGMENT_COUNT = 2;
 
-    private static final String KEY_DETAIL_FRAGMENT_TAG = "detailFragTag";
-    private static final String KEY_UPDATES_FRAGMENT_TAG = "updatesFragTag";
-
-    private String mDetailFragmentTag;
-    private String mUpdatesFragmentTag;
+    private static final String KEY_CONTACT_HAS_UPDATES = "contactHasUpdates";
 
     private enum LayoutMode {
         TWO_COLUMN, VIEW_PAGER_AND_CAROUSEL,
     }
 
+    private final LayoutInflater mLayoutInflater;
     private final FragmentManager mFragmentManager;
 
-    private ContactDetailFragment mContactDetailFragment;
-    private ContactDetailUpdatesFragment mContactDetailUpdatesFragment;
+    private ContactDetailFragment mDetailFragment;
+    private ContactDetailUpdatesFragment mUpdatesFragment;
+
+    private View mDetailFragmentView;
+    private View mUpdatesFragmentView;
 
     private final ViewPager mViewPager;
     private final ContactDetailTabCarousel mTabCarousel;
-    private ContactDetailFragment mPagerContactDetailFragment;
-    private ContactDetailUpdatesFragment mPagerContactDetailUpdatesFragment;
+    private ContactDetailViewPagerAdapter mViewPagerAdapter;
 
     private ContactDetailFragmentListener mContactDetailFragmentListener;
 
     private ContactLoader.Result mContactData;
 
-    private boolean mIsInitialized;
+    private boolean mContactHasUpdates;
 
     private LayoutMode mLayoutMode;
 
-    public ContactDetailLayoutController(FragmentManager fragmentManager, ViewPager viewPager,
-            ContactDetailTabCarousel tabCarousel, ContactDetailFragmentListener
+    public ContactDetailLayoutController(Context context, Bundle savedState,
+            FragmentManager fragmentManager, View viewContainer, ContactDetailFragmentListener
             contactDetailFragmentListener) {
+
         if (fragmentManager == null) {
             throw new IllegalStateException("Cannot initialize a ContactDetailLayoutController "
                     + "without a non-null FragmentManager");
         }
 
+        mLayoutInflater = (LayoutInflater) context.getSystemService(
+                Context.LAYOUT_INFLATER_SERVICE);
         mFragmentManager = fragmentManager;
-        mViewPager = viewPager;
-        mTabCarousel = tabCarousel;
         mContactDetailFragmentListener = contactDetailFragmentListener;
 
-        // Determine the layout based on whether the {@link ViewPager} is null or not. If the
+        // Retrieve views in case this is view pager and carousel mode
+        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
+        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;
 
+        initialize(savedState);
     }
 
-    public boolean isInitialized() {
-        return mIsInitialized;
-    }
+    private void initialize(Bundle savedState) {
+        boolean fragmentsAddedToFragmentManager = true;
+        mDetailFragment = (ContactDetailFragment) mFragmentManager.findFragmentByTag(
+                ContactDetailViewPagerAdapter.ABOUT_FRAGMENT_TAG);
+        mUpdatesFragment = (ContactDetailUpdatesFragment) mFragmentManager.findFragmentByTag(
+                ContactDetailViewPagerAdapter.UPDTES_FRAGMENT_TAG);
 
-    public void initialize() {
-        mIsInitialized = true;
-        if (mDetailFragmentTag != null || mUpdatesFragmentTag != null) {
-            // Manually remove any {@link ViewPager} fragments if there was an orientation change
-            ContactDetailFragment oldDetailFragment = (ContactDetailFragment) mFragmentManager.
-                    findFragmentByTag(mDetailFragmentTag);
-            ContactDetailUpdatesFragment oldUpdatesFragment = (ContactDetailUpdatesFragment)
-                    mFragmentManager.findFragmentByTag(mUpdatesFragmentTag);
+        // If the detail fragment was found in the {@link FragmentManager} then we don't need to add
+        // it again. Otherwise, create the fragments dynamically and remember to add them to the
+        // {@link FragmentManager}.
+        if (mDetailFragment == null) {
+            mDetailFragment = new ContactDetailFragment();
+            mUpdatesFragment = new ContactDetailUpdatesFragment();
+            fragmentsAddedToFragmentManager = false;
+        }
 
-            if (oldDetailFragment != null && oldUpdatesFragment != null) {
-                FragmentTransaction ft = mFragmentManager.beginTransaction();
-                ft.remove(oldDetailFragment);
-                ft.remove(oldUpdatesFragment);
-                ft.commitAllowingStateLoss();
+        mDetailFragment.setListener(mContactDetailFragmentListener);
+        mDetailFragment.setVerticalScrollListener(mVerticalScrollListener);
+
+        switch (mLayoutMode) {
+            case VIEW_PAGER_AND_CAROUSEL: {
+                mTabCarousel.setListener(mTabCarouselListener);
+                // 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) mLayoutInflater.inflate(
+                        R.layout.contact_detail_about_fragment_container, mViewPager, false);
+                ViewGroup updatesContainer = (ViewGroup) mLayoutInflater.inflate(
+                        R.layout.contact_detail_updates_fragment_container, mViewPager, false);
+
+                mViewPagerAdapter = new ContactDetailViewPagerAdapter();
+                mViewPagerAdapter.setAboutFragmentView(detailContainer);
+                mViewPagerAdapter.setUpdatesFragmentView(updatesContainer);
+
+                mViewPager.addView(detailContainer);
+                mViewPager.addView(updatesContainer);
+                mViewPager.setAdapter(mViewPagerAdapter);
+                mViewPager.setOnPageChangeListener(mOnPageChangeListener);
+
+                FragmentTransaction transaction = mFragmentManager.beginTransaction();
+                if (!fragmentsAddedToFragmentManager) {
+                    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();
+                break;
+            }
+            case TWO_COLUMN: {
+                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();
+                }
             }
         }
-        if (mViewPager != null) {
-            mViewPager.setAdapter(new ViewPagerAdapter(mFragmentManager));
-            mViewPager.setOnPageChangeListener(mOnPageChangeListener);
-            mTabCarousel.setListener(mTabCarouselListener);
+
+        if (savedState != null) {
+            if (savedState.getBoolean(KEY_CONTACT_HAS_UPDATES)) {
+                showContactWithUpdates();
+            } else {
+                showContactWithoutUpdates();
+            }
         }
     }
 
-    public void setContactDetailFragment(ContactDetailFragment contactDetailFragment) {
-        mContactDetailFragment = contactDetailFragment;
-    }
-
-    public void setContactDetailUpdatesFragment(ContactDetailUpdatesFragment updatesFragment) {
-        mContactDetailUpdatesFragment = updatesFragment;
-    }
-
     public void setContactData(ContactLoader.Result data) {
         mContactData = data;
-        if (!data.getStreamItems().isEmpty()) {
+        mContactHasUpdates = !data.getStreamItems().isEmpty();
+        if (mContactHasUpdates) {
             showContactWithUpdates();
         } else {
             showContactWithoutUpdates();
@@ -132,117 +185,59 @@
     }
 
     private void showContactWithUpdates() {
-        FragmentTransaction ft = mFragmentManager.beginTransaction();
-
         switch (mLayoutMode) {
             case TWO_COLUMN: {
                 // Set the contact data (hide the static photo because the photo will already be in
                 // the header that scrolls with contact details).
-                mContactDetailFragment.setShowStaticPhoto(false);
-                mContactDetailFragment.setData(mContactData.getLookupUri(), mContactData);
-                mContactDetailUpdatesFragment.setData(mContactData.getLookupUri(), mContactData);
-
-                // Update fragment visibility
-                ft.show(mContactDetailUpdatesFragment);
+                mDetailFragment.setShowStaticPhoto(false);
+                // Show the updates fragment
+                mUpdatesFragmentView.setVisibility(View.VISIBLE);
                 break;
             }
             case VIEW_PAGER_AND_CAROUSEL: {
-                // Set the contact data
+                // Update and show the tab carousel
                 mTabCarousel.loadData(mContactData);
-                mPagerContactDetailFragment.setData(mContactData.getLookupUri(), mContactData);
-                mPagerContactDetailUpdatesFragment.setData(mContactData.getLookupUri(),
-                        mContactData);
-
-                // Update fragment and view visibility
-                mViewPager.setVisibility(View.VISIBLE);
                 mTabCarousel.setVisibility(View.VISIBLE);
-                ft.hide(mContactDetailFragment);
+                // Update ViewPager so that it has the max # of tabs (to show updates)
+                mViewPagerAdapter.setFragmentViewCount(FRAGMENT_COUNT);
                 break;
             }
             default:
                 throw new IllegalStateException("Invalid LayoutMode " + mLayoutMode);
         }
 
-        // If the activity has already saved its state, then allow this fragment
-        // transaction to be dropped because there's nothing else we can do to update the UI.
-        // The fact that the contact URI has already been saved by the activity means we can
-        // restore this later.
-        ft.commitAllowingStateLoss();
+        if (mContactData != null) {
+            mDetailFragment.setData(mContactData.getLookupUri(), mContactData);
+            mUpdatesFragment.setData(mContactData.getLookupUri(), mContactData);
+        }
     }
 
     private void showContactWithoutUpdates() {
-        FragmentTransaction ft = mFragmentManager.beginTransaction();
-
         switch (mLayoutMode) {
             case TWO_COLUMN:
-                mContactDetailFragment.setShowStaticPhoto(true);
-                mContactDetailFragment.setData(mContactData.getLookupUri(), mContactData);
-                ft.hide(mContactDetailUpdatesFragment);
+                // Show the static photo which is next to the list of scrolling contact details
+                mDetailFragment.setShowStaticPhoto(true);
+                // Hide the updates fragment
+                mUpdatesFragmentView.setVisibility(View.GONE);
                 break;
             case VIEW_PAGER_AND_CAROUSEL:
-                mContactDetailFragment.setData(mContactData.getLookupUri(), mContactData);
-                ft.show(mContactDetailFragment);
-                mViewPager.setVisibility(View.GONE);
+                // 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);
+                mViewPager.setCurrentItem(0);
                 break;
             default:
                 throw new IllegalStateException("Invalid LayoutMode " + mLayoutMode);
         }
 
-        // If the activity has already saved its state, then allow this fragment
-        // transaction to be dropped because there's nothing else we can do to update the UI.
-        // The fact that the contact URI has already been saved by the activity means we can
-        // restore this later.
-        ft.commitAllowingStateLoss();
+        if (mContactData != null) {
+            mDetailFragment.setData(mContactData.getLookupUri(), mContactData);
+        }
     }
 
     public void onSaveInstanceState(Bundle outState) {
-        if (mPagerContactDetailFragment != null) {
-            outState.putString(KEY_DETAIL_FRAGMENT_TAG,
-                    mPagerContactDetailFragment.getTag());
-            outState.putString(KEY_UPDATES_FRAGMENT_TAG,
-                    mPagerContactDetailUpdatesFragment.getTag());
-        }
-    }
-
-    public void onRestoreInstanceState(Bundle savedState) {
-        mDetailFragmentTag = savedState.getString(KEY_DETAIL_FRAGMENT_TAG);
-        mUpdatesFragmentTag = savedState.getString(KEY_UPDATES_FRAGMENT_TAG);
-    }
-
-    public class ViewPagerAdapter extends FragmentPagerAdapter{
-
-        public ViewPagerAdapter(FragmentManager fm) {
-            super(fm);
-        }
-
-        @Override
-        public Fragment getItem(int position) {
-            switch (position) {
-                case 0:
-                    mPagerContactDetailFragment = new ContactDetailFragment();
-                    if (mContactData != null) {
-                        mPagerContactDetailFragment.setData(mContactData.getLookupUri(),
-                                mContactData);
-                    }
-                    mPagerContactDetailFragment.setListener(mContactDetailFragmentListener);
-                    mPagerContactDetailFragment.setVerticalScrollListener(mVerticalScrollListener);
-                    return mPagerContactDetailFragment;
-                case 1:
-                    mPagerContactDetailUpdatesFragment = new ContactDetailUpdatesFragment();
-                    if (mContactData != null) {
-                        mPagerContactDetailUpdatesFragment.setData(mContactData.getLookupUri(),
-                                mContactData);
-                    }
-                    return mPagerContactDetailUpdatesFragment;
-            }
-            throw new IllegalStateException("No fragment at position " + position);
-        }
-
-        @Override
-        public int getCount() {
-            return FRAGMENT_COUNT;
-        }
+        outState.putBoolean(KEY_CONTACT_HAS_UPDATES, mContactHasUpdates);
     }
 
     private OnPageChangeListener mOnPageChangeListener = new OnPageChangeListener() {
diff --git a/src/com/android/contacts/detail/ContactDetailViewPagerAdapter.java b/src/com/android/contacts/detail/ContactDetailViewPagerAdapter.java
index 39544df..d7f2743 100644
--- a/src/com/android/contacts/detail/ContactDetailViewPagerAdapter.java
+++ b/src/com/android/contacts/detail/ContactDetailViewPagerAdapter.java
@@ -29,11 +29,13 @@
     public static final String ABOUT_FRAGMENT_TAG = "view-pager-about-fragment";
     public static final String UPDTES_FRAGMENT_TAG = "view-pager-updates-fragment";
 
-    private static final int FRAGMENT_COUNT = 2;
-
     private static final int INDEX_ABOUT_FRAGMENT = 0;
     private static final int INDEX_UPDATES_FRAGMENT = 1;
 
+    private static final int MAX_FRAGMENT_VIEW_COUNT = 2;
+
+    private int mFragmentViewCount = MAX_FRAGMENT_VIEW_COUNT;
+
     private ViewGroup mAboutFragmentView;
     private ViewGroup mUpdatesFragmentView;
 
@@ -48,9 +50,18 @@
         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;
+        notifyDataSetChanged();
+    }
+
     @Override
     public int getCount() {
-        return FRAGMENT_COUNT;
+        return mFragmentViewCount;
     }
 
     /** Gets called when the number of items changes. */