ContactDetailFragmentCarousel.java revision ccf3b6bb9cba613eb31163c7ab97be71307234d1
18f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan/* 28f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan * Copyright (C) 2011 The Android Open Source Project 38f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan * 48f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan * Licensed under the Apache License, Version 2.0 (the "License"); 58f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan * you may not use this file except in compliance with the License. 68f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan * You may obtain a copy of the License at 78f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan * 88f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan * http://www.apache.org/licenses/LICENSE-2.0 98f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan * 108f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan * Unless required by applicable law or agreed to in writing, software 118f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan * distributed under the License is distributed on an "AS IS" BASIS, 128f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 138f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan * See the License for the specific language governing permissions and 148f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan * limitations under the License. 158f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan */ 168f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan 178f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuanpackage com.android.contacts.detail; 188f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan 198f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuanimport com.android.contacts.R; 208f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan 218f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuanimport android.content.Context; 228f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuanimport android.util.AttributeSet; 238f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuanimport android.view.LayoutInflater; 248f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuanimport android.view.MotionEvent; 258f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuanimport android.view.View; 268f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuanimport android.view.View.OnTouchListener; 278f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuanimport android.widget.HorizontalScrollView; 288f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan 298f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan/** 308f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan * This is a horizontally scrolling carousel with 2 fragments: one to see info about the contact and 318f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan * one to see updates from the contact. Depending on the scroll position and user selection of which 328f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan * fragment to currently view, the alpha values and touch interceptors over each fragment are 338f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan * configured accordingly. 348f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan */ 358f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuanpublic class ContactDetailFragmentCarousel extends HorizontalScrollView implements OnTouchListener { 368f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan 378f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan private static final String TAG = ContactDetailFragmentCarousel.class.getSimpleName(); 388f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan 39db0d8669cd1ffaa45827edb65b2b0eecb27561f5Katherine Kuan /** 40db0d8669cd1ffaa45827edb65b2b0eecb27561f5Katherine Kuan * Number of pixels that this view can be scrolled horizontally. 41db0d8669cd1ffaa45827edb65b2b0eecb27561f5Katherine Kuan */ 428f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan private int mAllowedHorizontalScrollLength = Integer.MIN_VALUE; 43db0d8669cd1ffaa45827edb65b2b0eecb27561f5Katherine Kuan 44db0d8669cd1ffaa45827edb65b2b0eecb27561f5Katherine Kuan /** 45db0d8669cd1ffaa45827edb65b2b0eecb27561f5Katherine Kuan * Minimum X scroll position that must be surpassed (if the user is on the "about" page of the 46db0d8669cd1ffaa45827edb65b2b0eecb27561f5Katherine Kuan * contact card), in order for this view to automatically snap to the "updates" page. 47db0d8669cd1ffaa45827edb65b2b0eecb27561f5Katherine Kuan */ 488f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan private int mLowerThreshold = Integer.MIN_VALUE; 49db0d8669cd1ffaa45827edb65b2b0eecb27561f5Katherine Kuan 50db0d8669cd1ffaa45827edb65b2b0eecb27561f5Katherine Kuan /** 51db0d8669cd1ffaa45827edb65b2b0eecb27561f5Katherine Kuan * Maximum X scroll position (if the user is on the "updates" page of the contact card), below 52db0d8669cd1ffaa45827edb65b2b0eecb27561f5Katherine Kuan * which this view will automatically snap to the "about" page. 53db0d8669cd1ffaa45827edb65b2b0eecb27561f5Katherine Kuan */ 548f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan private int mUpperThreshold = Integer.MIN_VALUE; 558f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan 5651f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan /** 5751f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan * Minimum width of a fragment (if there is more than 1 fragment in the carousel, then this is 5851f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan * the width of one of the fragments). 5951f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan */ 6051f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan private int mMinFragmentWidth = Integer.MIN_VALUE; 6151f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan 6251f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan /** 6351f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan * Maximum alpha value of the overlay on the fragment that is not currently selected 6451f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan * (if there are 1+ fragments in the carousel). 6551f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan */ 6651f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan private static final float MAX_ALPHA = 0.5f; 6751f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan 6851f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan /** 6951f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan * Fragment width (if there are 1+ fragments in the carousel) as defined as a fraction of the 7051f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan * screen width. 7151f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan */ 7251f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan private static final float FRAGMENT_WIDTH_SCREEN_WIDTH_FRACTION = 0.85f; 7351f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan 748f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan private static final int ABOUT_PAGE = 0; 758f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan private static final int UPDATES_PAGE = 1; 768f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan 7751f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan private static final int MAX_FRAGMENT_VIEW_COUNT = 2; 7851f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan 7951f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan private boolean mEnableSwipe; 8051f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan 818f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan private int mCurrentPage = ABOUT_PAGE; 828f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan private int mLastScrollPosition; 838f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan 842ad0dea36362beb70f5a92ac9b4c6a1db7bbb8b9Katherine Kuan private ViewOverlay mAboutFragment; 852ad0dea36362beb70f5a92ac9b4c6a1db7bbb8b9Katherine Kuan private ViewOverlay mUpdatesFragment; 868f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan 8751f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan private View mDetailFragmentView; 8851f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan private View mUpdatesFragmentView; 898f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan 908f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan public ContactDetailFragmentCarousel(Context context) { 918f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan this(context, null); 928f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan } 938f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan 948f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan public ContactDetailFragmentCarousel(Context context, AttributeSet attrs) { 958f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan this(context, attrs, 0); 968f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan } 978f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan 988f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan public ContactDetailFragmentCarousel(Context context, AttributeSet attrs, int defStyle) { 998f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan super(context, attrs, defStyle); 1008f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan 1018f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan final LayoutInflater inflater = 1028f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 1038f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan inflater.inflate(R.layout.contact_detail_fragment_carousel, this); 1048f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan 1058f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan setOnTouchListener(this); 1068f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan } 1078f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan 108db0d8669cd1ffaa45827edb65b2b0eecb27561f5Katherine Kuan @Override 109db0d8669cd1ffaa45827edb65b2b0eecb27561f5Katherine Kuan protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 11051f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan int screenWidth = MeasureSpec.getSize(widthMeasureSpec); 11151f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan int screenHeight = MeasureSpec.getSize(heightMeasureSpec); 112db0d8669cd1ffaa45827edb65b2b0eecb27561f5Katherine Kuan 113db0d8669cd1ffaa45827edb65b2b0eecb27561f5Katherine Kuan // Take the width of this view as the width of the screen and compute necessary thresholds. 114db0d8669cd1ffaa45827edb65b2b0eecb27561f5Katherine Kuan // Only do this computation 1x. 115db0d8669cd1ffaa45827edb65b2b0eecb27561f5Katherine Kuan if (mAllowedHorizontalScrollLength == Integer.MIN_VALUE) { 11651f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan mMinFragmentWidth = (int) (FRAGMENT_WIDTH_SCREEN_WIDTH_FRACTION * screenWidth); 11751f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan mAllowedHorizontalScrollLength = (MAX_FRAGMENT_VIEW_COUNT * mMinFragmentWidth) - 11851f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan screenWidth; 11951f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan mLowerThreshold = (screenWidth - mMinFragmentWidth) / MAX_FRAGMENT_VIEW_COUNT; 120db0d8669cd1ffaa45827edb65b2b0eecb27561f5Katherine Kuan mUpperThreshold = mAllowedHorizontalScrollLength - mLowerThreshold; 121db0d8669cd1ffaa45827edb65b2b0eecb27561f5Katherine Kuan } 12251f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan 12351f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan if (getChildCount() > 0) { 12451f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan View child = getChildAt(0); 12551f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan // If we enable swipe, then the {@link LinearLayout} child width must be the sum of the 12651f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan // width of all its children fragments. 12751f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan if (mEnableSwipe) { 12851f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan child.measure(MeasureSpec.makeMeasureSpec( 12951f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan mMinFragmentWidth * MAX_FRAGMENT_VIEW_COUNT, MeasureSpec.EXACTLY), 13051f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan MeasureSpec.makeMeasureSpec(screenHeight, MeasureSpec.EXACTLY)); 13151f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan } else { 13251f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan // Otherwise, the {@link LinearLayout} child width will just be the screen width 13351f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan // because it will only have 1 child fragment. 13451f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan child.measure(MeasureSpec.makeMeasureSpec(screenWidth, MeasureSpec.EXACTLY), 13551f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan MeasureSpec.makeMeasureSpec(screenHeight, MeasureSpec.EXACTLY)); 13651f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan } 13751f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan } 13851f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan 13951f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan setMeasuredDimension( 14051f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan resolveSize(screenWidth, widthMeasureSpec), 14151f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan resolveSize(screenHeight, heightMeasureSpec)); 142db0d8669cd1ffaa45827edb65b2b0eecb27561f5Katherine Kuan } 143db0d8669cd1ffaa45827edb65b2b0eecb27561f5Katherine Kuan 14451f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan /** 145ccf3b6bb9cba613eb31163c7ab97be71307234d1Katherine Kuan * Set the current page. This dims out the non-selected page but doesn't do any scrolling of 146ccf3b6bb9cba613eb31163c7ab97be71307234d1Katherine Kuan * the carousel. 14751f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan */ 148db0d8669cd1ffaa45827edb65b2b0eecb27561f5Katherine Kuan public void setCurrentPage(int pageIndex) { 14951f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan mCurrentPage = pageIndex; 15025594d6db384d27641b402cddf23d44818e1cd10Katherine Kuan 15151f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan if (mAboutFragment != null && mUpdatesFragment != null) { 15251f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan mAboutFragment.setAlphaLayerValue(mCurrentPage == ABOUT_PAGE ? 0 : MAX_ALPHA); 15351f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan mUpdatesFragment.setAlphaLayerValue(mCurrentPage == UPDATES_PAGE ? 0 : MAX_ALPHA); 154db0d8669cd1ffaa45827edb65b2b0eecb27561f5Katherine Kuan } 1558f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan } 1568f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan 15751f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan /** 15851f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan * Set the view containers for the detail and updates fragment. 15951f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan */ 16051f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan public void setFragmentViews(View detailFragmentView, View updatesFragmentView) { 16151f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan mDetailFragmentView = detailFragmentView; 16251f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan mUpdatesFragmentView = updatesFragmentView; 16351f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan } 16451f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan 16551f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan /** 16651f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan * Set the detail and updates fragment. 16751f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan */ 168db0d8669cd1ffaa45827edb65b2b0eecb27561f5Katherine Kuan public void setFragments(ViewOverlay aboutFragment, ViewOverlay updatesFragment) { 169db0d8669cd1ffaa45827edb65b2b0eecb27561f5Katherine Kuan mAboutFragment = aboutFragment; 170db0d8669cd1ffaa45827edb65b2b0eecb27561f5Katherine Kuan mUpdatesFragment = updatesFragment; 17151f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan } 172db0d8669cd1ffaa45827edb65b2b0eecb27561f5Katherine Kuan 17351f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan /** 17451f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan * Enable swiping if the detail and update fragments should be showing. Otherwise disable 17551f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan * swiping if only the detail fragment should be showing. 17651f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan */ 17751f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan public void enableSwipe(boolean enable) { 17851f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan if (mEnableSwipe != enable) { 17951f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan mEnableSwipe = enable; 18051f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan if (mUpdatesFragmentView != null) { 18151f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan mUpdatesFragmentView.setVisibility(enable ? View.VISIBLE : View.GONE); 182ccf3b6bb9cba613eb31163c7ab97be71307234d1Katherine Kuan if (mCurrentPage == ABOUT_PAGE) { 183ccf3b6bb9cba613eb31163c7ab97be71307234d1Katherine Kuan mDetailFragmentView.requestFocus(); 184ccf3b6bb9cba613eb31163c7ab97be71307234d1Katherine Kuan } else { 185ccf3b6bb9cba613eb31163c7ab97be71307234d1Katherine Kuan mUpdatesFragmentView.requestFocus(); 186ccf3b6bb9cba613eb31163c7ab97be71307234d1Katherine Kuan } 187ccf3b6bb9cba613eb31163c7ab97be71307234d1Katherine Kuan updateTouchInterceptors(); 18851f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan } 18951f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan } 19025594d6db384d27641b402cddf23d44818e1cd10Katherine Kuan } 19125594d6db384d27641b402cddf23d44818e1cd10Katherine Kuan 1928f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan public int getCurrentPage() { 1938f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan return mCurrentPage; 1948f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan } 1958f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan 1968f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan private final OnClickListener mAboutFragTouchInterceptListener = new OnClickListener() { 1978f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan @Override 1988f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan public void onClick(View v) { 1998f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan mCurrentPage = ABOUT_PAGE; 2008f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan snapToEdge(); 2018f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan } 2028f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan }; 2038f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan 2048f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan private final OnClickListener mUpdatesFragTouchInterceptListener = new OnClickListener() { 2058f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan @Override 2068f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan public void onClick(View v) { 2078f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan mCurrentPage = UPDATES_PAGE; 2088f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan snapToEdge(); 2098f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan } 2108f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan }; 2118f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan 2128f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan private void updateTouchInterceptors() { 2138f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan switch (mCurrentPage) { 2148f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan case ABOUT_PAGE: 2158f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan // The "about this contact" page has been selected, so disable the touch interceptor 2168f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan // on this page and enable it for the "updates" page. 2178f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan mAboutFragment.disableTouchInterceptor(); 2188f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan mUpdatesFragment.enableTouchInterceptor(mUpdatesFragTouchInterceptListener); 2198f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan break; 2208f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan case UPDATES_PAGE: 2218f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan mUpdatesFragment.disableTouchInterceptor(); 2228f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan mAboutFragment.enableTouchInterceptor(mAboutFragTouchInterceptListener); 2238f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan break; 2248f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan } 2258f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan } 2268f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan 2278f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan private void updateAlphaLayers() { 2288f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan mAboutFragment.setAlphaLayerValue(mLastScrollPosition * MAX_ALPHA / 229db0d8669cd1ffaa45827edb65b2b0eecb27561f5Katherine Kuan mAllowedHorizontalScrollLength); 2308f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan mUpdatesFragment.setAlphaLayerValue(MAX_ALPHA - mLastScrollPosition * MAX_ALPHA / 231db0d8669cd1ffaa45827edb65b2b0eecb27561f5Katherine Kuan mAllowedHorizontalScrollLength); 2328f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan } 2338f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan 2348f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan @Override 2358f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan protected void onScrollChanged(int l, int t, int oldl, int oldt) { 2368f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan super.onScrollChanged(l, t, oldl, oldt); 23751f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan if (!mEnableSwipe) { 23851f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan return; 23951f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan } 2408f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan mLastScrollPosition= l; 2418f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan updateAlphaLayers(); 2428f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan } 2438f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan 2448f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan private void snapToEdge() { 2458f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan switch (mCurrentPage) { 2468f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan case ABOUT_PAGE: 2478f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan smoothScrollTo(0, 0); 2488f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan break; 2498f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan case UPDATES_PAGE: 250db0d8669cd1ffaa45827edb65b2b0eecb27561f5Katherine Kuan smoothScrollTo(mAllowedHorizontalScrollLength, 0); 2518f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan break; 2528f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan } 2538f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan updateTouchInterceptors(); 2548f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan } 2558f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan 2568f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan /** 2578f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan * Returns the desired page we should scroll to based on the current X scroll position and the 2588f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan * current page. 2598f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan */ 2608f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan private int getDesiredPage() { 2618f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan switch (mCurrentPage) { 2628f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan case ABOUT_PAGE: 2638f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan // If the user is on the "about" page, and the scroll position exceeds the lower 2648f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan // threshold, then we should switch to the "updates" page. 265db0d8669cd1ffaa45827edb65b2b0eecb27561f5Katherine Kuan return (mLastScrollPosition > mLowerThreshold) ? UPDATES_PAGE : ABOUT_PAGE; 2668f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan case UPDATES_PAGE: 2678f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan // If the user is on the "updates" page, and the scroll position goes below the 2688f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan // upper threshold, then we should switch to the "about" page. 269db0d8669cd1ffaa45827edb65b2b0eecb27561f5Katherine Kuan return (mLastScrollPosition < mUpperThreshold) ? ABOUT_PAGE : UPDATES_PAGE; 2708f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan } 2718f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan throw new IllegalStateException("Invalid current page " + mCurrentPage); 2728f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan } 2738f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan 2748f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan @Override 2758f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan public boolean onTouch(View v, MotionEvent event) { 27651f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan if (!mEnableSwipe) { 27751f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan return false; 27851f1071a1dc91dace0de73be1c5fbba4f091f054Katherine Kuan } 2798f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan if (event.getAction() == MotionEvent.ACTION_UP) { 2808f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan mCurrentPage = getDesiredPage(); 2818f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan snapToEdge(); 2828f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan return true; 2838f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan } 2848f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan return false; 2858f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan } 2868f0f3343e4363a5e1f11b35392c8393f263aaa41Katherine Kuan} 287