BottomSheetBehavior.java revision 91177092bb7b2a0586f194de4d207349cdfabf30
1452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki/*
2452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * Copyright (C) 2015 The Android Open Source Project
3452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki *
4452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * Licensed under the Apache License, Version 2.0 (the "License");
5452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * you may not use this file except in compliance with the License.
6452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * You may obtain a copy of the License at
7452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki *
8452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki *      http://www.apache.org/licenses/LICENSE-2.0
9452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki *
10452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * Unless required by applicable law or agreed to in writing, software
11452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * distributed under the License is distributed on an "AS IS" BASIS,
12452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * See the License for the specific language governing permissions and
14452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * limitations under the License.
15452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki */
16452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
17452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakipackage android.support.design.widget;
18452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
19452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.content.Context;
20452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.content.res.TypedArray;
21452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.os.Parcel;
22452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.os.Parcelable;
23452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.support.annotation.IntDef;
24dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Arakiimport android.support.annotation.NonNull;
25452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.support.design.R;
2605f5ba020fa6caa658c75b6d77436aa980ca0fccChris Banesimport android.support.v4.os.ParcelableCompat;
2705f5ba020fa6caa658c75b6d77436aa980ca0fccChris Banesimport android.support.v4.os.ParcelableCompatCreatorCallbacks;
2805f5ba020fa6caa658c75b6d77436aa980ca0fccChris Banesimport android.support.v4.view.AbsSavedState;
29452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.support.v4.view.MotionEventCompat;
309aec720809a123c6193304730acf8b55d6ce5a7aYuichi Arakiimport android.support.v4.view.NestedScrollingChild;
31e3e7063749d095bba8743cad0aeb7164a567890dYuichi Arakiimport android.support.v4.view.VelocityTrackerCompat;
32452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.support.v4.view.ViewCompat;
33452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.support.v4.widget.ViewDragHelper;
34452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.util.AttributeSet;
35452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.view.MotionEvent;
36e3e7063749d095bba8743cad0aeb7164a567890dYuichi Arakiimport android.view.VelocityTracker;
37452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.view.View;
38e3e7063749d095bba8743cad0aeb7164a567890dYuichi Arakiimport android.view.ViewConfiguration;
39452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.view.ViewGroup;
40452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
41452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport java.lang.annotation.Retention;
42452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport java.lang.annotation.RetentionPolicy;
43452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport java.lang.ref.WeakReference;
44452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
45452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
46452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki/**
47452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * An interaction behavior plugin for a child view of {@link CoordinatorLayout} to make it work as
48452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * a bottom sheet.
49452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki */
50452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakipublic class BottomSheetBehavior<V extends View> extends CoordinatorLayout.Behavior<V> {
51452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
52452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    /**
534df3c15e330c2f9730d3aa712f57befec8536dffYuichi Araki     * Callback for monitoring events about bottom sheets.
54f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     */
554df3c15e330c2f9730d3aa712f57befec8536dffYuichi Araki    public abstract static class BottomSheetCallback {
56f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
57f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        /**
58f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki         * Called when the bottom sheet changes its state.
59f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki         *
60dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki         * @param bottomSheet The bottom sheet view.
61dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki         * @param newState    The new state. This will be one of {@link #STATE_DRAGGING},
62dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki         *                    {@link #STATE_SETTLING}, {@link #STATE_EXPANDED},
63dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki         *                    {@link #STATE_COLLAPSED}, or {@link #STATE_HIDDEN}.
64f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki         */
65dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki        public abstract void onStateChanged(@NonNull View bottomSheet, @State int newState);
66f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
67f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        /**
68f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki         * Called when the bottom sheet is being dragged.
69f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki         *
70dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki         * @param bottomSheet The bottom sheet view.
7191177092bb7b2a0586f194de4d207349cdfabf30Aurimas Liutikas         * @param slideOffset The new offset of this bottom sheet within [-1,1] range. Offset
7291177092bb7b2a0586f194de4d207349cdfabf30Aurimas Liutikas         *                    increases as this bottom sheet is moving upward. From 0 to 1 the sheet
7391177092bb7b2a0586f194de4d207349cdfabf30Aurimas Liutikas         *                    is between collapsed and expanded states and from -1 to 0 it is
7491177092bb7b2a0586f194de4d207349cdfabf30Aurimas Liutikas         *                    between hidden and collapsed states.
75f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki         */
76dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki        public abstract void onSlide(@NonNull View bottomSheet, float slideOffset);
77f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    }
78f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
79f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    /**
80452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * The bottom sheet is dragging.
81452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     */
82452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public static final int STATE_DRAGGING = 1;
83452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
84452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    /**
85452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * The bottom sheet is settling.
86452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     */
87452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public static final int STATE_SETTLING = 2;
88452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
89452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    /**
90452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * The bottom sheet is expanded.
91452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     */
92452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public static final int STATE_EXPANDED = 3;
93452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
94452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    /**
95452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * The bottom sheet is collapsed.
96452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     */
97452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public static final int STATE_COLLAPSED = 4;
98452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
99f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    /**
100f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     * The bottom sheet is hidden.
101f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     */
102f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    public static final int STATE_HIDDEN = 5;
103f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
104452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    /** @hide */
105f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    @IntDef({STATE_EXPANDED, STATE_COLLAPSED, STATE_DRAGGING, STATE_SETTLING, STATE_HIDDEN})
106452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    @Retention(RetentionPolicy.SOURCE)
107452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public @interface State {}
108452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
109f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    private static final float HIDE_THRESHOLD = 0.5f;
110f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
111f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    private static final float HIDE_FRICTION = 0.1f;
112f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
113e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki    private float mMaximumVelocity;
114f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
115452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    private int mPeekHeight;
116452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
117452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    private int mMinOffset;
118452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
119452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    private int mMaxOffset;
120452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
121f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    private boolean mHideable;
122f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
123362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki    private boolean mSkipCollapsed;
124362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki
125452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    @State
126452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    private int mState = STATE_COLLAPSED;
127452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
128452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    private ViewDragHelper mViewDragHelper;
129452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
130452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    private boolean mIgnoreEvents;
131452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
132e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki    private int mLastNestedScrollDy;
133e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki
13449a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki    private boolean mNestedScrolled;
13549a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki
136452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    private int mParentHeight;
137452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
138452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    private WeakReference<V> mViewRef;
139452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
1409aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki    private WeakReference<View> mNestedScrollingChildRef;
141f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
1429aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki    private BottomSheetCallback mCallback;
143f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
144e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki    private VelocityTracker mVelocityTracker;
145e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki
146e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki    private int mActivePointerId;
147f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
1484eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki    private int mInitialY;
1494eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki
150b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki    private boolean mTouchingScrollingChild;
151b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki
152452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    /**
153452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * Default constructor for instantiating BottomSheetBehaviors.
154452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     */
155452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public BottomSheetBehavior() {
156452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
157452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
158452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    /**
159452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * Default constructor for inflating BottomSheetBehaviors from layout.
160452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     *
161452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * @param context The {@link Context}.
162452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * @param attrs   The {@link AttributeSet}.
163452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     */
164452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public BottomSheetBehavior(Context context, AttributeSet attrs) {
165452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        super(context, attrs);
166452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        TypedArray a = context.obtainStyledAttributes(attrs,
167c6cbbb50a06ec08e6888bd1c3dfd7fdf588d9db5Chris Banes                R.styleable.BottomSheetBehavior_Layout);
168452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        setPeekHeight(a.getDimensionPixelSize(
169c6cbbb50a06ec08e6888bd1c3dfd7fdf588d9db5Chris Banes                R.styleable.BottomSheetBehavior_Layout_behavior_peekHeight, 0));
170c6cbbb50a06ec08e6888bd1c3dfd7fdf588d9db5Chris Banes        setHideable(a.getBoolean(R.styleable.BottomSheetBehavior_Layout_behavior_hideable, false));
171362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki        setSkipCollapsed(a.getBoolean(R.styleable.BottomSheetBehavior_Layout_behavior_skipCollapsed,
172362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki                false));
173452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        a.recycle();
174e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        ViewConfiguration configuration = ViewConfiguration.get(context);
175e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
176452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
177452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
178452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    @Override
179452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public Parcelable onSaveInstanceState(CoordinatorLayout parent, V child) {
180452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        return new SavedState(super.onSaveInstanceState(parent, child), mState);
181452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
182452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
183452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    @Override
184452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public void onRestoreInstanceState(CoordinatorLayout parent, V child, Parcelable state) {
185452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        SavedState ss = (SavedState) state;
186452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        super.onRestoreInstanceState(parent, child, ss.getSuperState());
187452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        // Intermediate states are restored as collapsed state
188f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        if (ss.state == STATE_DRAGGING || ss.state == STATE_SETTLING) {
189452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            mState = STATE_COLLAPSED;
190f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        } else {
191f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            mState = ss.state;
192452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
193452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
194452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
195452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    @Override
196452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public boolean onLayoutChild(CoordinatorLayout parent, V child, int layoutDirection) {
1976bef5a31fd4bbfc70b21c0f694bcb272e88400a3Yuichi Araki        if (ViewCompat.getFitsSystemWindows(parent) && !ViewCompat.getFitsSystemWindows(child)) {
1986bef5a31fd4bbfc70b21c0f694bcb272e88400a3Yuichi Araki            ViewCompat.setFitsSystemWindows(child, true);
199f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        }
2006bef5a31fd4bbfc70b21c0f694bcb272e88400a3Yuichi Araki        int savedTop = child.getTop();
2016bef5a31fd4bbfc70b21c0f694bcb272e88400a3Yuichi Araki        // First let the parent lay it out
2026bef5a31fd4bbfc70b21c0f694bcb272e88400a3Yuichi Araki        parent.onLayoutChild(child, layoutDirection);
203452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        // Offset the bottom sheet
204452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        mParentHeight = parent.getHeight();
205452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        mMinOffset = Math.max(0, mParentHeight - child.getHeight());
2063bd9d18c5855600254e907d6668f2ec4d7fd1c51Yuichi Araki        mMaxOffset = Math.max(mParentHeight - mPeekHeight, mMinOffset);
207452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        if (mState == STATE_EXPANDED) {
208452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            ViewCompat.offsetTopAndBottom(child, mMinOffset);
209f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        } else if (mHideable && mState == STATE_HIDDEN) {
210f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            ViewCompat.offsetTopAndBottom(child, mParentHeight);
211f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        } else if (mState == STATE_COLLAPSED) {
212452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            ViewCompat.offsetTopAndBottom(child, mMaxOffset);
2136bef5a31fd4bbfc70b21c0f694bcb272e88400a3Yuichi Araki        } else if (mState == STATE_DRAGGING || mState == STATE_SETTLING) {
2146bef5a31fd4bbfc70b21c0f694bcb272e88400a3Yuichi Araki            ViewCompat.offsetTopAndBottom(child, savedTop - child.getTop());
215452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
216452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        if (mViewDragHelper == null) {
217452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            mViewDragHelper = ViewDragHelper.create(parent, mDragCallback);
218452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
219452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        mViewRef = new WeakReference<>(child);
2209aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki        mNestedScrollingChildRef = new WeakReference<>(findScrollingChild(child));
221452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        return true;
222452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
223452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
224452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    @Override
225452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public boolean onInterceptTouchEvent(CoordinatorLayout parent, V child, MotionEvent event) {
22617fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki        if (!child.isShown()) {
22717fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki            return false;
22817fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki        }
229452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        int action = MotionEventCompat.getActionMasked(event);
230e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        // Record the velocity
231e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        if (action == MotionEvent.ACTION_DOWN) {
232e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki            reset();
233e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        }
234e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        if (mVelocityTracker == null) {
235e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki            mVelocityTracker = VelocityTracker.obtain();
236e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        }
237e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        mVelocityTracker.addMovement(event);
238452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        switch (action) {
239452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            case MotionEvent.ACTION_UP:
240452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            case MotionEvent.ACTION_CANCEL:
241b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki                mTouchingScrollingChild = false;
242e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki                mActivePointerId = MotionEvent.INVALID_POINTER_ID;
243452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                // Reset the ignore flag
244452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                if (mIgnoreEvents) {
245452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                    mIgnoreEvents = false;
246452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                    return false;
247452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                }
248452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                break;
249452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            case MotionEvent.ACTION_DOWN:
2504eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki                int initialX = (int) event.getX();
2514eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki                mInitialY = (int) event.getY();
2529aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki                View scroll = mNestedScrollingChildRef.get();
2534eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki                if (scroll != null && parent.isPointInChildBounds(scroll, initialX, mInitialY)) {
254e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki                    mActivePointerId = event.getPointerId(event.getActionIndex());
255b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki                    mTouchingScrollingChild = true;
2569aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki                }
257e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki                mIgnoreEvents = mActivePointerId == MotionEvent.INVALID_POINTER_ID &&
2584eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki                        !parent.isPointInChildBounds(child, initialX, mInitialY);
259452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                break;
260452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
2614eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki        if (!mIgnoreEvents && mViewDragHelper.shouldInterceptTouchEvent(event)) {
2624eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki            return true;
2634eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki        }
2644eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki        // We have to handle cases that the ViewDragHelper does not capture the bottom sheet because
2654eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki        // it is not the top most view of its parent. This is not necessary when the touch event is
2664eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki        // happening over the scrolling content as nested scrolling logic handles that case.
2674eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki        View scroll = mNestedScrollingChildRef.get();
2684eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki        return action == MotionEvent.ACTION_MOVE && scroll != null &&
2694eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki                !mIgnoreEvents && mState != STATE_DRAGGING &&
2704eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki                !parent.isPointInChildBounds(scroll, (int) event.getX(), (int) event.getY()) &&
2714eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki                Math.abs(mInitialY - event.getY()) > mViewDragHelper.getTouchSlop();
272452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
273452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
274452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    @Override
275452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public boolean onTouchEvent(CoordinatorLayout parent, V child, MotionEvent event) {
27617fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki        if (!child.isShown()) {
27717fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki            return false;
27817fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki        }
279e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        int action = MotionEventCompat.getActionMasked(event);
280e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        if (mState == STATE_DRAGGING && action == MotionEvent.ACTION_DOWN) {
281e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki            return true;
282e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        }
283452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        mViewDragHelper.processTouchEvent(event);
284e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        // Record the velocity
285e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        if (action == MotionEvent.ACTION_DOWN) {
286e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki            reset();
287e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        }
288e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        if (mVelocityTracker == null) {
289e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki            mVelocityTracker = VelocityTracker.obtain();
290e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        }
291e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        mVelocityTracker.addMovement(event);
2924eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki        // The ViewDragHelper tries to capture only the top-most View. We have to explicitly tell it
2934eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki        // to capture the bottom sheet in case it is not captured and the touch slop is passed.
294912d40d353f5b6d0a4fa18740ca40aa4b25b0f9cYuichi Araki        if (action == MotionEvent.ACTION_MOVE && !mIgnoreEvents) {
2954eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki            if (Math.abs(mInitialY - event.getY()) > mViewDragHelper.getTouchSlop()) {
2964eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki                mViewDragHelper.captureChildView(child, event.getPointerId(event.getActionIndex()));
2974eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki            }
2984eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki        }
2991dbdc6baec537b45e9bd8e5afabcb5c35f1a8004Yuichi Araki        return !mIgnoreEvents;
300452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
301452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
302e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki    @Override
303e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki    public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, V child,
304e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki            View directTargetChild, View target, int nestedScrollAxes) {
305e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        mLastNestedScrollDy = 0;
30649a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki        mNestedScrolled = false;
307e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        return (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;
308e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki    }
309e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki
310e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki    @Override
311e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki    public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, V child, View target, int dx,
312e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki            int dy, int[] consumed) {
313e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        View scrollingChild = mNestedScrollingChildRef.get();
314e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        if (target != scrollingChild) {
315e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki            return;
316e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        }
317e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        int currentTop = child.getTop();
318e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        int newTop = currentTop - dy;
319e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        if (dy > 0) { // Upward
320e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki            if (newTop < mMinOffset) {
321e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki                consumed[1] = currentTop - mMinOffset;
322e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki                ViewCompat.offsetTopAndBottom(child, -consumed[1]);
323e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki                setStateInternal(STATE_EXPANDED);
324e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki            } else {
325e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki                consumed[1] = dy;
326e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki                ViewCompat.offsetTopAndBottom(child, -dy);
327e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki                setStateInternal(STATE_DRAGGING);
328e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki            }
329e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        } else if (dy < 0) { // Downward
330e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki            if (!ViewCompat.canScrollVertically(target, -1)) {
331e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki                if (newTop <= mMaxOffset || mHideable) {
332e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki                    consumed[1] = dy;
333e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki                    ViewCompat.offsetTopAndBottom(child, -dy);
334e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki                    setStateInternal(STATE_DRAGGING);
335e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki                } else {
336e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki                    consumed[1] = currentTop - mMaxOffset;
337e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki                    ViewCompat.offsetTopAndBottom(child, -consumed[1]);
338e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki                    setStateInternal(STATE_COLLAPSED);
339e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki                }
340e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki            }
341e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        }
342e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        dispatchOnSlide(child.getTop());
343e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        mLastNestedScrollDy = dy;
34449a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki        mNestedScrolled = true;
345e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki    }
346e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki
347e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki    @Override
348e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki    public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, V child, View target) {
349b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki        if (child.getTop() == mMinOffset) {
350b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki            setStateInternal(STATE_EXPANDED);
351b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki            return;
352b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki        }
353b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki        if (target != mNestedScrollingChildRef.get() || !mNestedScrolled) {
354e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki            return;
355e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        }
356e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        int top;
357e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        int targetState;
358e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        if (mLastNestedScrollDy > 0) {
359e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki            top = mMinOffset;
360e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki            targetState = STATE_EXPANDED;
361e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        } else if (mHideable && shouldHide(child, getYVelocity())) {
362e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki            top = mParentHeight;
363e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki            targetState = STATE_HIDDEN;
36449a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki        } else if (mLastNestedScrollDy == 0) {
36549a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki            int currentTop = child.getTop();
36649a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki            if (Math.abs(currentTop - mMinOffset) < Math.abs(currentTop - mMaxOffset)) {
36749a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki                top = mMinOffset;
36849a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki                targetState = STATE_EXPANDED;
36949a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki            } else {
37049a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki                top = mMaxOffset;
37149a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki                targetState = STATE_COLLAPSED;
37249a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki            }
373e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        } else {
374e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki            top = mMaxOffset;
375e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki            targetState = STATE_COLLAPSED;
376e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        }
377e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        if (mViewDragHelper.smoothSlideViewTo(child, child.getLeft(), top)) {
378e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki            setStateInternal(STATE_SETTLING);
379e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki            ViewCompat.postOnAnimation(child, new SettleRunnable(child, targetState));
380e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        } else {
381e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki            setStateInternal(targetState);
382e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        }
38349a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki        mNestedScrolled = false;
384e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki    }
385e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki
386e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki    @Override
387e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki    public boolean onNestedPreFling(CoordinatorLayout coordinatorLayout, V child, View target,
388e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki            float velocityX, float velocityY) {
389e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        return target == mNestedScrollingChildRef.get() &&
390e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki                (mState != STATE_EXPANDED ||
391e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki                        super.onNestedPreFling(coordinatorLayout, child, target,
392e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki                                velocityX, velocityY));
393e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki    }
394e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki
395452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    /**
396452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * Sets the height of the bottom sheet when it is collapsed.
397452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     *
398452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * @param peekHeight The height of the collapsed bottom sheet in pixels.
39973e7a06fb66110495fa4e98a91831a47feab2526Chris Banes     * @attr ref android.support.design.R.styleable#BottomSheetBehavior_Layout_behavior_peekHeight
400452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     */
401452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public final void setPeekHeight(int peekHeight) {
402452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        mPeekHeight = Math.max(0, peekHeight);
403452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        mMaxOffset = mParentHeight - peekHeight;
404452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
405452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
406452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    /**
407452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * Gets the height of the bottom sheet when it is collapsed.
408452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     *
409452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * @return The height of the collapsed bottom sheet.
41073e7a06fb66110495fa4e98a91831a47feab2526Chris Banes     * @attr ref android.support.design.R.styleable#BottomSheetBehavior_Layout_behavior_peekHeight
411452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     */
412452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public final int getPeekHeight() {
413452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        return mPeekHeight;
414452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
415452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
416452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    /**
417f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     * Sets whether this bottom sheet can hide when it is swiped down.
418f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     *
419f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     * @param hideable {@code true} to make this bottom sheet hideable.
42073e7a06fb66110495fa4e98a91831a47feab2526Chris Banes     * @attr ref android.support.design.R.styleable#BottomSheetBehavior_Layout_behavior_hideable
421f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     */
422f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    public void setHideable(boolean hideable) {
423f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        mHideable = hideable;
424f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    }
425f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
426f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    /**
427f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     * Gets whether this bottom sheet can hide when it is swiped down.
428f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     *
429f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     * @return {@code true} if this bottom sheet can hide.
43073e7a06fb66110495fa4e98a91831a47feab2526Chris Banes     * @attr ref android.support.design.R.styleable#BottomSheetBehavior_Layout_behavior_hideable
431f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     */
432f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    public boolean isHideable() {
433f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        return mHideable;
434f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    }
435f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
436f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    /**
437362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki     * Sets whether this bottom sheet should skip the collapsed state when it is being hidden
438362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki     * after it is expanded once. Setting this to true has no effect unless the sheet is hideable.
439362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki     *
440362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki     * @param skipCollapsed True if the bottom sheet should skip the collapsed state.
441362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki     * @attr ref android.support.design.R.styleable#BottomSheetBehavior_Layout_behavior_skipCollapsed
442362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki     */
443362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki    public void setSkipCollapsed(boolean skipCollapsed) {
444362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki        mSkipCollapsed = skipCollapsed;
445362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki    }
446362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki
447362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki    /**
448362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki     * Sets whether this bottom sheet should skip the collapsed state when it is being hidden
449362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki     * after it is expanded once.
450362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki     *
451362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki     * @return Whether the bottom sheet should skip the collapsed state.
452362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki     * @attr ref android.support.design.R.styleable#BottomSheetBehavior_Layout_behavior_skipCollapsed
453362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki     */
454362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki    public boolean getSkipCollapsed() {
455362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki        return mSkipCollapsed;
456362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki    }
457362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki
458362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki    /**
4594df3c15e330c2f9730d3aa712f57befec8536dffYuichi Araki     * Sets a callback to be notified of bottom sheet events.
460f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     *
4614df3c15e330c2f9730d3aa712f57befec8536dffYuichi Araki     * @param callback The callback to notify when bottom sheet events occur.
462f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     */
4634df3c15e330c2f9730d3aa712f57befec8536dffYuichi Araki    public void setBottomSheetCallback(BottomSheetCallback callback) {
4644df3c15e330c2f9730d3aa712f57befec8536dffYuichi Araki        mCallback = callback;
465f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    }
466f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
467f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    /**
468452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * Sets the state of the bottom sheet. The bottom sheet will transition to that state with
469452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * animation.
470452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     *
471f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     * @param state One of {@link #STATE_COLLAPSED}, {@link #STATE_EXPANDED}, or
472f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     *              {@link #STATE_HIDDEN}.
473452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     */
474452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public final void setState(@State int state) {
475e0573dfb5896eb66e266ea366d8c58437c739c95Yuichi Araki        if (state == mState) {
476e0573dfb5896eb66e266ea366d8c58437c739c95Yuichi Araki            return;
477e0573dfb5896eb66e266ea366d8c58437c739c95Yuichi Araki        }
47898475d29e771d7b15e4a109b22f410c7c1cf33d7Taeho Kim        if (mViewRef == null) {
4796deb3a9dc52be7ab61702c430bb327343ef099acYuichi Araki            // The view is not laid out yet; modify mState and let onLayoutChild handle it later
4806deb3a9dc52be7ab61702c430bb327343ef099acYuichi Araki            if (state == STATE_COLLAPSED || state == STATE_EXPANDED ||
4816deb3a9dc52be7ab61702c430bb327343ef099acYuichi Araki                    (mHideable && state == STATE_HIDDEN)) {
4826deb3a9dc52be7ab61702c430bb327343ef099acYuichi Araki                mState = state;
4836deb3a9dc52be7ab61702c430bb327343ef099acYuichi Araki            }
48498475d29e771d7b15e4a109b22f410c7c1cf33d7Taeho Kim            return;
48598475d29e771d7b15e4a109b22f410c7c1cf33d7Taeho Kim        }
486452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        V child = mViewRef.get();
487452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        if (child == null) {
488452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            return;
489452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
490452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        int top;
491452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        if (state == STATE_COLLAPSED) {
492452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            top = mMaxOffset;
493452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        } else if (state == STATE_EXPANDED) {
494452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            top = mMinOffset;
495f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        } else if (mHideable && state == STATE_HIDDEN) {
496f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            top = mParentHeight;
497452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        } else {
498452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            throw new IllegalArgumentException("Illegal state argument: " + state);
499452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
500452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        setStateInternal(STATE_SETTLING);
501452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        if (mViewDragHelper.smoothSlideViewTo(child, child.getLeft(), top)) {
502452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            ViewCompat.postOnAnimation(child, new SettleRunnable(child, state));
503452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
504452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
505452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
506452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    /**
507452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * Gets the current state of the bottom sheet.
508452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     *
509452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * @return One of {@link #STATE_EXPANDED}, {@link #STATE_COLLAPSED}, {@link #STATE_DRAGGING},
510452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * and {@link #STATE_SETTLING}.
511452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     */
512452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    @State
513452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public final int getState() {
514452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        return mState;
515452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
516452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
517452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    private void setStateInternal(@State int state) {
518452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        if (mState == state) {
519452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            return;
520452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
521452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        mState = state;
522dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki        View bottomSheet = mViewRef.get();
523dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki        if (bottomSheet != null && mCallback != null) {
524dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki            mCallback.onStateChanged(bottomSheet, state);
525f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        }
526f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    }
527f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
528e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki    private void reset() {
529e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        mActivePointerId = ViewDragHelper.INVALID_POINTER;
530e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        if (mVelocityTracker != null) {
531e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki            mVelocityTracker.recycle();
532e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki            mVelocityTracker = null;
533e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        }
534e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki    }
535e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki
536f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    private boolean shouldHide(View child, float yvel) {
537362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki        if (mSkipCollapsed) {
538362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki            return true;
539362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki        }
540f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        if (child.getTop() < mMaxOffset) {
541f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            // It should not hide, but collapse.
542f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            return false;
543f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        }
544f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        final float newTop = child.getTop() + yvel * HIDE_FRICTION;
545f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        return Math.abs(newTop - mMaxOffset) / (float) mPeekHeight > HIDE_THRESHOLD;
546f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    }
547f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
5489aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki    private View findScrollingChild(View view) {
5499aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki        if (view instanceof NestedScrollingChild) {
5509aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki            return view;
5519aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki        }
5529aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki        if (view instanceof ViewGroup) {
5539aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki            ViewGroup group = (ViewGroup) view;
5549aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki            for (int i = 0, count = group.getChildCount(); i < count; i++) {
5559aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki                View scrollingChild = findScrollingChild(group.getChildAt(i));
5569aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki                if (scrollingChild != null) {
5579aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki                    return scrollingChild;
5589aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki                }
5599aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki            }
5609aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki        }
5619aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki        return null;
562452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
563452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
564e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki    private float getYVelocity() {
565e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        mVelocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
566e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        return VelocityTrackerCompat.getYVelocity(mVelocityTracker, mActivePointerId);
567e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki    }
568e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki
569452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    private final ViewDragHelper.Callback mDragCallback = new ViewDragHelper.Callback() {
570452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
571452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        @Override
572452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        public boolean tryCaptureView(View child, int pointerId) {
573e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki            if (mState == STATE_DRAGGING) {
574e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki                return false;
575e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki            }
576b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki            if (mTouchingScrollingChild) {
577b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki                return false;
578b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki            }
579e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki            if (mState == STATE_EXPANDED && mActivePointerId == pointerId) {
5809aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki                View scroll = mNestedScrollingChildRef.get();
5819aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki                if (scroll != null && ViewCompat.canScrollVertically(scroll, -1)) {
5829aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki                    // Let the content scroll up
5839aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki                    return false;
5849aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki                }
5859aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki            }
586f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            return mViewRef != null && mViewRef.get() == child;
587f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        }
588f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
589f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        @Override
590f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
591f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            dispatchOnSlide(top);
592452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
593452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
594452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        @Override
595452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        public void onViewDragStateChanged(int state) {
596452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            if (state == ViewDragHelper.STATE_DRAGGING) {
597452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                setStateInternal(STATE_DRAGGING);
598452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            }
599452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
600452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
601452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        @Override
602452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        public void onViewReleased(View releasedChild, float xvel, float yvel) {
603452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            int top;
604452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            @State int targetState;
605f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            if (yvel < 0) { // Moving up
606452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                top = mMinOffset;
607452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                targetState = STATE_EXPANDED;
608f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            } else if (mHideable && shouldHide(releasedChild, yvel)) {
609f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                top = mParentHeight;
610f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                targetState = STATE_HIDDEN;
61149a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki            } else if (yvel == 0.f) {
61249a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki                int currentTop = releasedChild.getTop();
61349a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki                if (Math.abs(currentTop - mMinOffset) < Math.abs(currentTop - mMaxOffset)) {
61449a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki                    top = mMinOffset;
61549a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki                    targetState = STATE_EXPANDED;
61649a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki                } else {
61749a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki                    top = mMaxOffset;
61849a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki                    targetState = STATE_COLLAPSED;
61949a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki                }
620452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            } else {
621452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                top = mMaxOffset;
622452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                targetState = STATE_COLLAPSED;
623452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            }
624452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            if (mViewDragHelper.settleCapturedViewAt(releasedChild.getLeft(), top)) {
625f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                setStateInternal(STATE_SETTLING);
626452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                ViewCompat.postOnAnimation(releasedChild,
627452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                        new SettleRunnable(releasedChild, targetState));
628f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            } else {
629f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                setStateInternal(targetState);
630452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            }
631452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
632452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
633452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        @Override
634452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        public int clampViewPositionVertical(View child, int top, int dy) {
635f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            return MathUtils.constrain(top, mMinOffset, mHideable ? mParentHeight : mMaxOffset);
636452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
637452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
638452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        @Override
639452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        public int clampViewPositionHorizontal(View child, int left, int dx) {
640452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            return child.getLeft();
641452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
642f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
6439aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki        @Override
6449aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki        public int getViewVerticalDragRange(View child) {
6459aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki            if (mHideable) {
6469aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki                return mParentHeight - mMinOffset;
6479aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki            } else {
6489aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki                return mMaxOffset - mMinOffset;
6499aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki            }
6509aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki        }
651452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    };
652452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
653f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    private void dispatchOnSlide(int top) {
654dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki        View bottomSheet = mViewRef.get();
655dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki        if (bottomSheet != null && mCallback != null) {
656f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            if (top > mMaxOffset) {
657dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki                mCallback.onSlide(bottomSheet, (float) (mMaxOffset - top) / mPeekHeight);
658f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            } else {
659dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki                mCallback.onSlide(bottomSheet,
660dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki                        (float) (mMaxOffset - top) / ((mMaxOffset - mMinOffset)));
661f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            }
662f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        }
663f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    }
664f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
665452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    private class SettleRunnable implements Runnable {
666452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
667452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        private final View mView;
668452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
669452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        @State
670452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        private final int mTargetState;
671452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
672452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        SettleRunnable(View view, @State int targetState) {
673452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            mView = view;
674452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            mTargetState = targetState;
675452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
676452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
677452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        @Override
678452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        public void run() {
679452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            if (mViewDragHelper != null && mViewDragHelper.continueSettling(true)) {
680452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                ViewCompat.postOnAnimation(mView, this);
681452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            } else {
682452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                setStateInternal(mTargetState);
683452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            }
684452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
685452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
686452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
68705f5ba020fa6caa658c75b6d77436aa980ca0fccChris Banes    protected static class SavedState extends AbsSavedState {
688452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        @State
689452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        final int state;
690452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
691452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        public SavedState(Parcel source) {
69205f5ba020fa6caa658c75b6d77436aa980ca0fccChris Banes            this(source, null);
69305f5ba020fa6caa658c75b6d77436aa980ca0fccChris Banes        }
69405f5ba020fa6caa658c75b6d77436aa980ca0fccChris Banes
69505f5ba020fa6caa658c75b6d77436aa980ca0fccChris Banes        public SavedState(Parcel source, ClassLoader loader) {
69605f5ba020fa6caa658c75b6d77436aa980ca0fccChris Banes            super(source, loader);
697452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            //noinspection ResourceType
698452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            state = source.readInt();
699452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
700452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
701452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        public SavedState(Parcelable superState, @State int state) {
702452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            super(superState);
703452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            this.state = state;
704452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
705452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
706452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        @Override
707452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        public void writeToParcel(Parcel out, int flags) {
708452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            super.writeToParcel(out, flags);
709452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            out.writeInt(state);
710452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
711452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
71205f5ba020fa6caa658c75b6d77436aa980ca0fccChris Banes        public static final Creator<SavedState> CREATOR = ParcelableCompat.newCreator(
71305f5ba020fa6caa658c75b6d77436aa980ca0fccChris Banes                new ParcelableCompatCreatorCallbacks<SavedState>() {
714452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                    @Override
71505f5ba020fa6caa658c75b6d77436aa980ca0fccChris Banes                    public SavedState createFromParcel(Parcel in, ClassLoader loader) {
71605f5ba020fa6caa658c75b6d77436aa980ca0fccChris Banes                        return new SavedState(in, loader);
717452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                    }
718452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
719452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                    @Override
720452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                    public SavedState[] newArray(int size) {
721452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                        return new SavedState[size];
722452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                    }
72305f5ba020fa6caa658c75b6d77436aa980ca0fccChris Banes                });
724452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
725452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
726f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    /**
727452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * A utility function to get the {@link BottomSheetBehavior} associated with the {@code view}.
728452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     *
729452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * @param view The {@link View} with {@link BottomSheetBehavior}.
730452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * @return The {@link BottomSheetBehavior} associated with the {@code view}.
731452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     */
732452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    @SuppressWarnings("unchecked")
733452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public static <V extends View> BottomSheetBehavior<V> from(V view) {
734452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        ViewGroup.LayoutParams params = view.getLayoutParams();
735452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        if (!(params instanceof CoordinatorLayout.LayoutParams)) {
736452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            throw new IllegalArgumentException("The view is not a child of CoordinatorLayout");
737452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
738452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        CoordinatorLayout.Behavior behavior = ((CoordinatorLayout.LayoutParams) params)
739452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                .getBehavior();
740452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        if (!(behavior instanceof BottomSheetBehavior)) {
741452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            throw new IllegalArgumentException(
742452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                    "The view is not associated with BottomSheetBehavior");
743452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
744452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        return (BottomSheetBehavior<V>) behavior;
745452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
746452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
747452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki}
748