11fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell/*
2ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas * Copyright 2018 The Android Open Source Project
31fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell *
41fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell * Licensed under the Apache License, Version 2.0 (the "License");
51fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell * you may not use this file except in compliance with the License.
61fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell * You may obtain a copy of the License at
71fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell *
81fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell *      http://www.apache.org/licenses/LICENSE-2.0
91fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell *
101fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell * Unless required by applicable law or agreed to in writing, software
111fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell * distributed under the License is distributed on an "AS IS" BASIS,
121fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
131fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell * See the License for the specific language governing permissions and
141fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell * limitations under the License.
151fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell */
161fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell
171fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell
18ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikaspackage androidx.core.view;
191fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell
20ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport static androidx.core.view.ViewCompat.TYPE_NON_TOUCH;
21ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport static androidx.core.view.ViewCompat.TYPE_TOUCH;
2276daed103193a1756535d1f59b165e98e1d17445Chris Banes
239dede51868bbbe16aadcd65e04860bea8ea50e05Aurimas Liutikasimport android.view.View;
249dede51868bbbe16aadcd65e04860bea8ea50e05Aurimas Liutikasimport android.view.ViewParent;
259dede51868bbbe16aadcd65e04860bea8ea50e05Aurimas Liutikas
26ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.annotation.NonNull;
27ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.annotation.Nullable;
28ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.core.view.ViewCompat.NestedScrollType;
29ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikasimport androidx.core.view.ViewCompat.ScrollAxis;
301fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell
311fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell/**
321fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell * Helper class for implementing nested scrolling child views compatible with Android platform
331fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell * versions earlier than Android 5.0 Lollipop (API 21).
341fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell *
351fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell * <p>{@link android.view.View View} subclasses should instantiate a final instance of this
361fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell * class as a field at construction. For each <code>View</code> method that has a matching
37c9a859537b0871f84afeeb706a5b425fe3f2b4ddAurimas Liutikas * method signature in this class, delegate the operation to the helper instance in an overridden
381fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell * method implementation. This implements the standard framework policy for nested scrolling.</p>
391fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell *
401fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell * <p>Views invoking nested scrolling functionality should always do so from the relevant
41ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas * {@link androidx.core.view.ViewCompat}, {@link androidx.core.view.ViewGroupCompat} or
42ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas * {@link androidx.core.view.ViewParentCompat} compatibility
431fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell * shim static methods. This ensures interoperability with nested scrolling views on Android
441fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell * 5.0 Lollipop and newer.</p>
451fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell */
461fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powellpublic class NestedScrollingChildHelper {
4776daed103193a1756535d1f59b165e98e1d17445Chris Banes    private ViewParent mNestedScrollingParentTouch;
4876daed103193a1756535d1f59b165e98e1d17445Chris Banes    private ViewParent mNestedScrollingParentNonTouch;
491fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell    private final View mView;
501fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell    private boolean mIsNestedScrollingEnabled;
511fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell    private int[] mTempNestedScrollConsumed;
521fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell
531fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell    /**
541fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     * Construct a new helper for a given view.
551fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     */
5676daed103193a1756535d1f59b165e98e1d17445Chris Banes    public NestedScrollingChildHelper(@NonNull View view) {
571fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell        mView = view;
581fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell    }
591fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell
601fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell    /**
611fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     * Enable nested scrolling.
621fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     *
631fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     * <p>This is a delegate method. Call it from your {@link android.view.View View} subclass
64ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas     * method/{@link androidx.core.view.NestedScrollingChild} interface method with the same
653ac77bf186f87ecad4bf0063b2f6c4384efbd56aKirill Grouchnikov     * signature to implement the standard policy.</p>
661fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     *
671fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     * @param enabled true to enable nested scrolling dispatch from this view, false otherwise
681fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     */
691fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell    public void setNestedScrollingEnabled(boolean enabled) {
701fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell        if (mIsNestedScrollingEnabled) {
711fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell            ViewCompat.stopNestedScroll(mView);
721fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell        }
731fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell        mIsNestedScrollingEnabled = enabled;
741fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell    }
751fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell
761fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell    /**
771fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     * Check if nested scrolling is enabled for this view.
781fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     *
791fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     * <p>This is a delegate method. Call it from your {@link android.view.View View} subclass
80ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas     * method/{@link androidx.core.view.NestedScrollingChild} interface method with the same
813ac77bf186f87ecad4bf0063b2f6c4384efbd56aKirill Grouchnikov     * signature to implement the standard policy.</p>
821fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     *
831fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     * @return true if nested scrolling is enabled for this view
841fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     */
851fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell    public boolean isNestedScrollingEnabled() {
861fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell        return mIsNestedScrollingEnabled;
871fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell    }
881fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell
891fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell    /**
901fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     * Check if this view has a nested scrolling parent view currently receiving events for
9176daed103193a1756535d1f59b165e98e1d17445Chris Banes     * a nested scroll in progress with the type of touch.
921fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     *
931fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     * <p>This is a delegate method. Call it from your {@link android.view.View View} subclass
94ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas     * method/{@link androidx.core.view.NestedScrollingChild} interface method with the same
953ac77bf186f87ecad4bf0063b2f6c4384efbd56aKirill Grouchnikov     * signature to implement the standard policy.</p>
961fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     *
971fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     * @return true if this view has a nested scrolling parent, false otherwise
981fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     */
991fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell    public boolean hasNestedScrollingParent() {
10076daed103193a1756535d1f59b165e98e1d17445Chris Banes        return hasNestedScrollingParent(TYPE_TOUCH);
10176daed103193a1756535d1f59b165e98e1d17445Chris Banes    }
10276daed103193a1756535d1f59b165e98e1d17445Chris Banes
10376daed103193a1756535d1f59b165e98e1d17445Chris Banes    /**
10476daed103193a1756535d1f59b165e98e1d17445Chris Banes     * Check if this view has a nested scrolling parent view currently receiving events for
10576daed103193a1756535d1f59b165e98e1d17445Chris Banes     * a nested scroll in progress with the given type.
10676daed103193a1756535d1f59b165e98e1d17445Chris Banes     *
10776daed103193a1756535d1f59b165e98e1d17445Chris Banes     * <p>This is a delegate method. Call it from your {@link android.view.View View} subclass
108ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas     * method/{@link androidx.core.view.NestedScrollingChild} interface method with the same
10976daed103193a1756535d1f59b165e98e1d17445Chris Banes     * signature to implement the standard policy.</p>
11076daed103193a1756535d1f59b165e98e1d17445Chris Banes     *
11176daed103193a1756535d1f59b165e98e1d17445Chris Banes     * @return true if this view has a nested scrolling parent, false otherwise
11276daed103193a1756535d1f59b165e98e1d17445Chris Banes     */
11376daed103193a1756535d1f59b165e98e1d17445Chris Banes    public boolean hasNestedScrollingParent(@NestedScrollType int type) {
11476daed103193a1756535d1f59b165e98e1d17445Chris Banes        return getNestedScrollingParentForType(type) != null;
1151fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell    }
1161fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell
1171fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell    /**
1181fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     * Start a new nested scroll for this view.
1191fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     *
1201fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     * <p>This is a delegate method. Call it from your {@link android.view.View View} subclass
121ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas     * method/{@link androidx.core.view.NestedScrollingChild} interface method with the same
1223ac77bf186f87ecad4bf0063b2f6c4384efbd56aKirill Grouchnikov     * signature to implement the standard policy.</p>
1231fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     *
1241fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     * @param axes Supported nested scroll axes.
125ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas     *             See {@link androidx.core.view.NestedScrollingChild#startNestedScroll(int)}.
1261fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     * @return true if a cooperating parent view was found and nested scrolling started successfully
1271fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     */
12876daed103193a1756535d1f59b165e98e1d17445Chris Banes    public boolean startNestedScroll(@ScrollAxis int axes) {
12976daed103193a1756535d1f59b165e98e1d17445Chris Banes        return startNestedScroll(axes, TYPE_TOUCH);
13076daed103193a1756535d1f59b165e98e1d17445Chris Banes    }
13176daed103193a1756535d1f59b165e98e1d17445Chris Banes
13276daed103193a1756535d1f59b165e98e1d17445Chris Banes    /**
13376daed103193a1756535d1f59b165e98e1d17445Chris Banes     * Start a new nested scroll for this view.
13476daed103193a1756535d1f59b165e98e1d17445Chris Banes     *
13576daed103193a1756535d1f59b165e98e1d17445Chris Banes     * <p>This is a delegate method. Call it from your {@link android.view.View View} subclass
136ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas     * method/{@link androidx.core.view.NestedScrollingChild2} interface method with the same
13776daed103193a1756535d1f59b165e98e1d17445Chris Banes     * signature to implement the standard policy.</p>
13876daed103193a1756535d1f59b165e98e1d17445Chris Banes     *
13976daed103193a1756535d1f59b165e98e1d17445Chris Banes     * @param axes Supported nested scroll axes.
140ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas     *             See {@link androidx.core.view.NestedScrollingChild2#startNestedScroll(int,
14176daed103193a1756535d1f59b165e98e1d17445Chris Banes     *             int)}.
14276daed103193a1756535d1f59b165e98e1d17445Chris Banes     * @return true if a cooperating parent view was found and nested scrolling started successfully
14376daed103193a1756535d1f59b165e98e1d17445Chris Banes     */
14476daed103193a1756535d1f59b165e98e1d17445Chris Banes    public boolean startNestedScroll(@ScrollAxis int axes, @NestedScrollType int type) {
14576daed103193a1756535d1f59b165e98e1d17445Chris Banes        if (hasNestedScrollingParent(type)) {
1461fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell            // Already in progress
1471fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell            return true;
1481fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell        }
1491fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell        if (isNestedScrollingEnabled()) {
1501fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell            ViewParent p = mView.getParent();
1511fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell            View child = mView;
1521fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell            while (p != null) {
15376daed103193a1756535d1f59b165e98e1d17445Chris Banes                if (ViewParentCompat.onStartNestedScroll(p, child, mView, axes, type)) {
15476daed103193a1756535d1f59b165e98e1d17445Chris Banes                    setNestedScrollingParentForType(type, p);
15576daed103193a1756535d1f59b165e98e1d17445Chris Banes                    ViewParentCompat.onNestedScrollAccepted(p, child, mView, axes, type);
1561fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell                    return true;
1571fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell                }
1581fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell                if (p instanceof View) {
1591fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell                    child = (View) p;
1601fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell                }
1611fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell                p = p.getParent();
1621fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell            }
1631fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell        }
1641fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell        return false;
1651fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell    }
1661fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell
1671fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell    /**
1681fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     * Stop a nested scroll in progress.
1691fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     *
1701fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     * <p>This is a delegate method. Call it from your {@link android.view.View View} subclass
171ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas     * method/{@link androidx.core.view.NestedScrollingChild} interface method with the same
1723ac77bf186f87ecad4bf0063b2f6c4384efbd56aKirill Grouchnikov     * signature to implement the standard policy.</p>
1731fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     */
1741fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell    public void stopNestedScroll() {
17576daed103193a1756535d1f59b165e98e1d17445Chris Banes        stopNestedScroll(TYPE_TOUCH);
17676daed103193a1756535d1f59b165e98e1d17445Chris Banes    }
17776daed103193a1756535d1f59b165e98e1d17445Chris Banes
17876daed103193a1756535d1f59b165e98e1d17445Chris Banes    /**
17976daed103193a1756535d1f59b165e98e1d17445Chris Banes     * Stop a nested scroll in progress.
18076daed103193a1756535d1f59b165e98e1d17445Chris Banes     *
18176daed103193a1756535d1f59b165e98e1d17445Chris Banes     * <p>This is a delegate method. Call it from your {@link android.view.View View} subclass
182ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas     * method/{@link androidx.core.view.NestedScrollingChild2} interface method with the same
18376daed103193a1756535d1f59b165e98e1d17445Chris Banes     * signature to implement the standard policy.</p>
18476daed103193a1756535d1f59b165e98e1d17445Chris Banes     */
18576daed103193a1756535d1f59b165e98e1d17445Chris Banes    public void stopNestedScroll(@NestedScrollType int type) {
18676daed103193a1756535d1f59b165e98e1d17445Chris Banes        ViewParent parent = getNestedScrollingParentForType(type);
18776daed103193a1756535d1f59b165e98e1d17445Chris Banes        if (parent != null) {
18876daed103193a1756535d1f59b165e98e1d17445Chris Banes            ViewParentCompat.onStopNestedScroll(parent, mView, type);
18976daed103193a1756535d1f59b165e98e1d17445Chris Banes            setNestedScrollingParentForType(type, null);
1901fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell        }
1911fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell    }
1921fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell
1931fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell    /**
1941fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     * Dispatch one step of a nested scrolling operation to the current nested scrolling parent.
1951fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     *
1961fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     * <p>This is a delegate method. Call it from your {@link android.view.View View} subclass
197ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas     * method/{@link androidx.core.view.NestedScrollingChild} interface method with the same
1983ac77bf186f87ecad4bf0063b2f6c4384efbd56aKirill Grouchnikov     * signature to implement the standard policy.</p>
1991fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     *
2001fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     * @return true if the parent consumed any of the nested scroll
2011fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     */
2021fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell    public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed,
20376daed103193a1756535d1f59b165e98e1d17445Chris Banes            int dxUnconsumed, int dyUnconsumed, @Nullable int[] offsetInWindow) {
20476daed103193a1756535d1f59b165e98e1d17445Chris Banes        return dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed,
20576daed103193a1756535d1f59b165e98e1d17445Chris Banes                offsetInWindow, TYPE_TOUCH);
20676daed103193a1756535d1f59b165e98e1d17445Chris Banes    }
20776daed103193a1756535d1f59b165e98e1d17445Chris Banes
20876daed103193a1756535d1f59b165e98e1d17445Chris Banes    /**
20976daed103193a1756535d1f59b165e98e1d17445Chris Banes     * Dispatch one step of a nested scrolling operation to the current nested scrolling parent.
21076daed103193a1756535d1f59b165e98e1d17445Chris Banes     *
21176daed103193a1756535d1f59b165e98e1d17445Chris Banes     * <p>This is a delegate method. Call it from your {@link android.view.View View} subclass
212ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas     * method/{@link androidx.core.view.NestedScrollingChild2} interface method with the same
21376daed103193a1756535d1f59b165e98e1d17445Chris Banes     * signature to implement the standard policy.</p>
21476daed103193a1756535d1f59b165e98e1d17445Chris Banes     *
21576daed103193a1756535d1f59b165e98e1d17445Chris Banes     * @return true if the parent consumed any of the nested scroll
21676daed103193a1756535d1f59b165e98e1d17445Chris Banes     */
21776daed103193a1756535d1f59b165e98e1d17445Chris Banes    public boolean dispatchNestedScroll(int dxConsumed, int dyConsumed,
21876daed103193a1756535d1f59b165e98e1d17445Chris Banes            int dxUnconsumed, int dyUnconsumed, @Nullable int[] offsetInWindow,
21976daed103193a1756535d1f59b165e98e1d17445Chris Banes            @NestedScrollType int type) {
22076daed103193a1756535d1f59b165e98e1d17445Chris Banes        if (isNestedScrollingEnabled()) {
22176daed103193a1756535d1f59b165e98e1d17445Chris Banes            final ViewParent parent = getNestedScrollingParentForType(type);
22276daed103193a1756535d1f59b165e98e1d17445Chris Banes            if (parent == null) {
22376daed103193a1756535d1f59b165e98e1d17445Chris Banes                return false;
22476daed103193a1756535d1f59b165e98e1d17445Chris Banes            }
22576daed103193a1756535d1f59b165e98e1d17445Chris Banes
2261fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell            if (dxConsumed != 0 || dyConsumed != 0 || dxUnconsumed != 0 || dyUnconsumed != 0) {
2271fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell                int startX = 0;
2281fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell                int startY = 0;
2291fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell                if (offsetInWindow != null) {
2301fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell                    mView.getLocationInWindow(offsetInWindow);
2311fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell                    startX = offsetInWindow[0];
2321fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell                    startY = offsetInWindow[1];
2331fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell                }
2341fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell
23576daed103193a1756535d1f59b165e98e1d17445Chris Banes                ViewParentCompat.onNestedScroll(parent, mView, dxConsumed,
23676daed103193a1756535d1f59b165e98e1d17445Chris Banes                        dyConsumed, dxUnconsumed, dyUnconsumed, type);
2371fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell
2381fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell                if (offsetInWindow != null) {
2391fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell                    mView.getLocationInWindow(offsetInWindow);
2401fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell                    offsetInWindow[0] -= startX;
2411fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell                    offsetInWindow[1] -= startY;
2421fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell                }
2431fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell                return true;
2441fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell            } else if (offsetInWindow != null) {
2451fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell                // No motion, no dispatch. Keep offsetInWindow up to date.
2461fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell                offsetInWindow[0] = 0;
2471fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell                offsetInWindow[1] = 0;
2481fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell            }
2491fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell        }
2501fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell        return false;
2511fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell    }
2521fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell
2531fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell    /**
2541fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     * Dispatch one step of a nested pre-scrolling operation to the current nested scrolling parent.
2551fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     *
2561fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     * <p>This is a delegate method. Call it from your {@link android.view.View View} subclass
257ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas     * method/{@link androidx.core.view.NestedScrollingChild} interface method with the same
2583ac77bf186f87ecad4bf0063b2f6c4384efbd56aKirill Grouchnikov     * signature to implement the standard policy.</p>
2591fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     *
2601fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     * @return true if the parent consumed any of the nested scroll
2611fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     */
26276daed103193a1756535d1f59b165e98e1d17445Chris Banes    public boolean dispatchNestedPreScroll(int dx, int dy, @Nullable int[] consumed,
26376daed103193a1756535d1f59b165e98e1d17445Chris Banes            @Nullable int[] offsetInWindow) {
26476daed103193a1756535d1f59b165e98e1d17445Chris Banes        return dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow, TYPE_TOUCH);
26576daed103193a1756535d1f59b165e98e1d17445Chris Banes    }
26676daed103193a1756535d1f59b165e98e1d17445Chris Banes
26776daed103193a1756535d1f59b165e98e1d17445Chris Banes    /**
26876daed103193a1756535d1f59b165e98e1d17445Chris Banes     * Dispatch one step of a nested pre-scrolling operation to the current nested scrolling parent.
26976daed103193a1756535d1f59b165e98e1d17445Chris Banes     *
27076daed103193a1756535d1f59b165e98e1d17445Chris Banes     * <p>This is a delegate method. Call it from your {@link android.view.View View} subclass
271ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas     * method/{@link androidx.core.view.NestedScrollingChild2} interface method with the same
27276daed103193a1756535d1f59b165e98e1d17445Chris Banes     * signature to implement the standard policy.</p>
27376daed103193a1756535d1f59b165e98e1d17445Chris Banes     *
27476daed103193a1756535d1f59b165e98e1d17445Chris Banes     * @return true if the parent consumed any of the nested scroll
27576daed103193a1756535d1f59b165e98e1d17445Chris Banes     */
27676daed103193a1756535d1f59b165e98e1d17445Chris Banes    public boolean dispatchNestedPreScroll(int dx, int dy, @Nullable int[] consumed,
27776daed103193a1756535d1f59b165e98e1d17445Chris Banes            @Nullable int[] offsetInWindow, @NestedScrollType int type) {
27876daed103193a1756535d1f59b165e98e1d17445Chris Banes        if (isNestedScrollingEnabled()) {
27976daed103193a1756535d1f59b165e98e1d17445Chris Banes            final ViewParent parent = getNestedScrollingParentForType(type);
28076daed103193a1756535d1f59b165e98e1d17445Chris Banes            if (parent == null) {
28176daed103193a1756535d1f59b165e98e1d17445Chris Banes                return false;
28276daed103193a1756535d1f59b165e98e1d17445Chris Banes            }
28376daed103193a1756535d1f59b165e98e1d17445Chris Banes
2841fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell            if (dx != 0 || dy != 0) {
2851fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell                int startX = 0;
2861fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell                int startY = 0;
2871fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell                if (offsetInWindow != null) {
2881fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell                    mView.getLocationInWindow(offsetInWindow);
2891fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell                    startX = offsetInWindow[0];
2901fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell                    startY = offsetInWindow[1];
2911fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell                }
2921fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell
2931fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell                if (consumed == null) {
2941fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell                    if (mTempNestedScrollConsumed == null) {
2951fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell                        mTempNestedScrollConsumed = new int[2];
2961fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell                    }
2971fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell                    consumed = mTempNestedScrollConsumed;
2981fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell                }
2991fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell                consumed[0] = 0;
3001fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell                consumed[1] = 0;
30176daed103193a1756535d1f59b165e98e1d17445Chris Banes                ViewParentCompat.onNestedPreScroll(parent, mView, dx, dy, consumed, type);
3021fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell
3031fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell                if (offsetInWindow != null) {
3041fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell                    mView.getLocationInWindow(offsetInWindow);
3051fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell                    offsetInWindow[0] -= startX;
3061fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell                    offsetInWindow[1] -= startY;
3071fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell                }
3081fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell                return consumed[0] != 0 || consumed[1] != 0;
3091fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell            } else if (offsetInWindow != null) {
3101fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell                offsetInWindow[0] = 0;
3111fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell                offsetInWindow[1] = 0;
3121fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell            }
3131fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell        }
3141fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell        return false;
3151fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell    }
3161fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell
3171fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell    /**
3181fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     * Dispatch a nested fling operation to the current nested scrolling parent.
3191fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     *
3201fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     * <p>This is a delegate method. Call it from your {@link android.view.View View} subclass
321ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas     * method/{@link androidx.core.view.NestedScrollingChild} interface method with the same
3223ac77bf186f87ecad4bf0063b2f6c4384efbd56aKirill Grouchnikov     * signature to implement the standard policy.</p>
3231fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     *
3241fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     * @return true if the parent consumed the nested fling
3251fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     */
3261fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell    public boolean dispatchNestedFling(float velocityX, float velocityY, boolean consumed) {
32776daed103193a1756535d1f59b165e98e1d17445Chris Banes        if (isNestedScrollingEnabled()) {
32876daed103193a1756535d1f59b165e98e1d17445Chris Banes            ViewParent parent = getNestedScrollingParentForType(TYPE_TOUCH);
32976daed103193a1756535d1f59b165e98e1d17445Chris Banes            if (parent != null) {
33076daed103193a1756535d1f59b165e98e1d17445Chris Banes                return ViewParentCompat.onNestedFling(parent, mView, velocityX,
33176daed103193a1756535d1f59b165e98e1d17445Chris Banes                        velocityY, consumed);
33276daed103193a1756535d1f59b165e98e1d17445Chris Banes            }
3331fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell        }
3341fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell        return false;
3351fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell    }
3361fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell
3371fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell    /**
3381fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     * Dispatch a nested pre-fling operation to the current nested scrolling parent.
3391fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     *
3401fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     * <p>This is a delegate method. Call it from your {@link android.view.View View} subclass
341ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas     * method/{@link androidx.core.view.NestedScrollingChild} interface method with the same
3423ac77bf186f87ecad4bf0063b2f6c4384efbd56aKirill Grouchnikov     * signature to implement the standard policy.</p>
3431fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     *
3441fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     * @return true if the parent consumed the nested fling
3451fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     */
3461fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell    public boolean dispatchNestedPreFling(float velocityX, float velocityY) {
34776daed103193a1756535d1f59b165e98e1d17445Chris Banes        if (isNestedScrollingEnabled()) {
34876daed103193a1756535d1f59b165e98e1d17445Chris Banes            ViewParent parent = getNestedScrollingParentForType(TYPE_TOUCH);
34976daed103193a1756535d1f59b165e98e1d17445Chris Banes            if (parent != null) {
35076daed103193a1756535d1f59b165e98e1d17445Chris Banes                return ViewParentCompat.onNestedPreFling(parent, mView, velocityX,
35176daed103193a1756535d1f59b165e98e1d17445Chris Banes                        velocityY);
35276daed103193a1756535d1f59b165e98e1d17445Chris Banes            }
3531fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell        }
3541fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell        return false;
3551fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell    }
3561fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell
3571fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell    /**
3581fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     * View subclasses should always call this method on their
3591fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     * <code>NestedScrollingChildHelper</code> when detached from a window.
3601fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     *
3611fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     * <p>This is a delegate method. Call it from your {@link android.view.View View} subclass
362ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas     * method/{@link androidx.core.view.NestedScrollingChild} interface method with the same
3633ac77bf186f87ecad4bf0063b2f6c4384efbd56aKirill Grouchnikov     * signature to implement the standard policy.</p>
3641fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     */
3651fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell    public void onDetachedFromWindow() {
3661fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell        ViewCompat.stopNestedScroll(mView);
3671fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell    }
3681fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell
3691fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell    /**
3701fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     * Called when a nested scrolling child stops its current nested scroll operation.
3711fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     *
3721fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     * <p>This is a delegate method. Call it from your {@link android.view.View View} subclass
373ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas     * method/{@link androidx.core.view.NestedScrollingChild} interface method with the same
3743ac77bf186f87ecad4bf0063b2f6c4384efbd56aKirill Grouchnikov     * signature to implement the standard policy.</p>
3751fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     *
3761fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     * @param child Child view stopping its nested scroll. This may not be a direct child view.
3771fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell     */
37876daed103193a1756535d1f59b165e98e1d17445Chris Banes    public void onStopNestedScroll(@NonNull View child) {
3791fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell        ViewCompat.stopNestedScroll(mView);
3801fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell    }
38176daed103193a1756535d1f59b165e98e1d17445Chris Banes
38276daed103193a1756535d1f59b165e98e1d17445Chris Banes    private ViewParent getNestedScrollingParentForType(@NestedScrollType int type) {
38376daed103193a1756535d1f59b165e98e1d17445Chris Banes        switch (type) {
38476daed103193a1756535d1f59b165e98e1d17445Chris Banes            case TYPE_TOUCH:
38576daed103193a1756535d1f59b165e98e1d17445Chris Banes                return mNestedScrollingParentTouch;
38676daed103193a1756535d1f59b165e98e1d17445Chris Banes            case TYPE_NON_TOUCH:
38776daed103193a1756535d1f59b165e98e1d17445Chris Banes                return mNestedScrollingParentNonTouch;
38876daed103193a1756535d1f59b165e98e1d17445Chris Banes        }
38976daed103193a1756535d1f59b165e98e1d17445Chris Banes        return null;
39076daed103193a1756535d1f59b165e98e1d17445Chris Banes    }
39176daed103193a1756535d1f59b165e98e1d17445Chris Banes
39276daed103193a1756535d1f59b165e98e1d17445Chris Banes    private void setNestedScrollingParentForType(@NestedScrollType int type, ViewParent p) {
39376daed103193a1756535d1f59b165e98e1d17445Chris Banes        switch (type) {
39476daed103193a1756535d1f59b165e98e1d17445Chris Banes            case TYPE_TOUCH:
39576daed103193a1756535d1f59b165e98e1d17445Chris Banes                mNestedScrollingParentTouch = p;
39676daed103193a1756535d1f59b165e98e1d17445Chris Banes                break;
39776daed103193a1756535d1f59b165e98e1d17445Chris Banes            case TYPE_NON_TOUCH:
39876daed103193a1756535d1f59b165e98e1d17445Chris Banes                mNestedScrollingParentNonTouch = p;
39976daed103193a1756535d1f59b165e98e1d17445Chris Banes                break;
40076daed103193a1756535d1f59b165e98e1d17445Chris Banes        }
40176daed103193a1756535d1f59b165e98e1d17445Chris Banes    }
4021fcce4485ef99aca928ebfb877859c5ecd47716cAdam Powell}
403