Allow phone contact card to switch b/t having/not having social updates

- Make phone portrait and landscape layouts have all views necessary
to switch between showing/hiding social updates. Disable swipe
if only the detail fragment is showing.

- Make ContactDetailActivity use ContactDetailLayoutController to
reduce code duplication, add another state for fragment carousel
in ContactDetailLayoutController

- Make fragment widths in fragment carousel configurable based
on screen width instead of fixed dip value

- Make setAlphaLayerValue() save the alpha value if the view
isn't ready yet (otherwise it's a no-op and the caller must
call it setAlphaLayerValue again when the view is attached) -->
this allows us to remove the code to set fragments in the
fragment carousel every time the data is reloaded

- Remove enableAlphaLayer() code and just make the alpha layer
view visible in the XML

Bug: 5164029

Change-Id: I8f28ac27d125502a12221f084ce253611e6f78a1
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_container_without_updates.xml b/res/layout/contact_detail_container_without_updates.xml
deleted file mode 100644
index 884f280..0000000
--- a/res/layout/contact_detail_container_without_updates.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<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>
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/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/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.
      */