1e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee/*
2e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee * Copyright (C) 2012 The Android Open Source Project
3e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee *
4e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee * Licensed under the Apache License, Version 2.0 (the "License");
5e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee * you may not use this file except in compliance with the License.
6e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee * You may obtain a copy of the License at
7e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee *
8e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee *      http://www.apache.org/licenses/LICENSE-2.0
9e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee *
10e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee * Unless required by applicable law or agreed to in writing, software
11e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee * distributed under the License is distributed on an "AS IS" BASIS,
12e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee * See the License for the specific language governing permissions and
14e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee * limitations under the License.
15e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee */
16e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
17e709fd21eda44df07327f649e4e6a257918555a9Yorke Leepackage com.android.dialer.widget;
18e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
19e709fd21eda44df07327f649e4e6a257918555a9Yorke Leeimport android.content.Context;
20e709fd21eda44df07327f649e4e6a257918555a9Yorke Leeimport android.content.res.TypedArray;
21e709fd21eda44df07327f649e4e6a257918555a9Yorke Leeimport android.graphics.Canvas;
22e709fd21eda44df07327f649e4e6a257918555a9Yorke Leeimport android.graphics.PixelFormat;
23e709fd21eda44df07327f649e4e6a257918555a9Yorke Leeimport android.graphics.Rect;
24e709fd21eda44df07327f649e4e6a257918555a9Yorke Leeimport android.graphics.drawable.Drawable;
25e709fd21eda44df07327f649e4e6a257918555a9Yorke Leeimport android.os.Build;
26e709fd21eda44df07327f649e4e6a257918555a9Yorke Leeimport android.os.Parcel;
27e709fd21eda44df07327f649e4e6a257918555a9Yorke Leeimport android.os.Parcelable;
28e709fd21eda44df07327f649e4e6a257918555a9Yorke Leeimport android.support.v4.view.AccessibilityDelegateCompat;
29e709fd21eda44df07327f649e4e6a257918555a9Yorke Leeimport android.support.v4.view.MotionEventCompat;
30e709fd21eda44df07327f649e4e6a257918555a9Yorke Leeimport android.support.v4.view.ViewCompat;
31e709fd21eda44df07327f649e4e6a257918555a9Yorke Leeimport android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
32e709fd21eda44df07327f649e4e6a257918555a9Yorke Leeimport android.util.AttributeSet;
33e709fd21eda44df07327f649e4e6a257918555a9Yorke Leeimport android.util.Log;
34e709fd21eda44df07327f649e4e6a257918555a9Yorke Leeimport android.view.MotionEvent;
35e709fd21eda44df07327f649e4e6a257918555a9Yorke Leeimport android.view.View;
36764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwellimport android.view.ViewConfiguration;
37e709fd21eda44df07327f649e4e6a257918555a9Yorke Leeimport android.view.ViewGroup;
38e709fd21eda44df07327f649e4e6a257918555a9Yorke Leeimport android.view.ViewParent;
39e709fd21eda44df07327f649e4e6a257918555a9Yorke Leeimport android.view.accessibility.AccessibilityEvent;
40e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
41e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee/**
42e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee * A custom layout that aligns its child views vertically as two panes, and allows for the bottom
43e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee * pane to be dragged upwards to overlap and hide the top pane. This layout is adapted from
44e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee * {@link android.support.v4.widget.SlidingPaneLayout}.
45e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee */
46e709fd21eda44df07327f649e4e6a257918555a9Yorke Leepublic class OverlappingPaneLayout extends ViewGroup {
47e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    private static final String TAG = "SlidingPaneLayout";
485c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee    private static final boolean DEBUG = false;
49e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
50e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    /**
51e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee     * Default size of the overhang for a pane in the open state.
52e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee     * At least this much of a sliding pane will remain visible.
53e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee     * This indicates that there is more content available and provides
54e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee     * a "physical" edge to grab to pull it closed.
55e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee     */
56e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    private static final int DEFAULT_OVERHANG_SIZE = 32; // dp;
57e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
58e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    /**
59e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee     * If no fade color is given by default it will fade to 80% gray.
60e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee     */
61e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    private static final int DEFAULT_FADE_COLOR = 0xcccccccc;
62e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
63e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    /**
64e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee     * Minimum velocity that will be detected as a fling
65e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee     */
66e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    private static final int MIN_FLING_VELOCITY = 400; // dips per second
67e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
68e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    /**
69e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee     * The size of the overhang in pixels.
70e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee     * This is the minimum section of the sliding panel that will
71e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee     * be visible in the open state to allow for a closing drag.
72e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee     */
73e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    private final int mOverhangSize;
74e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
75e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    /**
76e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee     * True if a panel can slide with the current measurements
77e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee     */
78e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    private boolean mCanSlide;
79e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
80e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    /**
81e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee     * The child view that can slide, if any.
82e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee     */
83e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    private View mSlideableView;
84e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
85e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    /**
86e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee     * The view that can be used to start the drag with.
87e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee     */
88e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    private View mCapturableView;
89e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
90e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    /**
91e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee     * How far the panel is offset from its closed position.
92e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee     * range [0, 1] where 0 = closed, 1 = open.
93e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee     */
94e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    private float mSlideOffset;
95e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
96e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    /**
975c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee     * How far the panel is offset from its closed position, in pixels.
985c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee     * range [0, {@link #mSlideRange}] where 0 is completely closed.
995c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee     */
1005c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee    private int mSlideOffsetPx;
1015c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee
1025c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee    /**
103e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee     * How far in pixels the slideable panel may move.
104e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee     */
105e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    private int mSlideRange;
106e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
107e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    /**
108e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee     * A panel view is locked into internal scrolling or another condition that
109e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee     * is preventing a drag.
110e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee     */
111e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    private boolean mIsUnableToDrag;
112e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
113bd180af7f0b73b0dd79a7117fb0c14370ef4d12eYorke Lee    /**
114bd180af7f0b73b0dd79a7117fb0c14370ef4d12eYorke Lee     * Tracks whether or not a child view is in the process of a nested scroll.
115bd180af7f0b73b0dd79a7117fb0c14370ef4d12eYorke Lee     */
116bd180af7f0b73b0dd79a7117fb0c14370ef4d12eYorke Lee    private boolean mIsInNestedScroll;
117bd180af7f0b73b0dd79a7117fb0c14370ef4d12eYorke Lee
1185c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee    /**
1195c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee     * Indicates that the layout is currently in the process of a nested pre-scroll operation where
120764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell     * the child scrolling view is being dragged downwards.
1215c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee     */
122764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell    private boolean mInNestedPreScrollDownwards;
12340ed60dab29e90e28f95a0d8a9c612fed7a253ceYorke Lee
12440ed60dab29e90e28f95a0d8a9c612fed7a253ceYorke Lee    /**
125764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell     * Indicates that the layout is currently in the process of a nested pre-scroll operation where
126764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell     * the child scrolling view is being dragged upwards.
12740ed60dab29e90e28f95a0d8a9c612fed7a253ceYorke Lee     */
128764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell    private boolean mInNestedPreScrollUpwards;
129764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell
130764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell    /**
131764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell     * Indicates that the layout is currently in the process of a fling initiated by a pre-fling
132764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell     * from the child scrolling view.
133764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell     */
134764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell    private boolean mIsInNestedFling;
135764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell
136764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell    /**
137764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell     * Indicates the direction of the pre fling. We need to store this information since
138764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell     * OverScoller doesn't expose the direction of its velocity.
139764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell     */
140764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell    private boolean mInUpwardsPreFling;
1415c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee
1425c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee    /**
1435c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee     * Stores an offset used to represent a point somewhere in between the panel's fully closed
1445c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee     * state and fully opened state where the panel can be temporarily pinned or opened up to
1455c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee     * during scrolling.
1465c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee     */
1475c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee    private int mIntermediateOffset = 0;
1485c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee
149e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    private float mInitialMotionX;
150e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    private float mInitialMotionY;
151e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
152764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell    private PanelSlideCallbacks mPanelSlideCallbacks;
153e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
154e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    private final ViewDragHelper mDragHelper;
155e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
156e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    /**
157e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee     * Stores whether or not the pane was open the last time it was slideable.
158e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee     * If open/close operations are invoked this state is modified. Used by
159e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee     * instance state save/restore.
160e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee     */
161e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    private boolean mPreservedOpenState;
162e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    private boolean mFirstLayout = true;
163e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
164e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    private final Rect mTmpRect = new Rect();
165e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
166e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    /**
167764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell     * How many dips we need to scroll past a position before we can snap to the next position
168764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell     * on release. Using this prevents accidentally snapping to positions.
169764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell     *
170764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell     * This is needed since vertical nested scrolling can be passed to this class even if the
171764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell     * vertical scroll is less than the the nested list's touch slop.
172e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee     */
173764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell    private final int mReleaseScrollSlop;
174764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell
175764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell    /**
176764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell     * Callbacks for interacting with sliding panes.
177764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell     */
178764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell    public interface PanelSlideCallbacks {
179e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        /**
180e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee         * Called when a sliding pane's position changes.
181e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee         * @param panel The child view that was moved
182e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee         * @param slideOffset The new offset of this sliding pane within its range, from 0-1
183e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee         */
184e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        public void onPanelSlide(View panel, float slideOffset);
185e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        /**
186e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee         * Called when a sliding pane becomes slid completely open. The pane may or may not
187e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee         * be interactive at this point depending on how much of the pane is visible.
188e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee         * @param panel The child view that was slid to an open position, revealing other panes
189e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee         */
190e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        public void onPanelOpened(View panel);
191e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
192e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        /**
193e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee         * Called when a sliding pane becomes slid completely closed. The pane is now guaranteed
194e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee         * to be interactive. It may now obscure other views in the layout.
195e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee         * @param panel The child view that was slid to a closed position
196e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee         */
197e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        public void onPanelClosed(View panel);
198764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell
199764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell        /**
200764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell         * Called when a sliding pane is flung as far open/closed as it can be.
201764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell         * @param velocityY Velocity of the panel once its fling goes as far as it can.
202764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell         */
203764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell        public void onPanelFlingReachesEdge(int velocityY);
204764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell
205764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell        /**
206764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell         * Returns true if the second panel's contents haven't been scrolled at all. This value is
207764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell         * used to determine whether or not we can fully expand the header on downwards scrolls.
208764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell         *
209764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell         * Instead of using this callback, it would be preferable to instead fully expand the header
210764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell         * on a View#onNestedFlingOver() callback. The behavior would be nicer. Unfortunately,
211764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell         * no such callback exists yet (b/17547693).
212764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell         */
213764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell        public boolean isScrollableChildUnscrolled();
214e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    }
215e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
216e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    public OverlappingPaneLayout(Context context) {
217e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        this(context, null);
218e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    }
219e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
220e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    public OverlappingPaneLayout(Context context, AttributeSet attrs) {
221e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        this(context, attrs, 0);
222e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    }
223e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
224e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    public OverlappingPaneLayout(Context context, AttributeSet attrs, int defStyle) {
225e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        super(context, attrs, defStyle);
226e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
227e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        final float density = context.getResources().getDisplayMetrics().density;
228e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        mOverhangSize = (int) (DEFAULT_OVERHANG_SIZE * density + 0.5f);
229e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
230e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        setWillNotDraw(false);
231e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
232e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        ViewCompat.setAccessibilityDelegate(this, new AccessibilityDelegate());
233e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        ViewCompat.setImportantForAccessibility(this, ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES);
234e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
235e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        mDragHelper = ViewDragHelper.create(this, 0.5f, new DragHelperCallback());
236e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        mDragHelper.setMinVelocity(MIN_FLING_VELOCITY * density);
237764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell
238764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell        mReleaseScrollSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
239e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    }
240e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
241e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    /**
2425c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee     * Set an offset, somewhere in between the panel's fully closed state and fully opened state,
2435c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee     * where the panel can be temporarily pinned or opened up to.
2445c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee     *
2455c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee     * @param offset Offset in pixels
2465c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee     */
2475c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee    public void setIntermediatePinnedOffset(int offset) {
2485c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee        mIntermediateOffset = offset;
2495c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee    }
2505c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee
2515c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee    /**
252e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee     * Set the view that can be used to start dragging the sliding pane.
253e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee     */
254e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    public void setCapturableView(View capturableView) {
255e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        mCapturableView = capturableView;
256e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    }
257e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
258764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell    public void setPanelSlideCallbacks(PanelSlideCallbacks listener) {
259764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell        mPanelSlideCallbacks = listener;
260e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    }
261e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
262e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    void dispatchOnPanelSlide(View panel) {
263764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell        mPanelSlideCallbacks.onPanelSlide(panel, mSlideOffset);
264e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    }
265e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
266e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    void dispatchOnPanelOpened(View panel) {
267764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell        mPanelSlideCallbacks.onPanelOpened(panel);
268e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
269e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    }
270e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
271e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    void dispatchOnPanelClosed(View panel) {
272764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell        mPanelSlideCallbacks.onPanelClosed(panel);
273e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
274e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    }
275e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
276e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    void updateObscuredViewsVisibility(View panel) {
277e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        final int startBound = getPaddingTop();
278e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        final int endBound = getHeight() - getPaddingBottom();
279e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
280e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        final int leftBound = getPaddingLeft();
281e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        final int rightBound = getWidth() - getPaddingRight();
282e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        final int left;
283e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        final int right;
284e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        final int top;
285e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        final int bottom;
286e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        if (panel != null && viewIsOpaque(panel)) {
287e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            left = panel.getLeft();
288e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            right = panel.getRight();
289e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            top = panel.getTop();
290e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            bottom = panel.getBottom();
291e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        } else {
292e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            left = right = top = bottom = 0;
293e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        }
294e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
295e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        for (int i = 0, childCount = getChildCount(); i < childCount; i++) {
296e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            final View child = getChildAt(i);
297e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
298e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            if (child == panel) {
299e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                // There are still more children above the panel but they won't be affected.
300e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                break;
301e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            }
302e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
303e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            final int clampedChildLeft = Math.max(leftBound, child.getLeft());
304e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            final int clampedChildRight = Math.min(rightBound, child.getRight());
305e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            final int clampedChildTop = Math.max(startBound, child.getTop());
306e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            final int clampedChildBottom = Math.min(endBound, child.getBottom());
307e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
308e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            final int vis;
309e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            if (clampedChildLeft >= left && clampedChildTop >= top &&
310e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                    clampedChildRight <= right && clampedChildBottom <= bottom) {
311e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                vis = INVISIBLE;
312e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            } else {
313e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                vis = VISIBLE;
314e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            }
315e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            child.setVisibility(vis);
316e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        }
317e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    }
318e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
319e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    void setAllChildrenVisible() {
320e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        for (int i = 0, childCount = getChildCount(); i < childCount; i++) {
321e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            final View child = getChildAt(i);
322e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            if (child.getVisibility() == INVISIBLE) {
323e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                child.setVisibility(VISIBLE);
324e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            }
325e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        }
326e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    }
327e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
328e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    private static boolean viewIsOpaque(View v) {
329e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        if (ViewCompat.isOpaque(v)) return true;
330e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
331e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        final Drawable bg = v.getBackground();
332e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        if (bg != null) {
333e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            return bg.getOpacity() == PixelFormat.OPAQUE;
334e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        }
335e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        return false;
336e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    }
337e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
338e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    @Override
339e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    protected void onAttachedToWindow() {
340e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        super.onAttachedToWindow();
341e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        mFirstLayout = true;
342e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    }
343e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
344e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    @Override
345e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    protected void onDetachedFromWindow() {
346e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        super.onDetachedFromWindow();
347e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        mFirstLayout = true;
348e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    }
349e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
350e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    @Override
351e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
352e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
353e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
354e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
355e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
356e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
357e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
358e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        if (widthMode != MeasureSpec.EXACTLY) {
359e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            if (isInEditMode()) {
360e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                // Don't crash the layout editor. Consume all of the space if specified
361e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                // or pick a magic number from thin air otherwise.
362e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                // TODO Better communication with tools of this bogus state.
363e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                // It will crash on a real device.
364e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                if (widthMode == MeasureSpec.AT_MOST) {
365e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                    widthMode = MeasureSpec.EXACTLY;
366e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                } else if (widthMode == MeasureSpec.UNSPECIFIED) {
367e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                    widthMode = MeasureSpec.EXACTLY;
368e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                    widthSize = 300;
369e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                }
370e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            } else {
371e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                throw new IllegalStateException("Width must have an exact value or MATCH_PARENT");
372e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            }
373e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        } else if (heightMode == MeasureSpec.UNSPECIFIED) {
374e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            if (isInEditMode()) {
375e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                // Don't crash the layout editor. Pick a magic number from thin air instead.
376e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                // TODO Better communication with tools of this bogus state.
377e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                // It will crash on a real device.
378e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                if (heightMode == MeasureSpec.UNSPECIFIED) {
379e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                    heightMode = MeasureSpec.AT_MOST;
380e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                    heightSize = 300;
381e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                }
382e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            } else {
383e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                throw new IllegalStateException("Height must not be UNSPECIFIED");
384e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            }
385e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        }
386e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
387e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        int layoutWidth = 0;
388e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        int maxLayoutWidth = -1;
389e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        switch (widthMode) {
390e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            case MeasureSpec.EXACTLY:
391e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                layoutWidth = maxLayoutWidth = widthSize - getPaddingLeft() - getPaddingRight();
392e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                break;
393e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            case MeasureSpec.AT_MOST:
394e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                maxLayoutWidth = widthSize - getPaddingLeft() - getPaddingRight();
395e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                break;
396e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        }
397e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
398e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        float weightSum = 0;
399e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        boolean canSlide = false;
400e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        final int heightAvailable = heightSize - getPaddingTop() - getPaddingBottom();
401e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        int heightRemaining = heightAvailable;
402e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        final int childCount = getChildCount();
403e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
404e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        if (childCount > 2) {
405e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            Log.e(TAG, "onMeasure: More than two child views are not supported.");
406e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        }
407e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
408e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        // We'll find the current one below.
409e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        mSlideableView = null;
410e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
411e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        // First pass. Measure based on child LayoutParams width/height.
412e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        // Weight will incur a second pass.
413e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        for (int i = 0; i < childCount; i++) {
414e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            final View child = getChildAt(i);
415e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
416e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
417e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            if (child.getVisibility() == GONE) {
418e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                continue;
419e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            }
420e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
421e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            if (lp.weight > 0) {
422e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                weightSum += lp.weight;
423e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
424e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                // If we have no height, weight is the only contributor to the final size.
425e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                // Measure this view on the weight pass only.
426e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                if (lp.height == 0) continue;
427e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            }
428e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
429e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            int childHeightSpec;
430e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            final int verticalMargin = lp.topMargin + lp.bottomMargin;
431e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            if (lp.height == LayoutParams.WRAP_CONTENT) {
432e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                childHeightSpec = MeasureSpec.makeMeasureSpec(heightAvailable - verticalMargin,
433e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                        MeasureSpec.AT_MOST);
434e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            } else if (lp.height == LayoutParams.MATCH_PARENT) {
435e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                childHeightSpec = MeasureSpec.makeMeasureSpec(heightAvailable - verticalMargin,
436e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                        MeasureSpec.EXACTLY);
437e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            } else {
438e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                childHeightSpec = MeasureSpec.makeMeasureSpec(lp.height, MeasureSpec.EXACTLY);
439e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            }
440e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
441e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            int childWidthSpec;
442e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            if (lp.width == LayoutParams.WRAP_CONTENT) {
443e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                childWidthSpec = MeasureSpec.makeMeasureSpec(maxLayoutWidth, MeasureSpec.AT_MOST);
444e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            } else if (lp.width == LayoutParams.MATCH_PARENT) {
445e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                childWidthSpec = MeasureSpec.makeMeasureSpec(maxLayoutWidth, MeasureSpec.EXACTLY);
446e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            } else {
447e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                childWidthSpec = MeasureSpec.makeMeasureSpec(lp.width, MeasureSpec.EXACTLY);
448e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            }
449e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
450e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            child.measure(childWidthSpec, childHeightSpec);
451e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            final int childWidth = child.getMeasuredWidth();
452e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            final int childHeight = child.getMeasuredHeight();
453e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
454e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            if (widthMode == MeasureSpec.AT_MOST && childWidth > layoutWidth) {
455e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                layoutWidth = Math.min(childWidth, maxLayoutWidth);
456e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            }
457e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
458e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            heightRemaining -= childHeight;
459e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            canSlide |= lp.slideable = heightRemaining < 0;
460e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            if (lp.slideable) {
461e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                mSlideableView = child;
462e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            }
463e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        }
464e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
465e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        // Resolve weight and make sure non-sliding panels are smaller than the full screen.
466e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        if (canSlide || weightSum > 0) {
467e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            final int fixedPanelHeightLimit = heightAvailable - mOverhangSize;
468e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
469e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            for (int i = 0; i < childCount; i++) {
470e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                final View child = getChildAt(i);
471e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
472e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                if (child.getVisibility() == GONE) {
473e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                    continue;
474e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                }
475e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
476e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
477e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
478e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                if (child.getVisibility() == GONE) {
479e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                    continue;
480e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                }
481e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
482e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                final boolean skippedFirstPass = lp.height == 0 && lp.weight > 0;
483e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                final int measuredHeight = skippedFirstPass ? 0 : child.getMeasuredHeight();
484e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                if (canSlide && child != mSlideableView) {
485e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                    if (lp.height < 0 && (measuredHeight > fixedPanelHeightLimit || lp.weight > 0)) {
486e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                        // Fixed panels in a sliding configuration should
487e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                        // be clamped to the fixed panel limit.
488e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                        final int childWidthSpec;
489e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                        if (skippedFirstPass) {
490e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                            // Do initial width measurement if we skipped measuring this view
491e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                            // the first time around.
492e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                            if (lp.width == LayoutParams.WRAP_CONTENT) {
493e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                                childWidthSpec = MeasureSpec.makeMeasureSpec(maxLayoutWidth,
494e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                                        MeasureSpec.AT_MOST);
495e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                            } else if (lp.height == LayoutParams.MATCH_PARENT) {
496e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                                childWidthSpec = MeasureSpec.makeMeasureSpec(maxLayoutWidth,
497e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                                        MeasureSpec.EXACTLY);
498e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                            } else {
499e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                                childWidthSpec = MeasureSpec.makeMeasureSpec(lp.width,
500e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                                        MeasureSpec.EXACTLY);
501e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                            }
502e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                        } else {
503e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                            childWidthSpec = MeasureSpec.makeMeasureSpec(
504e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                                    child.getMeasuredWidth(), MeasureSpec.EXACTLY);
505e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                        }
506e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                        final int childHeightSpec = MeasureSpec.makeMeasureSpec(
507e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                                fixedPanelHeightLimit, MeasureSpec.EXACTLY);
508e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                        child.measure(childWidthSpec, childHeightSpec);
509e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                    }
510e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                } else if (lp.weight > 0) {
511e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                    int childWidthSpec;
512e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                    if (lp.height == 0) {
513e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                        // This was skipped the first time; figure out a real width spec.
514e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                        if (lp.width == LayoutParams.WRAP_CONTENT) {
515e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                            childWidthSpec = MeasureSpec.makeMeasureSpec(maxLayoutWidth,
516e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                                    MeasureSpec.AT_MOST);
517e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                        } else if (lp.width == LayoutParams.MATCH_PARENT) {
518e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                            childWidthSpec = MeasureSpec.makeMeasureSpec(maxLayoutWidth,
519e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                                    MeasureSpec.EXACTLY);
520e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                        } else {
521e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                            childWidthSpec = MeasureSpec.makeMeasureSpec(lp.width,
522e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                                    MeasureSpec.EXACTLY);
523e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                        }
524e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                    } else {
525e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                        childWidthSpec = MeasureSpec.makeMeasureSpec(
526e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                                child.getMeasuredWidth(), MeasureSpec.EXACTLY);
527e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                    }
528e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
529e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                    if (canSlide) {
530e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                        // Consume available space
531e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                        final int verticalMargin = lp.topMargin + lp.bottomMargin;
532e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                        final int newHeight = heightAvailable - verticalMargin;
533e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                        final int childHeightSpec = MeasureSpec.makeMeasureSpec(
534e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                                newHeight, MeasureSpec.EXACTLY);
535e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                        if (measuredHeight != newHeight) {
536e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                            child.measure(childWidthSpec, childHeightSpec);
537e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                        }
538e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                    } else {
539e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                        // Distribute the extra width proportionally similar to LinearLayout
540e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                        final int heightToDistribute = Math.max(0, heightRemaining);
541e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                        final int addedHeight = (int) (lp.weight * heightToDistribute / weightSum);
542e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                        final int childHeightSpec = MeasureSpec.makeMeasureSpec(
543e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                                measuredHeight + addedHeight, MeasureSpec.EXACTLY);
544e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                        child.measure(childWidthSpec, childHeightSpec);
545e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                    }
546e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                }
547e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            }
548e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        }
549e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
550e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        final int measuredHeight = heightSize;
551e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        final int measuredWidth = layoutWidth + getPaddingLeft() + getPaddingRight();
552e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
553e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        setMeasuredDimension(measuredWidth, measuredHeight);
554e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        mCanSlide = canSlide;
555e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
556e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        if (mDragHelper.getViewDragState() != ViewDragHelper.STATE_IDLE && !canSlide) {
557e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            // Cancel scrolling in progress, it's no longer relevant.
558e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            mDragHelper.abort();
559e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        }
560e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    }
561e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
562e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    @Override
563e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    protected void onLayout(boolean changed, int l, int t, int r, int b) {
564e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        mDragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_TOP);
565e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
566e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        final int height = b - t;
567e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        final int paddingTop = getPaddingTop();
568e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        final int paddingBottom = getPaddingBottom();
569e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        final int paddingLeft = getPaddingLeft();
570e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
571e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        final int childCount = getChildCount();
572e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        int yStart = paddingTop;
573e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        int nextYStart = yStart;
574e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
575e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        if (mFirstLayout) {
576e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            mSlideOffset = mCanSlide && mPreservedOpenState ? 1.f : 0.f;
577e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        }
578e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
579e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        for (int i = 0; i < childCount; i++) {
580e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            final View child = getChildAt(i);
581e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
582e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            if (child.getVisibility() == GONE) {
583e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                continue;
584e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            }
585e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
586e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
587e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
588e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            final int childHeight = child.getMeasuredHeight();
589e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
590e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            if (lp.slideable) {
591e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                final int margin = lp.topMargin + lp.bottomMargin;
592e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                final int range = Math.min(nextYStart,
593e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                        height - paddingBottom - mOverhangSize) - yStart - margin;
594e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                mSlideRange = range;
595e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                final int lpMargin = lp.topMargin;
596e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                final int pos = (int) (range * mSlideOffset);
597e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                yStart += pos + lpMargin;
5985c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee                updateSlideOffset(pos);
599e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            } else {
600e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                yStart = nextYStart;
601e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            }
602e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
603e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            final int childTop = yStart;
604e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            final int childBottom = childTop + childHeight;
605e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            final int childLeft = paddingLeft;
606e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            final int childRight = childLeft + child.getMeasuredWidth();
607e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
608e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            child.layout(childLeft, childTop, childRight, childBottom);
609e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
610e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            nextYStart += child.getHeight();
611e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        }
612e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
613e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        if (mFirstLayout) {
614e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            updateObscuredViewsVisibility(mSlideableView);
615e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        }
616e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
617e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        mFirstLayout = false;
618e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    }
619e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
620e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    @Override
621e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
622e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        super.onSizeChanged(w, h, oldw, oldh);
623e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        // Recalculate sliding panes and their details
624e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        if (h != oldh) {
625e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            mFirstLayout = true;
626e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        }
627e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    }
628e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
629e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    @Override
630e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    public void requestChildFocus(View child, View focused) {
631e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        super.requestChildFocus(child, focused);
632e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        if (!isInTouchMode() && !mCanSlide) {
633e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            mPreservedOpenState = child == mSlideableView;
634e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        }
635e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    }
636e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
637e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    @Override
638e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    public boolean onInterceptTouchEvent(MotionEvent ev) {
639e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        final int action = MotionEventCompat.getActionMasked(ev);
640e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
641e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        // Preserve the open state based on the last view that was touched.
642e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        if (!mCanSlide && action == MotionEvent.ACTION_DOWN && getChildCount() > 1) {
643e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            // After the first things will be slideable.
644e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            final View secondChild = getChildAt(1);
645e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            if (secondChild != null) {
646e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                mPreservedOpenState = !mDragHelper.isViewUnder(secondChild,
647e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                        (int) ev.getX(), (int) ev.getY());
648e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            }
649e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        }
650e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
651e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        if (!mCanSlide || (mIsUnableToDrag && action != MotionEvent.ACTION_DOWN)) {
652bd180af7f0b73b0dd79a7117fb0c14370ef4d12eYorke Lee            if (!mIsInNestedScroll) {
653bd180af7f0b73b0dd79a7117fb0c14370ef4d12eYorke Lee                mDragHelper.cancel();
654bd180af7f0b73b0dd79a7117fb0c14370ef4d12eYorke Lee            }
655e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            return super.onInterceptTouchEvent(ev);
656e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        }
657e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
658e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {
659bd180af7f0b73b0dd79a7117fb0c14370ef4d12eYorke Lee            if (!mIsInNestedScroll) {
660bd180af7f0b73b0dd79a7117fb0c14370ef4d12eYorke Lee                mDragHelper.cancel();
661bd180af7f0b73b0dd79a7117fb0c14370ef4d12eYorke Lee            }
662e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            return false;
663e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        }
664e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
665e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        switch (action) {
666e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            case MotionEvent.ACTION_DOWN: {
667e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                mIsUnableToDrag = false;
668e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                final float x = ev.getX();
669e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                final float y = ev.getY();
670e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                mInitialMotionX = x;
671e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                mInitialMotionY = y;
672e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
673e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                break;
674e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            }
675e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
676e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            case MotionEvent.ACTION_MOVE: {
677e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                final float x = ev.getX();
678e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                final float y = ev.getY();
679e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                final float adx = Math.abs(x - mInitialMotionX);
680e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                final float ady = Math.abs(y - mInitialMotionY);
681e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                final int slop = mDragHelper.getTouchSlop();
682e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                if (ady > slop && adx > ady || !isCapturableViewUnder((int) x, (int) y)) {
683bd180af7f0b73b0dd79a7117fb0c14370ef4d12eYorke Lee                    if (!mIsInNestedScroll) {
684bd180af7f0b73b0dd79a7117fb0c14370ef4d12eYorke Lee                        mDragHelper.cancel();
685bd180af7f0b73b0dd79a7117fb0c14370ef4d12eYorke Lee                    }
686e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                    mIsUnableToDrag = true;
687e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                    return false;
688e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                }
689e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            }
690e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        }
691e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
692e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        final boolean interceptForDrag = mDragHelper.shouldInterceptTouchEvent(ev);
693e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
69410812203e52353f666cbb3ef02e423711dd64758Yorke Lee        return interceptForDrag;
695e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    }
696e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
697e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    @Override
698e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    public boolean onTouchEvent(MotionEvent ev) {
699e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        if (!mCanSlide) {
700e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            return super.onTouchEvent(ev);
701e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        }
702e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
703e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        mDragHelper.processTouchEvent(ev);
704e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
705e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        final int action = ev.getAction();
706e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        boolean wantTouchEvents = true;
707e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
708e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        switch (action & MotionEventCompat.ACTION_MASK) {
709e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            case MotionEvent.ACTION_DOWN: {
710e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                final float x = ev.getX();
711e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                final float y = ev.getY();
712e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                mInitialMotionX = x;
713e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                mInitialMotionY = y;
714e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                break;
715e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            }
716e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        }
717e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
718e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        return wantTouchEvents;
719e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    }
720e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
721e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    private boolean closePane(View pane, int initialVelocity) {
722e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        if (mFirstLayout || smoothSlideTo(0.f, initialVelocity)) {
723e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            mPreservedOpenState = false;
724e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            return true;
725e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        }
726e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        return false;
727e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    }
728e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
729e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    private boolean openPane(View pane, int initialVelocity) {
730e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        if (mFirstLayout || smoothSlideTo(1.f, initialVelocity)) {
731e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            mPreservedOpenState = true;
732e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            return true;
733e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        }
734e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        return false;
735e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    }
736e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
7375c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee    private void updateSlideOffset(int offsetPx) {
7385c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee        mSlideOffsetPx = offsetPx;
7395c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee        mSlideOffset = (float) mSlideOffsetPx / mSlideRange;
7405c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee    }
7415c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee
742e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    /**
743e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee     * Open the sliding pane if it is currently slideable. If first layout
744e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee     * has already completed this will animate.
745e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee     *
746e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee     * @return true if the pane was slideable and is now open/in the process of opening
747e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee     */
748e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    public boolean openPane() {
749e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        return openPane(mSlideableView, 0);
750e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    }
751e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
752e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    /**
753e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee     * Close the sliding pane if it is currently slideable. If first layout
754e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee     * has already completed this will animate.
755e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee     *
756e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee     * @return true if the pane was slideable and is now closed/in the process of closing
757e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee     */
758e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    public boolean closePane() {
759e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        return closePane(mSlideableView, 0);
760e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    }
761e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
762e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    /**
7635c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee     * Check if the layout is open. It can be open either because the slider
764e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee     * itself is open revealing the left pane, or if all content fits without sliding.
765e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee     *
7665c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee     * @return true if sliding panels are open
767e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee     */
768e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    public boolean isOpen() {
7695c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee        return !mCanSlide || mSlideOffset > 0;
770e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    }
771e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
772e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    /**
773e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee     * Check if the content in this layout cannot fully fit side by side and therefore
774e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee     * the content pane can be slid back and forth.
775e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee     *
776e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee     * @return true if content in this layout can be slid open and closed
777e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee     */
778e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    public boolean isSlideable() {
779e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        return mCanSlide;
780e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    }
781e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
782e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    private void onPanelDragged(int newTop) {
783e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        if (mSlideableView == null) {
784e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            // This can happen if we're aborting motion during layout because everything now fits.
785e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            mSlideOffset = 0;
786e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            return;
787e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        }
788e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        final LayoutParams lp = (LayoutParams) mSlideableView.getLayoutParams();
789e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
790e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        final int lpMargin = lp.topMargin;
791e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        final int topBound = getPaddingTop() + lpMargin;
792e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
7935c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee        updateSlideOffset(newTop - topBound);
794e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
795e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        dispatchOnPanelSlide(mSlideableView);
796e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    }
797e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
798e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    @Override
799e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
800e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        final LayoutParams lp = (LayoutParams) child.getLayoutParams();
801e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        boolean result;
802e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        final int save = canvas.save(Canvas.CLIP_SAVE_FLAG);
803e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
804e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        if (mCanSlide && !lp.slideable && mSlideableView != null) {
805e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            // Clip against the slider; no sense drawing what will immediately be covered.
806e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            canvas.getClipBounds(mTmpRect);
807e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
808e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            mTmpRect.bottom = Math.min(mTmpRect.bottom, mSlideableView.getTop());
809e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            canvas.clipRect(mTmpRect);
810e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        }
811e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
812e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        if (Build.VERSION.SDK_INT >= 11) { // HC
813e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            result = super.drawChild(canvas, child, drawingTime);
814e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        } else {
81510812203e52353f666cbb3ef02e423711dd64758Yorke Lee            if (child.isDrawingCacheEnabled()) {
81610812203e52353f666cbb3ef02e423711dd64758Yorke Lee                child.setDrawingCacheEnabled(false);
817e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            }
81810812203e52353f666cbb3ef02e423711dd64758Yorke Lee            result = super.drawChild(canvas, child, drawingTime);
819e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        }
820e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
821e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        canvas.restoreToCount(save);
822e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
823e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        return result;
824e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    }
825e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
826e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    /**
827e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee     * Smoothly animate mDraggingPane to the target X position within its range.
828e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee     *
829e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee     * @param slideOffset position to animate to
830e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee     * @param velocity initial velocity in case of fling, or 0.
831e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee     */
832e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    boolean smoothSlideTo(float slideOffset, int velocity) {
833e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        if (!mCanSlide) {
834e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            // Nothing to do.
835e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            return false;
836e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        }
837e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
838e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        final LayoutParams lp = (LayoutParams) mSlideableView.getLayoutParams();
839e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
840e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        int y;
841e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        int topBound = getPaddingTop() + lp.topMargin;
842e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        y = (int) (topBound + slideOffset * mSlideRange);
843e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
844e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        if (mDragHelper.smoothSlideViewTo(mSlideableView, mSlideableView.getLeft(), y)) {
845e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            setAllChildrenVisible();
846e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            ViewCompat.postInvalidateOnAnimation(this);
847e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            return true;
848e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        }
849e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        return false;
850e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    }
851e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
852e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    @Override
853e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    public void computeScroll() {
854764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell        if (mDragHelper.continueSettling(/* deferCallbacks = */ false)) {
855e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            if (!mCanSlide) {
856e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                mDragHelper.abort();
857e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                return;
858e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            }
859e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
860e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            ViewCompat.postInvalidateOnAnimation(this);
861e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        }
862e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    }
863e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
864e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    private boolean isCapturableViewUnder(int x, int y) {
865e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        View capturableView = mCapturableView != null ? mCapturableView : mSlideableView;
866e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        if (capturableView == null) {
867e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            return false;
868e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        }
869e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        int[] viewLocation = new int[2];
870e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        capturableView.getLocationOnScreen(viewLocation);
871e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        int[] parentLocation = new int[2];
872e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        this.getLocationOnScreen(parentLocation);
873e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        int screenX = parentLocation[0] + x;
874e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        int screenY = parentLocation[1] + y;
875e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        return screenX >= viewLocation[0]
876e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                && screenX < viewLocation[0] + capturableView.getWidth()
877e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                && screenY >= viewLocation[1]
878e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                && screenY < viewLocation[1] + capturableView.getHeight();
879e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    }
880e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
881e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    @Override
882e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
883e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        return new LayoutParams();
884e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    }
885e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
886e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    @Override
887e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
888e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        return p instanceof MarginLayoutParams
889e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                ? new LayoutParams((MarginLayoutParams) p)
890e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                : new LayoutParams(p);
891e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    }
892e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
893e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    @Override
894e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
895e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        return p instanceof LayoutParams && super.checkLayoutParams(p);
896e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    }
897e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
898e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    @Override
899e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
900e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        return new LayoutParams(getContext(), attrs);
901e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    }
902e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
903e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    @Override
904e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    protected Parcelable onSaveInstanceState() {
905e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        Parcelable superState = super.onSaveInstanceState();
906e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
907e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        SavedState ss = new SavedState(superState);
908e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        ss.isOpen = isSlideable() ? isOpen() : mPreservedOpenState;
909e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
910e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        return ss;
911e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    }
912e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
913e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    @Override
914e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    protected void onRestoreInstanceState(Parcelable state) {
915e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        SavedState ss = (SavedState) state;
916e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        super.onRestoreInstanceState(ss.getSuperState());
917e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
918e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        if (ss.isOpen) {
919e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            openPane();
920e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        } else {
921e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            closePane();
922e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        }
923e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        mPreservedOpenState = ss.isOpen;
924e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    }
925e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
926bd180af7f0b73b0dd79a7117fb0c14370ef4d12eYorke Lee    @Override
927bd180af7f0b73b0dd79a7117fb0c14370ef4d12eYorke Lee    public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
928bd180af7f0b73b0dd79a7117fb0c14370ef4d12eYorke Lee        final boolean startNestedScroll = (nestedScrollAxes & SCROLL_AXIS_VERTICAL) != 0;
929bd180af7f0b73b0dd79a7117fb0c14370ef4d12eYorke Lee        if (startNestedScroll) {
930bd180af7f0b73b0dd79a7117fb0c14370ef4d12eYorke Lee            mIsInNestedScroll = true;
931bd180af7f0b73b0dd79a7117fb0c14370ef4d12eYorke Lee            mDragHelper.startNestedScroll(mSlideableView);
932bd180af7f0b73b0dd79a7117fb0c14370ef4d12eYorke Lee        }
9335c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee        if (DEBUG) {
9345c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee            Log.d(TAG, "onStartNestedScroll: " + startNestedScroll);
9355c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee        }
936bd180af7f0b73b0dd79a7117fb0c14370ef4d12eYorke Lee        return startNestedScroll;
937bd180af7f0b73b0dd79a7117fb0c14370ef4d12eYorke Lee    }
938bd180af7f0b73b0dd79a7117fb0c14370ef4d12eYorke Lee
939bd180af7f0b73b0dd79a7117fb0c14370ef4d12eYorke Lee    @Override
940bd180af7f0b73b0dd79a7117fb0c14370ef4d12eYorke Lee    public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
9415c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee        if (dy == 0) {
9425c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee            // Nothing to do
9435c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee            return;
9445c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee        }
9455c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee        if (DEBUG) {
9465c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee            Log.d(TAG, "onNestedPreScroll: " + dy);
9475c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee        }
948764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell
949764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell        mInNestedPreScrollDownwards = dy < 0;
950764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell        mInNestedPreScrollUpwards = dy > 0;
951764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell        mIsInNestedFling = false;
95263a10bcbce3d5db9604e697caf1072bc3323ae3cYorke Lee        mDragHelper.processNestedScroll(mSlideableView, 0, -dy, consumed);
953bd180af7f0b73b0dd79a7117fb0c14370ef4d12eYorke Lee    }
954bd180af7f0b73b0dd79a7117fb0c14370ef4d12eYorke Lee
955bd180af7f0b73b0dd79a7117fb0c14370ef4d12eYorke Lee    @Override
956764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell    public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
957764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell        if (!(velocityY > 0 && mSlideOffsetPx != 0
958764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                || velocityY < 0 && mSlideOffsetPx < mIntermediateOffset
959764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                || velocityY < 0 && mSlideOffsetPx < mSlideRange
960764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                && mPanelSlideCallbacks.isScrollableChildUnscrolled())) {
961764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell            // No need to consume the fling if the fling won't collapse or expand the header.
962764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell            // How far we are willing to expand the header depends on isScrollableChildUnscrolled().
963764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell            return false;
964764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell        }
965764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell
966764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell        if (DEBUG) {
967764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell            Log.d(TAG, "onNestedPreFling: " + velocityY);
968764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell        }
969764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell        mInUpwardsPreFling = velocityY > 0;
970764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell        mIsInNestedFling = true;
971764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell        mIsInNestedScroll = false;
972764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell        mDragHelper.processNestedFling(mSlideableView, (int) -velocityY);
973764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell        return true;
974764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell    }
975764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell
976764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell    @Override
9775c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee    public void onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed,
9785c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee            int dyUnconsumed) {
9795c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee        if (DEBUG) {
9805c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee            Log.d(TAG, "onNestedScroll: " + dyUnconsumed);
9815c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee        }
982764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell        mIsInNestedFling = false;
9835c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee        mDragHelper.processNestedScroll(mSlideableView, 0, -dyUnconsumed, null);
9845c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee    }
9855c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee
9865c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee    @Override
987bd180af7f0b73b0dd79a7117fb0c14370ef4d12eYorke Lee    public void onStopNestedScroll(View child) {
9885c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee        if (DEBUG) {
9895c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee            Log.d(TAG, "onStopNestedScroll");
9905c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee        }
9917355a4e1a7d03715451501f43ae06b1597ea597dBrian Attwell        if (mIsInNestedScroll && !mIsInNestedFling) {
9925c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee            mDragHelper.stopNestedScroll(mSlideableView);
993764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell            mInNestedPreScrollDownwards = false;
994764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell            mInNestedPreScrollUpwards = false;
995764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell            mIsInNestedScroll = false;
9965c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee        }
997bd180af7f0b73b0dd79a7117fb0c14370ef4d12eYorke Lee    }
998bd180af7f0b73b0dd79a7117fb0c14370ef4d12eYorke Lee
999e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    private class DragHelperCallback extends ViewDragHelper.Callback {
1000e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
1001e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        @Override
1002e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        public boolean tryCaptureView(View child, int pointerId) {
1003e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            if (mIsUnableToDrag) {
1004e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                return false;
1005e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            }
1006e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
1007e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            return ((LayoutParams) child.getLayoutParams()).slideable;
1008e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        }
1009e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
1010e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        @Override
1011e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        public void onViewDragStateChanged(int state) {
1012764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell            if (DEBUG) {
1013764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                Log.d(TAG, "onViewDragStateChanged: " + state);
1014764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell            }
1015764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell
1016e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            if (mDragHelper.getViewDragState() == ViewDragHelper.STATE_IDLE) {
1017e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                if (mSlideOffset == 0) {
1018e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                    updateObscuredViewsVisibility(mSlideableView);
1019e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                    dispatchOnPanelClosed(mSlideableView);
1020e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                    mPreservedOpenState = false;
1021e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                } else {
1022e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                    dispatchOnPanelOpened(mSlideableView);
1023e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                    mPreservedOpenState = true;
1024e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                }
1025e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            }
1026764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell
10277355a4e1a7d03715451501f43ae06b1597ea597dBrian Attwell            if (state == ViewDragHelper.STATE_IDLE
10287355a4e1a7d03715451501f43ae06b1597ea597dBrian Attwell                    && mDragHelper.getVelocityMagnitude() > 0
1029764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                    && mIsInNestedFling) {
1030764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                mIsInNestedFling = false;
1031764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                final int flingVelocity = !mInUpwardsPreFling ?
1032764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                        -mDragHelper.getVelocityMagnitude() : mDragHelper.getVelocityMagnitude();
1033764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                mPanelSlideCallbacks.onPanelFlingReachesEdge(flingVelocity);
1034764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell            }
1035e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        }
1036e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
1037e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        @Override
1038e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        public void onViewCaptured(View capturedChild, int activePointerId) {
1039e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            // Make all child views visible in preparation for sliding things around
1040e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            setAllChildrenVisible();
1041e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        }
1042e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
1043e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        @Override
1044e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
1045e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            onPanelDragged(top);
1046e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            invalidate();
1047e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        }
1048e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
1049e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        @Override
1050764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell        public void onViewFling(View releasedChild, float xVelocity, float yVelocity) {
1051764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell            if (releasedChild == null) {
1052764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                return;
1053764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell            }
1054764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell            if (DEBUG) {
1055764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                Log.d(TAG, "onViewFling: " + yVelocity);
1056764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell            }
1057764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell
1058764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell            // Flings won't always fully expand or collapse the header. Instead of performing the
1059764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell            // fling and then waiting for the fling to end before snapping into place, we
1060764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell            // immediately snap into place if we predict the fling won't fully expand or collapse
1061764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell            // the header.
1062764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell            int yOffsetPx = mDragHelper.predictFlingYOffset((int) yVelocity);
1063764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell            if (yVelocity < 0) {
1064764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                // Only perform a fling if we know the fling will fully compress the header.
1065764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                if (-yOffsetPx > mSlideOffsetPx) {
1066764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                    mDragHelper.flingCapturedView(releasedChild.getLeft(), /* minTop = */ 0,
1067764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                            mSlideRange, Integer.MAX_VALUE, (int) yVelocity);
1068764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                } else {
1069764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                    mIsInNestedFling = false;
1070764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                    onViewReleased(releasedChild, xVelocity, yVelocity);
1071764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                }
1072764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell            } else {
1073764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                // Only perform a fling if we know the fling will expand the header as far
1074764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                // as it can possible be expanded, given the isScrollableChildUnscrolled() value.
1075764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                if (yOffsetPx + mSlideOffsetPx >= mSlideRange
1076764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                        && mPanelSlideCallbacks.isScrollableChildUnscrolled()) {
1077764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                    mDragHelper.flingCapturedView(releasedChild.getLeft(), /* minTop = */ 0,
1078764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                            Integer.MAX_VALUE, mSlideRange, (int) yVelocity);
1079764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                } else if (yOffsetPx + mSlideOffsetPx >= mIntermediateOffset
1080764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                        && mSlideOffsetPx <= mIntermediateOffset
1081764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                        && !mPanelSlideCallbacks.isScrollableChildUnscrolled()) {
1082764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                    mDragHelper.flingCapturedView(releasedChild.getLeft(), /* minTop = */ 0,
1083764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                            Integer.MAX_VALUE, mIntermediateOffset, (int) yVelocity);
1084764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                } else {
1085764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                    mIsInNestedFling = false;
1086764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                    onViewReleased(releasedChild, xVelocity, yVelocity);
1087764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                }
1088764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell            }
1089764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell
1090764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell            mInNestedPreScrollDownwards = false;
1091764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell            mInNestedPreScrollUpwards = false;
1092764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell
1093764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell            // Without this invalidate, some calls to flingCapturedView can have no affect.
1094764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell            invalidate();
1095764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell        }
1096764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell
1097764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell        @Override
1098e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        public void onViewReleased(View releasedChild, float xvel, float yvel) {
1099764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell            if (DEBUG) {
1100764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                Log.d(TAG, "onViewReleased: "
11017355a4e1a7d03715451501f43ae06b1597ea597dBrian Attwell                        + " mIsInNestedFling=" + mIsInNestedFling
1102764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                        + " unscrolled=" + mPanelSlideCallbacks.isScrollableChildUnscrolled()
1103764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                        + ", mInNestedPreScrollDownwards = " + mInNestedPreScrollDownwards
1104764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                        + ", mInNestedPreScrollUpwards = " + mInNestedPreScrollUpwards
1105764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                        + ", yvel=" + yvel);
1106764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell            }
11077511cffbedffe82de98d0f439f089ed684d39947Jay Shrauner            if (releasedChild == null) {
11087511cffbedffe82de98d0f439f089ed684d39947Jay Shrauner                return;
11097511cffbedffe82de98d0f439f089ed684d39947Jay Shrauner            }
1110e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
1111764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell            final LayoutParams lp = (LayoutParams) releasedChild.getLayoutParams();
1112e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            int top = getPaddingTop() + lp.topMargin;
11135c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee
1114764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell            // Decide where to snap to according to the current direction of motion and the current
1115764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell            // position. The velocity's magnitude has no bearing on this.
1116764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell            if (mInNestedPreScrollDownwards || yvel > 0) {
1117764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                // Scrolling downwards
1118764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                if (mSlideOffsetPx > mIntermediateOffset + mReleaseScrollSlop) {
1119764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                    top += mSlideRange;
1120764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                } else if (mSlideOffsetPx > mReleaseScrollSlop) {
1121764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                    top += mIntermediateOffset;
1122764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                } else {
1123764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                    // Offset is very close to 0
1124764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                }
1125764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell            } else if (mInNestedPreScrollUpwards || yvel < 0) {
1126764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                // Scrolling upwards
1127764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                if (mSlideOffsetPx > mSlideRange - mReleaseScrollSlop) {
1128764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                    // Offset is very close to mSlideRange
11295c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee                    top += mSlideRange;
1130764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                } else if (mSlideOffsetPx > mIntermediateOffset - mReleaseScrollSlop) {
1131764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                    // Offset is between mIntermediateOffset and mSlideRange.
1132764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                    top += mIntermediateOffset;
1133764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                } else {
1134764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                    // Offset is between 0 and mIntermediateOffset.
1135764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                }
1136764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell            } else {
1137764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                // Not moving upwards or downwards. This case can only be triggered when directly
1138764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                // dragging the tabs. We don't bother to remember previous scroll direction
1139764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                // when directly dragging the tabs.
1140764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                if (0 <= mSlideOffsetPx && mSlideOffsetPx <= mIntermediateOffset / 2) {
11415c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee                    // Offset is between 0 and mIntermediateOffset, but closer to 0
11425c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee                    // Leave top unchanged
11435c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee                } else if (mIntermediateOffset / 2 <= mSlideOffsetPx
11445c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee                        && mSlideOffsetPx <= (mIntermediateOffset + mSlideRange) / 2) {
11455c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee                    // Offset is closest to mIntermediateOffset
11465c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee                    top += mIntermediateOffset;
11475c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee                } else {
11485c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee                    // Offset is between mIntermediateOffset and mSlideRange, but closer to
11495c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee                    // mSlideRange
11505c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee                    top += mSlideRange;
11515c7e73087ccb1615c6e460beb6c9734e665c527fYorke Lee                }
1152e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            }
1153e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
1154e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            mDragHelper.settleCapturedViewAt(releasedChild.getLeft(), top);
1155e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            invalidate();
1156e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        }
1157e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
1158e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        @Override
1159e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        public int getViewVerticalDragRange(View child) {
1160e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            return mSlideRange;
1161e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        }
1162e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
1163e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        @Override
1164e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        public int clampViewPositionHorizontal(View child, int left, int dx) {
1165e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            // Make sure we never move views horizontally.
1166e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            return child.getLeft();
1167e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        }
1168e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
1169e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        @Override
1170e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        public int clampViewPositionVertical(View child, int top, int dy) {
1171e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            final LayoutParams lp = (LayoutParams) mSlideableView.getLayoutParams();
1172e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
1173e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            final int newTop;
1174764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell            int previousTop = top - dy;
1175e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            int topBound = getPaddingTop() + lp.topMargin;
1176764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell            int bottomBound = topBound + (mPanelSlideCallbacks.isScrollableChildUnscrolled()
1177764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                    || !mIsInNestedScroll ? mSlideRange : mIntermediateOffset);
1178764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell            if (previousTop > bottomBound) {
1179764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                // We were previously below the bottomBound, so loosen the bottomBound so that this
1180764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                // makes sense. This can occur after the view was directly dragged by the tabs.
1181764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell                bottomBound = Math.max(bottomBound, mSlideRange);
1182764f652b451d27282cfaf73407d31c9522e6cb0eBrian Attwell            }
1183e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            newTop = Math.min(Math.max(top, topBound), bottomBound);
1184e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
1185e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            return newTop;
1186e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        }
1187e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
1188e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        @Override
1189e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        public void onEdgeDragStarted(int edgeFlags, int pointerId) {
1190e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            mDragHelper.captureChildView(mSlideableView, pointerId);
1191e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        }
1192e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    }
1193e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
1194e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    public static class LayoutParams extends ViewGroup.MarginLayoutParams {
1195e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        private static final int[] ATTRS = new int[] {
1196e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            android.R.attr.layout_weight
1197e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        };
1198e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
1199e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        /**
1200e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee         * The weighted proportion of how much of the leftover space
1201e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee         * this child should consume after measurement.
1202e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee         */
1203e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        public float weight = 0;
1204e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
1205e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        /**
1206e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee         * True if this pane is the slideable pane in the layout.
1207e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee         */
1208e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        boolean slideable;
1209e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
1210e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        public LayoutParams() {
1211e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            super(FILL_PARENT, FILL_PARENT);
1212e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        }
1213e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
1214e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        public LayoutParams(int width, int height) {
1215e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            super(width, height);
1216e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        }
1217e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
1218e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        public LayoutParams(android.view.ViewGroup.LayoutParams source) {
1219e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            super(source);
1220e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        }
1221e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
1222e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        public LayoutParams(MarginLayoutParams source) {
1223e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            super(source);
1224e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        }
1225e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
1226e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        public LayoutParams(LayoutParams source) {
1227e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            super(source);
1228e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            this.weight = source.weight;
1229e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        }
1230e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
1231e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        public LayoutParams(Context c, AttributeSet attrs) {
1232e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            super(c, attrs);
1233e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
1234e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            final TypedArray a = c.obtainStyledAttributes(attrs, ATTRS);
1235e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            this.weight = a.getFloat(0, 0);
1236e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            a.recycle();
1237e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        }
1238e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
1239e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    }
1240e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
1241e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    static class SavedState extends BaseSavedState {
1242e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        boolean isOpen;
1243e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
1244e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        SavedState(Parcelable superState) {
1245e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            super(superState);
1246e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        }
1247e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
1248e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        private SavedState(Parcel in) {
1249e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            super(in);
1250e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            isOpen = in.readInt() != 0;
1251e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        }
1252e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
1253e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        @Override
1254e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        public void writeToParcel(Parcel out, int flags) {
1255e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            super.writeToParcel(out, flags);
1256e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            out.writeInt(isOpen ? 1 : 0);
1257e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        }
1258e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
1259e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        public static final Parcelable.Creator<SavedState> CREATOR =
1260e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                new Parcelable.Creator<SavedState>() {
1261e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            public SavedState createFromParcel(Parcel in) {
1262e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                return new SavedState(in);
1263e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            }
1264e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
1265e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            public SavedState[] newArray(int size) {
1266e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                return new SavedState[size];
1267e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            }
1268e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        };
1269e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    }
1270e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
1271e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    class AccessibilityDelegate extends AccessibilityDelegateCompat {
1272e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        private final Rect mTmpRect = new Rect();
1273e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
1274e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        @Override
1275e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfoCompat info) {
1276e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            final AccessibilityNodeInfoCompat superNode = AccessibilityNodeInfoCompat.obtain(info);
1277e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            super.onInitializeAccessibilityNodeInfo(host, superNode);
1278e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            copyNodeInfoNoChildren(info, superNode);
1279e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            superNode.recycle();
1280e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
1281e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            info.setClassName(OverlappingPaneLayout.class.getName());
1282e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            info.setSource(host);
1283e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
1284e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            final ViewParent parent = ViewCompat.getParentForAccessibility(host);
1285e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            if (parent instanceof View) {
1286e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                info.setParent((View) parent);
1287e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            }
1288e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
1289e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            // This is a best-approximation of addChildrenForAccessibility()
1290e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            // that accounts for filtering.
1291e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            final int childCount = getChildCount();
1292e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            for (int i = 0; i < childCount; i++) {
1293e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                final View child = getChildAt(i);
129410812203e52353f666cbb3ef02e423711dd64758Yorke Lee                if (child.getVisibility() == View.VISIBLE) {
1295e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                    // Force importance to "yes" since we can't read the value.
1296e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                    ViewCompat.setImportantForAccessibility(
1297e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                            child, ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES);
1298e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                    info.addChild(child);
1299e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                }
1300e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            }
1301e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        }
1302e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
1303e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        @Override
1304e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) {
1305e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            super.onInitializeAccessibilityEvent(host, event);
1306e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
1307e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            event.setClassName(OverlappingPaneLayout.class.getName());
1308e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        }
1309e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
1310e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        /**
1311e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee         * This should really be in AccessibilityNodeInfoCompat, but there unfortunately
1312e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee         * seem to be a few elements that are not easily cloneable using the underlying API.
1313e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee         * Leave it private here as it's not general-purpose useful.
1314e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee         */
1315e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        private void copyNodeInfoNoChildren(AccessibilityNodeInfoCompat dest,
1316e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee                AccessibilityNodeInfoCompat src) {
1317e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            final Rect rect = mTmpRect;
1318e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
1319e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            src.getBoundsInParent(rect);
1320e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            dest.setBoundsInParent(rect);
1321e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
1322e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            src.getBoundsInScreen(rect);
1323e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            dest.setBoundsInScreen(rect);
1324e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
1325e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            dest.setVisibleToUser(src.isVisibleToUser());
1326e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            dest.setPackageName(src.getPackageName());
1327e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            dest.setClassName(src.getClassName());
1328e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            dest.setContentDescription(src.getContentDescription());
1329e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
1330e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            dest.setEnabled(src.isEnabled());
1331e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            dest.setClickable(src.isClickable());
1332e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            dest.setFocusable(src.isFocusable());
1333e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            dest.setFocused(src.isFocused());
1334e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            dest.setAccessibilityFocused(src.isAccessibilityFocused());
1335e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            dest.setSelected(src.isSelected());
1336e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            dest.setLongClickable(src.isLongClickable());
1337e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
1338e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            dest.addAction(src.getActions());
1339e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee
1340e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee            dest.setMovementGranularities(src.getMovementGranularities());
1341e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee        }
1342e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee    }
1343e709fd21eda44df07327f649e4e6a257918555a9Yorke Lee}
1344