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