158fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan/*
258fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan * Copyright (C) 2011 The Android Open Source Project
358fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan *
458fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan * Licensed under the Apache License, Version 2.0 (the "License");
558fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan * you may not use this file except in compliance with the License.
658fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan * You may obtain a copy of the License at
758fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan *
858fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan *      http://www.apache.org/licenses/LICENSE-2.0
958fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan *
1058fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan * Unless required by applicable law or agreed to in writing, software
1158fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan * distributed under the License is distributed on an "AS IS" BASIS,
1258fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1358fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan * See the License for the specific language governing permissions and
1458fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan * limitations under the License.
1558fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan */
1658fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan
1758fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuanpackage com.android.contacts.detail;
1858fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan
19226dcdf399e0a637711f9a76b575b7a23d2c7782Katherine Kuanimport android.animation.Animator;
20226dcdf399e0a637711f9a76b575b7a23d2c7782Katherine Kuanimport android.animation.Animator.AnimatorListener;
216c0470e21d8506fb53915df7463634fd47288343Katherine Kuanimport android.animation.ObjectAnimator;
22a3364bc45b73c6a3bb0e0ec4586110f962ddf8c2Nick Pellyimport android.app.Activity;
2358fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuanimport android.app.FragmentManager;
2458fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuanimport android.app.FragmentTransaction;
253bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuanimport android.content.Context;
26ab5387bb8728c34bafcb554830961341f1f9daeaKatherine Kuanimport android.net.Uri;
2758fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuanimport android.os.Bundle;
2858fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuanimport android.support.v4.view.ViewPager;
2958fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuanimport android.support.v4.view.ViewPager.OnPageChangeListener;
303bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuanimport android.view.LayoutInflater;
3158fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuanimport android.view.View;
322f41fe6bcc8d055bf53ad070425552fad57dff21Daniel Lehmannimport android.view.ViewPropertyAnimator;
336c0470e21d8506fb53915df7463634fd47288343Katherine Kuanimport android.view.animation.AnimationUtils;
346c0470e21d8506fb53915df7463634fd47288343Katherine Kuanimport android.widget.AbsListView;
356c0470e21d8506fb53915df7463634fd47288343Katherine Kuanimport android.widget.AbsListView.OnScrollListener;
3658fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan
37e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.NfcHandler;
38e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.R;
39e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.activities.ContactDetailActivity.FragmentKeyListener;
40851222a96b5d68602fb361ea3527101e893f67e3Maurice Chuimport com.android.contacts.model.Contact;
41e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.util.PhoneCapabilityTester;
42e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.util.UriUtils;
43e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.widget.FrameLayoutWithOverlay;
44e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.widget.TransitionAnimationView;
45e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Cheng
4658fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan/**
4758fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan * Determines the layout of the contact card.
4858fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan */
4958fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuanpublic class ContactDetailLayoutController {
5058fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan
51ab5387bb8728c34bafcb554830961341f1f9daeaKatherine Kuan    private static final String KEY_CONTACT_URI = "contactUri";
523bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan    private static final String KEY_CONTACT_HAS_UPDATES = "contactHasUpdates";
5351f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan    private static final String KEY_CURRENT_PAGE_INDEX = "currentPageIndex";
5451f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan
556c0470e21d8506fb53915df7463634fd47288343Katherine Kuan    private static final int TAB_INDEX_DETAIL = 0;
566c0470e21d8506fb53915df7463634fd47288343Katherine Kuan    private static final int TAB_INDEX_UPDATES = 1;
576c0470e21d8506fb53915df7463634fd47288343Katherine Kuan
582f41fe6bcc8d055bf53ad070425552fad57dff21Daniel Lehmann    private final int SINGLE_PANE_FADE_IN_DURATION = 275;
592f41fe6bcc8d055bf53ad070425552fad57dff21Daniel Lehmann
6051f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan    /**
6113f6f26cb8b2f78f0b92dfc1d102222c13217300Maurice Chu     * There are 4 possible layouts for the contact detail screen: TWO_COLUMN,
6213f6f26cb8b2f78f0b92dfc1d102222c13217300Maurice Chu     * VIEW_PAGER_AND_TAB_CAROUSEL, FRAGMENT_CAROUSEL, and TWO_COLUMN_FRAGMENT_CAROUSEL.
6351f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan     */
6413f6f26cb8b2f78f0b92dfc1d102222c13217300Maurice Chu    private interface LayoutMode {
6513f6f26cb8b2f78f0b92dfc1d102222c13217300Maurice Chu        /**
6613f6f26cb8b2f78f0b92dfc1d102222c13217300Maurice Chu         * Tall and wide screen with details and updates shown side-by-side.
6713f6f26cb8b2f78f0b92dfc1d102222c13217300Maurice Chu         */
6813f6f26cb8b2f78f0b92dfc1d102222c13217300Maurice Chu        static final int TWO_COLUMN = 0;
6913f6f26cb8b2f78f0b92dfc1d102222c13217300Maurice Chu        /**
7013f6f26cb8b2f78f0b92dfc1d102222c13217300Maurice Chu         * Tall and narrow screen to allow swipe between the details and updates.
7113f6f26cb8b2f78f0b92dfc1d102222c13217300Maurice Chu         */
7213f6f26cb8b2f78f0b92dfc1d102222c13217300Maurice Chu        static final int VIEW_PAGER_AND_TAB_CAROUSEL = 1;
7313f6f26cb8b2f78f0b92dfc1d102222c13217300Maurice Chu        /**
7413f6f26cb8b2f78f0b92dfc1d102222c13217300Maurice Chu         * Short and wide screen to allow part of the other page to show.
7513f6f26cb8b2f78f0b92dfc1d102222c13217300Maurice Chu         */
7613f6f26cb8b2f78f0b92dfc1d102222c13217300Maurice Chu        static final int FRAGMENT_CAROUSEL = 2;
7713f6f26cb8b2f78f0b92dfc1d102222c13217300Maurice Chu        /**
7813f6f26cb8b2f78f0b92dfc1d102222c13217300Maurice Chu         * Same as FRAGMENT_CAROUSEL (allowing part of the other page to show) except the details
7913f6f26cb8b2f78f0b92dfc1d102222c13217300Maurice Chu         * layout is similar to the details layout in TWO_COLUMN mode.
8013f6f26cb8b2f78f0b92dfc1d102222c13217300Maurice Chu         */
8113f6f26cb8b2f78f0b92dfc1d102222c13217300Maurice Chu        static final int TWO_COLUMN_FRAGMENT_CAROUSEL = 3;
8258fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan    }
8358fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan
84a3364bc45b73c6a3bb0e0ec4586110f962ddf8c2Nick Pelly    private final Activity mActivity;
853bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan    private final LayoutInflater mLayoutInflater;
8658fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan    private final FragmentManager mFragmentManager;
8758fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan
882f41fe6bcc8d055bf53ad070425552fad57dff21Daniel Lehmann    private final View mViewContainer;
892f41fe6bcc8d055bf53ad070425552fad57dff21Daniel Lehmann    private final TransitionAnimationView mTransitionAnimationView;
903bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan    private ContactDetailFragment mDetailFragment;
913bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan    private ContactDetailUpdatesFragment mUpdatesFragment;
923bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan
933bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan    private View mDetailFragmentView;
943bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan    private View mUpdatesFragmentView;
9558fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan
9658fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan    private final ViewPager mViewPager;
973bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan    private ContactDetailViewPagerAdapter mViewPagerAdapter;
986c0470e21d8506fb53915df7463634fd47288343Katherine Kuan    private int mViewPagerState;
9958fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan
1006c0470e21d8506fb53915df7463634fd47288343Katherine Kuan    private final ContactDetailTabCarousel mTabCarousel;
1016c0470e21d8506fb53915df7463634fd47288343Katherine Kuan    private final ContactDetailFragmentCarousel mFragmentCarousel;
10251f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan
1032f41fe6bcc8d055bf53ad070425552fad57dff21Daniel Lehmann    private final ContactDetailFragment.Listener mContactDetailFragmentListener;
10458fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan
105851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu    private Contact mContactData;
106ab5387bb8728c34bafcb554830961341f1f9daeaKatherine Kuan    private Uri mContactUri;
10758fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan
108226dcdf399e0a637711f9a76b575b7a23d2c7782Katherine Kuan    private boolean mTabCarouselIsAnimating;
1092a45e35ab3273c8901d9df3671e51614dc0250c6Daniel Lehmann
1103bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan    private boolean mContactHasUpdates;
11158fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan
11213f6f26cb8b2f78f0b92dfc1d102222c13217300Maurice Chu    private int mLayoutMode;
11358fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan
114a3364bc45b73c6a3bb0e0ec4586110f962ddf8c2Nick Pelly    public ContactDetailLayoutController(Activity activity, Bundle savedState,
1152f41fe6bcc8d055bf53ad070425552fad57dff21Daniel Lehmann            FragmentManager fragmentManager, TransitionAnimationView animationView,
1162f41fe6bcc8d055bf53ad070425552fad57dff21Daniel Lehmann            View viewContainer, ContactDetailFragment.Listener contactDetailFragmentListener) {
1173bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan
11858fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan        if (fragmentManager == null) {
11958fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan            throw new IllegalStateException("Cannot initialize a ContactDetailLayoutController "
12058fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan                    + "without a non-null FragmentManager");
12158fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan        }
12258fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan
123a3364bc45b73c6a3bb0e0ec4586110f962ddf8c2Nick Pelly        mActivity = activity;
124a3364bc45b73c6a3bb0e0ec4586110f962ddf8c2Nick Pelly        mLayoutInflater = (LayoutInflater) activity.getSystemService(
1253bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan                Context.LAYOUT_INFLATER_SERVICE);
12658fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan        mFragmentManager = fragmentManager;
12758fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan        mContactDetailFragmentListener = contactDetailFragmentListener;
12858fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan
1292f41fe6bcc8d055bf53ad070425552fad57dff21Daniel Lehmann        mTransitionAnimationView = animationView;
1302f41fe6bcc8d055bf53ad070425552fad57dff21Daniel Lehmann
1313bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan        // Retrieve views in case this is view pager and carousel mode
1322a45e35ab3273c8901d9df3671e51614dc0250c6Daniel Lehmann        mViewContainer = viewContainer;
1332f41fe6bcc8d055bf53ad070425552fad57dff21Daniel Lehmann
1343bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan        mViewPager = (ViewPager) viewContainer.findViewById(R.id.pager);
1353bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan        mTabCarousel = (ContactDetailTabCarousel) viewContainer.findViewById(R.id.tab_carousel);
1363bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan
13751f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan        // Retrieve view in case this is in fragment carousel mode
13851f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan        mFragmentCarousel = (ContactDetailFragmentCarousel) viewContainer.findViewById(
13951f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan                R.id.fragment_carousel);
14051f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan
14151f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan        // Retrieve container views in case they are already in the XML layout
1423bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan        mDetailFragmentView = viewContainer.findViewById(R.id.about_fragment_container);
1433bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan        mUpdatesFragmentView = viewContainer.findViewById(R.id.updates_fragment_container);
1443bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan
14551f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan        // Determine the layout mode based on the presence of certain views in the layout XML.
14651f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan        if (mViewPager != null) {
14751f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan            mLayoutMode = LayoutMode.VIEW_PAGER_AND_TAB_CAROUSEL;
148187c8167d77687fbc04237c9ac1e87564b2d5f33Josh Gargus        } else if (mFragmentCarousel != null) {
14913f6f26cb8b2f78f0b92dfc1d102222c13217300Maurice Chu            if (PhoneCapabilityTester.isUsingTwoPanes(mActivity)) {
15013f6f26cb8b2f78f0b92dfc1d102222c13217300Maurice Chu                mLayoutMode = LayoutMode.TWO_COLUMN_FRAGMENT_CAROUSEL;
15113f6f26cb8b2f78f0b92dfc1d102222c13217300Maurice Chu            } else {
15213f6f26cb8b2f78f0b92dfc1d102222c13217300Maurice Chu                mLayoutMode = LayoutMode.FRAGMENT_CAROUSEL;
15313f6f26cb8b2f78f0b92dfc1d102222c13217300Maurice Chu            }
15451f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan        } else {
155187c8167d77687fbc04237c9ac1e87564b2d5f33Josh Gargus            mLayoutMode = LayoutMode.TWO_COLUMN;
15651f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan        }
15758fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan
1583bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan        initialize(savedState);
15958fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan    }
16058fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan
1613bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan    private void initialize(Bundle savedState) {
1623bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan        boolean fragmentsAddedToFragmentManager = true;
1633bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan        mDetailFragment = (ContactDetailFragment) mFragmentManager.findFragmentByTag(
1643bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan                ContactDetailViewPagerAdapter.ABOUT_FRAGMENT_TAG);
1653bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan        mUpdatesFragment = (ContactDetailUpdatesFragment) mFragmentManager.findFragmentByTag(
166187c8167d77687fbc04237c9ac1e87564b2d5f33Josh Gargus                ContactDetailViewPagerAdapter.UPDATES_FRAGMENT_TAG);
1673bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan
1683bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan        // If the detail fragment was found in the {@link FragmentManager} then we don't need to add
1693bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan        // it again. Otherwise, create the fragments dynamically and remember to add them to the
1703bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan        // {@link FragmentManager}.
1713bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan        if (mDetailFragment == null) {
1723bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan            mDetailFragment = new ContactDetailFragment();
1733bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan            mUpdatesFragment = new ContactDetailUpdatesFragment();
1743bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan            fragmentsAddedToFragmentManager = false;
1753bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan        }
1763bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan
1773bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan        mDetailFragment.setListener(mContactDetailFragmentListener);
178a3364bc45b73c6a3bb0e0ec4586110f962ddf8c2Nick Pelly        NfcHandler.register(mActivity, mDetailFragment);
17958fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan
18051f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan        // Read from savedState if possible
18151f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan        int currentPageIndex = 0;
18251f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan        if (savedState != null) {
183ab5387bb8728c34bafcb554830961341f1f9daeaKatherine Kuan            mContactUri = savedState.getParcelable(KEY_CONTACT_URI);
18451f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan            mContactHasUpdates = savedState.getBoolean(KEY_CONTACT_HAS_UPDATES);
18551f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan            currentPageIndex = savedState.getInt(KEY_CURRENT_PAGE_INDEX, 0);
18651f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan        }
18751f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan
1883bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan        switch (mLayoutMode) {
18913f6f26cb8b2f78f0b92dfc1d102222c13217300Maurice Chu            case LayoutMode.VIEW_PAGER_AND_TAB_CAROUSEL: {
1903bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan                // Inflate 2 view containers to pass in as children to the {@link ViewPager},
1913bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan                // which will in turn be the parents to the mDetailFragment and mUpdatesFragment
1923bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan                // since the fragments must have the same parent view IDs in both landscape and
1933bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan                // portrait layouts.
1946c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                mDetailFragmentView = mLayoutInflater.inflate(
1953bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan                        R.layout.contact_detail_about_fragment_container, mViewPager, false);
1966c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                mUpdatesFragmentView = mLayoutInflater.inflate(
1973bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan                        R.layout.contact_detail_updates_fragment_container, mViewPager, false);
1983bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan
1993bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan                mViewPagerAdapter = new ContactDetailViewPagerAdapter();
2006c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                mViewPagerAdapter.setAboutFragmentView(mDetailFragmentView);
2016c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                mViewPagerAdapter.setUpdatesFragmentView(mUpdatesFragmentView);
2023bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan
2036c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                mViewPager.addView(mDetailFragmentView);
2046c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                mViewPager.addView(mUpdatesFragmentView);
2053bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan                mViewPager.setAdapter(mViewPagerAdapter);
2063bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan                mViewPager.setOnPageChangeListener(mOnPageChangeListener);
2073bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan
2083bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan                if (!fragmentsAddedToFragmentManager) {
20951f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan                    FragmentTransaction transaction = mFragmentManager.beginTransaction();
2103bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan                    transaction.add(R.id.about_fragment_container, mDetailFragment,
2113bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan                            ContactDetailViewPagerAdapter.ABOUT_FRAGMENT_TAG);
2123bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan                    transaction.add(R.id.updates_fragment_container, mUpdatesFragment,
213187c8167d77687fbc04237c9ac1e87564b2d5f33Josh Gargus                            ContactDetailViewPagerAdapter.UPDATES_FRAGMENT_TAG);
2144b25da79091157935042d2942a8961ceba92166fMinh Pham                    transaction.commitAllowingStateLoss();
21551f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan                    mFragmentManager.executePendingTransactions();
2163bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan                }
21751f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan
21851f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan                mTabCarousel.setListener(mTabCarouselListener);
219226dcdf399e0a637711f9a76b575b7a23d2c7782Katherine Kuan                mTabCarousel.restoreCurrentTab(currentPageIndex);
2206c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                mDetailFragment.setVerticalScrollListener(
2216c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                        new VerticalScrollListener(TAB_INDEX_DETAIL));
2226c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                mUpdatesFragment.setVerticalScrollListener(
2236c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                        new VerticalScrollListener(TAB_INDEX_UPDATES));
22451f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan                mViewPager.setCurrentItem(currentPageIndex);
2253bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan                break;
2263bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan            }
22713f6f26cb8b2f78f0b92dfc1d102222c13217300Maurice Chu            case LayoutMode.TWO_COLUMN: {
2283bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan                if (!fragmentsAddedToFragmentManager) {
2293bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan                    FragmentTransaction transaction = mFragmentManager.beginTransaction();
2303bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan                    transaction.add(R.id.about_fragment_container, mDetailFragment,
2313bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan                            ContactDetailViewPagerAdapter.ABOUT_FRAGMENT_TAG);
2323bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan                    transaction.add(R.id.updates_fragment_container, mUpdatesFragment,
233187c8167d77687fbc04237c9ac1e87564b2d5f33Josh Gargus                            ContactDetailViewPagerAdapter.UPDATES_FRAGMENT_TAG);
2344b25da79091157935042d2942a8961ceba92166fMinh Pham                    transaction.commitAllowingStateLoss();
2353bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan                    mFragmentManager.executePendingTransactions();
2363bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan                }
23751f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan                break;
23851f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan            }
23913f6f26cb8b2f78f0b92dfc1d102222c13217300Maurice Chu            case LayoutMode.FRAGMENT_CAROUSEL:
24013f6f26cb8b2f78f0b92dfc1d102222c13217300Maurice Chu            case LayoutMode.TWO_COLUMN_FRAGMENT_CAROUSEL: {
24151f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan                // Add the fragments to the fragment containers in the carousel using a
24251f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan                // {@link FragmentTransaction} if they haven't already been added to the
24351f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan                // {@link FragmentManager}.
24451f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan                if (!fragmentsAddedToFragmentManager) {
24551f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan                    FragmentTransaction transaction = mFragmentManager.beginTransaction();
24651f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan                    transaction.add(R.id.about_fragment_container, mDetailFragment,
24751f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan                            ContactDetailViewPagerAdapter.ABOUT_FRAGMENT_TAG);
24851f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan                    transaction.add(R.id.updates_fragment_container, mUpdatesFragment,
249187c8167d77687fbc04237c9ac1e87564b2d5f33Josh Gargus                            ContactDetailViewPagerAdapter.UPDATES_FRAGMENT_TAG);
2504b25da79091157935042d2942a8961ceba92166fMinh Pham                    transaction.commitAllowingStateLoss();
25151f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan                    mFragmentManager.executePendingTransactions();
25251f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan                }
25351f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan
2547edad9dd95a411cc5ed69815e5f0be8a5d1e8b19Josh Gargus                mFragmentCarousel.setFragmentViews(
2557edad9dd95a411cc5ed69815e5f0be8a5d1e8b19Josh Gargus                        (FrameLayoutWithOverlay) mDetailFragmentView,
2567edad9dd95a411cc5ed69815e5f0be8a5d1e8b19Josh Gargus                        (FrameLayoutWithOverlay) mUpdatesFragmentView);
257ccf3b6bb9cba613eb31163c7ab97be71307234d1Katherine Kuan                mFragmentCarousel.setCurrentPage(currentPageIndex);
2587edad9dd95a411cc5ed69815e5f0be8a5d1e8b19Josh Gargus
25951f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan                break;
26058fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan            }
26158fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan        }
26258fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan
26351f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan        // Setup the layout if we already have a saved state
2643bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan        if (savedState != null) {
26551f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan            if (mContactHasUpdates) {
2662a45e35ab3273c8901d9df3671e51614dc0250c6Daniel Lehmann                showContactWithUpdates(false);
2673bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan            } else {
2683bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan                showContactWithoutUpdates();
2693bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan            }
2703bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan        }
27158fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan    }
27258fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan
273851222a96b5d68602fb361ea3527101e893f67e3Maurice Chu    public void setContactData(Contact data) {
2742f41fe6bcc8d055bf53ad070425552fad57dff21Daniel Lehmann        final boolean contactWasLoaded;
2752f41fe6bcc8d055bf53ad070425552fad57dff21Daniel Lehmann        final boolean contactHadUpdates;
276cf3d9f04955a8ec3cb405b8a4ddcaddcece2a245Daniel Lehmann        final boolean isDifferentContact;
2772a45e35ab3273c8901d9df3671e51614dc0250c6Daniel Lehmann        if (mContactData == null) {
2782f41fe6bcc8d055bf53ad070425552fad57dff21Daniel Lehmann            contactHadUpdates = false;
2792f41fe6bcc8d055bf53ad070425552fad57dff21Daniel Lehmann            contactWasLoaded = false;
280cf3d9f04955a8ec3cb405b8a4ddcaddcece2a245Daniel Lehmann            isDifferentContact = true;
2812a45e35ab3273c8901d9df3671e51614dc0250c6Daniel Lehmann        } else {
2822a45e35ab3273c8901d9df3671e51614dc0250c6Daniel Lehmann            contactHadUpdates = mContactHasUpdates;
2832f41fe6bcc8d055bf53ad070425552fad57dff21Daniel Lehmann            contactWasLoaded = true;
284cf3d9f04955a8ec3cb405b8a4ddcaddcece2a245Daniel Lehmann            isDifferentContact =
285cf3d9f04955a8ec3cb405b8a4ddcaddcece2a245Daniel Lehmann                    !UriUtils.areEqual(mContactData.getLookupUri(), data.getLookupUri());
2862a45e35ab3273c8901d9df3671e51614dc0250c6Daniel Lehmann        }
28758fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan        mContactData = data;
2883bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan        mContactHasUpdates = !data.getStreamItems().isEmpty();
2892f41fe6bcc8d055bf53ad070425552fad57dff21Daniel Lehmann
2902f41fe6bcc8d055bf53ad070425552fad57dff21Daniel Lehmann        if (PhoneCapabilityTester.isUsingTwoPanes(mActivity)) {
2912f41fe6bcc8d055bf53ad070425552fad57dff21Daniel Lehmann            // Tablet: If we already showed data before, we want to cross-fade from screen to screen
292cf3d9f04955a8ec3cb405b8a4ddcaddcece2a245Daniel Lehmann            if (contactWasLoaded && mTransitionAnimationView != null && isDifferentContact) {
2936e607d54ce08ebcc78d94963646a42605697f132Maurice Chu                mTransitionAnimationView.startMaskTransition(mContactData == null);
2942f41fe6bcc8d055bf53ad070425552fad57dff21Daniel Lehmann            }
2952f41fe6bcc8d055bf53ad070425552fad57dff21Daniel Lehmann        } else {
2962f41fe6bcc8d055bf53ad070425552fad57dff21Daniel Lehmann            // Small screen: We are on our own screen. Fade the data in, but only the first time
2972f41fe6bcc8d055bf53ad070425552fad57dff21Daniel Lehmann            if (!contactWasLoaded) {
2982f41fe6bcc8d055bf53ad070425552fad57dff21Daniel Lehmann                mViewContainer.setAlpha(0.0f);
2992f41fe6bcc8d055bf53ad070425552fad57dff21Daniel Lehmann                final ViewPropertyAnimator animator = mViewContainer.animate();
3002f41fe6bcc8d055bf53ad070425552fad57dff21Daniel Lehmann                animator.alpha(1.0f);
3012f41fe6bcc8d055bf53ad070425552fad57dff21Daniel Lehmann                animator.setDuration(SINGLE_PANE_FADE_IN_DURATION);
3022f41fe6bcc8d055bf53ad070425552fad57dff21Daniel Lehmann            }
3032f41fe6bcc8d055bf53ad070425552fad57dff21Daniel Lehmann        }
3042f41fe6bcc8d055bf53ad070425552fad57dff21Daniel Lehmann
3053bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan        if (mContactHasUpdates) {
3062a45e35ab3273c8901d9df3671e51614dc0250c6Daniel Lehmann            showContactWithUpdates(
3072f41fe6bcc8d055bf53ad070425552fad57dff21Daniel Lehmann                    contactWasLoaded && contactHadUpdates == false);
30858fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan        } else {
30958fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan            showContactWithoutUpdates();
31058fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan        }
31158fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan    }
31258fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan
313050c3893fadaf6d02951a3fe29684f4cd94fa9c9Daisuke Miyakawa    public void showEmptyState() {
314050c3893fadaf6d02951a3fe29684f4cd94fa9c9Daisuke Miyakawa        switch (mLayoutMode) {
31513f6f26cb8b2f78f0b92dfc1d102222c13217300Maurice Chu            case LayoutMode.FRAGMENT_CAROUSEL: {
316226dcdf399e0a637711f9a76b575b7a23d2c7782Katherine Kuan                mFragmentCarousel.setCurrentPage(0);
317050c3893fadaf6d02951a3fe29684f4cd94fa9c9Daisuke Miyakawa                mFragmentCarousel.enableSwipe(false);
318050c3893fadaf6d02951a3fe29684f4cd94fa9c9Daisuke Miyakawa                mDetailFragment.showEmptyState();
319050c3893fadaf6d02951a3fe29684f4cd94fa9c9Daisuke Miyakawa                break;
320050c3893fadaf6d02951a3fe29684f4cd94fa9c9Daisuke Miyakawa            }
32113f6f26cb8b2f78f0b92dfc1d102222c13217300Maurice Chu            case LayoutMode.TWO_COLUMN: {
32213f6f26cb8b2f78f0b92dfc1d102222c13217300Maurice Chu                mDetailFragment.setShowStaticPhoto(false);
32313f6f26cb8b2f78f0b92dfc1d102222c13217300Maurice Chu                mUpdatesFragmentView.setVisibility(View.GONE);
32413f6f26cb8b2f78f0b92dfc1d102222c13217300Maurice Chu                mDetailFragment.showEmptyState();
32513f6f26cb8b2f78f0b92dfc1d102222c13217300Maurice Chu                break;
32613f6f26cb8b2f78f0b92dfc1d102222c13217300Maurice Chu            }
32713f6f26cb8b2f78f0b92dfc1d102222c13217300Maurice Chu            case LayoutMode.TWO_COLUMN_FRAGMENT_CAROUSEL: {
32813f6f26cb8b2f78f0b92dfc1d102222c13217300Maurice Chu                mFragmentCarousel.setCurrentPage(0);
32913f6f26cb8b2f78f0b92dfc1d102222c13217300Maurice Chu                mFragmentCarousel.enableSwipe(false);
330050c3893fadaf6d02951a3fe29684f4cd94fa9c9Daisuke Miyakawa                mDetailFragment.setShowStaticPhoto(false);
331050c3893fadaf6d02951a3fe29684f4cd94fa9c9Daisuke Miyakawa                mUpdatesFragmentView.setVisibility(View.GONE);
332050c3893fadaf6d02951a3fe29684f4cd94fa9c9Daisuke Miyakawa                mDetailFragment.showEmptyState();
333050c3893fadaf6d02951a3fe29684f4cd94fa9c9Daisuke Miyakawa                break;
334050c3893fadaf6d02951a3fe29684f4cd94fa9c9Daisuke Miyakawa            }
33513f6f26cb8b2f78f0b92dfc1d102222c13217300Maurice Chu            case LayoutMode.VIEW_PAGER_AND_TAB_CAROUSEL: {
336050c3893fadaf6d02951a3fe29684f4cd94fa9c9Daisuke Miyakawa                mDetailFragment.setShowStaticPhoto(false);
337050c3893fadaf6d02951a3fe29684f4cd94fa9c9Daisuke Miyakawa                mDetailFragment.showEmptyState();
338050c3893fadaf6d02951a3fe29684f4cd94fa9c9Daisuke Miyakawa                mTabCarousel.loadData(null);
339050c3893fadaf6d02951a3fe29684f4cd94fa9c9Daisuke Miyakawa                mTabCarousel.setVisibility(View.GONE);
340050c3893fadaf6d02951a3fe29684f4cd94fa9c9Daisuke Miyakawa                mViewPagerAdapter.enableSwipe(false);
341050c3893fadaf6d02951a3fe29684f4cd94fa9c9Daisuke Miyakawa                mViewPager.setCurrentItem(0);
342050c3893fadaf6d02951a3fe29684f4cd94fa9c9Daisuke Miyakawa                break;
343050c3893fadaf6d02951a3fe29684f4cd94fa9c9Daisuke Miyakawa            }
344050c3893fadaf6d02951a3fe29684f4cd94fa9c9Daisuke Miyakawa            default:
345050c3893fadaf6d02951a3fe29684f4cd94fa9c9Daisuke Miyakawa                throw new IllegalStateException("Invalid LayoutMode " + mLayoutMode);
346050c3893fadaf6d02951a3fe29684f4cd94fa9c9Daisuke Miyakawa        }
347050c3893fadaf6d02951a3fe29684f4cd94fa9c9Daisuke Miyakawa    }
348050c3893fadaf6d02951a3fe29684f4cd94fa9c9Daisuke Miyakawa
34951f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan    /**
350ab5387bb8728c34bafcb554830961341f1f9daeaKatherine Kuan     * Setup the layout for the contact with updates.
351ab5387bb8728c34bafcb554830961341f1f9daeaKatherine Kuan     * TODO: Clean up this method so it's easier to understand.
35251f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan     */
3532a45e35ab3273c8901d9df3671e51614dc0250c6Daniel Lehmann    private void showContactWithUpdates(boolean animateStateChange) {
35451f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan        if (mContactData == null) {
35551f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan            return;
35651f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan        }
357ab5387bb8728c34bafcb554830961341f1f9daeaKatherine Kuan
358ab5387bb8728c34bafcb554830961341f1f9daeaKatherine Kuan        Uri previousContactUri = mContactUri;
359ab5387bb8728c34bafcb554830961341f1f9daeaKatherine Kuan        mContactUri = mContactData.getLookupUri();
360ab5387bb8728c34bafcb554830961341f1f9daeaKatherine Kuan        boolean isDifferentContact = !UriUtils.areEqual(previousContactUri, mContactUri);
361ab5387bb8728c34bafcb554830961341f1f9daeaKatherine Kuan
36258fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan        switch (mLayoutMode) {
36313f6f26cb8b2f78f0b92dfc1d102222c13217300Maurice Chu            case LayoutMode.TWO_COLUMN: {
364cf3d9f04955a8ec3cb405b8a4ddcaddcece2a245Daniel Lehmann                if (!isDifferentContact && animateStateChange) {
365cf3d9f04955a8ec3cb405b8a4ddcaddcece2a245Daniel Lehmann                    // This is screen is very hard to animate properly, because there is such a hard
366cf3d9f04955a8ec3cb405b8a4ddcaddcece2a245Daniel Lehmann                    // cut from the regular version. A proper animation would have to reflow text
367cf3d9f04955a8ec3cb405b8a4ddcaddcece2a245Daniel Lehmann                    // and move things around. Doing a simple cross-fade instead.
3686e607d54ce08ebcc78d94963646a42605697f132Maurice Chu                    mTransitionAnimationView.startMaskTransition(false);
369cf3d9f04955a8ec3cb405b8a4ddcaddcece2a245Daniel Lehmann                }
3702a45e35ab3273c8901d9df3671e51614dc0250c6Daniel Lehmann
3719bd85b3ecd9129feb2f317784a3d8023aa211d42Katherine Kuan                // Set the contact data (hide the static photo because the photo will already be in
3729bd85b3ecd9129feb2f317784a3d8023aa211d42Katherine Kuan                // the header that scrolls with contact details).
3733bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan                mDetailFragment.setShowStaticPhoto(false);
3743bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan                // Show the updates fragment
3753bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan                mUpdatesFragmentView.setVisibility(View.VISIBLE);
37658fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan                break;
37758fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan            }
37813f6f26cb8b2f78f0b92dfc1d102222c13217300Maurice Chu            case LayoutMode.VIEW_PAGER_AND_TAB_CAROUSEL: {
3796c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                // Update and show the tab carousel (also restore its last saved position)
38058fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan                mTabCarousel.loadData(mContactData);
3816c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                mTabCarousel.restoreYCoordinate();
38258fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan                mTabCarousel.setVisibility(View.VISIBLE);
38351f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan                // Update ViewPager to allow swipe between all the fragments (to see updates)
38451f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan                mViewPagerAdapter.enableSwipe(true);
385ab5387bb8728c34bafcb554830961341f1f9daeaKatherine Kuan                // If this is a different contact than before, then reset some views.
386ab5387bb8728c34bafcb554830961341f1f9daeaKatherine Kuan                if (isDifferentContact) {
387ab5387bb8728c34bafcb554830961341f1f9daeaKatherine Kuan                    resetViewPager();
388ab5387bb8728c34bafcb554830961341f1f9daeaKatherine Kuan                    resetTabCarousel();
389ab5387bb8728c34bafcb554830961341f1f9daeaKatherine Kuan                }
3902a45e35ab3273c8901d9df3671e51614dc0250c6Daniel Lehmann                if (!isDifferentContact && animateStateChange) {
3912a45e35ab3273c8901d9df3671e51614dc0250c6Daniel Lehmann                    mTabCarousel.animateAppear(mViewContainer.getWidth(),
3922a45e35ab3273c8901d9df3671e51614dc0250c6Daniel Lehmann                            mDetailFragment.getFirstListItemOffset());
3932a45e35ab3273c8901d9df3671e51614dc0250c6Daniel Lehmann                }
39451f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan                break;
39551f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan            }
39613f6f26cb8b2f78f0b92dfc1d102222c13217300Maurice Chu            case LayoutMode.FRAGMENT_CAROUSEL: {
39751f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan                // Allow swiping between all fragments
39851f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan                mFragmentCarousel.enableSwipe(true);
3992a45e35ab3273c8901d9df3671e51614dc0250c6Daniel Lehmann                if (!isDifferentContact && animateStateChange) {
4002a45e35ab3273c8901d9df3671e51614dc0250c6Daniel Lehmann                    mFragmentCarousel.animateAppear();
4012a45e35ab3273c8901d9df3671e51614dc0250c6Daniel Lehmann                }
40258fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan                break;
40358fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan            }
40413f6f26cb8b2f78f0b92dfc1d102222c13217300Maurice Chu            case LayoutMode.TWO_COLUMN_FRAGMENT_CAROUSEL: {
40513f6f26cb8b2f78f0b92dfc1d102222c13217300Maurice Chu                // Allow swiping between all fragments
40613f6f26cb8b2f78f0b92dfc1d102222c13217300Maurice Chu                mFragmentCarousel.enableSwipe(true);
4070b398b3d178d1fe8fd3ebfb9396e36d1228b53c6Maurice Chu                if (isDifferentContact) {
4080b398b3d178d1fe8fd3ebfb9396e36d1228b53c6Maurice Chu                    mFragmentCarousel.reset();
4090b398b3d178d1fe8fd3ebfb9396e36d1228b53c6Maurice Chu                }
41013f6f26cb8b2f78f0b92dfc1d102222c13217300Maurice Chu                if (!isDifferentContact && animateStateChange) {
41113f6f26cb8b2f78f0b92dfc1d102222c13217300Maurice Chu                    mFragmentCarousel.animateAppear();
41213f6f26cb8b2f78f0b92dfc1d102222c13217300Maurice Chu                }
41313f6f26cb8b2f78f0b92dfc1d102222c13217300Maurice Chu                mDetailFragment.setShowStaticPhoto(false);
41413f6f26cb8b2f78f0b92dfc1d102222c13217300Maurice Chu                break;
41513f6f26cb8b2f78f0b92dfc1d102222c13217300Maurice Chu            }
41658fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan            default:
41758fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan                throw new IllegalStateException("Invalid LayoutMode " + mLayoutMode);
41858fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan        }
41958fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan
420ab5387bb8728c34bafcb554830961341f1f9daeaKatherine Kuan        if (isDifferentContact) {
421ab5387bb8728c34bafcb554830961341f1f9daeaKatherine Kuan            resetFragments();
422ab5387bb8728c34bafcb554830961341f1f9daeaKatherine Kuan        }
423ab5387bb8728c34bafcb554830961341f1f9daeaKatherine Kuan
424ab5387bb8728c34bafcb554830961341f1f9daeaKatherine Kuan        mDetailFragment.setData(mContactUri, mContactData);
425ab5387bb8728c34bafcb554830961341f1f9daeaKatherine Kuan        mUpdatesFragment.setData(mContactUri, mContactData);
42658fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan    }
42758fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan
428ab5387bb8728c34bafcb554830961341f1f9daeaKatherine Kuan    /**
429ab5387bb8728c34bafcb554830961341f1f9daeaKatherine Kuan     * Setup the layout for the contact without updates.
430ab5387bb8728c34bafcb554830961341f1f9daeaKatherine Kuan     * TODO: Clean up this method so it's easier to understand.
431ab5387bb8728c34bafcb554830961341f1f9daeaKatherine Kuan     */
43258fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan    private void showContactWithoutUpdates() {
43351f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan        if (mContactData == null) {
43451f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan            return;
43551f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan        }
436ab5387bb8728c34bafcb554830961341f1f9daeaKatherine Kuan
437ab5387bb8728c34bafcb554830961341f1f9daeaKatherine Kuan        Uri previousContactUri = mContactUri;
438ab5387bb8728c34bafcb554830961341f1f9daeaKatherine Kuan        mContactUri = mContactData.getLookupUri();
439ab5387bb8728c34bafcb554830961341f1f9daeaKatherine Kuan        boolean isDifferentContact = !UriUtils.areEqual(previousContactUri, mContactUri);
440ab5387bb8728c34bafcb554830961341f1f9daeaKatherine Kuan
44158fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan        switch (mLayoutMode) {
44213f6f26cb8b2f78f0b92dfc1d102222c13217300Maurice Chu            case LayoutMode.TWO_COLUMN:
4433bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan                // Show the static photo which is next to the list of scrolling contact details
4443bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan                mDetailFragment.setShowStaticPhoto(true);
4453bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan                // Hide the updates fragment
4463bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan                mUpdatesFragmentView.setVisibility(View.GONE);
44758fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan                break;
44813f6f26cb8b2f78f0b92dfc1d102222c13217300Maurice Chu            case LayoutMode.VIEW_PAGER_AND_TAB_CAROUSEL:
4493bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan                // Hide the tab carousel
45058fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan                mTabCarousel.setVisibility(View.GONE);
45151f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan                // Update ViewPager to disable swipe so that it only shows the detail fragment
45251f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan                // and switch to the detail fragment
45351f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan                mViewPagerAdapter.enableSwipe(false);
454253b3366bbb1b6c935ccaf7610511f97569ad956Katherine Kuan                mViewPager.setCurrentItem(0, false /* smooth transition */);
45558fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan                break;
45613f6f26cb8b2f78f0b92dfc1d102222c13217300Maurice Chu            case LayoutMode.FRAGMENT_CAROUSEL:
45751f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan                // Disable swipe so only the detail fragment shows
458226dcdf399e0a637711f9a76b575b7a23d2c7782Katherine Kuan                mFragmentCarousel.setCurrentPage(0);
45951f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan                mFragmentCarousel.enableSwipe(false);
46051f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan                break;
46113f6f26cb8b2f78f0b92dfc1d102222c13217300Maurice Chu            case LayoutMode.TWO_COLUMN_FRAGMENT_CAROUSEL:
46213f6f26cb8b2f78f0b92dfc1d102222c13217300Maurice Chu                mFragmentCarousel.setCurrentPage(0);
46313f6f26cb8b2f78f0b92dfc1d102222c13217300Maurice Chu                mFragmentCarousel.enableSwipe(false);
46413f6f26cb8b2f78f0b92dfc1d102222c13217300Maurice Chu                mDetailFragment.setShowStaticPhoto(true);
46513f6f26cb8b2f78f0b92dfc1d102222c13217300Maurice Chu                break;
46658fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan            default:
46758fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan                throw new IllegalStateException("Invalid LayoutMode " + mLayoutMode);
46858fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan        }
46958fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan
470ab5387bb8728c34bafcb554830961341f1f9daeaKatherine Kuan        if (isDifferentContact) {
471ab5387bb8728c34bafcb554830961341f1f9daeaKatherine Kuan            resetFragments();
472ab5387bb8728c34bafcb554830961341f1f9daeaKatherine Kuan        }
473ab5387bb8728c34bafcb554830961341f1f9daeaKatherine Kuan
474ab5387bb8728c34bafcb554830961341f1f9daeaKatherine Kuan        mDetailFragment.setData(mContactUri, mContactData);
475ab5387bb8728c34bafcb554830961341f1f9daeaKatherine Kuan    }
476ab5387bb8728c34bafcb554830961341f1f9daeaKatherine Kuan
477ab5387bb8728c34bafcb554830961341f1f9daeaKatherine Kuan    private void resetTabCarousel() {
478ab5387bb8728c34bafcb554830961341f1f9daeaKatherine Kuan        mTabCarousel.reset();
479ab5387bb8728c34bafcb554830961341f1f9daeaKatherine Kuan    }
480ab5387bb8728c34bafcb554830961341f1f9daeaKatherine Kuan
481ab5387bb8728c34bafcb554830961341f1f9daeaKatherine Kuan    private void resetViewPager() {
482ab5387bb8728c34bafcb554830961341f1f9daeaKatherine Kuan        mViewPager.setCurrentItem(0, false /* smooth transition */);
483ab5387bb8728c34bafcb554830961341f1f9daeaKatherine Kuan    }
484ab5387bb8728c34bafcb554830961341f1f9daeaKatherine Kuan
485ab5387bb8728c34bafcb554830961341f1f9daeaKatherine Kuan    private void resetFragments() {
486ab5387bb8728c34bafcb554830961341f1f9daeaKatherine Kuan        mDetailFragment.resetAdapter();
487ab5387bb8728c34bafcb554830961341f1f9daeaKatherine Kuan        mUpdatesFragment.resetAdapter();
48851f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan    }
48951f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan
49051f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan    public FragmentKeyListener getCurrentPage() {
49151f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan        switch (getCurrentPageIndex()) {
49251f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan            case 0:
49351f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan                return mDetailFragment;
49451f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan            case 1:
49551f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan                return mUpdatesFragment;
49651f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan            default:
49751f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan                throw new IllegalStateException("Invalid current item for ViewPager");
49851f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan        }
49951f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan    }
50051f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan
50151f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan    private int getCurrentPageIndex() {
50251f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan        // If the contact has social updates, then retrieve the current page based on the
50351f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan        // {@link ViewPager} or fragment carousel.
50451f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan        if (mContactHasUpdates) {
50551f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan            if (mViewPager != null) {
50651f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan                return mViewPager.getCurrentItem();
50751f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan            } else if (mFragmentCarousel != null) {
50851f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan                return mFragmentCarousel.getCurrentPage();
50951f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan            }
51058fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan        }
51151f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan        // Otherwise return the default page (detail fragment).
51251f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan        return 0;
51358fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan    }
51458fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan
5153bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan    public void onSaveInstanceState(Bundle outState) {
516ab5387bb8728c34bafcb554830961341f1f9daeaKatherine Kuan        outState.putParcelable(KEY_CONTACT_URI, mContactUri);
5173bbd9a0c3e85262365376ae212f9a8bc521e37d4Katherine Kuan        outState.putBoolean(KEY_CONTACT_HAS_UPDATES, mContactHasUpdates);
51851f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan        outState.putInt(KEY_CURRENT_PAGE_INDEX, getCurrentPageIndex());
51958fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan    }
52058fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan
5216c0470e21d8506fb53915df7463634fd47288343Katherine Kuan    private final OnPageChangeListener mOnPageChangeListener = new OnPageChangeListener() {
5226c0470e21d8506fb53915df7463634fd47288343Katherine Kuan
5236c0470e21d8506fb53915df7463634fd47288343Katherine Kuan        private ObjectAnimator mTabCarouselAnimator;
52458fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan
52558fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan        @Override
52658fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
52758fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan            // The user is horizontally dragging the {@link ViewPager}, so send
52858fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan            // these scroll changes to the tab carousel. Ignore these events though if the carousel
52958fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan            // is actually controlling the {@link ViewPager} scrolls because it will already be
53058fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan            // in the correct position.
53184edfd9a76657a653491faac53b5976adf9fd2cbJosh Gargus            if (mViewPager.isFakeDragging()) return;
53284edfd9a76657a653491faac53b5976adf9fd2cbJosh Gargus
53358fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan            int x = (int) ((position + positionOffset) *
53458fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan                    mTabCarousel.getAllowedHorizontalScrollLength());
53558fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan            mTabCarousel.scrollTo(x, 0);
53658fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan        }
53758fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan
53858fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan        @Override
53958fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan        public void onPageSelected(int position) {
5406c0470e21d8506fb53915df7463634fd47288343Katherine Kuan            // Since the {@link ViewPager} has committed to a new page now (but may not have
5416c0470e21d8506fb53915df7463634fd47288343Katherine Kuan            // finished scrolling yet), update the tab selection in the carousel.
54258fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan            mTabCarousel.setCurrentTab(position);
54358fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan        }
54458fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan
54558fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan        @Override
5466c0470e21d8506fb53915df7463634fd47288343Katherine Kuan        public void onPageScrollStateChanged(int state) {
5476c0470e21d8506fb53915df7463634fd47288343Katherine Kuan            if (mViewPagerState == ViewPager.SCROLL_STATE_IDLE) {
5486c0470e21d8506fb53915df7463634fd47288343Katherine Kuan
5496c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                // If we are leaving the IDLE state, we are starting a swipe.
5506c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                // First cancel any pending animations on the tab carousel.
5516c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                cancelTabCarouselAnimator();
5526c0470e21d8506fb53915df7463634fd47288343Katherine Kuan
5536c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                // Sync the two lists because the list on the other page will start to show as
5546c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                // we swipe over more.
5556c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                syncScrollStateBetweenLists(mViewPager.getCurrentItem());
5566c0470e21d8506fb53915df7463634fd47288343Katherine Kuan
5576c0470e21d8506fb53915df7463634fd47288343Katherine Kuan            } else if (state == ViewPager.SCROLL_STATE_IDLE) {
5586c0470e21d8506fb53915df7463634fd47288343Katherine Kuan
5596c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                // Otherwise if the {@link ViewPager} is idle now, a page has been selected and
5606c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                // scrolled into place. Perform an animation of the tab carousel is needed.
5616c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                int currentPageIndex = mViewPager.getCurrentItem();
5626c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                int tabCarouselOffset = (int) mTabCarousel.getY();
5636c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                boolean shouldAnimateTabCarousel;
5646c0470e21d8506fb53915df7463634fd47288343Katherine Kuan
5656c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                // Find the offset position of the first item in the list of the current page.
5666c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                int listOffset = getOffsetOfFirstItemInList(currentPageIndex);
5676c0470e21d8506fb53915df7463634fd47288343Katherine Kuan
5686c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                // If the list was able to successfully offset by the tab carousel amount, then
5696c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                // log this as the new Y coordinate for that page, and no animation is needed.
5706c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                if (listOffset == tabCarouselOffset) {
5716c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                    mTabCarousel.storeYCoordinate(currentPageIndex, tabCarouselOffset);
5726c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                    shouldAnimateTabCarousel = false;
5736c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                } else if (listOffset == Integer.MIN_VALUE) {
5746c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                    // If the offset of the first item in the list is unknown (i.e. the item
5756c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                    // is no longer visible on screen) then just animate the tab carousel to the
5766c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                    // previously logged position.
5776c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                    shouldAnimateTabCarousel = true;
5786c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                } else if (Math.abs(listOffset) < Math.abs(tabCarouselOffset)) {
5796c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                    // If the list could not offset the full amount of the tab carousel offset (i.e.
5806c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                    // the list can only be scrolled a tiny amount), then animate the carousel down
5816c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                    // to compensate.
5826c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                    mTabCarousel.storeYCoordinate(currentPageIndex, listOffset);
5836c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                    shouldAnimateTabCarousel = true;
5846c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                } else {
5856c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                    // By default, animate back to the Y coordinate of the tab carousel the last
5866c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                    // time the other page was selected.
5876c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                    shouldAnimateTabCarousel = true;
5886c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                }
5896c0470e21d8506fb53915df7463634fd47288343Katherine Kuan
5906c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                if (shouldAnimateTabCarousel) {
5916c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                    float desiredOffset = mTabCarousel.getStoredYCoordinateForTab(currentPageIndex);
5926c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                    if (desiredOffset != tabCarouselOffset) {
5936c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                        createTabCarouselAnimator(desiredOffset);
5946c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                        mTabCarouselAnimator.start();
5956c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                    }
5966c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                }
5976c0470e21d8506fb53915df7463634fd47288343Katherine Kuan            }
5986c0470e21d8506fb53915df7463634fd47288343Katherine Kuan            mViewPagerState = state;
5996c0470e21d8506fb53915df7463634fd47288343Katherine Kuan        }
6006c0470e21d8506fb53915df7463634fd47288343Katherine Kuan
6016c0470e21d8506fb53915df7463634fd47288343Katherine Kuan        private void createTabCarouselAnimator(float desiredValue) {
6026c0470e21d8506fb53915df7463634fd47288343Katherine Kuan            mTabCarouselAnimator = ObjectAnimator.ofFloat(
6036c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                    mTabCarousel, "y", desiredValue).setDuration(75);
6046c0470e21d8506fb53915df7463634fd47288343Katherine Kuan            mTabCarouselAnimator.setInterpolator(AnimationUtils.loadInterpolator(
605a3364bc45b73c6a3bb0e0ec4586110f962ddf8c2Nick Pelly                    mActivity, android.R.anim.accelerate_decelerate_interpolator));
606226dcdf399e0a637711f9a76b575b7a23d2c7782Katherine Kuan            mTabCarouselAnimator.addListener(mTabCarouselAnimatorListener);
6076c0470e21d8506fb53915df7463634fd47288343Katherine Kuan        }
60858fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan
6096c0470e21d8506fb53915df7463634fd47288343Katherine Kuan        private void cancelTabCarouselAnimator() {
6106c0470e21d8506fb53915df7463634fd47288343Katherine Kuan            if (mTabCarouselAnimator != null) {
6116c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                mTabCarouselAnimator.cancel();
6126c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                mTabCarouselAnimator = null;
613226dcdf399e0a637711f9a76b575b7a23d2c7782Katherine Kuan                mTabCarouselIsAnimating = false;
6146c0470e21d8506fb53915df7463634fd47288343Katherine Kuan            }
6156c0470e21d8506fb53915df7463634fd47288343Katherine Kuan        }
61658fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan    };
61758fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan
6186c0470e21d8506fb53915df7463634fd47288343Katherine Kuan    private void syncScrollStateBetweenLists(int currentPageIndex) {
6196c0470e21d8506fb53915df7463634fd47288343Katherine Kuan        // Since the user interacted with the currently visible page, we need to sync the
6206c0470e21d8506fb53915df7463634fd47288343Katherine Kuan        // list on the other page (i.e. if the updates page is the current page, modify the
6216c0470e21d8506fb53915df7463634fd47288343Katherine Kuan        // list in the details page).
6226c0470e21d8506fb53915df7463634fd47288343Katherine Kuan        if (currentPageIndex == TAB_INDEX_UPDATES) {
6236c0470e21d8506fb53915df7463634fd47288343Katherine Kuan            mDetailFragment.requestToMoveToOffset((int) mTabCarousel.getY());
6246c0470e21d8506fb53915df7463634fd47288343Katherine Kuan        } else {
6256c0470e21d8506fb53915df7463634fd47288343Katherine Kuan            mUpdatesFragment.requestToMoveToOffset((int) mTabCarousel.getY());
6266c0470e21d8506fb53915df7463634fd47288343Katherine Kuan        }
6276c0470e21d8506fb53915df7463634fd47288343Katherine Kuan    }
6286c0470e21d8506fb53915df7463634fd47288343Katherine Kuan
6296c0470e21d8506fb53915df7463634fd47288343Katherine Kuan    private int getOffsetOfFirstItemInList(int currentPageIndex) {
6306c0470e21d8506fb53915df7463634fd47288343Katherine Kuan        if (currentPageIndex == TAB_INDEX_DETAIL) {
6316c0470e21d8506fb53915df7463634fd47288343Katherine Kuan            return mDetailFragment.getFirstListItemOffset();
6326c0470e21d8506fb53915df7463634fd47288343Katherine Kuan        } else {
6336c0470e21d8506fb53915df7463634fd47288343Katherine Kuan            return mUpdatesFragment.getFirstListItemOffset();
6346c0470e21d8506fb53915df7463634fd47288343Katherine Kuan        }
6356c0470e21d8506fb53915df7463634fd47288343Katherine Kuan    }
6366c0470e21d8506fb53915df7463634fd47288343Katherine Kuan
637226dcdf399e0a637711f9a76b575b7a23d2c7782Katherine Kuan    /**
638226dcdf399e0a637711f9a76b575b7a23d2c7782Katherine Kuan     * This listener keeps track of whether the tab carousel animation is currently going on or not,
639226dcdf399e0a637711f9a76b575b7a23d2c7782Katherine Kuan     * in order to prevent other simultaneous changes to the Y position of the tab carousel which
640226dcdf399e0a637711f9a76b575b7a23d2c7782Katherine Kuan     * can cause flicker.
641226dcdf399e0a637711f9a76b575b7a23d2c7782Katherine Kuan     */
642226dcdf399e0a637711f9a76b575b7a23d2c7782Katherine Kuan    private final AnimatorListener mTabCarouselAnimatorListener = new AnimatorListener() {
643226dcdf399e0a637711f9a76b575b7a23d2c7782Katherine Kuan
644226dcdf399e0a637711f9a76b575b7a23d2c7782Katherine Kuan        @Override
645226dcdf399e0a637711f9a76b575b7a23d2c7782Katherine Kuan        public void onAnimationCancel(Animator animation) {
646226dcdf399e0a637711f9a76b575b7a23d2c7782Katherine Kuan            mTabCarouselIsAnimating = false;
647226dcdf399e0a637711f9a76b575b7a23d2c7782Katherine Kuan        }
648226dcdf399e0a637711f9a76b575b7a23d2c7782Katherine Kuan
649226dcdf399e0a637711f9a76b575b7a23d2c7782Katherine Kuan        @Override
650226dcdf399e0a637711f9a76b575b7a23d2c7782Katherine Kuan        public void onAnimationEnd(Animator animation) {
651226dcdf399e0a637711f9a76b575b7a23d2c7782Katherine Kuan            mTabCarouselIsAnimating = false;
652226dcdf399e0a637711f9a76b575b7a23d2c7782Katherine Kuan        }
653226dcdf399e0a637711f9a76b575b7a23d2c7782Katherine Kuan
654226dcdf399e0a637711f9a76b575b7a23d2c7782Katherine Kuan        @Override
655226dcdf399e0a637711f9a76b575b7a23d2c7782Katherine Kuan        public void onAnimationRepeat(Animator animation) {
656226dcdf399e0a637711f9a76b575b7a23d2c7782Katherine Kuan            mTabCarouselIsAnimating = true;
657226dcdf399e0a637711f9a76b575b7a23d2c7782Katherine Kuan        }
658226dcdf399e0a637711f9a76b575b7a23d2c7782Katherine Kuan
659226dcdf399e0a637711f9a76b575b7a23d2c7782Katherine Kuan        @Override
660226dcdf399e0a637711f9a76b575b7a23d2c7782Katherine Kuan        public void onAnimationStart(Animator animation) {
661226dcdf399e0a637711f9a76b575b7a23d2c7782Katherine Kuan            mTabCarouselIsAnimating = true;
662226dcdf399e0a637711f9a76b575b7a23d2c7782Katherine Kuan        }
663226dcdf399e0a637711f9a76b575b7a23d2c7782Katherine Kuan    };
664226dcdf399e0a637711f9a76b575b7a23d2c7782Katherine Kuan
6657edad9dd95a411cc5ed69815e5f0be8a5d1e8b19Josh Gargus    private final ContactDetailTabCarousel.Listener mTabCarouselListener
66684edfd9a76657a653491faac53b5976adf9fd2cbJosh Gargus            = new ContactDetailTabCarousel.Listener() {
66758fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan
66858fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan        @Override
66958fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan        public void onTouchDown() {
67084edfd9a76657a653491faac53b5976adf9fd2cbJosh Gargus            // The user just started scrolling the carousel, so begin
67184edfd9a76657a653491faac53b5976adf9fd2cbJosh Gargus            // "fake dragging" the {@link ViewPager} if it's not already
67284edfd9a76657a653491faac53b5976adf9fd2cbJosh Gargus            // doing so.
67384edfd9a76657a653491faac53b5976adf9fd2cbJosh Gargus            if (!mViewPager.isFakeDragging()) mViewPager.beginFakeDrag();
67458fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan        }
67558fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan
67658fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan        @Override
67758fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan        public void onTouchUp() {
67884edfd9a76657a653491faac53b5976adf9fd2cbJosh Gargus            // The user just stopped scrolling the carousel, so stop
67984edfd9a76657a653491faac53b5976adf9fd2cbJosh Gargus            // "fake dragging" the {@link ViewPager} if it was doing so
68084edfd9a76657a653491faac53b5976adf9fd2cbJosh Gargus            // before.
68184edfd9a76657a653491faac53b5976adf9fd2cbJosh Gargus            if (mViewPager.isFakeDragging()) mViewPager.endFakeDrag();
68258fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan        }
68358fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan
68458fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan        @Override
68558fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan        public void onScrollChanged(int l, int t, int oldl, int oldt) {
68684edfd9a76657a653491faac53b5976adf9fd2cbJosh Gargus            // The user is scrolling the carousel, so send the scroll
68784edfd9a76657a653491faac53b5976adf9fd2cbJosh Gargus            // deltas to the {@link ViewPager} so it can move in sync.
68858fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan            if (mViewPager.isFakeDragging()) {
68984edfd9a76657a653491faac53b5976adf9fd2cbJosh Gargus                mViewPager.fakeDragBy(oldl - l);
69058fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan            }
69158fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan        }
69258fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan
69358fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan        @Override
69458fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan        public void onTabSelected(int position) {
69558fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan            // The user selected a tab, so update the {@link ViewPager}
69658fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan            mViewPager.setCurrentItem(position);
69758fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan        }
69858fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan    };
6996c0470e21d8506fb53915df7463634fd47288343Katherine Kuan
7006c0470e21d8506fb53915df7463634fd47288343Katherine Kuan    private final class VerticalScrollListener implements OnScrollListener {
7016c0470e21d8506fb53915df7463634fd47288343Katherine Kuan
7026c0470e21d8506fb53915df7463634fd47288343Katherine Kuan        private final int mPageIndex;
7036c0470e21d8506fb53915df7463634fd47288343Katherine Kuan
7046c0470e21d8506fb53915df7463634fd47288343Katherine Kuan        public VerticalScrollListener(int pageIndex) {
7056c0470e21d8506fb53915df7463634fd47288343Katherine Kuan            mPageIndex = pageIndex;
7066c0470e21d8506fb53915df7463634fd47288343Katherine Kuan        }
7076c0470e21d8506fb53915df7463634fd47288343Katherine Kuan
7086c0470e21d8506fb53915df7463634fd47288343Katherine Kuan        @Override
7096c0470e21d8506fb53915df7463634fd47288343Katherine Kuan        public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
7106c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                int totalItemCount) {
7116c0470e21d8506fb53915df7463634fd47288343Katherine Kuan            int currentPageIndex = mViewPager.getCurrentItem();
7126c0470e21d8506fb53915df7463634fd47288343Katherine Kuan            // Don't move the carousel if: 1) the contact does not have social updates because then
713226dcdf399e0a637711f9a76b575b7a23d2c7782Katherine Kuan            // tab carousel must not be visible, 2) if the view pager is still being scrolled,
714226dcdf399e0a637711f9a76b575b7a23d2c7782Katherine Kuan            // 3) if the current page being viewed is not this one, or 4) if the tab carousel
715226dcdf399e0a637711f9a76b575b7a23d2c7782Katherine Kuan            // is already being animated vertically.
7166c0470e21d8506fb53915df7463634fd47288343Katherine Kuan            if (!mContactHasUpdates || mViewPagerState != ViewPager.SCROLL_STATE_IDLE ||
717226dcdf399e0a637711f9a76b575b7a23d2c7782Katherine Kuan                    mPageIndex != currentPageIndex || mTabCarouselIsAnimating) {
7186c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                return;
7196c0470e21d8506fb53915df7463634fd47288343Katherine Kuan            }
7206c0470e21d8506fb53915df7463634fd47288343Katherine Kuan            // If the FIRST item is not visible on the screen, then the carousel must be pinned
7216c0470e21d8506fb53915df7463634fd47288343Katherine Kuan            // at the top of the screen.
7226c0470e21d8506fb53915df7463634fd47288343Katherine Kuan            if (firstVisibleItem != 0) {
7236c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                mTabCarousel.moveToYCoordinate(mPageIndex,
7246c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                        -mTabCarousel.getAllowedVerticalScrollLength());
7256c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                return;
7266c0470e21d8506fb53915df7463634fd47288343Katherine Kuan            }
7276c0470e21d8506fb53915df7463634fd47288343Katherine Kuan            View topView = view.getChildAt(firstVisibleItem);
7286c0470e21d8506fb53915df7463634fd47288343Katherine Kuan            if (topView == null) {
7296c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                return;
7306c0470e21d8506fb53915df7463634fd47288343Katherine Kuan            }
7316c0470e21d8506fb53915df7463634fd47288343Katherine Kuan            int amtToScroll = Math.max((int) view.getChildAt(firstVisibleItem).getY(),
7326c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                    -mTabCarousel.getAllowedVerticalScrollLength());
7336c0470e21d8506fb53915df7463634fd47288343Katherine Kuan            mTabCarousel.moveToYCoordinate(mPageIndex, amtToScroll);
7346c0470e21d8506fb53915df7463634fd47288343Katherine Kuan        }
7356c0470e21d8506fb53915df7463634fd47288343Katherine Kuan
7366c0470e21d8506fb53915df7463634fd47288343Katherine Kuan        @Override
7376c0470e21d8506fb53915df7463634fd47288343Katherine Kuan        public void onScrollStateChanged(AbsListView view, int scrollState) {
7386c0470e21d8506fb53915df7463634fd47288343Katherine Kuan            // Once the list has become IDLE, check if we need to sync the scroll position of
7396c0470e21d8506fb53915df7463634fd47288343Katherine Kuan            // the other list now. This will make swiping faster by doing the re-layout now
7406c0470e21d8506fb53915df7463634fd47288343Katherine Kuan            // (instead of at the start of a swipe). However, there will still be another check
7416c0470e21d8506fb53915df7463634fd47288343Katherine Kuan            // when we start swiping if the scroll positions are correct (to catch the edge case
7426c0470e21d8506fb53915df7463634fd47288343Katherine Kuan            // where the user flings and immediately starts a swipe so we never get the idle state).
7436c0470e21d8506fb53915df7463634fd47288343Katherine Kuan            if (scrollState == SCROLL_STATE_IDLE) {
7446c0470e21d8506fb53915df7463634fd47288343Katherine Kuan                syncScrollStateBetweenLists(mPageIndex);
7456c0470e21d8506fb53915df7463634fd47288343Katherine Kuan            }
7466c0470e21d8506fb53915df7463634fd47288343Katherine Kuan        }
7476c0470e21d8506fb53915df7463634fd47288343Katherine Kuan    }
74858fc577bd7966e6566cdcac09589a0d3e05128e7Katherine Kuan}
749