1 /*
2  * Copyright 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package androidx.core.view;
18 
19 import android.os.Build;
20 import android.util.Log;
21 import android.view.MotionEvent;
22 import android.view.VelocityTracker;
23 import android.view.View;
24 import android.view.ViewConfiguration;
25 import android.view.ViewParent;
26 import android.view.accessibility.AccessibilityEvent;
27 
28 import androidx.annotation.RequiresApi;
29 
30 import org.jspecify.annotations.NonNull;
31 
32 /**
33  * Helper for accessing features in {@link ViewParent}.
34  */
35 public final class ViewParentCompat {
36 
37     private static final String TAG = "ViewParentCompat";
38     private static int[] sTempNestedScrollConsumed;
39 
40     /*
41      * Hide the constructor.
42      */
ViewParentCompat()43     private ViewParentCompat() {}
44 
45     /**
46      * Called by a child to request from its parent to send an {@link AccessibilityEvent}.
47      * The child has already populated a record for itself in the event and is delegating
48      * to its parent to send the event. The parent can optionally add a record for itself.
49      * <p>
50      * Note: An accessibility event is fired by an individual view which populates the
51      *       event with a record for its state and requests from its parent to perform
52      *       the sending. The parent can optionally add a record for itself before
53      *       dispatching the request to its parent. A parent can also choose not to
54      *       respect the request for sending the event. The accessibility event is sent
55      *       by the topmost view in the view tree.</p>
56      *
57      * @param parent The parent whose method to invoke.
58      * @param child The child which requests sending the event.
59      * @param event The event to be sent.
60      * @return True if the event was sent.
61      *
62      * @deprecated Use {@link ViewParent#requestSendAccessibilityEvent(View, AccessibilityEvent)}
63      * directly.
64      */
65     @androidx.annotation.ReplaceWith(expression = "parent.requestSendAccessibilityEvent(child, event)")
66     @Deprecated
requestSendAccessibilityEvent( ViewParent parent, View child, AccessibilityEvent event)67     public static boolean requestSendAccessibilityEvent(
68             ViewParent parent, View child, AccessibilityEvent event) {
69         return parent.requestSendAccessibilityEvent(child, event);
70     }
71 
72     /**
73      * React to a descendant view initiating a nestable scroll operation, claiming the
74      * nested scroll operation if appropriate.
75      *
76      * <p>This version of the method just calls
77      * {@link #onStartNestedScroll(ViewParent, View, View, int, int)} using the touch input type.
78      * </p>
79      *
80      * @param parent ViewParent that contains the child view.
81      * @param child Direct child of this ViewParent containing target
82      * @param target View that initiated the nested scroll
83      * @param nestedScrollAxes Flags consisting of {@link ViewCompat#SCROLL_AXIS_HORIZONTAL},
84      *                         {@link ViewCompat#SCROLL_AXIS_VERTICAL} or both
85      * @return true if this ViewParent accepts the nested scroll operation
86      */
onStartNestedScroll(@onNull ViewParent parent, @NonNull View child, @NonNull View target, int nestedScrollAxes)87     public static boolean onStartNestedScroll(@NonNull ViewParent parent, @NonNull View child,
88             @NonNull View target, int nestedScrollAxes) {
89         return onStartNestedScroll(parent, child, target, nestedScrollAxes, ViewCompat.TYPE_TOUCH);
90     }
91 
92     /**
93      * React to the successful claiming of a nested scroll operation.
94      *
95      * <p>This version of the method just calls
96      * {@link #onNestedScrollAccepted(ViewParent, View, View, int, int)} using the touch input type.
97      * </p>
98      *
99      * @param parent ViewParent that contains the child view.
100      * @param child Direct child of this ViewParent containing target
101      * @param target View that initiated the nested scroll
102      * @param nestedScrollAxes Flags consisting of {@link ViewCompat#SCROLL_AXIS_HORIZONTAL},
103      *                         {@link ViewCompat#SCROLL_AXIS_VERTICAL} or both
104      */
onNestedScrollAccepted(@onNull ViewParent parent, @NonNull View child, @NonNull View target, int nestedScrollAxes)105     public static void onNestedScrollAccepted(@NonNull ViewParent parent, @NonNull View child,
106             @NonNull View target, int nestedScrollAxes) {
107         onNestedScrollAccepted(parent, child, target, nestedScrollAxes, ViewCompat.TYPE_TOUCH);
108     }
109 
110     /**
111      * React to a nested scroll operation ending.
112      *
113      * <p>This version of the method just calls {@link #onStopNestedScroll(ViewParent, View, int)}
114      * using the touch input type.</p>
115      *
116      * @param parent ViewParent that contains the target view.
117      * @param target View that initiated the nested scroll
118      */
onStopNestedScroll(@onNull ViewParent parent, @NonNull View target)119     public static void onStopNestedScroll(@NonNull ViewParent parent, @NonNull View target) {
120         onStopNestedScroll(parent, target, ViewCompat.TYPE_TOUCH);
121     }
122 
123     /**
124      * React to a nested scroll in progress.
125      *
126      * <p>This version of the method just calls
127      * {@link #onNestedScroll(ViewParent, View, int, int, int, int, int)} using the touch input
128      * type.
129      *
130      * @param parent ViewParent that contains the target view.
131      * @param target The descendent view controlling the nested scroll
132      * @param dxConsumed Horizontal scroll distance in pixels already consumed by target
133      * @param dyConsumed Vertical scroll distance in pixels already consumed by target
134      * @param dxUnconsumed Horizontal scroll distance in pixels not consumed by target
135      * @param dyUnconsumed Vertical scroll distance in pixels not consumed by target
136      */
onNestedScroll(@onNull ViewParent parent, @NonNull View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed)137     public static void onNestedScroll(@NonNull ViewParent parent, @NonNull View target,
138             int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
139         onNestedScroll(parent, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed,
140                 ViewCompat.TYPE_TOUCH, getTempNestedScrollConsumed());
141     }
142 
143     /**
144      * React to a nested scroll in progress.
145      *
146      * <p>This method will be called when the ViewParent's current nested scrolling child view
147      * dispatches a nested scroll event. To receive calls to this method the ViewParent must have
148      * previously returned <code>true</code> for a call to
149      * {@link #onStartNestedScroll(ViewParent, View, View, int, int)}.</p>
150      *
151      * <p>Both the consumed and unconsumed portions of the scroll distance are reported to the
152      * ViewParent. An implementation may choose to use the consumed portion to match or chase scroll
153      * position of multiple child elements, for example. The unconsumed portion may be used to
154      * allow continuous dragging of multiple scrolling or draggable elements, such as scrolling
155      * a list within a vertical drawer where the drawer begins dragging once the edge of inner
156      * scrolling content is reached.</p>
157      *
158      * @param parent ViewParent that contains the target view.
159      * @param target The descendant view controlling the nested scroll
160      * @param dxConsumed Horizontal scroll distance in pixels already consumed by target
161      * @param dyConsumed Vertical scroll distance in pixels already consumed by target
162      * @param dxUnconsumed Horizontal scroll distance in pixels not consumed by target
163      * @param dyUnconsumed Vertical scroll distance in pixels not consumed by target
164      * @param type the type of input which cause this scroll event
165      */
onNestedScroll(@onNull ViewParent parent, @NonNull View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int type)166     public static void onNestedScroll(@NonNull ViewParent parent, @NonNull View target,
167             int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int type) {
168         onNestedScroll(parent, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed,
169                 type, getTempNestedScrollConsumed());
170     }
171 
172     /**
173      * React to a nested scroll in progress before the target view consumes a portion of the scroll.
174      *
175      * <p>This version of the method just calls
176      * {@link #onNestedPreScroll(ViewParent, View, int, int, int[], int)} using the touch input
177      * type.</p>
178      *
179      * @param parent ViewParent that contains the target view.
180      * @param target View that initiated the nested scroll
181      * @param dx Horizontal scroll distance in pixels
182      * @param dy Vertical scroll distance in pixels
183      * @param consumed Output. The horizontal and vertical scroll distance consumed by this parent
184      */
onNestedPreScroll(@onNull ViewParent parent, @NonNull View target, int dx, int dy, int @NonNull [] consumed)185     public static void onNestedPreScroll(@NonNull ViewParent parent, @NonNull View target, int dx,
186             int dy, int @NonNull [] consumed) {
187         onNestedPreScroll(parent, target, dx, dy, consumed, ViewCompat.TYPE_TOUCH);
188     }
189 
190     /**
191      * React to a descendant view initiating a nestable scroll operation, claiming the
192      * nested scroll operation if appropriate.
193      *
194      * <p>This method will be called in response to a descendant view invoking
195      * {@link ViewCompat#startNestedScroll(View, int)}. Each parent up the view hierarchy will be
196      * given an opportunity to respond and claim the nested scrolling operation by returning
197      * <code>true</code>.</p>
198      *
199      * <p>This method may be overridden by ViewParent implementations to indicate when the view
200      * is willing to support a nested scrolling operation that is about to begin. If it returns
201      * true, this ViewParent will become the target view's nested scrolling parent for the duration
202      * of the scroll operation in progress. When the nested scroll is finished this ViewParent
203      * will receive a call to {@link #onStopNestedScroll(ViewParent, View, int)}.
204      * </p>
205      *
206      * @param parent ViewParent that contains the child view.
207      * @param child Direct child of this ViewParent containing target
208      * @param target View that initiated the nested scroll
209      * @param nestedScrollAxes Flags consisting of {@link ViewCompat#SCROLL_AXIS_HORIZONTAL},
210      *                         {@link ViewCompat#SCROLL_AXIS_VERTICAL} or both
211      * @param type the type of input which cause this scroll event
212      * @return true if this ViewParent accepts the nested scroll operation
213      */
214     @SuppressWarnings("RedundantCast") // Intentionally invoking interface method.
onStartNestedScroll(@onNull ViewParent parent, @NonNull View child, @NonNull View target, int nestedScrollAxes, int type)215     public static boolean onStartNestedScroll(@NonNull ViewParent parent, @NonNull View child,
216             @NonNull View target, int nestedScrollAxes, int type) {
217         if (parent instanceof NestedScrollingParent2) {
218             // First try the NestedScrollingParent2 API
219             return ((NestedScrollingParent2) parent).onStartNestedScroll(child, target,
220                     nestedScrollAxes, type);
221         } else if (type == ViewCompat.TYPE_TOUCH) {
222             // Else if the type is the default (touch), try the NestedScrollingParent API
223             if (Build.VERSION.SDK_INT >= 21) {
224                 try {
225                     return Api21Impl.onStartNestedScroll(parent, child, target, nestedScrollAxes);
226                 } catch (AbstractMethodError e) {
227                     Log.e(TAG, "ViewParent " + parent + " does not implement interface "
228                             + "method onStartNestedScroll", e);
229                 }
230             } else if (parent instanceof NestedScrollingParent) {
231                 return ((NestedScrollingParent) parent).onStartNestedScroll(child, target,
232                         nestedScrollAxes);
233             }
234         }
235         return false;
236     }
237 
238     /**
239      * React to the successful claiming of a nested scroll operation.
240      *
241      * <p>This method will be called after
242      * {@link #onStartNestedScroll(ViewParent, View, View, int) onStartNestedScroll} returns true.
243      * It offers an opportunity for the view and its superclasses to perform initial configuration
244      * for the nested scroll. Implementations of this method should always call their superclass's
245      * implementation of this method if one is present.</p>
246      *
247      * @param parent ViewParent that contains the child view.
248      * @param child Direct child of this ViewParent containing target
249      * @param target View that initiated the nested scroll
250      * @param nestedScrollAxes Flags consisting of {@link ViewCompat#SCROLL_AXIS_HORIZONTAL},
251      *                         {@link ViewCompat#SCROLL_AXIS_VERTICAL} or both
252      * @param type the type of input which cause this scroll event
253      * @see #onStartNestedScroll(ViewParent, View, View, int)
254      * @see #onStopNestedScroll(ViewParent, View, int)
255      */
256     @SuppressWarnings("RedundantCast") // Intentionally invoking interface method.
onNestedScrollAccepted(@onNull ViewParent parent, @NonNull View child, @NonNull View target, int nestedScrollAxes, int type)257     public static void onNestedScrollAccepted(@NonNull ViewParent parent, @NonNull View child,
258             @NonNull View target, int nestedScrollAxes, int type) {
259         if (parent instanceof NestedScrollingParent2) {
260             // First try the NestedScrollingParent2 API
261             ((NestedScrollingParent2) parent).onNestedScrollAccepted(child, target,
262                     nestedScrollAxes, type);
263         } else if (type == ViewCompat.TYPE_TOUCH) {
264             // Else if the type is the default (touch), try the NestedScrollingParent API
265             if (Build.VERSION.SDK_INT >= 21) {
266                 try {
267                     Api21Impl.onNestedScrollAccepted(parent, child, target, nestedScrollAxes);
268                 } catch (AbstractMethodError e) {
269                     Log.e(TAG, "ViewParent " + parent + " does not implement interface "
270                             + "method onNestedScrollAccepted", e);
271                 }
272             } else if (parent instanceof NestedScrollingParent) {
273                 ((NestedScrollingParent) parent).onNestedScrollAccepted(child, target,
274                         nestedScrollAxes);
275             }
276         }
277     }
278 
279     /**
280      * React to a nested scroll operation ending.
281      *
282      * <p>Perform cleanup after a nested scrolling operation.
283      * This method will be called when a nested scroll stops, for example when a nested touch
284      * scroll ends with a {@link MotionEvent#ACTION_UP} or {@link MotionEvent#ACTION_CANCEL} event.
285      * Implementations of this method should always call their superclass's implementation of this
286      * method if one is present.</p>
287      *
288      * @param parent ViewParent that contains the target view.
289      * @param target View that initiated the nested scroll
290      * @param type the type of input which cause this scroll event
291      */
292     @SuppressWarnings("RedundantCast") // Intentionally invoking interface method.
onStopNestedScroll(@onNull ViewParent parent, @NonNull View target, int type)293     public static void onStopNestedScroll(@NonNull ViewParent parent, @NonNull View target,
294             int type) {
295         if (parent instanceof NestedScrollingParent2) {
296             // First try the NestedScrollingParent2 API
297             ((NestedScrollingParent2) parent).onStopNestedScroll(target, type);
298         } else if (type == ViewCompat.TYPE_TOUCH) {
299             // Else if the type is the default (touch), try the NestedScrollingParent API
300             if (Build.VERSION.SDK_INT >= 21) {
301                 try {
302                     Api21Impl.onStopNestedScroll(parent, target);
303                 } catch (AbstractMethodError e) {
304                     Log.e(TAG, "ViewParent " + parent + " does not implement interface "
305                             + "method onStopNestedScroll", e);
306                 }
307             } else if (parent instanceof NestedScrollingParent) {
308                 ((NestedScrollingParent) parent).onStopNestedScroll(target);
309             }
310         }
311     }
312 
313     /**
314      * React to a nested scroll in progress.
315      *
316      * <p>This method will be called when the ViewParent's current nested scrolling child view
317      * dispatches a nested scroll event. To receive calls to this method the ViewParent must have
318      * previously returned <code>true</code> for a call to
319      * {@link #onStartNestedScroll(ViewParent, View, View, int, int)}.</p>
320      *
321      * <p>Both the consumed and unconsumed portions of the scroll distance are reported to the
322      * ViewParent. An implementation may choose to use the consumed portion to match or chase scroll
323      * position of multiple child elements, for example. The unconsumed portion may be used to
324      * allow continuous dragging of multiple scrolling or draggable elements, such as scrolling
325      * a list within a vertical drawer where the drawer begins dragging once the edge of inner
326      * scrolling content is reached.</p>
327      *
328      * @param parent ViewParent that contains the target view.
329      * @param target The descendent view controlling the nested scroll
330      * @param dxConsumed Horizontal scroll distance in pixels already consumed by target
331      * @param dyConsumed Vertical scroll distance in pixels already consumed by target
332      * @param dxUnconsumed Horizontal scroll distance in pixels not consumed by target
333      * @param dyUnconsumed Vertical scroll distance in pixels not consumed by target
334      * @param type the type of input which cause this scroll event
335      * @param consumed Output. If not null, upon this method returning, will contain the scroll
336      *                 distances consumed by this nested scrolling parent and the scroll distances
337      *                 consumed by any other parent up the view hierarchy.
338      */
onNestedScroll(@onNull ViewParent parent, @NonNull View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int type, int @NonNull [] consumed)339     public static void onNestedScroll(@NonNull ViewParent parent, @NonNull View target,
340             int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int type,
341             int @NonNull [] consumed) {
342 
343         if (parent instanceof NestedScrollingParent3) {
344             ((NestedScrollingParent3) parent).onNestedScroll(target, dxConsumed, dyConsumed,
345                     dxUnconsumed, dyUnconsumed, type, consumed);
346         } else {
347             // If we are calling anything less than NestedScrollingParent3, add the unconsumed
348             // distances to the consumed parameter so calling NestedScrollingChild3 implementations
349             // are told the entire scroll distance was consumed (for backwards compat).
350             consumed[0] += dxUnconsumed;
351             consumed[1] += dyUnconsumed;
352 
353             if (parent instanceof NestedScrollingParent2) {
354                 ((NestedScrollingParent2) parent).onNestedScroll(target, dxConsumed, dyConsumed,
355                         dxUnconsumed, dyUnconsumed, type);
356             } else if (type == ViewCompat.TYPE_TOUCH) {
357                 // Else if the type is the default (touch), try the NestedScrollingParent API
358                 if (Build.VERSION.SDK_INT >= 21) {
359                     try {
360                         Api21Impl.onNestedScroll(parent, target, dxConsumed, dyConsumed,
361                                 dxUnconsumed, dyUnconsumed);
362                     } catch (AbstractMethodError e) {
363                         Log.e(TAG, "ViewParent " + parent + " does not implement interface "
364                                 + "method onNestedScroll", e);
365                     }
366                 } else if (parent instanceof NestedScrollingParent) {
367                     ((NestedScrollingParent) parent).onNestedScroll(target, dxConsumed, dyConsumed,
368                             dxUnconsumed, dyUnconsumed);
369                 }
370             }
371         }
372     }
373 
374     /**
375      * React to a nested scroll in progress before the target view consumes a portion of the scroll.
376      *
377      * <p>When working with nested scrolling often the parent view may want an opportunity
378      * to consume the scroll before the nested scrolling child does. An example of this is a
379      * drawer that contains a scrollable list. The user will want to be able to scroll the list
380      * fully into view before the list itself begins scrolling.</p>
381      *
382      * <p><code>onNestedPreScroll</code> is called when a nested scrolling child invokes
383      * {@link ViewCompat#dispatchNestedPreScroll(View, int, int, int[], int[])}. The implementation
384      * should report how any pixels of the scroll reported by dx, dy were consumed in the
385      * <code>consumed</code> array. Index 0 corresponds to dx and index 1 corresponds to dy.
386      * This parameter will never be null. Initial values for consumed[0] and consumed[1]
387      * will always be 0.</p>
388      *
389      * @param parent ViewParent that contains the target view.
390      * @param target View that initiated the nested scroll
391      * @param dx Horizontal scroll distance in pixels
392      * @param dy Vertical scroll distance in pixels
393      * @param consumed Output. The horizontal and vertical scroll distance consumed by this parent
394      * @param type the type of input which cause this scroll event
395      */
396     @SuppressWarnings("RedundantCast") // Intentionally invoking interface method.
onNestedPreScroll(@onNull ViewParent parent, @NonNull View target, int dx, int dy, int @NonNull [] consumed, int type)397     public static void onNestedPreScroll(@NonNull ViewParent parent, @NonNull View target, int dx,
398             int dy, int @NonNull [] consumed, int type) {
399         if (parent instanceof NestedScrollingParent2) {
400             // First try the NestedScrollingParent2 API
401             ((NestedScrollingParent2) parent).onNestedPreScroll(target, dx, dy, consumed, type);
402         } else if (type == ViewCompat.TYPE_TOUCH) {
403             // Else if the type is the default (touch), try the NestedScrollingParent API
404             if (Build.VERSION.SDK_INT >= 21) {
405                 try {
406                     Api21Impl.onNestedPreScroll(parent, target, dx, dy, consumed);
407                 } catch (AbstractMethodError e) {
408                     Log.e(TAG, "ViewParent " + parent + " does not implement interface "
409                             + "method onNestedPreScroll", e);
410                 }
411             } else if (parent instanceof NestedScrollingParent) {
412                 ((NestedScrollingParent) parent).onNestedPreScroll(target, dx, dy, consumed);
413             }
414         }
415     }
416 
417     /**
418      * Request a fling from a nested scroll.
419      *
420      * <p>This method signifies that a nested scrolling child has detected suitable conditions
421      * for a fling. Generally this means that a touch scroll has ended with a
422      * {@link VelocityTracker velocity} in the direction of scrolling that meets or exceeds
423      * the {@link ViewConfiguration#getScaledMinimumFlingVelocity() minimum fling velocity}
424      * along a scrollable axis.</p>
425      *
426      * <p>If a nested scrolling child view would normally fling but it is at the edge of
427      * its own content, it can use this method to delegate the fling to its nested scrolling
428      * parent instead. The parent may optionally consume the fling or observe a child fling.</p>
429      *
430      * @param parent ViewParent that contains the target view.
431      * @param target View that initiated the nested scroll
432      * @param velocityX Horizontal velocity in pixels per second
433      * @param velocityY Vertical velocity in pixels per second
434      * @param consumed true if the child consumed the fling, false otherwise
435      * @return true if this parent consumed or otherwise reacted to the fling
436      */
437     @SuppressWarnings("RedundantCast") // Intentionally invoking interface method.
onNestedFling(@onNull ViewParent parent, @NonNull View target, float velocityX, float velocityY, boolean consumed)438     public static boolean onNestedFling(@NonNull ViewParent parent, @NonNull View target,
439             float velocityX, float velocityY, boolean consumed) {
440         if (Build.VERSION.SDK_INT >= 21) {
441             try {
442                 return Api21Impl.onNestedFling(parent, target, velocityX, velocityY, consumed);
443             } catch (AbstractMethodError e) {
444                 Log.e(TAG, "ViewParent " + parent + " does not implement interface "
445                         + "method onNestedFling", e);
446             }
447         } else if (parent instanceof NestedScrollingParent) {
448             return ((NestedScrollingParent) parent).onNestedFling(target, velocityX, velocityY,
449                     consumed);
450         }
451         return false;
452     }
453 
454     /**
455      * React to a nested fling before the target view consumes it.
456      *
457      * <p>This method siginfies that a nested scrolling child has detected a fling with the given
458      * velocity along each axis. Generally this means that a touch scroll has ended with a
459      * {@link VelocityTracker velocity} in the direction of scrolling that meets or exceeds
460      * the {@link ViewConfiguration#getScaledMinimumFlingVelocity() minimum fling velocity}
461      * along a scrollable axis.</p>
462      *
463      * <p>If a nested scrolling parent is consuming motion as part of a
464      * {@link #onNestedPreScroll(ViewParent, View, int, int, int[]) pre-scroll}, it may be
465      * appropriate for it to also consume the pre-fling to complete that same motion. By returning
466      * <code>true</code> from this method, the parent indicates that the child should not
467      * fling its own internal content as well.</p>
468      *
469      * @param parent ViewParent that contains the target view.
470      * @param target View that initiated the nested scroll
471      * @param velocityX Horizontal velocity in pixels per second
472      * @param velocityY Vertical velocity in pixels per second
473      * @return true if this parent consumed the fling ahead of the target view
474      */
475     @SuppressWarnings("RedundantCast") // Intentionally invoking interface method.
onNestedPreFling(@onNull ViewParent parent, @NonNull View target, float velocityX, float velocityY)476     public static boolean onNestedPreFling(@NonNull ViewParent parent, @NonNull View target,
477             float velocityX, float velocityY) {
478         if (Build.VERSION.SDK_INT >= 21) {
479             try {
480                 return Api21Impl.onNestedPreFling(parent, target, velocityX, velocityY);
481             } catch (AbstractMethodError e) {
482                 Log.e(TAG, "ViewParent " + parent + " does not implement interface "
483                         + "method onNestedPreFling", e);
484             }
485         } else if (parent instanceof NestedScrollingParent) {
486             return ((NestedScrollingParent) parent).onNestedPreFling(target, velocityX,
487                     velocityY);
488         }
489         return false;
490     }
491 
492     /**
493      * Notifies a view parent that the accessibility state of one of its
494      * descendants has changed and that the structure of the subtree is
495      * different.
496      *
497      * @param parent ViewParent that contains the target view.
498      * @param child The direct child whose subtree has changed.
499      * @param source The descendant view that changed.
500      * @param changeType A bit mask of the types of changes that occurred. One
501      *            or more of:
502      *            <ul>
503      *            <li>{@link AccessibilityEvent#CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION}
504      *            <li>{@link AccessibilityEvent#CONTENT_CHANGE_TYPE_SUBTREE}
505      *            <li>{@link AccessibilityEvent#CONTENT_CHANGE_TYPE_TEXT}
506      *            <li>{@link AccessibilityEvent#CONTENT_CHANGE_TYPE_UNDEFINED}
507      *            </ul>
508      * @deprecated Call {@link ViewParent#notifySubtreeAccessibilityStateChanged()} directly.
509      */
510     @Deprecated
511     @androidx.annotation.ReplaceWith(expression = "parent.notifySubtreeAccessibilityStateChanged(child, source, changeType)")
notifySubtreeAccessibilityStateChanged(@onNull ViewParent parent, @NonNull View child, @NonNull View source, int changeType)512     public static void notifySubtreeAccessibilityStateChanged(@NonNull ViewParent parent,
513             @NonNull View child, @NonNull View source, int changeType) {
514         parent.notifySubtreeAccessibilityStateChanged(child, source, changeType);
515     }
516 
getTempNestedScrollConsumed()517     private static int[] getTempNestedScrollConsumed() {
518         if (sTempNestedScrollConsumed == null) {
519             sTempNestedScrollConsumed = new int[2];
520         } else {
521             sTempNestedScrollConsumed[0] = 0;
522             sTempNestedScrollConsumed[1] = 0;
523         }
524         return sTempNestedScrollConsumed;
525     }
526 
527     @RequiresApi(21)
528     static class Api21Impl {
Api21Impl()529         private Api21Impl() {
530             // This class is not instantiable.
531         }
532 
onStartNestedScroll(ViewParent viewParent, View view, View view1, int i)533         static boolean onStartNestedScroll(ViewParent viewParent, View view, View view1, int i) {
534             return viewParent.onStartNestedScroll(view, view1, i);
535         }
536 
onNestedScrollAccepted(ViewParent viewParent, View view, View view1, int i)537         static void onNestedScrollAccepted(ViewParent viewParent, View view, View view1, int i) {
538             viewParent.onNestedScrollAccepted(view, view1, i);
539         }
540 
onStopNestedScroll(ViewParent viewParent, View view)541         static void onStopNestedScroll(ViewParent viewParent, View view) {
542             viewParent.onStopNestedScroll(view);
543         }
544 
onNestedScroll(ViewParent viewParent, View view, int i, int i1, int i2, int i3)545         static void onNestedScroll(ViewParent viewParent, View view, int i, int i1, int i2,
546                 int i3) {
547             viewParent.onNestedScroll(view, i, i1, i2, i3);
548         }
549 
onNestedPreScroll(ViewParent viewParent, View view, int i, int i1, int[] ints)550         static void onNestedPreScroll(ViewParent viewParent, View view, int i, int i1, int[] ints) {
551             viewParent.onNestedPreScroll(view, i, i1, ints);
552         }
553 
onNestedFling(ViewParent viewParent, View view, float v, float v1, boolean b)554         static boolean onNestedFling(ViewParent viewParent, View view, float v, float v1,
555                 boolean b) {
556             return viewParent.onNestedFling(view, v, v1, b);
557         }
558 
onNestedPreFling(ViewParent viewParent, View view, float v, float v1)559         static boolean onNestedPreFling(ViewParent viewParent, View view, float v, float v1) {
560             return viewParent.onNestedPreFling(view, v, v1);
561         }
562     }
563 }
564