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
198e10080c914d1ad0784394fa3026b85535535847Aurimas Liutikasimport static android.support.annotation.RestrictTo.Scope.LIBRARY_GROUP;
208e10080c914d1ad0784394fa3026b85535535847Aurimas Liutikas
21452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.content.Context;
22452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.content.res.TypedArray;
23452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.os.Parcel;
24452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.os.Parcelable;
25452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.support.annotation.IntDef;
26dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Arakiimport android.support.annotation.NonNull;
27c39d9c75590eca86a5e7e32a8824ba04a0d42e9bAlan Viveretteimport android.support.annotation.RestrictTo;
28a7a51521e1ecd8a009e4bd618520af05d9917671Yuichi Arakiimport android.support.annotation.VisibleForTesting;
29452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.support.design.R;
3012e0a308d1ab838cb05c395baa6f1251fcbb2363Aurimas Liutikasimport android.support.v4.math.MathUtils;
3105f5ba020fa6caa658c75b6d77436aa980ca0fccChris Banesimport android.support.v4.view.AbsSavedState;
32452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.support.v4.view.ViewCompat;
33452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.support.v4.widget.ViewDragHelper;
34452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.util.AttributeSet;
3501ca48bfc8ad80dae2e2809420af1e4b80dd4ae5Yuichi Arakiimport android.util.TypedValue;
36452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.view.MotionEvent;
37e3e7063749d095bba8743cad0aeb7164a567890dYuichi Arakiimport android.view.VelocityTracker;
38452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.view.View;
39e3e7063749d095bba8743cad0aeb7164a567890dYuichi Arakiimport android.view.ViewConfiguration;
40452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.view.ViewGroup;
41bfd8da2625c8198bd7d6884acb9f4b73ff35a2afYuichi Arakiimport android.view.ViewParent;
42452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
43452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport java.lang.annotation.Retention;
44452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport java.lang.annotation.RetentionPolicy;
45452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport java.lang.ref.WeakReference;
46452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
47452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
48452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki/**
49452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * An interaction behavior plugin for a child view of {@link CoordinatorLayout} to make it work as
50452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * a bottom sheet.
51452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki */
52452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakipublic class BottomSheetBehavior<V extends View> extends CoordinatorLayout.Behavior<V> {
53452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
54452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    /**
554df3c15e330c2f9730d3aa712f57befec8536dffYuichi Araki     * Callback for monitoring events about bottom sheets.
56f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     */
574df3c15e330c2f9730d3aa712f57befec8536dffYuichi Araki    public abstract static class BottomSheetCallback {
58f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
59f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        /**
60f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki         * Called when the bottom sheet changes its state.
61f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki         *
62dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki         * @param bottomSheet The bottom sheet view.
63dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki         * @param newState    The new state. This will be one of {@link #STATE_DRAGGING},
64dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki         *                    {@link #STATE_SETTLING}, {@link #STATE_EXPANDED},
65dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki         *                    {@link #STATE_COLLAPSED}, or {@link #STATE_HIDDEN}.
66f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki         */
67dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki        public abstract void onStateChanged(@NonNull View bottomSheet, @State int newState);
68f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
69f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        /**
70f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki         * Called when the bottom sheet is being dragged.
71f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki         *
72dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki         * @param bottomSheet The bottom sheet view.
7391177092bb7b2a0586f194de4d207349cdfabf30Aurimas Liutikas         * @param slideOffset The new offset of this bottom sheet within [-1,1] range. Offset
7491177092bb7b2a0586f194de4d207349cdfabf30Aurimas Liutikas         *                    increases as this bottom sheet is moving upward. From 0 to 1 the sheet
7591177092bb7b2a0586f194de4d207349cdfabf30Aurimas Liutikas         *                    is between collapsed and expanded states and from -1 to 0 it is
7691177092bb7b2a0586f194de4d207349cdfabf30Aurimas Liutikas         *                    between hidden and collapsed states.
77f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki         */
78dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki        public abstract void onSlide(@NonNull View bottomSheet, float slideOffset);
79f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    }
80f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
81f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    /**
82452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * The bottom sheet is dragging.
83452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     */
84452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public static final int STATE_DRAGGING = 1;
85452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
86452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    /**
87452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * The bottom sheet is settling.
88452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     */
89452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public static final int STATE_SETTLING = 2;
90452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
91452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    /**
92452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * The bottom sheet is expanded.
93452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     */
94452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public static final int STATE_EXPANDED = 3;
95452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
96452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    /**
97452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * The bottom sheet is collapsed.
98452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     */
99452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public static final int STATE_COLLAPSED = 4;
100452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
101f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    /**
102f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     * The bottom sheet is hidden.
103f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     */
104f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    public static final int STATE_HIDDEN = 5;
105f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
106452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    /** @hide */
1078e10080c914d1ad0784394fa3026b85535535847Aurimas Liutikas    @RestrictTo(LIBRARY_GROUP)
108f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    @IntDef({STATE_EXPANDED, STATE_COLLAPSED, STATE_DRAGGING, STATE_SETTLING, STATE_HIDDEN})
109452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    @Retention(RetentionPolicy.SOURCE)
110452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public @interface State {}
111452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
11201ca48bfc8ad80dae2e2809420af1e4b80dd4ae5Yuichi Araki    /**
11301ca48bfc8ad80dae2e2809420af1e4b80dd4ae5Yuichi Araki     * Peek at the 16:9 ratio keyline of its parent.
114645afdf27340a6620c9970d14923b556e3c66574Yuichi Araki     *
115645afdf27340a6620c9970d14923b556e3c66574Yuichi Araki     * <p>This can be used as a parameter for {@link #setPeekHeight(int)}.
116645afdf27340a6620c9970d14923b556e3c66574Yuichi Araki     * {@link #getPeekHeight()} will return this when the value is set.</p>
11701ca48bfc8ad80dae2e2809420af1e4b80dd4ae5Yuichi Araki     */
11801ca48bfc8ad80dae2e2809420af1e4b80dd4ae5Yuichi Araki    public static final int PEEK_HEIGHT_AUTO = -1;
11901ca48bfc8ad80dae2e2809420af1e4b80dd4ae5Yuichi Araki
120f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    private static final float HIDE_THRESHOLD = 0.5f;
121f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
122f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    private static final float HIDE_FRICTION = 0.1f;
123f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
124e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki    private float mMaximumVelocity;
125f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
126452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    private int mPeekHeight;
127452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
12801ca48bfc8ad80dae2e2809420af1e4b80dd4ae5Yuichi Araki    private boolean mPeekHeightAuto;
12901ca48bfc8ad80dae2e2809420af1e4b80dd4ae5Yuichi Araki
13001ca48bfc8ad80dae2e2809420af1e4b80dd4ae5Yuichi Araki    private int mPeekHeightMin;
13101ca48bfc8ad80dae2e2809420af1e4b80dd4ae5Yuichi Araki
132657ea1100fee4750f148f9d0dcb7e7e2028f105eAurimas Liutikas    int mMinOffset;
133452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
134657ea1100fee4750f148f9d0dcb7e7e2028f105eAurimas Liutikas    int mMaxOffset;
135452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
136657ea1100fee4750f148f9d0dcb7e7e2028f105eAurimas Liutikas    boolean mHideable;
137f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
138362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki    private boolean mSkipCollapsed;
139362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki
140452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    @State
141657ea1100fee4750f148f9d0dcb7e7e2028f105eAurimas Liutikas    int mState = STATE_COLLAPSED;
142452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
143657ea1100fee4750f148f9d0dcb7e7e2028f105eAurimas Liutikas    ViewDragHelper mViewDragHelper;
144452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
145452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    private boolean mIgnoreEvents;
146452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
147e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki    private int mLastNestedScrollDy;
148e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki
14949a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki    private boolean mNestedScrolled;
15049a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki
151657ea1100fee4750f148f9d0dcb7e7e2028f105eAurimas Liutikas    int mParentHeight;
152452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
153657ea1100fee4750f148f9d0dcb7e7e2028f105eAurimas Liutikas    WeakReference<V> mViewRef;
154452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
155657ea1100fee4750f148f9d0dcb7e7e2028f105eAurimas Liutikas    WeakReference<View> mNestedScrollingChildRef;
156f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
1579aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki    private BottomSheetCallback mCallback;
158f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
159e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki    private VelocityTracker mVelocityTracker;
160e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki
161657ea1100fee4750f148f9d0dcb7e7e2028f105eAurimas Liutikas    int mActivePointerId;
162f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
1634eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki    private int mInitialY;
1644eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki
165657ea1100fee4750f148f9d0dcb7e7e2028f105eAurimas Liutikas    boolean mTouchingScrollingChild;
166b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki
167452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    /**
168452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * Default constructor for instantiating BottomSheetBehaviors.
169452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     */
170452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public BottomSheetBehavior() {
171452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
172452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
173452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    /**
174452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * Default constructor for inflating BottomSheetBehaviors from layout.
175452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     *
176452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * @param context The {@link Context}.
177452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * @param attrs   The {@link AttributeSet}.
178452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     */
179452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public BottomSheetBehavior(Context context, AttributeSet attrs) {
180452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        super(context, attrs);
181452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        TypedArray a = context.obtainStyledAttributes(attrs,
182c6cbbb50a06ec08e6888bd1c3dfd7fdf588d9db5Chris Banes                R.styleable.BottomSheetBehavior_Layout);
18301ca48bfc8ad80dae2e2809420af1e4b80dd4ae5Yuichi Araki        TypedValue value = a.peekValue(R.styleable.BottomSheetBehavior_Layout_behavior_peekHeight);
184606579592e9e9303a89cae2cf9bfe9f21572eec3Yuichi Araki        if (value != null && value.data == PEEK_HEIGHT_AUTO) {
18501ca48bfc8ad80dae2e2809420af1e4b80dd4ae5Yuichi Araki            setPeekHeight(value.data);
18601ca48bfc8ad80dae2e2809420af1e4b80dd4ae5Yuichi Araki        } else {
18701ca48bfc8ad80dae2e2809420af1e4b80dd4ae5Yuichi Araki            setPeekHeight(a.getDimensionPixelSize(
18801ca48bfc8ad80dae2e2809420af1e4b80dd4ae5Yuichi Araki                    R.styleable.BottomSheetBehavior_Layout_behavior_peekHeight, PEEK_HEIGHT_AUTO));
18901ca48bfc8ad80dae2e2809420af1e4b80dd4ae5Yuichi Araki        }
190c6cbbb50a06ec08e6888bd1c3dfd7fdf588d9db5Chris Banes        setHideable(a.getBoolean(R.styleable.BottomSheetBehavior_Layout_behavior_hideable, false));
191362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki        setSkipCollapsed(a.getBoolean(R.styleable.BottomSheetBehavior_Layout_behavior_skipCollapsed,
192362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki                false));
193452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        a.recycle();
194e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        ViewConfiguration configuration = ViewConfiguration.get(context);
195e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
196452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
197452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
198452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    @Override
199452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public Parcelable onSaveInstanceState(CoordinatorLayout parent, V child) {
200452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        return new SavedState(super.onSaveInstanceState(parent, child), mState);
201452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
202452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
203452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    @Override
204452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public void onRestoreInstanceState(CoordinatorLayout parent, V child, Parcelable state) {
205452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        SavedState ss = (SavedState) state;
206452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        super.onRestoreInstanceState(parent, child, ss.getSuperState());
207452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        // Intermediate states are restored as collapsed state
208f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        if (ss.state == STATE_DRAGGING || ss.state == STATE_SETTLING) {
209452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            mState = STATE_COLLAPSED;
210f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        } else {
211f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            mState = ss.state;
212452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
213452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
214452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
215452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    @Override
216452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public boolean onLayoutChild(CoordinatorLayout parent, V child, int layoutDirection) {
2176bef5a31fd4bbfc70b21c0f694bcb272e88400a3Yuichi Araki        if (ViewCompat.getFitsSystemWindows(parent) && !ViewCompat.getFitsSystemWindows(child)) {
2186bef5a31fd4bbfc70b21c0f694bcb272e88400a3Yuichi Araki            ViewCompat.setFitsSystemWindows(child, true);
219f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        }
2206bef5a31fd4bbfc70b21c0f694bcb272e88400a3Yuichi Araki        int savedTop = child.getTop();
2216bef5a31fd4bbfc70b21c0f694bcb272e88400a3Yuichi Araki        // First let the parent lay it out
2226bef5a31fd4bbfc70b21c0f694bcb272e88400a3Yuichi Araki        parent.onLayoutChild(child, layoutDirection);
223452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        // Offset the bottom sheet
224452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        mParentHeight = parent.getHeight();
22501ca48bfc8ad80dae2e2809420af1e4b80dd4ae5Yuichi Araki        int peekHeight;
22601ca48bfc8ad80dae2e2809420af1e4b80dd4ae5Yuichi Araki        if (mPeekHeightAuto) {
22701ca48bfc8ad80dae2e2809420af1e4b80dd4ae5Yuichi Araki            if (mPeekHeightMin == 0) {
22801ca48bfc8ad80dae2e2809420af1e4b80dd4ae5Yuichi Araki                mPeekHeightMin = parent.getResources().getDimensionPixelSize(
22901ca48bfc8ad80dae2e2809420af1e4b80dd4ae5Yuichi Araki                        R.dimen.design_bottom_sheet_peek_height_min);
23001ca48bfc8ad80dae2e2809420af1e4b80dd4ae5Yuichi Araki            }
23101ca48bfc8ad80dae2e2809420af1e4b80dd4ae5Yuichi Araki            peekHeight = Math.max(mPeekHeightMin, mParentHeight - parent.getWidth() * 9 / 16);
23201ca48bfc8ad80dae2e2809420af1e4b80dd4ae5Yuichi Araki        } else {
23301ca48bfc8ad80dae2e2809420af1e4b80dd4ae5Yuichi Araki            peekHeight = mPeekHeight;
23401ca48bfc8ad80dae2e2809420af1e4b80dd4ae5Yuichi Araki        }
235452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        mMinOffset = Math.max(0, mParentHeight - child.getHeight());
23601ca48bfc8ad80dae2e2809420af1e4b80dd4ae5Yuichi Araki        mMaxOffset = Math.max(mParentHeight - peekHeight, mMinOffset);
237452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        if (mState == STATE_EXPANDED) {
238452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            ViewCompat.offsetTopAndBottom(child, mMinOffset);
239f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        } else if (mHideable && mState == STATE_HIDDEN) {
240f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            ViewCompat.offsetTopAndBottom(child, mParentHeight);
241f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        } else if (mState == STATE_COLLAPSED) {
242452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            ViewCompat.offsetTopAndBottom(child, mMaxOffset);
2436bef5a31fd4bbfc70b21c0f694bcb272e88400a3Yuichi Araki        } else if (mState == STATE_DRAGGING || mState == STATE_SETTLING) {
2446bef5a31fd4bbfc70b21c0f694bcb272e88400a3Yuichi Araki            ViewCompat.offsetTopAndBottom(child, savedTop - child.getTop());
245452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
246452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        if (mViewDragHelper == null) {
247452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            mViewDragHelper = ViewDragHelper.create(parent, mDragCallback);
248452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
249452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        mViewRef = new WeakReference<>(child);
2509aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki        mNestedScrollingChildRef = new WeakReference<>(findScrollingChild(child));
251452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        return true;
252452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
253452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
254452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    @Override
255452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public boolean onInterceptTouchEvent(CoordinatorLayout parent, V child, MotionEvent event) {
25617fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki        if (!child.isShown()) {
2576cb44089e8c7a5abf8aa7a0cdff3cb6888790708Yuichi Araki            mIgnoreEvents = true;
25817fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki            return false;
25917fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki        }
2606ed40c1f86bcb172a1f0f069cde1c571a7781aeeAurimas Liutikas        int action = event.getActionMasked();
261e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        // Record the velocity
262e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        if (action == MotionEvent.ACTION_DOWN) {
263e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki            reset();
264e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        }
265e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        if (mVelocityTracker == null) {
266e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki            mVelocityTracker = VelocityTracker.obtain();
267e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        }
268e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        mVelocityTracker.addMovement(event);
269452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        switch (action) {
270452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            case MotionEvent.ACTION_UP:
271452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            case MotionEvent.ACTION_CANCEL:
272b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki                mTouchingScrollingChild = false;
273e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki                mActivePointerId = MotionEvent.INVALID_POINTER_ID;
274452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                // Reset the ignore flag
275452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                if (mIgnoreEvents) {
276452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                    mIgnoreEvents = false;
277452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                    return false;
278452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                }
279452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                break;
280452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            case MotionEvent.ACTION_DOWN:
2814eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki                int initialX = (int) event.getX();
2824eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki                mInitialY = (int) event.getY();
283eb0922a6531ce1debff929814fff4b3df4159a45Geoffrey Métais                View scroll = mNestedScrollingChildRef != null
284eb0922a6531ce1debff929814fff4b3df4159a45Geoffrey Métais                        ? mNestedScrollingChildRef.get() : null;
2854eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki                if (scroll != null && parent.isPointInChildBounds(scroll, initialX, mInitialY)) {
286e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki                    mActivePointerId = event.getPointerId(event.getActionIndex());
287b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki                    mTouchingScrollingChild = true;
2889aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki                }
289e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki                mIgnoreEvents = mActivePointerId == MotionEvent.INVALID_POINTER_ID &&
2904eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki                        !parent.isPointInChildBounds(child, initialX, mInitialY);
291452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                break;
292452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
2934eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki        if (!mIgnoreEvents && mViewDragHelper.shouldInterceptTouchEvent(event)) {
2944eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki            return true;
2954eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki        }
2964eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki        // We have to handle cases that the ViewDragHelper does not capture the bottom sheet because
2974eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki        // it is not the top most view of its parent. This is not necessary when the touch event is
2984eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki        // happening over the scrolling content as nested scrolling logic handles that case.
2994eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki        View scroll = mNestedScrollingChildRef.get();
3004eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki        return action == MotionEvent.ACTION_MOVE && scroll != null &&
3014eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki                !mIgnoreEvents && mState != STATE_DRAGGING &&
3024eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki                !parent.isPointInChildBounds(scroll, (int) event.getX(), (int) event.getY()) &&
3034eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki                Math.abs(mInitialY - event.getY()) > mViewDragHelper.getTouchSlop();
304452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
305452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
306452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    @Override
307452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public boolean onTouchEvent(CoordinatorLayout parent, V child, MotionEvent event) {
30817fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki        if (!child.isShown()) {
30917fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki            return false;
31017fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki        }
3116ed40c1f86bcb172a1f0f069cde1c571a7781aeeAurimas Liutikas        int action = event.getActionMasked();
312e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        if (mState == STATE_DRAGGING && action == MotionEvent.ACTION_DOWN) {
313e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki            return true;
314e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        }
315452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        mViewDragHelper.processTouchEvent(event);
316e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        // Record the velocity
317e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        if (action == MotionEvent.ACTION_DOWN) {
318e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki            reset();
319e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        }
320e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        if (mVelocityTracker == null) {
321e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki            mVelocityTracker = VelocityTracker.obtain();
322e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        }
323e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        mVelocityTracker.addMovement(event);
3244eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki        // The ViewDragHelper tries to capture only the top-most View. We have to explicitly tell it
3254eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki        // to capture the bottom sheet in case it is not captured and the touch slop is passed.
326912d40d353f5b6d0a4fa18740ca40aa4b25b0f9cYuichi Araki        if (action == MotionEvent.ACTION_MOVE && !mIgnoreEvents) {
3274eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki            if (Math.abs(mInitialY - event.getY()) > mViewDragHelper.getTouchSlop()) {
3284eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki                mViewDragHelper.captureChildView(child, event.getPointerId(event.getActionIndex()));
3294eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki            }
3304eb453c75e552a2e0231a93468d9597a4069286eYuichi Araki        }
3311dbdc6baec537b45e9bd8e5afabcb5c35f1a8004Yuichi Araki        return !mIgnoreEvents;
332452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
333452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
334e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki    @Override
335e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki    public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, V child,
336e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki            View directTargetChild, View target, int nestedScrollAxes) {
337e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        mLastNestedScrollDy = 0;
33849a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki        mNestedScrolled = false;
339e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        return (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;
340e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki    }
341e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki
342e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki    @Override
343e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki    public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, V child, View target, int dx,
344e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki            int dy, int[] consumed) {
345e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        View scrollingChild = mNestedScrollingChildRef.get();
346e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        if (target != scrollingChild) {
347e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki            return;
348e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        }
349e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        int currentTop = child.getTop();
350e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        int newTop = currentTop - dy;
351e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        if (dy > 0) { // Upward
352e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki            if (newTop < mMinOffset) {
353e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki                consumed[1] = currentTop - mMinOffset;
354e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki                ViewCompat.offsetTopAndBottom(child, -consumed[1]);
355e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki                setStateInternal(STATE_EXPANDED);
356e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki            } else {
357e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki                consumed[1] = dy;
358e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki                ViewCompat.offsetTopAndBottom(child, -dy);
359e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki                setStateInternal(STATE_DRAGGING);
360e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki            }
361e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        } else if (dy < 0) { // Downward
362e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki            if (!ViewCompat.canScrollVertically(target, -1)) {
363e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki                if (newTop <= mMaxOffset || mHideable) {
364e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki                    consumed[1] = dy;
365e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki                    ViewCompat.offsetTopAndBottom(child, -dy);
366e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki                    setStateInternal(STATE_DRAGGING);
367e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki                } else {
368e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki                    consumed[1] = currentTop - mMaxOffset;
369e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki                    ViewCompat.offsetTopAndBottom(child, -consumed[1]);
370e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki                    setStateInternal(STATE_COLLAPSED);
371e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki                }
372e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki            }
373e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        }
374e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        dispatchOnSlide(child.getTop());
375e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        mLastNestedScrollDy = dy;
37649a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki        mNestedScrolled = true;
377e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki    }
378e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki
379e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki    @Override
380e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki    public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, V child, View target) {
381b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki        if (child.getTop() == mMinOffset) {
382b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki            setStateInternal(STATE_EXPANDED);
383b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki            return;
384b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki        }
385d1e6ea34363dbb189490bb793692c86c2ebecf47Geoffrey Métais        if (mNestedScrollingChildRef == null || target != mNestedScrollingChildRef.get()
386d1e6ea34363dbb189490bb793692c86c2ebecf47Geoffrey Métais                || !mNestedScrolled) {
387e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki            return;
388e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        }
389e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        int top;
390e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        int targetState;
391e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        if (mLastNestedScrollDy > 0) {
392e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki            top = mMinOffset;
393e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki            targetState = STATE_EXPANDED;
394e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        } else if (mHideable && shouldHide(child, getYVelocity())) {
395e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki            top = mParentHeight;
396e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki            targetState = STATE_HIDDEN;
39749a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki        } else if (mLastNestedScrollDy == 0) {
39849a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki            int currentTop = child.getTop();
39949a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki            if (Math.abs(currentTop - mMinOffset) < Math.abs(currentTop - mMaxOffset)) {
40049a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki                top = mMinOffset;
40149a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki                targetState = STATE_EXPANDED;
40249a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki            } else {
40349a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki                top = mMaxOffset;
40449a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki                targetState = STATE_COLLAPSED;
40549a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki            }
406e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        } else {
407e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki            top = mMaxOffset;
408e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki            targetState = STATE_COLLAPSED;
409e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        }
410e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        if (mViewDragHelper.smoothSlideViewTo(child, child.getLeft(), top)) {
411e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki            setStateInternal(STATE_SETTLING);
412e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki            ViewCompat.postOnAnimation(child, new SettleRunnable(child, targetState));
413e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        } else {
414e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki            setStateInternal(targetState);
415e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        }
41649a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki        mNestedScrolled = false;
417e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki    }
418e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki
419e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki    @Override
420e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki    public boolean onNestedPreFling(CoordinatorLayout coordinatorLayout, V child, View target,
421e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki            float velocityX, float velocityY) {
422e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        return target == mNestedScrollingChildRef.get() &&
423e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki                (mState != STATE_EXPANDED ||
424e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki                        super.onNestedPreFling(coordinatorLayout, child, target,
425e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki                                velocityX, velocityY));
426e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki    }
427e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki
428452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    /**
429452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * Sets the height of the bottom sheet when it is collapsed.
430452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     *
43101ca48bfc8ad80dae2e2809420af1e4b80dd4ae5Yuichi Araki     * @param peekHeight The height of the collapsed bottom sheet in pixels, or
432a36fbe5e02568bfae82904e7c7ac39438bde4551Yuichi Araki     *                   {@link #PEEK_HEIGHT_AUTO} to configure the sheet to peek automatically
433a36fbe5e02568bfae82904e7c7ac39438bde4551Yuichi Araki     *                   at 16:9 ratio keyline.
43473e7a06fb66110495fa4e98a91831a47feab2526Chris Banes     * @attr ref android.support.design.R.styleable#BottomSheetBehavior_Layout_behavior_peekHeight
435452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     */
436452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public final void setPeekHeight(int peekHeight) {
43701ca48bfc8ad80dae2e2809420af1e4b80dd4ae5Yuichi Araki        boolean layout = false;
43801ca48bfc8ad80dae2e2809420af1e4b80dd4ae5Yuichi Araki        if (peekHeight == PEEK_HEIGHT_AUTO) {
43901ca48bfc8ad80dae2e2809420af1e4b80dd4ae5Yuichi Araki            if (!mPeekHeightAuto) {
44001ca48bfc8ad80dae2e2809420af1e4b80dd4ae5Yuichi Araki                mPeekHeightAuto = true;
44101ca48bfc8ad80dae2e2809420af1e4b80dd4ae5Yuichi Araki                layout = true;
44201ca48bfc8ad80dae2e2809420af1e4b80dd4ae5Yuichi Araki            }
44301ca48bfc8ad80dae2e2809420af1e4b80dd4ae5Yuichi Araki        } else if (mPeekHeightAuto || mPeekHeight != peekHeight) {
44401ca48bfc8ad80dae2e2809420af1e4b80dd4ae5Yuichi Araki            mPeekHeightAuto = false;
44501ca48bfc8ad80dae2e2809420af1e4b80dd4ae5Yuichi Araki            mPeekHeight = Math.max(0, peekHeight);
44601ca48bfc8ad80dae2e2809420af1e4b80dd4ae5Yuichi Araki            mMaxOffset = mParentHeight - peekHeight;
44701ca48bfc8ad80dae2e2809420af1e4b80dd4ae5Yuichi Araki            layout = true;
44801ca48bfc8ad80dae2e2809420af1e4b80dd4ae5Yuichi Araki        }
44901ca48bfc8ad80dae2e2809420af1e4b80dd4ae5Yuichi Araki        if (layout && mState == STATE_COLLAPSED && mViewRef != null) {
45001ca48bfc8ad80dae2e2809420af1e4b80dd4ae5Yuichi Araki            V view = mViewRef.get();
45101ca48bfc8ad80dae2e2809420af1e4b80dd4ae5Yuichi Araki            if (view != null) {
45201ca48bfc8ad80dae2e2809420af1e4b80dd4ae5Yuichi Araki                view.requestLayout();
45301ca48bfc8ad80dae2e2809420af1e4b80dd4ae5Yuichi Araki            }
45401ca48bfc8ad80dae2e2809420af1e4b80dd4ae5Yuichi Araki        }
455452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
456452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
457452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    /**
458452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * Gets the height of the bottom sheet when it is collapsed.
459452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     *
460a36fbe5e02568bfae82904e7c7ac39438bde4551Yuichi Araki     * @return The height of the collapsed bottom sheet in pixels, or {@link #PEEK_HEIGHT_AUTO}
461a36fbe5e02568bfae82904e7c7ac39438bde4551Yuichi Araki     *         if the sheet is configured to peek automatically at 16:9 ratio keyline
46273e7a06fb66110495fa4e98a91831a47feab2526Chris Banes     * @attr ref android.support.design.R.styleable#BottomSheetBehavior_Layout_behavior_peekHeight
463452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     */
464452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public final int getPeekHeight() {
465a36fbe5e02568bfae82904e7c7ac39438bde4551Yuichi Araki        return mPeekHeightAuto ? PEEK_HEIGHT_AUTO : mPeekHeight;
466452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
467452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
468452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    /**
469f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     * Sets whether this bottom sheet can hide when it is swiped down.
470f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     *
471f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     * @param hideable {@code true} to make this bottom sheet hideable.
47273e7a06fb66110495fa4e98a91831a47feab2526Chris Banes     * @attr ref android.support.design.R.styleable#BottomSheetBehavior_Layout_behavior_hideable
473f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     */
474f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    public void setHideable(boolean hideable) {
475f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        mHideable = hideable;
476f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    }
477f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
478f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    /**
479f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     * Gets whether this bottom sheet can hide when it is swiped down.
480f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     *
481f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     * @return {@code true} if this bottom sheet can hide.
48273e7a06fb66110495fa4e98a91831a47feab2526Chris Banes     * @attr ref android.support.design.R.styleable#BottomSheetBehavior_Layout_behavior_hideable
483f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     */
484f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    public boolean isHideable() {
485f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        return mHideable;
486f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    }
487f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
488f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    /**
489362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki     * Sets whether this bottom sheet should skip the collapsed state when it is being hidden
490362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki     * after it is expanded once. Setting this to true has no effect unless the sheet is hideable.
491362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki     *
492362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki     * @param skipCollapsed True if the bottom sheet should skip the collapsed state.
493362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki     * @attr ref android.support.design.R.styleable#BottomSheetBehavior_Layout_behavior_skipCollapsed
494362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki     */
495362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki    public void setSkipCollapsed(boolean skipCollapsed) {
496362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki        mSkipCollapsed = skipCollapsed;
497362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki    }
498362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki
499362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki    /**
500362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki     * Sets whether this bottom sheet should skip the collapsed state when it is being hidden
501362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki     * after it is expanded once.
502362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki     *
503362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki     * @return Whether the bottom sheet should skip the collapsed state.
504362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki     * @attr ref android.support.design.R.styleable#BottomSheetBehavior_Layout_behavior_skipCollapsed
505362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki     */
506362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki    public boolean getSkipCollapsed() {
507362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki        return mSkipCollapsed;
508362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki    }
509362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki
510362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki    /**
5114df3c15e330c2f9730d3aa712f57befec8536dffYuichi Araki     * Sets a callback to be notified of bottom sheet events.
512f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     *
5134df3c15e330c2f9730d3aa712f57befec8536dffYuichi Araki     * @param callback The callback to notify when bottom sheet events occur.
514f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     */
5154df3c15e330c2f9730d3aa712f57befec8536dffYuichi Araki    public void setBottomSheetCallback(BottomSheetCallback callback) {
5164df3c15e330c2f9730d3aa712f57befec8536dffYuichi Araki        mCallback = callback;
517f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    }
518f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
519f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    /**
520452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * Sets the state of the bottom sheet. The bottom sheet will transition to that state with
521452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * animation.
522452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     *
523f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     * @param state One of {@link #STATE_COLLAPSED}, {@link #STATE_EXPANDED}, or
524f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     *              {@link #STATE_HIDDEN}.
525452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     */
526bfd8da2625c8198bd7d6884acb9f4b73ff35a2afYuichi Araki    public final void setState(final @State int state) {
527e0573dfb5896eb66e266ea366d8c58437c739c95Yuichi Araki        if (state == mState) {
528e0573dfb5896eb66e266ea366d8c58437c739c95Yuichi Araki            return;
529e0573dfb5896eb66e266ea366d8c58437c739c95Yuichi Araki        }
53098475d29e771d7b15e4a109b22f410c7c1cf33d7Taeho Kim        if (mViewRef == null) {
5316deb3a9dc52be7ab61702c430bb327343ef099acYuichi Araki            // The view is not laid out yet; modify mState and let onLayoutChild handle it later
5326deb3a9dc52be7ab61702c430bb327343ef099acYuichi Araki            if (state == STATE_COLLAPSED || state == STATE_EXPANDED ||
5336deb3a9dc52be7ab61702c430bb327343ef099acYuichi Araki                    (mHideable && state == STATE_HIDDEN)) {
5346deb3a9dc52be7ab61702c430bb327343ef099acYuichi Araki                mState = state;
5356deb3a9dc52be7ab61702c430bb327343ef099acYuichi Araki            }
53698475d29e771d7b15e4a109b22f410c7c1cf33d7Taeho Kim            return;
53798475d29e771d7b15e4a109b22f410c7c1cf33d7Taeho Kim        }
538bfd8da2625c8198bd7d6884acb9f4b73ff35a2afYuichi Araki        final V child = mViewRef.get();
539452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        if (child == null) {
540452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            return;
541452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
542bfd8da2625c8198bd7d6884acb9f4b73ff35a2afYuichi Araki        // Start the animation; wait until a pending layout if there is one.
543bfd8da2625c8198bd7d6884acb9f4b73ff35a2afYuichi Araki        ViewParent parent = child.getParent();
544bfd8da2625c8198bd7d6884acb9f4b73ff35a2afYuichi Araki        if (parent != null && parent.isLayoutRequested() && ViewCompat.isAttachedToWindow(child)) {
545bfd8da2625c8198bd7d6884acb9f4b73ff35a2afYuichi Araki            child.post(new Runnable() {
546bfd8da2625c8198bd7d6884acb9f4b73ff35a2afYuichi Araki                @Override
547bfd8da2625c8198bd7d6884acb9f4b73ff35a2afYuichi Araki                public void run() {
548bfd8da2625c8198bd7d6884acb9f4b73ff35a2afYuichi Araki                    startSettlingAnimation(child, state);
549bfd8da2625c8198bd7d6884acb9f4b73ff35a2afYuichi Araki                }
550bfd8da2625c8198bd7d6884acb9f4b73ff35a2afYuichi Araki            });
551452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        } else {
552bfd8da2625c8198bd7d6884acb9f4b73ff35a2afYuichi Araki            startSettlingAnimation(child, state);
553452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
554452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
555452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
556452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    /**
557452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * Gets the current state of the bottom sheet.
558452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     *
559452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * @return One of {@link #STATE_EXPANDED}, {@link #STATE_COLLAPSED}, {@link #STATE_DRAGGING},
560452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * and {@link #STATE_SETTLING}.
561452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     */
562452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    @State
563452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public final int getState() {
564452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        return mState;
565452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
566452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
567657ea1100fee4750f148f9d0dcb7e7e2028f105eAurimas Liutikas    void setStateInternal(@State int state) {
568452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        if (mState == state) {
569452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            return;
570452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
571452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        mState = state;
572dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki        View bottomSheet = mViewRef.get();
573dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki        if (bottomSheet != null && mCallback != null) {
574dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki            mCallback.onStateChanged(bottomSheet, state);
575f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        }
576f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    }
577f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
578e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki    private void reset() {
579e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        mActivePointerId = ViewDragHelper.INVALID_POINTER;
580e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        if (mVelocityTracker != null) {
581e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki            mVelocityTracker.recycle();
582e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki            mVelocityTracker = null;
583e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        }
584e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki    }
585e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki
586657ea1100fee4750f148f9d0dcb7e7e2028f105eAurimas Liutikas    boolean shouldHide(View child, float yvel) {
587362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki        if (mSkipCollapsed) {
588362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki            return true;
589362585b01e5ca19d1c58e4b152ad0a863b5f6d91Yuichi Araki        }
590f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        if (child.getTop() < mMaxOffset) {
591f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            // It should not hide, but collapse.
592f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            return false;
593f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        }
594f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        final float newTop = child.getTop() + yvel * HIDE_FRICTION;
595f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        return Math.abs(newTop - mMaxOffset) / (float) mPeekHeight > HIDE_THRESHOLD;
596f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    }
597f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
59847a4a1aac79f0ad2279c7a3eeaad1673646f4d81Kassim Maguire    @VisibleForTesting
59947a4a1aac79f0ad2279c7a3eeaad1673646f4d81Kassim Maguire    View findScrollingChild(View view) {
60047a4a1aac79f0ad2279c7a3eeaad1673646f4d81Kassim Maguire        if (ViewCompat.isNestedScrollingEnabled(view)) {
6019aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki            return view;
6029aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki        }
6039aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki        if (view instanceof ViewGroup) {
6049aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki            ViewGroup group = (ViewGroup) view;
6059aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki            for (int i = 0, count = group.getChildCount(); i < count; i++) {
6069aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki                View scrollingChild = findScrollingChild(group.getChildAt(i));
6079aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki                if (scrollingChild != null) {
6089aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki                    return scrollingChild;
6099aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki                }
6109aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki            }
6119aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki        }
6129aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki        return null;
613452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
614452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
615e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki    private float getYVelocity() {
616e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki        mVelocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
617374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas        return mVelocityTracker.getYVelocity(mActivePointerId);
618e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki    }
619e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki
620657ea1100fee4750f148f9d0dcb7e7e2028f105eAurimas Liutikas    void startSettlingAnimation(View child, int state) {
621bfd8da2625c8198bd7d6884acb9f4b73ff35a2afYuichi Araki        int top;
622bfd8da2625c8198bd7d6884acb9f4b73ff35a2afYuichi Araki        if (state == STATE_COLLAPSED) {
623bfd8da2625c8198bd7d6884acb9f4b73ff35a2afYuichi Araki            top = mMaxOffset;
624bfd8da2625c8198bd7d6884acb9f4b73ff35a2afYuichi Araki        } else if (state == STATE_EXPANDED) {
625bfd8da2625c8198bd7d6884acb9f4b73ff35a2afYuichi Araki            top = mMinOffset;
626bfd8da2625c8198bd7d6884acb9f4b73ff35a2afYuichi Araki        } else if (mHideable && state == STATE_HIDDEN) {
627bfd8da2625c8198bd7d6884acb9f4b73ff35a2afYuichi Araki            top = mParentHeight;
628bfd8da2625c8198bd7d6884acb9f4b73ff35a2afYuichi Araki        } else {
629bfd8da2625c8198bd7d6884acb9f4b73ff35a2afYuichi Araki            throw new IllegalArgumentException("Illegal state argument: " + state);
630bfd8da2625c8198bd7d6884acb9f4b73ff35a2afYuichi Araki        }
631bfd8da2625c8198bd7d6884acb9f4b73ff35a2afYuichi Araki        if (mViewDragHelper.smoothSlideViewTo(child, child.getLeft(), top)) {
6325347bf6b48710e49eb2058403329bf821883959fYuichi Araki            setStateInternal(STATE_SETTLING);
633bfd8da2625c8198bd7d6884acb9f4b73ff35a2afYuichi Araki            ViewCompat.postOnAnimation(child, new SettleRunnable(child, state));
6345347bf6b48710e49eb2058403329bf821883959fYuichi Araki        } else {
6355347bf6b48710e49eb2058403329bf821883959fYuichi Araki            setStateInternal(state);
636bfd8da2625c8198bd7d6884acb9f4b73ff35a2afYuichi Araki        }
637bfd8da2625c8198bd7d6884acb9f4b73ff35a2afYuichi Araki    }
638bfd8da2625c8198bd7d6884acb9f4b73ff35a2afYuichi Araki
639452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    private final ViewDragHelper.Callback mDragCallback = new ViewDragHelper.Callback() {
640452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
641452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        @Override
642452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        public boolean tryCaptureView(View child, int pointerId) {
643e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki            if (mState == STATE_DRAGGING) {
644e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki                return false;
645e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki            }
646b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki            if (mTouchingScrollingChild) {
647b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki                return false;
648b1eb1357ec33343b7271a6d3876ac4af84e15510Yuichi Araki            }
649e3e7063749d095bba8743cad0aeb7164a567890dYuichi Araki            if (mState == STATE_EXPANDED && mActivePointerId == pointerId) {
6509aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki                View scroll = mNestedScrollingChildRef.get();
6519aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki                if (scroll != null && ViewCompat.canScrollVertically(scroll, -1)) {
6529aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki                    // Let the content scroll up
6539aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki                    return false;
6549aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki                }
6559aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki            }
656f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            return mViewRef != null && mViewRef.get() == child;
657f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        }
658f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
659f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        @Override
660f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
661f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            dispatchOnSlide(top);
662452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
663452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
664452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        @Override
665452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        public void onViewDragStateChanged(int state) {
666452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            if (state == ViewDragHelper.STATE_DRAGGING) {
667452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                setStateInternal(STATE_DRAGGING);
668452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            }
669452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
670452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
671452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        @Override
672452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        public void onViewReleased(View releasedChild, float xvel, float yvel) {
673452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            int top;
674452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            @State int targetState;
675f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            if (yvel < 0) { // Moving up
676452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                top = mMinOffset;
677452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                targetState = STATE_EXPANDED;
678f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            } else if (mHideable && shouldHide(releasedChild, yvel)) {
679f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                top = mParentHeight;
680f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                targetState = STATE_HIDDEN;
68149a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki            } else if (yvel == 0.f) {
68249a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki                int currentTop = releasedChild.getTop();
68349a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki                if (Math.abs(currentTop - mMinOffset) < Math.abs(currentTop - mMaxOffset)) {
68449a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki                    top = mMinOffset;
68549a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki                    targetState = STATE_EXPANDED;
68649a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki                } else {
68749a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki                    top = mMaxOffset;
68849a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki                    targetState = STATE_COLLAPSED;
68949a5904a773a7cfac127c5938671ed078d8ec8f3Yuichi Araki                }
690452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            } else {
691452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                top = mMaxOffset;
692452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                targetState = STATE_COLLAPSED;
693452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            }
694452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            if (mViewDragHelper.settleCapturedViewAt(releasedChild.getLeft(), top)) {
695f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                setStateInternal(STATE_SETTLING);
696452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                ViewCompat.postOnAnimation(releasedChild,
697452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                        new SettleRunnable(releasedChild, targetState));
698f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            } else {
699f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                setStateInternal(targetState);
700452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            }
701452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
702452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
703452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        @Override
704452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        public int clampViewPositionVertical(View child, int top, int dy) {
70512e0a308d1ab838cb05c395baa6f1251fcbb2363Aurimas Liutikas            return MathUtils.clamp(top, mMinOffset, mHideable ? mParentHeight : mMaxOffset);
706452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
707452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
708452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        @Override
709452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        public int clampViewPositionHorizontal(View child, int left, int dx) {
710452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            return child.getLeft();
711452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
712f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
7139aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki        @Override
7149aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki        public int getViewVerticalDragRange(View child) {
7159aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki            if (mHideable) {
7169aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki                return mParentHeight - mMinOffset;
7179aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki            } else {
7189aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki                return mMaxOffset - mMinOffset;
7199aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki            }
7209aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki        }
721452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    };
722452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
723657ea1100fee4750f148f9d0dcb7e7e2028f105eAurimas Liutikas    void dispatchOnSlide(int top) {
724dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki        View bottomSheet = mViewRef.get();
725dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki        if (bottomSheet != null && mCallback != null) {
726f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            if (top > mMaxOffset) {
727e9864e3df037a1a5610752c6addc4d71e6b292c7Yuichi Araki                mCallback.onSlide(bottomSheet, (float) (mMaxOffset - top) /
728e9864e3df037a1a5610752c6addc4d71e6b292c7Yuichi Araki                        (mParentHeight - mMaxOffset));
729f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            } else {
730dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki                mCallback.onSlide(bottomSheet,
731dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki                        (float) (mMaxOffset - top) / ((mMaxOffset - mMinOffset)));
732f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            }
733f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        }
734f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    }
735f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
736a7a51521e1ecd8a009e4bd618520af05d9917671Yuichi Araki    @VisibleForTesting
737a7a51521e1ecd8a009e4bd618520af05d9917671Yuichi Araki    int getPeekHeightMin() {
738a7a51521e1ecd8a009e4bd618520af05d9917671Yuichi Araki        return mPeekHeightMin;
739a7a51521e1ecd8a009e4bd618520af05d9917671Yuichi Araki    }
740a7a51521e1ecd8a009e4bd618520af05d9917671Yuichi Araki
741452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    private class SettleRunnable implements Runnable {
742452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
743452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        private final View mView;
744452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
745452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        @State
746452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        private final int mTargetState;
747452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
748452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        SettleRunnable(View view, @State int targetState) {
749452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            mView = view;
750452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            mTargetState = targetState;
751452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
752452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
753452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        @Override
754452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        public void run() {
755452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            if (mViewDragHelper != null && mViewDragHelper.continueSettling(true)) {
756452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                ViewCompat.postOnAnimation(mView, this);
757452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            } else {
758452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                setStateInternal(mTargetState);
759452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            }
760452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
761452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
762452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
76305f5ba020fa6caa658c75b6d77436aa980ca0fccChris Banes    protected static class SavedState extends AbsSavedState {
764452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        @State
765452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        final int state;
766452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
767452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        public SavedState(Parcel source) {
76805f5ba020fa6caa658c75b6d77436aa980ca0fccChris Banes            this(source, null);
76905f5ba020fa6caa658c75b6d77436aa980ca0fccChris Banes        }
77005f5ba020fa6caa658c75b6d77436aa980ca0fccChris Banes
77105f5ba020fa6caa658c75b6d77436aa980ca0fccChris Banes        public SavedState(Parcel source, ClassLoader loader) {
77205f5ba020fa6caa658c75b6d77436aa980ca0fccChris Banes            super(source, loader);
773452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            //noinspection ResourceType
774452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            state = source.readInt();
775452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
776452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
777452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        public SavedState(Parcelable superState, @State int state) {
778452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            super(superState);
779452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            this.state = state;
780452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
781452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
782452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        @Override
783452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        public void writeToParcel(Parcel out, int flags) {
784452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            super.writeToParcel(out, flags);
785452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            out.writeInt(state);
786452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
787452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
7884b25d63ff53d4676150ac54897851e4ff9f1049fAurimas Liutikas        public static final Creator<SavedState> CREATOR = new ClassLoaderCreator<SavedState>() {
7894b25d63ff53d4676150ac54897851e4ff9f1049fAurimas Liutikas            @Override
7904b25d63ff53d4676150ac54897851e4ff9f1049fAurimas Liutikas            public SavedState createFromParcel(Parcel in, ClassLoader loader) {
7914b25d63ff53d4676150ac54897851e4ff9f1049fAurimas Liutikas                return new SavedState(in, loader);
7924b25d63ff53d4676150ac54897851e4ff9f1049fAurimas Liutikas            }
7934b25d63ff53d4676150ac54897851e4ff9f1049fAurimas Liutikas
7944b25d63ff53d4676150ac54897851e4ff9f1049fAurimas Liutikas            @Override
7954b25d63ff53d4676150ac54897851e4ff9f1049fAurimas Liutikas            public SavedState createFromParcel(Parcel in) {
7964b25d63ff53d4676150ac54897851e4ff9f1049fAurimas Liutikas                return new SavedState(in, null);
7974b25d63ff53d4676150ac54897851e4ff9f1049fAurimas Liutikas            }
798452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
7994b25d63ff53d4676150ac54897851e4ff9f1049fAurimas Liutikas            @Override
8004b25d63ff53d4676150ac54897851e4ff9f1049fAurimas Liutikas            public SavedState[] newArray(int size) {
8014b25d63ff53d4676150ac54897851e4ff9f1049fAurimas Liutikas                return new SavedState[size];
8024b25d63ff53d4676150ac54897851e4ff9f1049fAurimas Liutikas            }
8034b25d63ff53d4676150ac54897851e4ff9f1049fAurimas Liutikas        };
804452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
805452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
806f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    /**
807452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * A utility function to get the {@link BottomSheetBehavior} associated with the {@code view}.
808452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     *
809452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * @param view The {@link View} with {@link BottomSheetBehavior}.
810452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * @return The {@link BottomSheetBehavior} associated with the {@code view}.
811452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     */
812452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    @SuppressWarnings("unchecked")
813452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public static <V extends View> BottomSheetBehavior<V> from(V view) {
814452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        ViewGroup.LayoutParams params = view.getLayoutParams();
815452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        if (!(params instanceof CoordinatorLayout.LayoutParams)) {
816452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            throw new IllegalArgumentException("The view is not a child of CoordinatorLayout");
817452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
818452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        CoordinatorLayout.Behavior behavior = ((CoordinatorLayout.LayoutParams) params)
819452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                .getBehavior();
820452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        if (!(behavior instanceof BottomSheetBehavior)) {
821452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            throw new IllegalArgumentException(
822452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                    "The view is not associated with BottomSheetBehavior");
823452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
824452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        return (BottomSheetBehavior<V>) behavior;
825452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
826452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
827452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki}
828