BottomSheetBehavior.java revision 17fc77f5ca7c91daeab2e110669d9baf9d1a8090
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;
21f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Arakiimport android.os.Build;
22452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.os.Parcel;
23452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.os.Parcelable;
24452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.support.annotation.IntDef;
25dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Arakiimport android.support.annotation.NonNull;
26452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.support.design.R;
27452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.support.v4.view.MotionEventCompat;
289aec720809a123c6193304730acf8b55d6ce5a7aYuichi Arakiimport android.support.v4.view.NestedScrollingChild;
29452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.support.v4.view.ViewCompat;
30452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.support.v4.widget.ViewDragHelper;
31452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.util.AttributeSet;
32452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.view.MotionEvent;
33452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.view.View;
34452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.view.ViewGroup;
35f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Arakiimport android.view.ViewParent;
36452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
37452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport java.lang.annotation.Retention;
38452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport java.lang.annotation.RetentionPolicy;
39452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport java.lang.ref.WeakReference;
40452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
41452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
42452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki/**
43452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * An interaction behavior plugin for a child view of {@link CoordinatorLayout} to make it work as
44452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * a bottom sheet.
45452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki */
46452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakipublic class BottomSheetBehavior<V extends View> extends CoordinatorLayout.Behavior<V> {
47452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
48452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    /**
494df3c15e330c2f9730d3aa712f57befec8536dffYuichi Araki     * Callback for monitoring events about bottom sheets.
50f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     */
514df3c15e330c2f9730d3aa712f57befec8536dffYuichi Araki    public abstract static class BottomSheetCallback {
52f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
53f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        /**
54f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki         * Called when the bottom sheet changes its state.
55f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki         *
56dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki         * @param bottomSheet The bottom sheet view.
57dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki         * @param newState    The new state. This will be one of {@link #STATE_DRAGGING},
58dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki         *                    {@link #STATE_SETTLING}, {@link #STATE_EXPANDED},
59dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki         *                    {@link #STATE_COLLAPSED}, or {@link #STATE_HIDDEN}.
60f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki         */
61dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki        public abstract void onStateChanged(@NonNull View bottomSheet, @State int newState);
62f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
63f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        /**
64f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki         * Called when the bottom sheet is being dragged.
65f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki         *
66dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki         * @param bottomSheet The bottom sheet view.
67f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki         * @param slideOffset The new offset of this bottom sheet within its range, from 0 to 1
68f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki         *                    when it is moving upward, and from 0 to -1 when it moving downward.
69f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki         */
70dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki        public abstract void onSlide(@NonNull View bottomSheet, float slideOffset);
71f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    }
72f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
73f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    /**
74452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * The bottom sheet is dragging.
75452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     */
76452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public static final int STATE_DRAGGING = 1;
77452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
78452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    /**
79452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * The bottom sheet is settling.
80452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     */
81452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public static final int STATE_SETTLING = 2;
82452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
83452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    /**
84452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * The bottom sheet is expanded.
85452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     */
86452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public static final int STATE_EXPANDED = 3;
87452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
88452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    /**
89452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * The bottom sheet is collapsed.
90452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     */
91452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public static final int STATE_COLLAPSED = 4;
92452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
93f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    /**
94f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     * The bottom sheet is hidden.
95f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     */
96f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    public static final int STATE_HIDDEN = 5;
97f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
98452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    /** @hide */
99f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    @IntDef({STATE_EXPANDED, STATE_COLLAPSED, STATE_DRAGGING, STATE_SETTLING, STATE_HIDDEN})
100452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    @Retention(RetentionPolicy.SOURCE)
101452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public @interface State {}
102452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
103f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    private static final float HIDE_THRESHOLD = 0.5f;
104f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
105f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    private static final float HIDE_FRICTION = 0.1f;
106f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
107f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    // Whether to enable workaround for black non-rendered square
108f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    private static final boolean NEEDS_INVALIDATING = Build.VERSION.SDK_INT < 23;
109f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
110452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    private int mPeekHeight;
111452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
112452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    private int mMinOffset;
113452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
114452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    private int mMaxOffset;
115452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
116f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    private boolean mHideable;
117f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
118452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    @State
119452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    private int mState = STATE_COLLAPSED;
120452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
121452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    private ViewDragHelper mViewDragHelper;
122452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
123452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    private boolean mIgnoreEvents;
124452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
125452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    private int mParentHeight;
126452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
127452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    private WeakReference<V> mViewRef;
128452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
1299aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki    private WeakReference<View> mNestedScrollingChildRef;
130f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
1319aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki    private BottomSheetCallback mCallback;
132f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
1339aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki    private int mScrollingChildPointerId = MotionEvent.INVALID_POINTER_ID;
134f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
135452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    /**
136452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * Default constructor for instantiating BottomSheetBehaviors.
137452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     */
138452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public BottomSheetBehavior() {
139452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
140452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
141452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    /**
142452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * Default constructor for inflating BottomSheetBehaviors from layout.
143452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     *
144452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * @param context The {@link Context}.
145452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * @param attrs   The {@link AttributeSet}.
146452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     */
147452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public BottomSheetBehavior(Context context, AttributeSet attrs) {
148452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        super(context, attrs);
149452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        TypedArray a = context.obtainStyledAttributes(attrs,
150452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                R.styleable.BottomSheetBehavior_Params);
151452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        setPeekHeight(a.getDimensionPixelSize(
152452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                R.styleable.BottomSheetBehavior_Params_behavior_peekHeight, 0));
153f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        setHideable(a.getBoolean(R.styleable.BottomSheetBehavior_Params_behavior_hideable, false));
154452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        a.recycle();
155452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
156452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
157452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    @Override
158452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public Parcelable onSaveInstanceState(CoordinatorLayout parent, V child) {
159452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        return new SavedState(super.onSaveInstanceState(parent, child), mState);
160452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
161452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
162452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    @Override
163452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public void onRestoreInstanceState(CoordinatorLayout parent, V child, Parcelable state) {
164452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        SavedState ss = (SavedState) state;
165452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        super.onRestoreInstanceState(parent, child, ss.getSuperState());
166452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        // Intermediate states are restored as collapsed state
167f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        if (ss.state == STATE_DRAGGING || ss.state == STATE_SETTLING) {
168452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            mState = STATE_COLLAPSED;
169f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        } else {
170f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            mState = ss.state;
171452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
172452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
173452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
174452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    @Override
175452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public boolean onLayoutChild(CoordinatorLayout parent, V child, int layoutDirection) {
176452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        // First let the parent lay it out
177f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        if (mState != STATE_DRAGGING && mState != STATE_SETTLING) {
178f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            parent.onLayoutChild(child, layoutDirection);
179f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        }
180452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        // Offset the bottom sheet
181452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        mParentHeight = parent.getHeight();
182452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        mMinOffset = Math.max(0, mParentHeight - child.getHeight());
183452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        mMaxOffset = mParentHeight - mPeekHeight;
184452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        if (mState == STATE_EXPANDED) {
185452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            ViewCompat.offsetTopAndBottom(child, mMinOffset);
186f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        } else if (mHideable && mState == STATE_HIDDEN) {
187f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            ViewCompat.offsetTopAndBottom(child, mParentHeight);
188f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        } else if (mState == STATE_COLLAPSED) {
189452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            ViewCompat.offsetTopAndBottom(child, mMaxOffset);
190452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
191452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        if (mViewDragHelper == null) {
192452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            mViewDragHelper = ViewDragHelper.create(parent, mDragCallback);
193452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
194452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        mViewRef = new WeakReference<>(child);
1959aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki        mNestedScrollingChildRef = new WeakReference<>(findScrollingChild(child));
196452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        return true;
197452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
198452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
199452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    @Override
200452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public boolean onInterceptTouchEvent(CoordinatorLayout parent, V child, MotionEvent event) {
20117fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki        if (!child.isShown()) {
20217fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki            return false;
20317fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki        }
204452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        int action = MotionEventCompat.getActionMasked(event);
205452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        switch (action) {
206452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            case MotionEvent.ACTION_UP:
207452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            case MotionEvent.ACTION_CANCEL:
2089aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki                mScrollingChildPointerId = MotionEvent.INVALID_POINTER_ID;
209452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                // Reset the ignore flag
210452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                if (mIgnoreEvents) {
211452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                    mIgnoreEvents = false;
212452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                    return false;
213452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                }
214452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                break;
215452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            case MotionEvent.ACTION_DOWN:
2169aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki                int x = (int) event.getX();
2179aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki                int y = (int) event.getY();
2189aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki                View scroll = mNestedScrollingChildRef.get();
2199aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki                if (scroll != null && parent.isPointInChildBounds(scroll, x, y)) {
2209aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki                    mScrollingChildPointerId = event.getPointerId(event.getActionIndex());
2219aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki                } else {
2229aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki                    mScrollingChildPointerId = MotionEvent.INVALID_POINTER_ID;
2239aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki                }
2249aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki                mIgnoreEvents = mScrollingChildPointerId == MotionEvent.INVALID_POINTER_ID &&
2259aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki                        !parent.isPointInChildBounds(child, x, y);
226452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                break;
227452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
228452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        return !mIgnoreEvents && mViewDragHelper.shouldInterceptTouchEvent(event);
229452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
230452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
231452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    @Override
232452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public boolean onTouchEvent(CoordinatorLayout parent, V child, MotionEvent event) {
23317fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki        if (!child.isShown()) {
23417fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki            return false;
23517fc77f5ca7c91daeab2e110669d9baf9d1a8090Yuichi Araki        }
236452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        mViewDragHelper.processTouchEvent(event);
237452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        return true;
238452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
239452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
240452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    /**
241452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * Sets the height of the bottom sheet when it is collapsed.
242452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     *
243452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * @param peekHeight The height of the collapsed bottom sheet in pixels.
244452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * @attr ref android.support.design.R.styleable#BottomSheetBehavior_Params_behavior_peekHeight
245452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     */
246452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public final void setPeekHeight(int peekHeight) {
247452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        mPeekHeight = Math.max(0, peekHeight);
248452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        mMaxOffset = mParentHeight - peekHeight;
249452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
250452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
251452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    /**
252452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * Gets the height of the bottom sheet when it is collapsed.
253452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     *
254452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * @return The height of the collapsed bottom sheet.
255452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * @attr ref android.support.design.R.styleable#BottomSheetBehavior_Params_behavior_peekHeight
256452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     */
257452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public final int getPeekHeight() {
258452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        return mPeekHeight;
259452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
260452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
261452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    /**
262f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     * Sets whether this bottom sheet can hide when it is swiped down.
263f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     *
264f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     * @param hideable {@code true} to make this bottom sheet hideable.
265f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     * @attr ref android.support.design.R.styleable#BottomSheetBehavior_Params_behavior_hideable
266f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     */
267f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    public void setHideable(boolean hideable) {
268f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        mHideable = hideable;
269f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    }
270f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
271f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    /**
272f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     * Gets whether this bottom sheet can hide when it is swiped down.
273f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     *
274f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     * @return {@code true} if this bottom sheet can hide.
275f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     * @attr ref android.support.design.R.styleable#BottomSheetBehavior_Params_behavior_hideable
276f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     */
277f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    public boolean isHideable() {
278f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        return mHideable;
279f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    }
280f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
281f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    /**
2824df3c15e330c2f9730d3aa712f57befec8536dffYuichi Araki     * Sets a callback to be notified of bottom sheet events.
283f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     *
2844df3c15e330c2f9730d3aa712f57befec8536dffYuichi Araki     * @param callback The callback to notify when bottom sheet events occur.
285f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     */
2864df3c15e330c2f9730d3aa712f57befec8536dffYuichi Araki    public void setBottomSheetCallback(BottomSheetCallback callback) {
2874df3c15e330c2f9730d3aa712f57befec8536dffYuichi Araki        mCallback = callback;
288f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    }
289f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
290f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    /**
291452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * Sets the state of the bottom sheet. The bottom sheet will transition to that state with
292452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * animation.
293452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     *
294f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     * @param state One of {@link #STATE_COLLAPSED}, {@link #STATE_EXPANDED}, or
295f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     *              {@link #STATE_HIDDEN}.
296452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     */
297452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public final void setState(@State int state) {
298452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        V child = mViewRef.get();
299452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        if (child == null) {
300452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            return;
301452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
302452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        int top;
303452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        if (state == STATE_COLLAPSED) {
304452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            top = mMaxOffset;
305452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        } else if (state == STATE_EXPANDED) {
306452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            top = mMinOffset;
307f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        } else if (mHideable && state == STATE_HIDDEN) {
308f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            top = mParentHeight;
309452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        } else {
310452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            throw new IllegalArgumentException("Illegal state argument: " + state);
311452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
312452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        setStateInternal(STATE_SETTLING);
313452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        if (mViewDragHelper.smoothSlideViewTo(child, child.getLeft(), top)) {
314452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            ViewCompat.postOnAnimation(child, new SettleRunnable(child, state));
315452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
316452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
317452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
318452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    /**
319452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * Gets the current state of the bottom sheet.
320452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     *
321452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * @return One of {@link #STATE_EXPANDED}, {@link #STATE_COLLAPSED}, {@link #STATE_DRAGGING},
322452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * and {@link #STATE_SETTLING}.
323452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     */
324452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    @State
325452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public final int getState() {
326452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        return mState;
327452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
328452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
329452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    private void setStateInternal(@State int state) {
330452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        if (mState == state) {
331452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            return;
332452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
333452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        mState = state;
334dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki        View bottomSheet = mViewRef.get();
335dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki        if (bottomSheet != null && mCallback != null) {
336dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki            mCallback.onStateChanged(bottomSheet, state);
337f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        }
338f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    }
339f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
340f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    private boolean shouldHide(View child, float yvel) {
341f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        if (child.getTop() < mMaxOffset) {
342f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            // It should not hide, but collapse.
343f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            return false;
344f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        }
345f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        final float newTop = child.getTop() + yvel * HIDE_FRICTION;
346f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        return Math.abs(newTop - mMaxOffset) / (float) mPeekHeight > HIDE_THRESHOLD;
347f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    }
348f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
3499aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki    private View findScrollingChild(View view) {
3509aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki        if (view instanceof NestedScrollingChild) {
3519aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki            return view;
3529aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki        }
3539aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki        if (view instanceof ViewGroup) {
3549aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki            ViewGroup group = (ViewGroup) view;
3559aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki            for (int i = 0, count = group.getChildCount(); i < count; i++) {
3569aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki                View scrollingChild = findScrollingChild(group.getChildAt(i));
3579aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki                if (scrollingChild != null) {
3589aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki                    return scrollingChild;
3599aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki                }
3609aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki            }
3619aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki        }
3629aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki        return null;
363452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
364452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
365452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    private final ViewDragHelper.Callback mDragCallback = new ViewDragHelper.Callback() {
366452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
367452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        @Override
368452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        public boolean tryCaptureView(View child, int pointerId) {
3699aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki            if (mState == STATE_EXPANDED && mScrollingChildPointerId == pointerId) {
3709aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki                View scroll = mNestedScrollingChildRef.get();
3719aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki                if (scroll != null && ViewCompat.canScrollVertically(scroll, -1)) {
3729aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki                    // Let the content scroll up
3739aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki                    return false;
3749aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki                }
3759aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki            }
376f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            return mViewRef != null && mViewRef.get() == child;
377f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        }
378f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
379f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        @Override
380f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
381f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            dispatchOnSlide(top);
382f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            if (NEEDS_INVALIDATING) {
383f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                if (dy < 0) { // Upward
384f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                    changedView.invalidate();
385f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                } else { // Downward
386f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                    ViewParent parent = changedView.getParent();
387f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                    if (parent instanceof View) {
388f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                        View v = (View) parent;
389f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                        v.invalidate(changedView.getLeft(), top - dy,
390f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                                changedView.getRight(), v.getHeight());
391f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                    }
392f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                }
393f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            }
394452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
395452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
396452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        @Override
397452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        public void onViewDragStateChanged(int state) {
398452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            if (state == ViewDragHelper.STATE_DRAGGING) {
399452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                setStateInternal(STATE_DRAGGING);
400452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            }
401452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
402452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
403452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        @Override
404452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        public void onViewReleased(View releasedChild, float xvel, float yvel) {
405452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            int top;
406452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            @State int targetState;
407f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            if (yvel < 0) { // Moving up
408452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                top = mMinOffset;
409452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                targetState = STATE_EXPANDED;
410f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            } else if (mHideable && shouldHide(releasedChild, yvel)) {
411f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                top = mParentHeight;
412f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                targetState = STATE_HIDDEN;
413452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            } else {
414452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                top = mMaxOffset;
415452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                targetState = STATE_COLLAPSED;
416452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            }
417452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            if (mViewDragHelper.settleCapturedViewAt(releasedChild.getLeft(), top)) {
418f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                setStateInternal(STATE_SETTLING);
419452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                ViewCompat.postOnAnimation(releasedChild,
420452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                        new SettleRunnable(releasedChild, targetState));
421f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            } else {
422f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                setStateInternal(targetState);
423452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            }
424452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
425452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
426452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        @Override
427452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        public int clampViewPositionVertical(View child, int top, int dy) {
428f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            return MathUtils.constrain(top, mMinOffset, mHideable ? mParentHeight : mMaxOffset);
429452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
430452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
431452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        @Override
432452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        public int clampViewPositionHorizontal(View child, int left, int dx) {
433452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            return child.getLeft();
434452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
435f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
4369aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki        @Override
4379aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki        public int getViewVerticalDragRange(View child) {
4389aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki            if (mHideable) {
4399aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki                return mParentHeight - mMinOffset;
4409aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki            } else {
4419aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki                return mMaxOffset - mMinOffset;
4429aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki            }
4439aec720809a123c6193304730acf8b55d6ce5a7aYuichi Araki        }
444452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    };
445452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
446f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    private void dispatchOnSlide(int top) {
447dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki        View bottomSheet = mViewRef.get();
448dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki        if (bottomSheet != null && mCallback != null) {
449f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            if (top > mMaxOffset) {
450dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki                mCallback.onSlide(bottomSheet, (float) (mMaxOffset - top) / mPeekHeight);
451f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            } else {
452dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki                mCallback.onSlide(bottomSheet,
453dffd8d4be91b2e5e0ce66ad96867182db0c02fd0Yuichi Araki                        (float) (mMaxOffset - top) / ((mMaxOffset - mMinOffset)));
454f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            }
455f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        }
456f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    }
457f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
458452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    private class SettleRunnable implements Runnable {
459452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
460452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        private final View mView;
461452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
462452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        @State
463452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        private final int mTargetState;
464452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
465452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        SettleRunnable(View view, @State int targetState) {
466452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            mView = view;
467452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            mTargetState = targetState;
468f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            if (NEEDS_INVALIDATING) {
469f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                // We need to invalidate the parent here, or the following animation won't be drawn.
470f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                ViewParent parent = mView.getParent();
471f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                if (parent instanceof View) {
472f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                    ((View) parent).invalidate();
473f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                }
474f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            }
475452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
476452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
477452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        @Override
478452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        public void run() {
479452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            if (mViewDragHelper != null && mViewDragHelper.continueSettling(true)) {
480452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                ViewCompat.postOnAnimation(mView, this);
481452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            } else {
482452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                setStateInternal(mTargetState);
483452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            }
484452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
485452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
486452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
487452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    protected static class SavedState extends View.BaseSavedState {
488452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
489452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        @State
490452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        final int state;
491452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
492452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        public SavedState(Parcel source) {
493452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            super(source);
494452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            //noinspection ResourceType
495452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            state = source.readInt();
496452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
497452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
498452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        public SavedState(Parcelable superState, @State int state) {
499452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            super(superState);
500452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            this.state = state;
501452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
502452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
503452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        @Override
504452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        public void writeToParcel(Parcel out, int flags) {
505452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            super.writeToParcel(out, flags);
506452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            out.writeInt(state);
507452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
508452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
509452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        public static final Parcelable.Creator<SavedState> CREATOR =
510452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                new Parcelable.Creator<SavedState>() {
511452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                    @Override
512452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                    public SavedState createFromParcel(Parcel source) {
513452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                        return new SavedState(source);
514452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                    }
515452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
516452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                    @Override
517452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                    public SavedState[] newArray(int size) {
518452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                        return new SavedState[size];
519452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                    }
520452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                };
521452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
522452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
523f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    /**
524452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * A utility function to get the {@link BottomSheetBehavior} associated with the {@code view}.
525452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     *
526452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * @param view The {@link View} with {@link BottomSheetBehavior}.
527452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * @return The {@link BottomSheetBehavior} associated with the {@code view}.
528452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     */
529452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    @SuppressWarnings("unchecked")
530452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public static <V extends View> BottomSheetBehavior<V> from(V view) {
531452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        ViewGroup.LayoutParams params = view.getLayoutParams();
532452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        if (!(params instanceof CoordinatorLayout.LayoutParams)) {
533452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            throw new IllegalArgumentException("The view is not a child of CoordinatorLayout");
534452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
535452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        CoordinatorLayout.Behavior behavior = ((CoordinatorLayout.LayoutParams) params)
536452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                .getBehavior();
537452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        if (!(behavior instanceof BottomSheetBehavior)) {
538452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            throw new IllegalArgumentException(
539452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                    "The view is not associated with BottomSheetBehavior");
540452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
541452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        return (BottomSheetBehavior<V>) behavior;
542452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
543452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
544452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki}
545