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