BottomSheetBehavior.java revision 4df3c15e330c2f9730d3aa712f57befec8536dff
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;
25452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.support.design.R;
26452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.support.v4.view.MotionEventCompat;
27f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Arakiimport android.support.v4.view.VelocityTrackerCompat;
28452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.support.v4.view.ViewCompat;
29452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.support.v4.widget.ViewDragHelper;
30452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.util.AttributeSet;
31452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.view.MotionEvent;
32f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Arakiimport android.view.VelocityTracker;
33452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.view.View;
34f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Arakiimport android.view.ViewConfiguration;
35452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport android.view.ViewGroup;
36f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Arakiimport android.view.ViewParent;
37452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
38452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport java.lang.annotation.Retention;
39452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport java.lang.annotation.RetentionPolicy;
40452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakiimport java.lang.ref.WeakReference;
41452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
42452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
43452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki/**
44452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * An interaction behavior plugin for a child view of {@link CoordinatorLayout} to make it work as
45452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki * a bottom sheet.
46452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki */
47452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Arakipublic class BottomSheetBehavior<V extends View> extends CoordinatorLayout.Behavior<V> {
48452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
49452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    /**
504df3c15e330c2f9730d3aa712f57befec8536dffYuichi Araki     * Callback for monitoring events about bottom sheets.
51f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     */
524df3c15e330c2f9730d3aa712f57befec8536dffYuichi Araki    public abstract static class BottomSheetCallback {
53f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
54f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        /**
55f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki         * Called when the bottom sheet changes its state.
56f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki         *
57f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki         * @param newState The new state. This will be one of {@link #STATE_DRAGGING},
58f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki         *                 {@link #STATE_SETTLING}, {@link #STATE_EXPANDED},
59f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki         *                 {@link #STATE_COLLAPSED}, or {@link #STATE_HIDDEN}.
60f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki         */
61f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        public abstract void onStateChanged(@State int newState);
62f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
63f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        /**
64f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki         * Called when the bottom sheet is being dragged.
65f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki         *
66f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki         * @param slideOffset The new offset of this bottom sheet within its range, from 0 to 1
67f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki         *                    when it is moving upward, and from 0 to -1 when it moving downward.
68f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki         */
69f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        public abstract void onSlide(float slideOffset);
70f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    }
71f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
72f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    /**
73452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * The bottom sheet is dragging.
74452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     */
75452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public static final int STATE_DRAGGING = 1;
76452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
77452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    /**
78452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * The bottom sheet is settling.
79452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     */
80452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public static final int STATE_SETTLING = 2;
81452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
82452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    /**
83452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * The bottom sheet is expanded.
84452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     */
85452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public static final int STATE_EXPANDED = 3;
86452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
87452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    /**
88452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * The bottom sheet is collapsed.
89452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     */
90452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public static final int STATE_COLLAPSED = 4;
91452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
92f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    /**
93f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     * The bottom sheet is hidden.
94f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     */
95f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    public static final int STATE_HIDDEN = 5;
96f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
97452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    /** @hide */
98f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    @IntDef({STATE_EXPANDED, STATE_COLLAPSED, STATE_DRAGGING, STATE_SETTLING, STATE_HIDDEN})
99452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    @Retention(RetentionPolicy.SOURCE)
100452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public @interface State {}
101452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
102f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    private static final float HIDE_THRESHOLD = 0.5f;
103f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
104f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    private static final float HIDE_FRICTION = 0.1f;
105f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
106f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    // Whether to enable workaround for black non-rendered square
107f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    private static final boolean NEEDS_INVALIDATING = Build.VERSION.SDK_INT < 23;
108f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
109f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    private float mMaximumVelocity;
110f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
111452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    private int mPeekHeight;
112452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
113452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    private int mMinOffset;
114452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
115452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    private int mMaxOffset;
116452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
117f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    private boolean mHideable;
118f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
119452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    @State
120452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    private int mState = STATE_COLLAPSED;
121452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
122452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    private ViewDragHelper mViewDragHelper;
123452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
124452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    private boolean mIgnoreEvents;
125452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
126452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    private int mLastNestedScrollDy;
127452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
128452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    private int mParentHeight;
129452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
130452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    private WeakReference<V> mViewRef;
131452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
1324df3c15e330c2f9730d3aa712f57befec8536dffYuichi Araki    private BottomSheetCallback mCallback;
133f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
134f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    private VelocityTracker mVelocityTracker;
135f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
136f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    private int mActivePointerId;
137f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
138452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    /**
139452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * Default constructor for instantiating BottomSheetBehaviors.
140452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     */
141452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public BottomSheetBehavior() {
142452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
143452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
144452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    /**
145452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * Default constructor for inflating BottomSheetBehaviors from layout.
146452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     *
147452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * @param context The {@link Context}.
148452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * @param attrs   The {@link AttributeSet}.
149452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     */
150452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public BottomSheetBehavior(Context context, AttributeSet attrs) {
151452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        super(context, attrs);
152452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        TypedArray a = context.obtainStyledAttributes(attrs,
153452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                R.styleable.BottomSheetBehavior_Params);
154452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        setPeekHeight(a.getDimensionPixelSize(
155452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                R.styleable.BottomSheetBehavior_Params_behavior_peekHeight, 0));
156f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        setHideable(a.getBoolean(R.styleable.BottomSheetBehavior_Params_behavior_hideable, false));
157452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        a.recycle();
158f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        ViewConfiguration configuration = ViewConfiguration.get(context);
159f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
160452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
161452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
162452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    @Override
163452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public Parcelable onSaveInstanceState(CoordinatorLayout parent, V child) {
164452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        return new SavedState(super.onSaveInstanceState(parent, child), mState);
165452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
166452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
167452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    @Override
168452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public void onRestoreInstanceState(CoordinatorLayout parent, V child, Parcelable state) {
169452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        SavedState ss = (SavedState) state;
170452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        super.onRestoreInstanceState(parent, child, ss.getSuperState());
171452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        // Intermediate states are restored as collapsed state
172f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        if (ss.state == STATE_DRAGGING || ss.state == STATE_SETTLING) {
173452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            mState = STATE_COLLAPSED;
174f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        } else {
175f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            mState = ss.state;
176452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
177452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
178452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
179452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    @Override
180452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public boolean onLayoutChild(CoordinatorLayout parent, V child, int layoutDirection) {
181452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        // First let the parent lay it out
182f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        if (mState != STATE_DRAGGING && mState != STATE_SETTLING) {
183f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            parent.onLayoutChild(child, layoutDirection);
184f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        }
185452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        // Offset the bottom sheet
186452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        mParentHeight = parent.getHeight();
187452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        mMinOffset = Math.max(0, mParentHeight - child.getHeight());
188452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        mMaxOffset = mParentHeight - mPeekHeight;
189452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        if (mState == STATE_EXPANDED) {
190452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            ViewCompat.offsetTopAndBottom(child, mMinOffset);
191f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        } else if (mHideable && mState == STATE_HIDDEN) {
192f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            ViewCompat.offsetTopAndBottom(child, mParentHeight);
193f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        } else if (mState == STATE_COLLAPSED) {
194452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            ViewCompat.offsetTopAndBottom(child, mMaxOffset);
195452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
196452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        if (mViewDragHelper == null) {
197452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            mViewDragHelper = ViewDragHelper.create(parent, mDragCallback);
198452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
199452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        mViewRef = new WeakReference<>(child);
200452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        return true;
201452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
202452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
203452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    @Override
204452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public boolean onInterceptTouchEvent(CoordinatorLayout parent, V child, MotionEvent event) {
205452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        int action = MotionEventCompat.getActionMasked(event);
206f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        // Record the velocity
207f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        if (action == MotionEvent.ACTION_DOWN) {
208f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            reset();
209f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        }
210f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        if (mVelocityTracker == null) {
211f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            mVelocityTracker = VelocityTracker.obtain();
212f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        }
213f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        mVelocityTracker.addMovement(event);
214452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        switch (action) {
215452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            case MotionEvent.ACTION_UP:
216452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            case MotionEvent.ACTION_CANCEL:
217452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                // Reset the ignore flag
218452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                if (mIgnoreEvents) {
219452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                    mIgnoreEvents = false;
220452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                    return false;
221452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                }
222452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                break;
223452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            case MotionEvent.ACTION_DOWN:
224452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                mIgnoreEvents = !parent.isPointInChildBounds(child,
225452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                        (int) event.getX(), (int) event.getY());
226f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                mActivePointerId = MotionEventCompat.getPointerId(event, 0);
227452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                break;
228452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
229452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        return !mIgnoreEvents && mViewDragHelper.shouldInterceptTouchEvent(event);
230452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
231452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
232452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    @Override
233452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public boolean onTouchEvent(CoordinatorLayout parent, V child, MotionEvent event) {
234452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        mViewDragHelper.processTouchEvent(event);
235f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        // Record the velocity
236f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        if (MotionEventCompat.getActionMasked(event) == MotionEvent.ACTION_DOWN) {
237f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            reset();
238f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        }
239f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        if (mVelocityTracker == null) {
240f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            mVelocityTracker = VelocityTracker.obtain();
241f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        }
242f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        mVelocityTracker.addMovement(event);
243452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        return true;
244452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
245452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
246452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    @Override
247452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, V child,
248452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            View directTargetChild, View target, int nestedScrollAxes) {
249452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        mLastNestedScrollDy = 0;
250452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        return (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;
251452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
252452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
253452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    @Override
254452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, V child, View target, int dx,
255452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            int dy, int[] consumed) {
256452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        int currentTop = child.getTop();
257452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        int newTop = currentTop - dy;
258f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        if (dy > 0) { // Upward
259452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            if (newTop < mMinOffset) {
260452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                consumed[1] = currentTop - mMinOffset;
261452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                child.offsetTopAndBottom(-consumed[1]);
262f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                if (NEEDS_INVALIDATING && mState != STATE_EXPANDED) {
263f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                    child.invalidate();
264f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                }
265452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                setStateInternal(STATE_EXPANDED);
266452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            } else {
267452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                consumed[1] = dy;
268452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                child.offsetTopAndBottom(-dy);
269452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                setStateInternal(STATE_DRAGGING);
270f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                if (NEEDS_INVALIDATING) {
271f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                    child.invalidate();
272f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                }
273452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            }
274f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        } else if (dy < 0) { // Downward
275452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            if (!ViewCompat.canScrollVertically(target, -1)) {
276f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                if (newTop <= mMaxOffset || mHideable) {
277452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                    consumed[1] = dy;
278452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                    child.offsetTopAndBottom(-dy);
279452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                    setStateInternal(STATE_DRAGGING);
280f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                    if (NEEDS_INVALIDATING) {
281f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                        coordinatorLayout.invalidate(child.getLeft(), currentTop,
282f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                                child.getRight(), coordinatorLayout.getHeight());
283f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                    }
284f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                } else {
285f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                    consumed[1] = currentTop - mMaxOffset;
286f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                    child.offsetTopAndBottom(-consumed[1]);
287f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                    setStateInternal(STATE_COLLAPSED);
288452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                }
289452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            }
290452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
291f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        dispatchOnSlide(child.getTop());
292452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        mLastNestedScrollDy = dy;
293452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
294452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
295452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    @Override
296452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, V child, View target) {
297f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        if (child.getTop() == mMinOffset) {
298452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            return;
299452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
300452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        int top;
301452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        int targetState;
302452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        if (mLastNestedScrollDy > 0) {
303452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            top = mMinOffset;
304452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            targetState = STATE_EXPANDED;
305f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        } else if (mHideable && shouldHide(child, getYVelocity())) {
306f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            top = mParentHeight;
307f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            targetState = STATE_HIDDEN;
308452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        } else {
309452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            top = mMaxOffset;
310452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            targetState = STATE_COLLAPSED;
311452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
312452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        if (mViewDragHelper.smoothSlideViewTo(child, child.getLeft(), top)) {
313f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            setStateInternal(STATE_SETTLING);
314452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            ViewCompat.postOnAnimation(child, new SettleRunnable(child, targetState));
315f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        } else {
316f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            setStateInternal(targetState);
317452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
318452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
319452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
320f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    @Override
321f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    public boolean onNestedPreFling(CoordinatorLayout coordinatorLayout, V child, View target,
322f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            float velocityX, float velocityY) {
323f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        return mState != STATE_EXPANDED ||
324f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                super.onNestedPreFling(coordinatorLayout, child, target, velocityX, velocityY);
325f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    }
326f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
327452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    /**
328452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * Sets the height of the bottom sheet when it is collapsed.
329452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     *
330452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * @param peekHeight The height of the collapsed bottom sheet in pixels.
331452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * @attr ref android.support.design.R.styleable#BottomSheetBehavior_Params_behavior_peekHeight
332452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     */
333452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public final void setPeekHeight(int peekHeight) {
334452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        mPeekHeight = Math.max(0, peekHeight);
335452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        mMaxOffset = mParentHeight - peekHeight;
336452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
337452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
338452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    /**
339452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * Gets the height of the bottom sheet when it is collapsed.
340452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     *
341452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * @return The height of the collapsed bottom sheet.
342452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * @attr ref android.support.design.R.styleable#BottomSheetBehavior_Params_behavior_peekHeight
343452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     */
344452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public final int getPeekHeight() {
345452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        return mPeekHeight;
346452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
347452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
348452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    /**
349f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     * Sets whether this bottom sheet can hide when it is swiped down.
350f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     *
351f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     * @param hideable {@code true} to make this bottom sheet hideable.
352f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     * @attr ref android.support.design.R.styleable#BottomSheetBehavior_Params_behavior_hideable
353f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     */
354f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    public void setHideable(boolean hideable) {
355f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        mHideable = hideable;
356f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    }
357f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
358f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    /**
359f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     * Gets whether this bottom sheet can hide when it is swiped down.
360f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     *
361f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     * @return {@code true} if this bottom sheet can hide.
362f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     * @attr ref android.support.design.R.styleable#BottomSheetBehavior_Params_behavior_hideable
363f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     */
364f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    public boolean isHideable() {
365f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        return mHideable;
366f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    }
367f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
368f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    /**
3694df3c15e330c2f9730d3aa712f57befec8536dffYuichi Araki     * Sets a callback to be notified of bottom sheet events.
370f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     *
3714df3c15e330c2f9730d3aa712f57befec8536dffYuichi Araki     * @param callback The callback to notify when bottom sheet events occur.
372f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     */
3734df3c15e330c2f9730d3aa712f57befec8536dffYuichi Araki    public void setBottomSheetCallback(BottomSheetCallback callback) {
3744df3c15e330c2f9730d3aa712f57befec8536dffYuichi Araki        mCallback = callback;
375f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    }
376f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
377f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    /**
378452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * Sets the state of the bottom sheet. The bottom sheet will transition to that state with
379452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * animation.
380452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     *
381f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     * @param state One of {@link #STATE_COLLAPSED}, {@link #STATE_EXPANDED}, or
382f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki     *              {@link #STATE_HIDDEN}.
383452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     */
384452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public final void setState(@State int state) {
385452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        V child = mViewRef.get();
386452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        if (child == null) {
387452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            return;
388452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
389452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        int top;
390452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        if (state == STATE_COLLAPSED) {
391452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            top = mMaxOffset;
392452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        } else if (state == STATE_EXPANDED) {
393452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            top = mMinOffset;
394f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        } else if (mHideable && state == STATE_HIDDEN) {
395f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            top = mParentHeight;
396452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        } else {
397452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            throw new IllegalArgumentException("Illegal state argument: " + state);
398452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
399452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        setStateInternal(STATE_SETTLING);
400452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        if (mViewDragHelper.smoothSlideViewTo(child, child.getLeft(), top)) {
401452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            ViewCompat.postOnAnimation(child, new SettleRunnable(child, state));
402452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
403452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
404452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
405452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    /**
406452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * Gets the current state of the bottom sheet.
407452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     *
408452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * @return One of {@link #STATE_EXPANDED}, {@link #STATE_COLLAPSED}, {@link #STATE_DRAGGING},
409452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * and {@link #STATE_SETTLING}.
410452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     */
411452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    @State
412452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public final int getState() {
413452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        return mState;
414452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
415452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
416452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    private void setStateInternal(@State int state) {
417452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        if (mState == state) {
418452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            return;
419452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
420452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        mState = state;
4214df3c15e330c2f9730d3aa712f57befec8536dffYuichi Araki        if (mCallback != null) {
4224df3c15e330c2f9730d3aa712f57befec8536dffYuichi Araki            mCallback.onStateChanged(state);
423f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        }
424f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    }
425f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
426f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    private void reset() {
427f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        mActivePointerId = ViewDragHelper.INVALID_POINTER;
428f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        if (mVelocityTracker != null) {
429f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            mVelocityTracker.recycle();
430f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            mVelocityTracker = null;
431f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        }
432f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    }
433f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
434f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    private boolean shouldHide(View child, float yvel) {
435f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        if (child.getTop() < mMaxOffset) {
436f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            // It should not hide, but collapse.
437f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            return false;
438f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        }
439f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        final float newTop = child.getTop() + yvel * HIDE_FRICTION;
440f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        return Math.abs(newTop - mMaxOffset) / (float) mPeekHeight > HIDE_THRESHOLD;
441f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    }
442f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
443f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    private float getYVelocity() {
444f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        mVelocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
445f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        return VelocityTrackerCompat.getYVelocity(mVelocityTracker, mActivePointerId);
446452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
447452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
448452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    private final ViewDragHelper.Callback mDragCallback = new ViewDragHelper.Callback() {
449452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
450452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        @Override
451452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        public boolean tryCaptureView(View child, int pointerId) {
452f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            return mViewRef != null && mViewRef.get() == child;
453f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        }
454f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
455f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        @Override
456f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
457f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            dispatchOnSlide(top);
458f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            if (NEEDS_INVALIDATING) {
459f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                if (dy < 0) { // Upward
460f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                    changedView.invalidate();
461f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                } else { // Downward
462f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                    ViewParent parent = changedView.getParent();
463f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                    if (parent instanceof View) {
464f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                        View v = (View) parent;
465f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                        v.invalidate(changedView.getLeft(), top - dy,
466f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                                changedView.getRight(), v.getHeight());
467f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                    }
468f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                }
469f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            }
470452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
471452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
472452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        @Override
473452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        public void onViewDragStateChanged(int state) {
474452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            if (state == ViewDragHelper.STATE_DRAGGING) {
475452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                setStateInternal(STATE_DRAGGING);
476452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            }
477452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
478452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
479452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        @Override
480452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        public void onViewReleased(View releasedChild, float xvel, float yvel) {
481452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            int top;
482452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            @State int targetState;
483f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            if (yvel < 0) { // Moving up
484452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                top = mMinOffset;
485452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                targetState = STATE_EXPANDED;
486f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            } else if (mHideable && shouldHide(releasedChild, yvel)) {
487f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                top = mParentHeight;
488f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                targetState = STATE_HIDDEN;
489452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            } else {
490452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                top = mMaxOffset;
491452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                targetState = STATE_COLLAPSED;
492452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            }
493452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            if (mViewDragHelper.settleCapturedViewAt(releasedChild.getLeft(), top)) {
494f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                setStateInternal(STATE_SETTLING);
495452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                ViewCompat.postOnAnimation(releasedChild,
496452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                        new SettleRunnable(releasedChild, targetState));
497f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            } else {
498f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                setStateInternal(targetState);
499452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            }
500452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
501452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
502452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        @Override
503452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        public int clampViewPositionVertical(View child, int top, int dy) {
504f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            return MathUtils.constrain(top, mMinOffset, mHideable ? mParentHeight : mMaxOffset);
505452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
506452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
507452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        @Override
508452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        public int clampViewPositionHorizontal(View child, int left, int dx) {
509452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            return child.getLeft();
510452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
511f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
512452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    };
513452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
514f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    private void dispatchOnSlide(int top) {
5154df3c15e330c2f9730d3aa712f57befec8536dffYuichi Araki        if (mCallback != null) {
516f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            if (top > mMaxOffset) {
5174df3c15e330c2f9730d3aa712f57befec8536dffYuichi Araki                mCallback.onSlide((float) (mMaxOffset - top) / mPeekHeight);
518f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            } else {
5194df3c15e330c2f9730d3aa712f57befec8536dffYuichi Araki                mCallback.onSlide((float) (mMaxOffset - top) / ((mMaxOffset - mMinOffset)));
520f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            }
521f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki        }
522f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    }
523f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki
524452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    private class SettleRunnable implements Runnable {
525452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
526452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        private final View mView;
527452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
528452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        @State
529452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        private final int mTargetState;
530452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
531452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        SettleRunnable(View view, @State int targetState) {
532452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            mView = view;
533452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            mTargetState = targetState;
534f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            if (NEEDS_INVALIDATING) {
535f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                // We need to invalidate the parent here, or the following animation won't be drawn.
536f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                ViewParent parent = mView.getParent();
537f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                if (parent instanceof View) {
538f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                    ((View) parent).invalidate();
539f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki                }
540f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki            }
541452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
542452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
543452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        @Override
544452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        public void run() {
545452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            if (mViewDragHelper != null && mViewDragHelper.continueSettling(true)) {
546452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                ViewCompat.postOnAnimation(mView, this);
547452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            } else {
548452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                setStateInternal(mTargetState);
549452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            }
550452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
551452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
552452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
553452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    protected static class SavedState extends View.BaseSavedState {
554452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
555452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        @State
556452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        final int state;
557452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
558452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        public SavedState(Parcel source) {
559452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            super(source);
560452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            //noinspection ResourceType
561452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            state = source.readInt();
562452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
563452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
564452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        public SavedState(Parcelable superState, @State int state) {
565452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            super(superState);
566452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            this.state = state;
567452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
568452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
569452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        @Override
570452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        public void writeToParcel(Parcel out, int flags) {
571452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            super.writeToParcel(out, flags);
572452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            out.writeInt(state);
573452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
574452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
575452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        public static final Parcelable.Creator<SavedState> CREATOR =
576452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                new Parcelable.Creator<SavedState>() {
577452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                    @Override
578452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                    public SavedState createFromParcel(Parcel source) {
579452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                        return new SavedState(source);
580452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                    }
581452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
582452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                    @Override
583452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                    public SavedState[] newArray(int size) {
584452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                        return new SavedState[size];
585452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                    }
586452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                };
587452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
588452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
589f28a0f76c7a46d61785ef7cbc407c19942ecab46Yuichi Araki    /**
590452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * A utility function to get the {@link BottomSheetBehavior} associated with the {@code view}.
591452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     *
592452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * @param view The {@link View} with {@link BottomSheetBehavior}.
593452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     * @return The {@link BottomSheetBehavior} associated with the {@code view}.
594452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki     */
595452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    @SuppressWarnings("unchecked")
596452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    public static <V extends View> BottomSheetBehavior<V> from(V view) {
597452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        ViewGroup.LayoutParams params = view.getLayoutParams();
598452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        if (!(params instanceof CoordinatorLayout.LayoutParams)) {
599452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            throw new IllegalArgumentException("The view is not a child of CoordinatorLayout");
600452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
601452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        CoordinatorLayout.Behavior behavior = ((CoordinatorLayout.LayoutParams) params)
602452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                .getBehavior();
603452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        if (!(behavior instanceof BottomSheetBehavior)) {
604452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki            throw new IllegalArgumentException(
605452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki                    "The view is not associated with BottomSheetBehavior");
606452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        }
607452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki        return (BottomSheetBehavior<V>) behavior;
608452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki    }
609452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki
610452f94d1c58e2a7476019b98c3bf0e4b322d1525Yuichi Araki}
611