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