Home | History | Annotate | Download | only in view
      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 static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
     20 
     21 import android.animation.ValueAnimator;
     22 import android.annotation.SuppressLint;
     23 import android.annotation.TargetApi;
     24 import android.content.ClipData;
     25 import android.content.Context;
     26 import android.content.res.ColorStateList;
     27 import android.graphics.Matrix;
     28 import android.graphics.Paint;
     29 import android.graphics.PorterDuff;
     30 import android.graphics.Rect;
     31 import android.graphics.drawable.Drawable;
     32 import android.os.Build;
     33 import android.os.Bundle;
     34 import android.util.Log;
     35 import android.view.Display;
     36 import android.view.MotionEvent;
     37 import android.view.PointerIcon;
     38 import android.view.VelocityTracker;
     39 import android.view.View;
     40 import android.view.ViewConfiguration;
     41 import android.view.ViewGroup;
     42 import android.view.ViewParent;
     43 import android.view.WindowInsets;
     44 import android.view.WindowManager;
     45 import android.view.accessibility.AccessibilityEvent;
     46 import android.view.accessibility.AccessibilityNodeProvider;
     47 
     48 import androidx.annotation.FloatRange;
     49 import androidx.annotation.IdRes;
     50 import androidx.annotation.IntDef;
     51 import androidx.annotation.NonNull;
     52 import androidx.annotation.Nullable;
     53 import androidx.annotation.Px;
     54 import androidx.annotation.RequiresApi;
     55 import androidx.annotation.RestrictTo;
     56 import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
     57 import androidx.core.view.accessibility.AccessibilityNodeProviderCompat;
     58 
     59 import java.lang.annotation.Retention;
     60 import java.lang.annotation.RetentionPolicy;
     61 import java.lang.reflect.Field;
     62 import java.lang.reflect.InvocationTargetException;
     63 import java.lang.reflect.Method;
     64 import java.util.Collection;
     65 import java.util.WeakHashMap;
     66 import java.util.concurrent.atomic.AtomicInteger;
     67 
     68 /**
     69  * Helper for accessing features in {@link View}.
     70  */
     71 public class ViewCompat {
     72     private static final String TAG = "ViewCompat";
     73 
     74     /** @hide */
     75     @RestrictTo(LIBRARY_GROUP)
     76     @IntDef({View.FOCUS_LEFT, View.FOCUS_UP, View.FOCUS_RIGHT, View.FOCUS_DOWN,
     77             View.FOCUS_FORWARD, View.FOCUS_BACKWARD})
     78     @Retention(RetentionPolicy.SOURCE)
     79     public @interface FocusDirection {}
     80 
     81     /** @hide */
     82     @RestrictTo(LIBRARY_GROUP)
     83     @IntDef({View.FOCUS_LEFT, View.FOCUS_UP, View.FOCUS_RIGHT, View.FOCUS_DOWN})
     84     @Retention(RetentionPolicy.SOURCE)
     85     public @interface FocusRealDirection {}
     86 
     87     /** @hide */
     88     @RestrictTo(LIBRARY_GROUP)
     89     @IntDef({View.FOCUS_FORWARD, View.FOCUS_BACKWARD})
     90     @Retention(RetentionPolicy.SOURCE)
     91     public @interface FocusRelativeDirection {}
     92 
     93     @IntDef({OVER_SCROLL_ALWAYS, OVER_SCROLL_IF_CONTENT_SCROLLS, OVER_SCROLL_NEVER})
     94     @Retention(RetentionPolicy.SOURCE)
     95     private @interface OverScroll {}
     96 
     97     /**
     98      * Always allow a user to over-scroll this view, provided it is a
     99      * view that can scroll.
    100      * @deprecated Use {@link View#OVER_SCROLL_ALWAYS} directly. This constant will be removed in
    101      * a future release.
    102      */
    103     @Deprecated
    104     public static final int OVER_SCROLL_ALWAYS = 0;
    105 
    106     /**
    107      * Allow a user to over-scroll this view only if the content is large
    108      * enough to meaningfully scroll, provided it is a view that can scroll.
    109      * @deprecated Use {@link View#OVER_SCROLL_IF_CONTENT_SCROLLS} directly. This constant will be
    110      * removed in a future release.
    111      */
    112     @Deprecated
    113     public static final int OVER_SCROLL_IF_CONTENT_SCROLLS = 1;
    114 
    115     /**
    116      * Never allow a user to over-scroll this view.
    117      * @deprecated Use {@link View#OVER_SCROLL_NEVER} directly. This constant will be removed in
    118      * a future release.
    119      */
    120     @Deprecated
    121     public static final int OVER_SCROLL_NEVER = 2;
    122 
    123     @TargetApi(Build.VERSION_CODES.O)
    124     @IntDef({
    125             View.IMPORTANT_FOR_AUTOFILL_AUTO,
    126             View.IMPORTANT_FOR_AUTOFILL_YES,
    127             View.IMPORTANT_FOR_AUTOFILL_NO,
    128             View.IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS,
    129             View.IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS
    130     })
    131     @Retention(RetentionPolicy.SOURCE)
    132     private @interface AutofillImportance {}
    133 
    134     @IntDef({
    135             IMPORTANT_FOR_ACCESSIBILITY_AUTO,
    136             IMPORTANT_FOR_ACCESSIBILITY_YES,
    137             IMPORTANT_FOR_ACCESSIBILITY_NO,
    138             IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
    139     })
    140     @Retention(RetentionPolicy.SOURCE)
    141     private @interface ImportantForAccessibility {}
    142 
    143     /**
    144      * Automatically determine whether a view is important for accessibility.
    145      */
    146     public static final int IMPORTANT_FOR_ACCESSIBILITY_AUTO = 0x00000000;
    147 
    148     /**
    149      * The view is important for accessibility.
    150      */
    151     public static final int IMPORTANT_FOR_ACCESSIBILITY_YES = 0x00000001;
    152 
    153     /**
    154      * The view is not important for accessibility.
    155      */
    156     public static final int IMPORTANT_FOR_ACCESSIBILITY_NO = 0x00000002;
    157 
    158     /**
    159      * The view is not important for accessibility, nor are any of its
    160      * descendant views.
    161      */
    162     public static final int IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS = 0x00000004;
    163 
    164     @IntDef({
    165             ACCESSIBILITY_LIVE_REGION_NONE,
    166             ACCESSIBILITY_LIVE_REGION_POLITE,
    167             ACCESSIBILITY_LIVE_REGION_ASSERTIVE
    168     })
    169     @Retention(RetentionPolicy.SOURCE)
    170     private @interface AccessibilityLiveRegion {}
    171 
    172     /**
    173      * Live region mode specifying that accessibility services should not
    174      * automatically announce changes to this view. This is the default live
    175      * region mode for most views.
    176      * <p>
    177      * Use with {@link ViewCompat#setAccessibilityLiveRegion(View, int)}.
    178      */
    179     public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0x00000000;
    180 
    181     /**
    182      * Live region mode specifying that accessibility services should announce
    183      * changes to this view.
    184      * <p>
    185      * Use with {@link ViewCompat#setAccessibilityLiveRegion(View, int)}.
    186      */
    187     public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 0x00000001;
    188 
    189     /**
    190      * Live region mode specifying that accessibility services should interrupt
    191      * ongoing speech to immediately announce changes to this view.
    192      * <p>
    193      * Use with {@link ViewCompat#setAccessibilityLiveRegion(View, int)}.
    194      */
    195     public static final int ACCESSIBILITY_LIVE_REGION_ASSERTIVE = 0x00000002;
    196 
    197     @IntDef({View.LAYER_TYPE_NONE, View.LAYER_TYPE_SOFTWARE, View.LAYER_TYPE_HARDWARE})
    198     @Retention(RetentionPolicy.SOURCE)
    199     private @interface LayerType {}
    200 
    201     /**
    202      * Indicates that the view does not have a layer.
    203      *
    204      * @deprecated Use {@link View#LAYER_TYPE_NONE} directly.
    205      */
    206     @Deprecated
    207     public static final int LAYER_TYPE_NONE = 0;
    208 
    209     /**
    210      * <p>Indicates that the view has a software layer. A software layer is backed
    211      * by a bitmap and causes the view to be rendered using Android's software
    212      * rendering pipeline, even if hardware acceleration is enabled.</p>
    213      *
    214      * <p>Software layers have various usages:</p>
    215      * <p>When the application is not using hardware acceleration, a software layer
    216      * is useful to apply a specific color filter and/or blending mode and/or
    217      * translucency to a view and all its children.</p>
    218      * <p>When the application is using hardware acceleration, a software layer
    219      * is useful to render drawing primitives not supported by the hardware
    220      * accelerated pipeline. It can also be used to cache a complex view tree
    221      * into a texture and reduce the complexity of drawing operations. For instance,
    222      * when animating a complex view tree with a translation, a software layer can
    223      * be used to render the view tree only once.</p>
    224      * <p>Software layers should be avoided when the affected view tree updates
    225      * often. Every update will require to re-render the software layer, which can
    226      * potentially be slow (particularly when hardware acceleration is turned on
    227      * since the layer will have to be uploaded into a hardware texture after every
    228      * update.)</p>
    229      *
    230      * @deprecated Use {@link View#LAYER_TYPE_SOFTWARE} directly.
    231      */
    232     @Deprecated
    233     public static final int LAYER_TYPE_SOFTWARE = 1;
    234 
    235     /**
    236      * <p>Indicates that the view has a hardware layer. A hardware layer is backed
    237      * by a hardware specific texture (generally Frame Buffer Objects or FBO on
    238      * OpenGL hardware) and causes the view to be rendered using Android's hardware
    239      * rendering pipeline, but only if hardware acceleration is turned on for the
    240      * view hierarchy. When hardware acceleration is turned off, hardware layers
    241      * behave exactly as {@link View#LAYER_TYPE_SOFTWARE software layers}.</p>
    242      *
    243      * <p>A hardware layer is useful to apply a specific color filter and/or
    244      * blending mode and/or translucency to a view and all its children.</p>
    245      * <p>A hardware layer can be used to cache a complex view tree into a
    246      * texture and reduce the complexity of drawing operations. For instance,
    247      * when animating a complex view tree with a translation, a hardware layer can
    248      * be used to render the view tree only once.</p>
    249      * <p>A hardware layer can also be used to increase the rendering quality when
    250      * rotation transformations are applied on a view. It can also be used to
    251      * prevent potential clipping issues when applying 3D transforms on a view.</p>
    252      *
    253      * @deprecated Use {@link View#LAYER_TYPE_HARDWARE} directly.
    254      */
    255     @Deprecated
    256     public static final int LAYER_TYPE_HARDWARE = 2;
    257 
    258     @IntDef({
    259             LAYOUT_DIRECTION_LTR,
    260             LAYOUT_DIRECTION_RTL,
    261             LAYOUT_DIRECTION_INHERIT,
    262             LAYOUT_DIRECTION_LOCALE})
    263     @Retention(RetentionPolicy.SOURCE)
    264     private @interface LayoutDirectionMode {}
    265 
    266     @IntDef({
    267             LAYOUT_DIRECTION_LTR,
    268             LAYOUT_DIRECTION_RTL
    269     })
    270     @Retention(RetentionPolicy.SOURCE)
    271     private @interface ResolvedLayoutDirectionMode {}
    272 
    273     /**
    274      * Horizontal layout direction of this view is from Left to Right.
    275      */
    276     public static final int LAYOUT_DIRECTION_LTR = 0;
    277 
    278     /**
    279      * Horizontal layout direction of this view is from Right to Left.
    280      */
    281     public static final int LAYOUT_DIRECTION_RTL = 1;
    282 
    283     /**
    284      * Horizontal layout direction of this view is inherited from its parent.
    285      * Use with {@link #setLayoutDirection}.
    286      */
    287     public static final int LAYOUT_DIRECTION_INHERIT = 2;
    288 
    289     /**
    290      * Horizontal layout direction of this view is from deduced from the default language
    291      * script for the locale. Use with {@link #setLayoutDirection}.
    292      */
    293     public static final int LAYOUT_DIRECTION_LOCALE = 3;
    294 
    295     /**
    296      * Bits of {@link #getMeasuredWidthAndState} and
    297      * {@link #getMeasuredWidthAndState} that provide the actual measured size.
    298      *
    299      * @deprecated Use {@link View#MEASURED_SIZE_MASK} directly.
    300      */
    301     @Deprecated
    302     public static final int MEASURED_SIZE_MASK = 0x00ffffff;
    303 
    304     /**
    305      * Bits of {@link #getMeasuredWidthAndState} and
    306      * {@link #getMeasuredWidthAndState} that provide the additional state bits.
    307      *
    308      * @deprecated Use {@link View#MEASURED_STATE_MASK} directly.
    309      */
    310     @Deprecated
    311     public static final int MEASURED_STATE_MASK = 0xff000000;
    312 
    313     /**
    314      * Bit shift of {@link #MEASURED_STATE_MASK} to get to the height bits
    315      * for functions that combine both width and height into a single int,
    316      * such as {@link #getMeasuredState} and the childState argument of
    317      * {@link #resolveSizeAndState(int, int, int)}.
    318      *
    319      * @deprecated Use {@link View#MEASURED_HEIGHT_STATE_SHIFT} directly.
    320      */
    321     @Deprecated
    322     public static final int MEASURED_HEIGHT_STATE_SHIFT = 16;
    323 
    324     /**
    325      * Bit of {@link #getMeasuredWidthAndState} and
    326      * {@link #getMeasuredWidthAndState} that indicates the measured size
    327      * is smaller that the space the view would like to have.
    328      *
    329      * @deprecated Use {@link View#MEASURED_STATE_TOO_SMALL} directly.
    330      */
    331     @Deprecated
    332     public static final int MEASURED_STATE_TOO_SMALL = 0x01000000;
    333 
    334     /**
    335      * @hide
    336      */
    337     @IntDef(value = {SCROLL_AXIS_NONE, SCROLL_AXIS_HORIZONTAL, SCROLL_AXIS_VERTICAL}, flag = true)
    338     @Retention(RetentionPolicy.SOURCE)
    339     @RestrictTo(LIBRARY_GROUP)
    340     public @interface ScrollAxis {}
    341 
    342     /**
    343      * Indicates no axis of view scrolling.
    344      */
    345     public static final int SCROLL_AXIS_NONE = 0;
    346 
    347     /**
    348      * Indicates scrolling along the horizontal axis.
    349      */
    350     public static final int SCROLL_AXIS_HORIZONTAL = 1 << 0;
    351 
    352     /**
    353      * Indicates scrolling along the vertical axis.
    354      */
    355     public static final int SCROLL_AXIS_VERTICAL = 1 << 1;
    356 
    357     /**
    358      * @hide
    359      */
    360     @IntDef({TYPE_TOUCH, TYPE_NON_TOUCH})
    361     @Retention(RetentionPolicy.SOURCE)
    362     @RestrictTo(LIBRARY_GROUP)
    363     public @interface NestedScrollType {}
    364 
    365     /**
    366      * Indicates that the input type for the gesture is from a user touching the screen.
    367      */
    368     public static final int TYPE_TOUCH = 0;
    369 
    370     /**
    371      * Indicates that the input type for the gesture is caused by something which is not a user
    372      * touching a screen. This is usually from a fling which is settling.
    373      */
    374     public static final int TYPE_NON_TOUCH = 1;
    375 
    376     /** @hide */
    377     @RestrictTo(LIBRARY_GROUP)
    378     @Retention(RetentionPolicy.SOURCE)
    379     @IntDef(flag = true,
    380             value = {
    381                     SCROLL_INDICATOR_TOP,
    382                     SCROLL_INDICATOR_BOTTOM,
    383                     SCROLL_INDICATOR_LEFT,
    384                     SCROLL_INDICATOR_RIGHT,
    385                     SCROLL_INDICATOR_START,
    386                     SCROLL_INDICATOR_END,
    387             })
    388     public @interface ScrollIndicators {}
    389 
    390     /**
    391      * Scroll indicator direction for the top edge of the view.
    392      *
    393      * @see #setScrollIndicators(View, int)
    394      * @see #setScrollIndicators(View, int, int)
    395      * @see #getScrollIndicators(View)
    396      */
    397     public static final int SCROLL_INDICATOR_TOP = 0x1;
    398 
    399     /**
    400      * Scroll indicator direction for the bottom edge of the view.
    401      *
    402      * @see #setScrollIndicators(View, int)
    403      * @see #setScrollIndicators(View, int, int)
    404      * @see #getScrollIndicators(View)
    405      */
    406     public static final int SCROLL_INDICATOR_BOTTOM = 0x2;
    407 
    408     /**
    409      * Scroll indicator direction for the left edge of the view.
    410      *
    411      * @see #setScrollIndicators(View, int)
    412      * @see #setScrollIndicators(View, int, int)
    413      * @see #getScrollIndicators(View)
    414      */
    415     public static final int SCROLL_INDICATOR_LEFT = 0x4;
    416 
    417     /**
    418      * Scroll indicator direction for the right edge of the view.
    419      *
    420      * @see #setScrollIndicators(View, int)
    421      * @see #setScrollIndicators(View, int, int)
    422      * @see #getScrollIndicators(View)
    423      */
    424     public static final int SCROLL_INDICATOR_RIGHT = 0x8;
    425 
    426     /**
    427      * Scroll indicator direction for the starting edge of the view.
    428      *
    429      * @see #setScrollIndicators(View, int)
    430      * @see #setScrollIndicators(View, int, int)
    431      * @see #getScrollIndicators(View)
    432      */
    433     public static final int SCROLL_INDICATOR_START = 0x10;
    434 
    435     /**
    436      * Scroll indicator direction for the ending edge of the view.
    437      *
    438      * @see #setScrollIndicators(View, int)
    439      * @see #setScrollIndicators(View, int, int)
    440      * @see #getScrollIndicators(View)
    441      */
    442     public static final int SCROLL_INDICATOR_END = 0x20;
    443 
    444     private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1);
    445 
    446     private static Field sMinWidthField;
    447     private static boolean sMinWidthFieldFetched;
    448     private static Field sMinHeightField;
    449     private static boolean sMinHeightFieldFetched;
    450 
    451     private static Method sDispatchStartTemporaryDetach;
    452     private static Method sDispatchFinishTemporaryDetach;
    453     private static boolean sTempDetachBound;
    454 
    455     private static WeakHashMap<View, String> sTransitionNameMap;
    456     private static WeakHashMap<View, ViewPropertyAnimatorCompat> sViewPropertyAnimatorMap = null;
    457 
    458     private static Method sChildrenDrawingOrderMethod;
    459     private static Field sAccessibilityDelegateField;
    460     private static boolean sAccessibilityDelegateCheckFailed = false;
    461 
    462     private static ThreadLocal<Rect> sThreadLocalRect;
    463 
    464     private static Rect getEmptyTempRect() {
    465         if (sThreadLocalRect == null) {
    466             sThreadLocalRect = new ThreadLocal<>();
    467         }
    468         Rect rect = sThreadLocalRect.get();
    469         if (rect == null) {
    470             rect = new Rect();
    471             sThreadLocalRect.set(rect);
    472         }
    473         rect.setEmpty();
    474         return rect;
    475     }
    476 
    477     /**
    478      * Check if this view can be scrolled horizontally in a certain direction.
    479      *
    480      * @param view The View against which to invoke the method.
    481      * @param direction Negative to check scrolling left, positive to check scrolling right.
    482      * @return true if this view can be scrolled in the specified direction, false otherwise.
    483      *
    484      * @deprecated Use {@link View#canScrollHorizontally(int)} directly.
    485      */
    486     @Deprecated
    487     public static boolean canScrollHorizontally(View view, int direction) {
    488         return view.canScrollHorizontally(direction);
    489     }
    490 
    491     /**
    492      * Check if this view can be scrolled vertically in a certain direction.
    493      *
    494      * @param view The View against which to invoke the method.
    495      * @param direction Negative to check scrolling up, positive to check scrolling down.
    496      * @return true if this view can be scrolled in the specified direction, false otherwise.
    497      *
    498      * @deprecated Use {@link View#canScrollVertically(int)} directly.
    499      */
    500     @Deprecated
    501     public static boolean canScrollVertically(View view, int direction) {
    502         return view.canScrollVertically(direction);
    503     }
    504 
    505     /**
    506      * Returns the over-scroll mode for this view. The result will be
    507      * one of {@link #OVER_SCROLL_ALWAYS} (default), {@link #OVER_SCROLL_IF_CONTENT_SCROLLS}
    508      * (allow over-scrolling only if the view content is larger than the container),
    509      * or {@link #OVER_SCROLL_NEVER}.
    510      *
    511      * @param v The View against which to invoke the method.
    512      * @return This view's over-scroll mode.
    513      * @deprecated Call {@link View#getOverScrollMode()} directly. This method will be
    514      * removed in a future release.
    515      */
    516     @Deprecated
    517     @OverScroll
    518     public static int getOverScrollMode(View v) {
    519         //noinspection ResourceType
    520         return v.getOverScrollMode();
    521     }
    522 
    523     /**
    524      * Set the over-scroll mode for this view. Valid over-scroll modes are
    525      * {@link #OVER_SCROLL_ALWAYS} (default), {@link #OVER_SCROLL_IF_CONTENT_SCROLLS}
    526      * (allow over-scrolling only if the view content is larger than the container),
    527      * or {@link #OVER_SCROLL_NEVER}.
    528      *
    529      * Setting the over-scroll mode of a view will have an effect only if the
    530      * view is capable of scrolling.
    531      *
    532      * @param v The View against which to invoke the method.
    533      * @param overScrollMode The new over-scroll mode for this view.
    534      * @deprecated Call {@link View#setOverScrollMode(int)} directly. This method will be
    535      * removed in a future release.
    536      */
    537     @Deprecated
    538     public static void setOverScrollMode(View v, @OverScroll int overScrollMode) {
    539         v.setOverScrollMode(overScrollMode);
    540     }
    541 
    542     /**
    543      * Called from {@link View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)}
    544      * giving a chance to this View to populate the accessibility event with its
    545      * text content. While this method is free to modify event
    546      * attributes other than text content, doing so should normally be performed in
    547      * {@link View#onInitializeAccessibilityEvent(AccessibilityEvent)}.
    548      * <p>
    549      * Example: Adding formatted date string to an accessibility event in addition
    550      *          to the text added by the super implementation:
    551      * <pre> public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
    552      *     super.onPopulateAccessibilityEvent(event);
    553      *     final int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_WEEKDAY;
    554      *     String selectedDateUtterance = DateUtils.formatDateTime(mContext,
    555      *         mCurrentDate.getTimeInMillis(), flags);
    556      *     event.getText().add(selectedDateUtterance);
    557      * }</pre>
    558      * <p>
    559      * If an {@link AccessibilityDelegateCompat} has been specified via calling
    560      * {@link ViewCompat#setAccessibilityDelegate(View, AccessibilityDelegateCompat)} its
    561      * {@link AccessibilityDelegateCompat#onPopulateAccessibilityEvent(View, AccessibilityEvent)}
    562      * is responsible for handling this call.
    563      * </p>
    564      * <p class="note"><strong>Note:</strong> Always call the super implementation before adding
    565      * information to the event, in case the default implementation has basic information to add.
    566      * </p>
    567      *
    568      * @param v The View against which to invoke the method.
    569      * @param event The accessibility event which to populate.
    570      *
    571      * @see View#sendAccessibilityEvent(int)
    572      * @see View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)
    573      *
    574      * @deprecated Call {@link View#onPopulateAccessibilityEvent(AccessibilityEvent)} directly.
    575      * This method will be removed in a future release.
    576      */
    577     @Deprecated
    578     public static void onPopulateAccessibilityEvent(View v, AccessibilityEvent event) {
    579         v.onPopulateAccessibilityEvent(event);
    580     }
    581 
    582     /**
    583      * Initializes an {@link AccessibilityEvent} with information about
    584      * this View which is the event source. In other words, the source of
    585      * an accessibility event is the view whose state change triggered firing
    586      * the event.
    587      * <p>
    588      * Example: Setting the password property of an event in addition
    589      *          to properties set by the super implementation:
    590      * <pre> public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
    591      *     super.onInitializeAccessibilityEvent(event);
    592      *     event.setPassword(true);
    593      * }</pre>
    594      * <p>
    595      * If an {@link AccessibilityDelegateCompat} has been specified via calling
    596      * {@link ViewCompat#setAccessibilityDelegate(View, AccessibilityDelegateCompat)}, its
    597      * {@link AccessibilityDelegateCompat#onInitializeAccessibilityEvent(View, AccessibilityEvent)}
    598      * is responsible for handling this call.
    599      *
    600      * @param v The View against which to invoke the method.
    601      * @param event The event to initialize.
    602      *
    603      * @see View#sendAccessibilityEvent(int)
    604      * @see View#dispatchPopulateAccessibilityEvent(AccessibilityEvent)
    605      *
    606      * @deprecated Call {@link View#onInitializeAccessibilityEvent(AccessibilityEvent)} directly.
    607      * This method will be removed in a future release.
    608      */
    609     @Deprecated
    610     public static void onInitializeAccessibilityEvent(View v, AccessibilityEvent event) {
    611         v.onInitializeAccessibilityEvent(event);
    612     }
    613 
    614     /**
    615      * Initializes an {@link AccessibilityNodeInfoCompat} with information
    616      * about this view. The base implementation sets:
    617      * <ul>
    618      * <li>{@link AccessibilityNodeInfoCompat#setParent(View)},</li>
    619      * <li>{@link AccessibilityNodeInfoCompat#setBoundsInParent(Rect)},</li>
    620      * <li>{@link AccessibilityNodeInfoCompat#setBoundsInScreen(Rect)},</li>
    621      * <li>{@link AccessibilityNodeInfoCompat#setPackageName(CharSequence)},</li>
    622      * <li>{@link AccessibilityNodeInfoCompat#setClassName(CharSequence)},</li>
    623      * <li>{@link AccessibilityNodeInfoCompat#setContentDescription(CharSequence)},</li>
    624      * <li>{@link AccessibilityNodeInfoCompat#setEnabled(boolean)},</li>
    625      * <li>{@link AccessibilityNodeInfoCompat#setClickable(boolean)},</li>
    626      * <li>{@link AccessibilityNodeInfoCompat#setFocusable(boolean)},</li>
    627      * <li>{@link AccessibilityNodeInfoCompat#setFocused(boolean)},</li>
    628      * <li>{@link AccessibilityNodeInfoCompat#setLongClickable(boolean)},</li>
    629      * <li>{@link AccessibilityNodeInfoCompat#setSelected(boolean)},</li>
    630      * </ul>
    631      * <p>
    632      * If an {@link AccessibilityDelegateCompat} has been specified via calling
    633      * {@link ViewCompat#setAccessibilityDelegate(View, AccessibilityDelegateCompat)}, its
    634      * {@link AccessibilityDelegateCompat#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfoCompat)}
    635      * method is responsible for handling this call.
    636      *
    637      * @param v The View against which to invoke the method.
    638      * @param info The instance to initialize.
    639      */
    640     public static void onInitializeAccessibilityNodeInfo(@NonNull View v,
    641             AccessibilityNodeInfoCompat info) {
    642         v.onInitializeAccessibilityNodeInfo(info.unwrap());
    643     }
    644 
    645     /**
    646      * Sets a delegate for implementing accessibility support via composition
    647      * (as opposed to inheritance). For more details, see
    648      * {@link AccessibilityDelegateCompat}.
    649      * <p>
    650      * <strong>Note:</strong> On platform versions prior to
    651      * {@link android.os.Build.VERSION_CODES#M API 23}, delegate methods on
    652      * views in the {@code android.widget.*} package are called <i>before</i>
    653      * host methods. This prevents certain properties such as class name from
    654      * being modified by overriding
    655      * {@link AccessibilityDelegateCompat#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfoCompat)},
    656      * as any changes will be overwritten by the host class.
    657      * <p>
    658      * Starting in {@link android.os.Build.VERSION_CODES#M API 23}, delegate
    659      * methods are called <i>after</i> host methods, which all properties to be
    660      * modified without being overwritten by the host class.
    661      *
    662      * @param delegate the object to which accessibility method calls should be
    663      *                 delegated
    664      * @see AccessibilityDelegateCompat
    665      */
    666     public static void setAccessibilityDelegate(@NonNull View v,
    667             AccessibilityDelegateCompat delegate) {
    668         v.setAccessibilityDelegate(delegate == null ? null : delegate.getBridge());
    669     }
    670 
    671     /**
    672      * Sets the hints that help an {@link android.service.autofill.AutofillService} determine how
    673      * to autofill the view with the user's data.
    674      *
    675      * <p>Typically, there is only one way to autofill a view, but there could be more than one.
    676      * For example, if the application accepts either an username or email address to identify
    677      * an user.
    678      *
    679      * <p>These hints are not validated by the Android System, but passed "as is" to the service.
    680      * Hence, they can have any value, but it's recommended to use the {@code AUTOFILL_HINT_}
    681      * constants such as:
    682      * {@link View#AUTOFILL_HINT_USERNAME}, {@link View#AUTOFILL_HINT_PASSWORD},
    683      * {@link View#AUTOFILL_HINT_EMAIL_ADDRESS},
    684      * {@link View#AUTOFILL_HINT_NAME},
    685      * {@link View#AUTOFILL_HINT_PHONE},
    686      * {@link View#AUTOFILL_HINT_POSTAL_ADDRESS}, {@link View#AUTOFILL_HINT_POSTAL_CODE},
    687      * {@link View#AUTOFILL_HINT_CREDIT_CARD_NUMBER},
    688      * {@link View#AUTOFILL_HINT_CREDIT_CARD_SECURITY_CODE},
    689      * {@link View#AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DATE},
    690      * {@link View#AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_DAY},
    691      * {@link View#AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_MONTH} or
    692      * {@link View#AUTOFILL_HINT_CREDIT_CARD_EXPIRATION_YEAR}.
    693      *
    694      * <p>This method is only supported on API >= 26.
    695      * On API 25 and below, it is a no-op</p>
    696      *
    697      * @param autofillHints The autofill hints to set. If the array is emtpy, {@code null} is set.
    698      * @attr ref android.R.styleable#View_autofillHints
    699      */
    700     public static void setAutofillHints(@NonNull View v, @Nullable String... autofillHints) {
    701         if (Build.VERSION.SDK_INT >= 26) {
    702             v.setAutofillHints(autofillHints);
    703         }
    704     }
    705 
    706     /**
    707      * Gets the mode for determining whether this view is important for autofill.
    708      *
    709      * <p>See {@link #setImportantForAutofill(View, int)} and {@link #isImportantForAutofill(View)}
    710      * for more info about this mode.
    711      *
    712      * <p>This method is only supported on API >= 26.
    713      * On API 25 and below, it will always return {@link View#IMPORTANT_FOR_AUTOFILL_AUTO}.</p>
    714      *
    715      * @return {@link View#IMPORTANT_FOR_AUTOFILL_AUTO} by default, or value passed to
    716      * {@link #setImportantForAutofill(View, int)}.
    717      *
    718      * @attr ref android.R.styleable#View_importantForAutofill
    719      */
    720     @SuppressLint("InlinedApi")
    721     public static @AutofillImportance int getImportantForAutofill(@NonNull View v) {
    722         if (Build.VERSION.SDK_INT >= 26) {
    723             return v.getImportantForAutofill();
    724         }
    725         return View.IMPORTANT_FOR_AUTOFILL_AUTO;
    726     }
    727 
    728     /**
    729      * Sets the mode for determining whether this view is considered important for autofill.
    730      *
    731      * <p>The platform determines the importance for autofill automatically but you
    732      * can use this method to customize the behavior. For example:
    733      *
    734      * <ol>
    735      *   <li>When the view contents is irrelevant for autofill (for example, a text field used in a
    736      *       "Captcha" challenge), it should be {@link View#IMPORTANT_FOR_AUTOFILL_NO}.
    737      *   <li>When both the view and its children are irrelevant for autofill (for example, the root
    738      *       view of an activity containing a spreadhseet editor), it should be
    739      *       {@link View#IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS}.
    740      *   <li>When the view content is relevant for autofill but its children aren't (for example,
    741      *       a credit card expiration date represented by a custom view that overrides the proper
    742      *       autofill methods and has 2 children representing the month and year), it should
    743      *       be {@link View#IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS}.
    744      * </ol>
    745      *
    746      * <p><b>NOTE:</strong> setting the mode as does {@link View#IMPORTANT_FOR_AUTOFILL_NO} or
    747      * {@link View#IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS} does not guarantee the view (and
    748      * its children) will be always be considered not important; for example, when the user
    749      * explicitly makes an autofill request, all views are considered important. See
    750      * {@link #isImportantForAutofill(View)} for more details about how the View's importance for
    751      * autofill is used.
    752      *
    753      * <p>This method is only supported on API >= 26.
    754      * On API 25 and below, it is a no-op</p>
    755      *
    756      *
    757      * @param mode {@link View#IMPORTANT_FOR_AUTOFILL_AUTO},
    758      * {@link View#IMPORTANT_FOR_AUTOFILL_YES},
    759      * {@link View#IMPORTANT_FOR_AUTOFILL_NO},
    760      * {@link View#IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS},
    761      * or {@link View#IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS}.
    762      *
    763      * @attr ref android.R.styleable#View_importantForAutofill
    764      */
    765     public static void setImportantForAutofill(@NonNull View v, @AutofillImportance int mode) {
    766         if (Build.VERSION.SDK_INT >= 26) {
    767             v.setImportantForAutofill(mode);
    768         }
    769     }
    770 
    771     /**
    772      * Hints the Android System whether the {@link android.app.assist.AssistStructure.ViewNode}
    773      * associated with this view is considered important for autofill purposes.
    774      *
    775      * <p>Generally speaking, a view is important for autofill if:
    776      * <ol>
    777      * <li>The view can be autofilled by an {@link android.service.autofill.AutofillService}.
    778      * <li>The view contents can help an {@link android.service.autofill.AutofillService}
    779      *     determine how other views can be autofilled.
    780      * <ol>
    781      *
    782      * <p>For example, view containers should typically return {@code false} for performance reasons
    783      * (since the important info is provided by their children), but if its properties have relevant
    784      * information (for example, a resource id called {@code credentials}, it should return
    785      * {@code true}. On the other hand, views representing labels or editable fields should
    786      * typically return {@code true}, but in some cases they could return {@code false}
    787      * (for example, if they're part of a "Captcha" mechanism).
    788      *
    789      * <p>The value returned by this method depends on the value returned by
    790      * {@link #getImportantForAutofill(View)}:
    791      *
    792      * <ol>
    793      *   <li>if it returns {@link View#IMPORTANT_FOR_AUTOFILL_YES} or
    794      *       {@link View#IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS},
    795      *       then it returns {@code true}
    796      *   <li>if it returns {@link View#IMPORTANT_FOR_AUTOFILL_NO} or
    797      *       {@link View#IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS},
    798      *       then it returns {@code false}
    799      *   <li>if it returns {@link View#IMPORTANT_FOR_AUTOFILL_AUTO},
    800      *   then it uses some simple heuristics that can return {@code true}
    801      *   in some cases (like a container with a resource id), but {@code false} in most.
    802      *   <li>otherwise, it returns {@code false}.
    803      * </ol>
    804      *
    805      * <p>When a view is considered important for autofill:
    806      * <ul>
    807      *   <li>The view might automatically trigger an autofill request when focused on.
    808      *   <li>The contents of the view are included in the {@link android.view.ViewStructure}
    809      *   used in an autofill request.
    810      * </ul>
    811      *
    812      * <p>On the other hand, when a view is considered not important for autofill:
    813      * <ul>
    814      *   <li>The view never automatically triggers autofill requests, but it can trigger a manual
    815      *       request through {@link android.view.autofill.AutofillManager#requestAutofill(View)}.
    816      *   <li>The contents of the view are not included in the {@link android.view.ViewStructure}
    817      *   used in an autofill request, unless the request has the
    818      *       {@link View#AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS} flag.
    819      * </ul>
    820      *
    821      * <p>This method is only supported on API >= 26.
    822      * On API 25 and below, it will always return {@code true}.</p>
    823      *
    824      * @return whether the view is considered important for autofill.
    825      *
    826      * @see #setImportantForAutofill(View, int)
    827      * @see View#IMPORTANT_FOR_AUTOFILL_AUTO
    828      * @see View#IMPORTANT_FOR_AUTOFILL_YES
    829      * @see View#IMPORTANT_FOR_AUTOFILL_NO
    830      * @see View#IMPORTANT_FOR_AUTOFILL_YES_EXCLUDE_DESCENDANTS
    831      * @see View#IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS
    832      * @see android.view.autofill.AutofillManager#requestAutofill(View)
    833      */
    834     public static boolean isImportantForAutofill(@NonNull View v) {
    835         if (Build.VERSION.SDK_INT >= 26) {
    836             return v.isImportantForAutofill();
    837         }
    838         return true;
    839     }
    840 
    841     /**
    842      * Checks whether provided View has an accessibility delegate attached to it.
    843      *
    844      * @param v The View instance to check
    845      * @return True if the View has an accessibility delegate
    846      */
    847     public static boolean hasAccessibilityDelegate(@NonNull View v) {
    848         if (sAccessibilityDelegateCheckFailed) {
    849             return false; // View implementation might have changed.
    850         }
    851         if (sAccessibilityDelegateField == null) {
    852             try {
    853                 sAccessibilityDelegateField = View.class
    854                         .getDeclaredField("mAccessibilityDelegate");
    855                 sAccessibilityDelegateField.setAccessible(true);
    856             } catch (Throwable t) {
    857                 sAccessibilityDelegateCheckFailed = true;
    858                 return false;
    859             }
    860         }
    861         try {
    862             return sAccessibilityDelegateField.get(v) != null;
    863         } catch (Throwable t) {
    864             sAccessibilityDelegateCheckFailed = true;
    865             return false;
    866         }
    867     }
    868 
    869     /**
    870      * Indicates whether the view is currently tracking transient state that the
    871      * app should not need to concern itself with saving and restoring, but that
    872      * the framework should take special note to preserve when possible.
    873      *
    874      * @param view View to check for transient state
    875      * @return true if the view has transient state
    876      */
    877     public static boolean hasTransientState(@NonNull View view) {
    878         if (Build.VERSION.SDK_INT >= 16) {
    879             return view.hasTransientState();
    880         }
    881         return false;
    882     }
    883 
    884     /**
    885      * Set whether this view is currently tracking transient state that the
    886      * framework should attempt to preserve when possible.
    887      *
    888      * @param view View tracking transient state
    889      * @param hasTransientState true if this view has transient state
    890      */
    891     public static void setHasTransientState(@NonNull View view, boolean hasTransientState) {
    892         if (Build.VERSION.SDK_INT >= 16) {
    893             view.setHasTransientState(hasTransientState);
    894         }
    895     }
    896 
    897     /**
    898      * <p>Cause an invalidate to happen on the next animation time step, typically the
    899      * next display frame.</p>
    900      *
    901      * <p>This method can be invoked from outside of the UI thread
    902      * only when this View is attached to a window.</p>
    903      *
    904      * @param view View to invalidate
    905      */
    906     public static void postInvalidateOnAnimation(@NonNull View view) {
    907         if (Build.VERSION.SDK_INT >= 16) {
    908             view.postInvalidateOnAnimation();
    909         } else {
    910             view.postInvalidate();
    911         }
    912     }
    913 
    914     /**
    915      * <p>Cause an invalidate of the specified area to happen on the next animation
    916      * time step, typically the next display frame.</p>
    917      *
    918      * <p>This method can be invoked from outside of the UI thread
    919      * only when this View is attached to a window.</p>
    920      *
    921      * @param view View to invalidate
    922      * @param left The left coordinate of the rectangle to invalidate.
    923      * @param top The top coordinate of the rectangle to invalidate.
    924      * @param right The right coordinate of the rectangle to invalidate.
    925      * @param bottom The bottom coordinate of the rectangle to invalidate.
    926      */
    927     public static void postInvalidateOnAnimation(@NonNull View view, int left, int top,
    928             int right, int bottom) {
    929         if (Build.VERSION.SDK_INT >= 16) {
    930             view.postInvalidateOnAnimation(left, top, right, bottom);
    931         } else {
    932             view.postInvalidate(left, top, right, bottom);
    933         }
    934     }
    935 
    936     /**
    937      * <p>Causes the Runnable to execute on the next animation time step.
    938      * The runnable will be run on the user interface thread.</p>
    939      *
    940      * <p>This method can be invoked from outside of the UI thread
    941      * only when this View is attached to a window.</p>
    942      *
    943      * @param view View to post this Runnable to
    944      * @param action The Runnable that will be executed.
    945      */
    946     public static void postOnAnimation(@NonNull View view, Runnable action) {
    947         if (Build.VERSION.SDK_INT >= 16) {
    948             view.postOnAnimation(action);
    949         } else {
    950             view.postDelayed(action, ValueAnimator.getFrameDelay());
    951         }
    952     }
    953 
    954     /**
    955      * <p>Causes the Runnable to execute on the next animation time step,
    956      * after the specified amount of time elapses.
    957      * The runnable will be run on the user interface thread.</p>
    958      *
    959      * <p>This method can be invoked from outside of the UI thread
    960      * only when this View is attached to a window.</p>
    961      *
    962      * @param view The view to post this Runnable to
    963      * @param action The Runnable that will be executed.
    964      * @param delayMillis The delay (in milliseconds) until the Runnable
    965      *        will be executed.
    966      */
    967     public static void postOnAnimationDelayed(@NonNull View view, Runnable action,
    968             long delayMillis) {
    969         if (Build.VERSION.SDK_INT >= 16) {
    970             view.postOnAnimationDelayed(action, delayMillis);
    971         } else {
    972             view.postDelayed(action, ValueAnimator.getFrameDelay() + delayMillis);
    973         }
    974     }
    975 
    976     /**
    977      * Gets the mode for determining whether this View is important for accessibility
    978      * which is if it fires accessibility events and if it is reported to
    979      * accessibility services that query the screen.
    980      *
    981      * @param view The view whose property to get.
    982      * @return The mode for determining whether a View is important for accessibility.
    983      *
    984      * @see #IMPORTANT_FOR_ACCESSIBILITY_YES
    985      * @see #IMPORTANT_FOR_ACCESSIBILITY_NO
    986      * @see #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
    987      * @see #IMPORTANT_FOR_ACCESSIBILITY_AUTO
    988      */
    989     @ImportantForAccessibility
    990     public static int getImportantForAccessibility(@NonNull View view) {
    991         if (Build.VERSION.SDK_INT >= 16) {
    992             return view.getImportantForAccessibility();
    993         }
    994         return IMPORTANT_FOR_ACCESSIBILITY_AUTO;
    995     }
    996 
    997     /**
    998      * Sets how to determine whether this view is important for accessibility
    999      * which is if it fires accessibility events and if it is reported to
   1000      * accessibility services that query the screen.
   1001      * <p>
   1002      * <em>Note:</em> If the current platform version does not support the
   1003      *  {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS} mode, then
   1004      *  {@link #IMPORTANT_FOR_ACCESSIBILITY_NO} will be used as it is the
   1005      *  closest terms of semantics.
   1006      * </p>
   1007      *
   1008      * @param view The view whose property to set.
   1009      * @param mode How to determine whether this view is important for accessibility.
   1010      *
   1011      * @see #IMPORTANT_FOR_ACCESSIBILITY_YES
   1012      * @see #IMPORTANT_FOR_ACCESSIBILITY_NO
   1013      * @see #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
   1014      * @see #IMPORTANT_FOR_ACCESSIBILITY_AUTO
   1015      */
   1016     public static void setImportantForAccessibility(@NonNull View view,
   1017             @ImportantForAccessibility int mode) {
   1018         if (Build.VERSION.SDK_INT >= 19) {
   1019             view.setImportantForAccessibility(mode);
   1020         } else if (Build.VERSION.SDK_INT >= 16) {
   1021             // IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS is not available
   1022             // on this platform so replace with IMPORTANT_FOR_ACCESSIBILITY_NO
   1023             // which is closer semantically.
   1024             if (mode == IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS) {
   1025                 mode = IMPORTANT_FOR_ACCESSIBILITY_NO;
   1026             }
   1027             //noinspection WrongConstant
   1028             view.setImportantForAccessibility(mode);
   1029         }
   1030     }
   1031 
   1032     /**
   1033      * Computes whether this view should be exposed for accessibility. In
   1034      * general, views that are interactive or provide information are exposed
   1035      * while views that serve only as containers are hidden.
   1036      * <p>
   1037      * If an ancestor of this view has importance
   1038      * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}, this method
   1039      * returns <code>false</code>.
   1040      * <p>
   1041      * Otherwise, the value is computed according to the view's
   1042      * {@link #getImportantForAccessibility(View)} value:
   1043      * <ol>
   1044      * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_NO} or
   1045      * {@link #IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS}, return <code>false
   1046      * </code>
   1047      * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_YES}, return <code>true</code>
   1048      * <li>{@link #IMPORTANT_FOR_ACCESSIBILITY_AUTO}, return <code>true</code> if
   1049      * view satisfies any of the following:
   1050      * <ul>
   1051      * <li>Is actionable, e.g. {@link View#isClickable()},
   1052      * {@link View#isLongClickable()}, or {@link View#isFocusable()}
   1053      * <li>Has an {@link AccessibilityDelegateCompat}
   1054      * <li>Has an interaction listener, e.g. {@link View.OnTouchListener},
   1055      * {@link View.OnKeyListener}, etc.
   1056      * <li>Is an accessibility live region, e.g.
   1057      * {@link #getAccessibilityLiveRegion(View)} is not
   1058      * {@link #ACCESSIBILITY_LIVE_REGION_NONE}.
   1059      * </ul>
   1060      * </ol>
   1061      * <p>
   1062      * <em>Note:</em> Prior to API 21, this method will always return {@code true}.
   1063      *
   1064      * @return Whether the view is exposed for accessibility.
   1065      * @see #setImportantForAccessibility(View, int)
   1066      * @see #getImportantForAccessibility(View)
   1067      */
   1068     public static boolean isImportantForAccessibility(@NonNull View view) {
   1069         if (Build.VERSION.SDK_INT >= 21) {
   1070             return view.isImportantForAccessibility();
   1071         }
   1072         return true;
   1073     }
   1074 
   1075     /**
   1076      * Performs the specified accessibility action on the view. For
   1077      * possible accessibility actions look at {@link AccessibilityNodeInfoCompat}.
   1078      * <p>
   1079      * If an {@link AccessibilityDelegateCompat} has been specified via calling
   1080      * {@link #setAccessibilityDelegate(View, AccessibilityDelegateCompat)} its
   1081      * {@link AccessibilityDelegateCompat#performAccessibilityAction(View, int, Bundle)}
   1082      * is responsible for handling this call.
   1083      * </p>
   1084      *
   1085      * @param action The action to perform.
   1086      * @param arguments Optional action arguments.
   1087      * @return Whether the action was performed.
   1088      */
   1089     public static boolean performAccessibilityAction(@NonNull View view, int action,
   1090             Bundle arguments) {
   1091         if (Build.VERSION.SDK_INT >= 16) {
   1092             return view.performAccessibilityAction(action, arguments);
   1093         }
   1094         return false;
   1095     }
   1096 
   1097     /**
   1098      * Gets the provider for managing a virtual view hierarchy rooted at this View
   1099      * and reported to {@link android.accessibilityservice.AccessibilityService}s
   1100      * that explore the window content.
   1101      * <p>
   1102      * If this method returns an instance, this instance is responsible for managing
   1103      * {@link AccessibilityNodeInfoCompat}s describing the virtual sub-tree rooted at
   1104      * this View including the one representing the View itself. Similarly the returned
   1105      * instance is responsible for performing accessibility actions on any virtual
   1106      * view or the root view itself.
   1107      * </p>
   1108      * <p>
   1109      * If an {@link AccessibilityDelegateCompat} has been specified via calling
   1110      * {@link #setAccessibilityDelegate(View, AccessibilityDelegateCompat)} its
   1111      * {@link AccessibilityDelegateCompat#getAccessibilityNodeProvider(View)}
   1112      * is responsible for handling this call.
   1113      * </p>
   1114      *
   1115      * @param view The view whose property to get.
   1116      * @return The provider.
   1117      *
   1118      * @see AccessibilityNodeProviderCompat
   1119      */
   1120     public static AccessibilityNodeProviderCompat getAccessibilityNodeProvider(@NonNull View view) {
   1121         if (Build.VERSION.SDK_INT >= 16) {
   1122             AccessibilityNodeProvider provider = view.getAccessibilityNodeProvider();
   1123             if (provider != null) {
   1124                 return new AccessibilityNodeProviderCompat(provider);
   1125             }
   1126         }
   1127         return null;
   1128     }
   1129 
   1130     /**
   1131      * The opacity of the view. This is a value from 0 to 1, where 0 means the view is
   1132      * completely transparent and 1 means the view is completely opaque.
   1133      *
   1134      * <p>By default this is 1.0f.
   1135      * @return The opacity of the view.
   1136      *
   1137      * @deprecated Use {@link View#getAlpha()} directly.
   1138      */
   1139     @Deprecated
   1140     public static float getAlpha(View view) {
   1141         return view.getAlpha();
   1142     }
   1143 
   1144     /**
   1145      * <p>Specifies the type of layer backing this view. The layer can be
   1146      * {@link View#LAYER_TYPE_NONE disabled}, {@link View#LAYER_TYPE_SOFTWARE software} or
   1147      * {@link View#LAYER_TYPE_HARDWARE hardware}.</p>
   1148      *
   1149      * <p>A layer is associated with an optional {@link android.graphics.Paint}
   1150      * instance that controls how the layer is composed on screen. The following
   1151      * properties of the paint are taken into account when composing the layer:</p>
   1152      * <ul>
   1153      * <li>{@link android.graphics.Paint#getAlpha() Translucency (alpha)}</li>
   1154      * <li>{@link android.graphics.Paint#getXfermode() Blending mode}</li>
   1155      * <li>{@link android.graphics.Paint#getColorFilter() Color filter}</li>
   1156      * </ul>
   1157      *
   1158      * <p>If this view has an alpha value set to < 1.0 by calling
   1159      * setAlpha(float), the alpha value of the layer's paint is replaced by
   1160      * this view's alpha value. Calling setAlpha(float) is therefore
   1161      * equivalent to setting a hardware layer on this view and providing a paint with
   1162      * the desired alpha value.<p>
   1163      *
   1164      * <p>Refer to the documentation of {@link View#LAYER_TYPE_NONE disabled},
   1165      * {@link View#LAYER_TYPE_SOFTWARE software} and {@link View#LAYER_TYPE_HARDWARE hardware}
   1166      * for more information on when and how to use layers.</p>
   1167      *
   1168      * @param view View to set the layer type for
   1169      * @param layerType The type of layer to use with this view, must be one of
   1170      *        {@link View#LAYER_TYPE_NONE}, {@link View#LAYER_TYPE_SOFTWARE} or
   1171      *        {@link View#LAYER_TYPE_HARDWARE}
   1172      * @param paint The paint used to compose the layer. This argument is optional
   1173      *        and can be null. It is ignored when the layer type is
   1174      *        {@link View#LAYER_TYPE_NONE}
   1175      *
   1176      * @deprecated Use {@link View#setLayerType(int, Paint)} directly.
   1177      */
   1178     @Deprecated
   1179     public static void setLayerType(View view, @LayerType int layerType, Paint paint) {
   1180         view.setLayerType(layerType, paint);
   1181     }
   1182 
   1183     /**
   1184      * Indicates what type of layer is currently associated with this view. By default
   1185      * a view does not have a layer, and the layer type is {@link View#LAYER_TYPE_NONE}.
   1186      * Refer to the documentation of
   1187      * {@link #setLayerType(android.view.View, int, android.graphics.Paint)}
   1188      * for more information on the different types of layers.
   1189      *
   1190      * @param view The view to fetch the layer type from
   1191      * @return {@link View#LAYER_TYPE_NONE}, {@link View#LAYER_TYPE_SOFTWARE} or
   1192      *         {@link View#LAYER_TYPE_HARDWARE}
   1193      *
   1194      * @see #setLayerType(android.view.View, int, android.graphics.Paint)
   1195      * @see View#LAYER_TYPE_NONE
   1196      * @see View#LAYER_TYPE_SOFTWARE
   1197      * @see View#LAYER_TYPE_HARDWARE
   1198      *
   1199      * @deprecated Use {@link View#getLayerType()} directly.
   1200      */
   1201     @Deprecated
   1202     @LayerType
   1203     public static int getLayerType(View view) {
   1204         //noinspection ResourceType
   1205         return view.getLayerType();
   1206     }
   1207 
   1208     /**
   1209      * Gets the id of a view for which a given view serves as a label for
   1210      * accessibility purposes.
   1211      *
   1212      * @param view The view on which to invoke the corresponding method.
   1213      * @return The labeled view id.
   1214      */
   1215     public static int getLabelFor(@NonNull View view) {
   1216         if (Build.VERSION.SDK_INT >= 17) {
   1217             return view.getLabelFor();
   1218         }
   1219         return 0;
   1220     }
   1221 
   1222     /**
   1223      * Sets the id of a view for which a given view serves as a label for
   1224      * accessibility purposes.
   1225      *
   1226      * @param view The view on which to invoke the corresponding method.
   1227      * @param labeledId The labeled view id.
   1228      */
   1229     public static void setLabelFor(@NonNull View view, @IdRes int labeledId) {
   1230         if (Build.VERSION.SDK_INT >= 17) {
   1231             view.setLabelFor(labeledId);
   1232         }
   1233     }
   1234 
   1235     /**
   1236      * Updates the {@link Paint} object used with the current layer (used only if the current
   1237      * layer type is not set to {@link View#LAYER_TYPE_NONE}). Changed properties of the Paint
   1238      * provided to {@link #setLayerType(android.view.View, int, android.graphics.Paint)}
   1239      * will be used the next time the View is redrawn, but
   1240      * {@link #setLayerPaint(android.view.View, android.graphics.Paint)}
   1241      * must be called to ensure that the view gets redrawn immediately.
   1242      *
   1243      * <p>A layer is associated with an optional {@link android.graphics.Paint}
   1244      * instance that controls how the layer is composed on screen. The following
   1245      * properties of the paint are taken into account when composing the layer:</p>
   1246      * <ul>
   1247      * <li>{@link android.graphics.Paint#getAlpha() Translucency (alpha)}</li>
   1248      * <li>{@link android.graphics.Paint#getXfermode() Blending mode}</li>
   1249      * <li>{@link android.graphics.Paint#getColorFilter() Color filter}</li>
   1250      * </ul>
   1251      *
   1252      * <p>If this view has an alpha value set to < 1.0 by calling
   1253      * View#setAlpha(float), the alpha value of the layer's paint is replaced by
   1254      * this view's alpha value. Calling View#setAlpha(float) is therefore
   1255      * equivalent to setting a hardware layer on this view and providing a paint with
   1256      * the desired alpha value.</p>
   1257      *
   1258      * @param view View to set a layer paint for
   1259      * @param paint The paint used to compose the layer. This argument is optional
   1260      *        and can be null. It is ignored when the layer type is
   1261      *        {@link View#LAYER_TYPE_NONE}
   1262      *
   1263      * @see #setLayerType(View, int, android.graphics.Paint)
   1264      */
   1265     public static void setLayerPaint(@NonNull View view, Paint paint) {
   1266         if (Build.VERSION.SDK_INT >= 17) {
   1267             view.setLayerPaint(paint);
   1268         } else {
   1269             // Make sure the paint is correct; this will be cheap if it's the same
   1270             // instance as was used to call setLayerType earlier.
   1271             view.setLayerType(view.getLayerType(), paint);
   1272             // This is expensive, but the only way to accomplish this before JB-MR1.
   1273             view.invalidate();
   1274         }
   1275     }
   1276 
   1277     /**
   1278      * Returns the resolved layout direction for this view.
   1279      *
   1280      * @param view View to get layout direction for
   1281      * @return {@link #LAYOUT_DIRECTION_RTL} if the layout direction is RTL or returns
   1282      * {@link #LAYOUT_DIRECTION_LTR} if the layout direction is not RTL.
   1283      *
   1284      * For compatibility, this will return {@link #LAYOUT_DIRECTION_LTR} if API version
   1285      * is lower than Jellybean MR1 (API 17)
   1286      */
   1287     @ResolvedLayoutDirectionMode
   1288     public static int getLayoutDirection(@NonNull View view) {
   1289         if (Build.VERSION.SDK_INT >= 17) {
   1290             return view.getLayoutDirection();
   1291         }
   1292         return LAYOUT_DIRECTION_LTR;
   1293     }
   1294 
   1295     /**
   1296      * Set the layout direction for this view. This will propagate a reset of layout direction
   1297      * resolution to the view's children and resolve layout direction for this view.
   1298      *
   1299      * @param view View to set layout direction for
   1300      * @param layoutDirection the layout direction to set. Should be one of:
   1301      *
   1302      * {@link #LAYOUT_DIRECTION_LTR},
   1303      * {@link #LAYOUT_DIRECTION_RTL},
   1304      * {@link #LAYOUT_DIRECTION_INHERIT},
   1305      * {@link #LAYOUT_DIRECTION_LOCALE}.
   1306      *
   1307      * Resolution will be done if the value is set to LAYOUT_DIRECTION_INHERIT. The resolution
   1308      * proceeds up the parent chain of the view to get the value. If there is no parent, then it
   1309      * will return the default {@link #LAYOUT_DIRECTION_LTR}.
   1310      */
   1311     public static void setLayoutDirection(@NonNull View view,
   1312             @LayoutDirectionMode int layoutDirection) {
   1313         if (Build.VERSION.SDK_INT >= 17) {
   1314             view.setLayoutDirection(layoutDirection);
   1315         }
   1316     }
   1317 
   1318     /**
   1319      * Gets the parent for accessibility purposes. Note that the parent for
   1320      * accessibility is not necessary the immediate parent. It is the first
   1321      * predecessor that is important for accessibility.
   1322      *
   1323      * @param view View to retrieve parent for
   1324      * @return The parent for use in accessibility inspection
   1325      */
   1326     public static ViewParent getParentForAccessibility(@NonNull View view) {
   1327         if (Build.VERSION.SDK_INT >= 16) {
   1328             return view.getParentForAccessibility();
   1329         }
   1330         return view.getParent();
   1331     }
   1332 
   1333     /**
   1334      * Finds the first descendant view with the given ID, the view itself if the ID matches
   1335      * {@link View#getId()}, or throws an IllegalArgumentException if the ID is invalid or there
   1336      * is no matching view in the hierarchy.
   1337      * <p>
   1338      * <strong>Note:</strong> In most cases -- depending on compiler support --
   1339      * the resulting view is automatically cast to the target class type. If
   1340      * the target class type is unconstrained, an explicit cast may be
   1341      * necessary.
   1342      *
   1343      * @param id the ID to search for
   1344      * @return a view with given ID
   1345      * @see View#findViewById(int)
   1346      */
   1347     @SuppressWarnings("TypeParameterUnusedInFormals")
   1348     @NonNull
   1349     public static <T extends View> T requireViewById(@NonNull View view, @IdRes int id) {
   1350         // TODO: use and link to View#requireViewById() directly, once available
   1351         T targetView = view.findViewById(id);
   1352         if (targetView == null) {
   1353             throw new IllegalArgumentException("ID does not reference a View inside this View");
   1354         }
   1355         return targetView;
   1356     }
   1357 
   1358     /**
   1359      * Indicates whether this View is opaque. An opaque View guarantees that it will
   1360      * draw all the pixels overlapping its bounds using a fully opaque color.
   1361      *
   1362      * @return True if this View is guaranteed to be fully opaque, false otherwise.
   1363      * @deprecated Use {@link View#isOpaque()} directly. This method will be
   1364      * removed in a future release.
   1365      */
   1366     @Deprecated
   1367     public static boolean isOpaque(View view) {
   1368         return view.isOpaque();
   1369     }
   1370 
   1371     /**
   1372      * Utility to reconcile a desired size and state, with constraints imposed
   1373      * by a MeasureSpec.  Will take the desired size, unless a different size
   1374      * is imposed by the constraints.  The returned value is a compound integer,
   1375      * with the resolved size in the {@link #MEASURED_SIZE_MASK} bits and
   1376      * optionally the bit {@link #MEASURED_STATE_TOO_SMALL} set if the resulting
   1377      * size is smaller than the size the view wants to be.
   1378      *
   1379      * @param size How big the view wants to be
   1380      * @param measureSpec Constraints imposed by the parent
   1381      * @return Size information bit mask as defined by
   1382      * {@link #MEASURED_SIZE_MASK} and {@link #MEASURED_STATE_TOO_SMALL}.
   1383      *
   1384      * @deprecated Use {@link View#resolveSizeAndState(int, int, int)} directly.
   1385      */
   1386     @Deprecated
   1387     public static int resolveSizeAndState(int size, int measureSpec, int childMeasuredState) {
   1388         return View.resolveSizeAndState(size, measureSpec, childMeasuredState);
   1389     }
   1390 
   1391     /**
   1392      * Return the full width measurement information for this view as computed
   1393      * by the most recent call to {@link android.view.View#measure(int, int)}.
   1394      * This result is a bit mask as defined by {@link #MEASURED_SIZE_MASK} and
   1395      * {@link #MEASURED_STATE_TOO_SMALL}.
   1396      * This should be used during measurement and layout calculations only. Use
   1397      * {@link android.view.View#getWidth()} to see how wide a view is after layout.
   1398      *
   1399      * @return The measured width of this view as a bit mask.
   1400      *
   1401      * @deprecated Use {@link View#getMeasuredWidth()} directly.
   1402      */
   1403     @Deprecated
   1404     public static int getMeasuredWidthAndState(View view) {
   1405         return view.getMeasuredWidthAndState();
   1406     }
   1407 
   1408     /**
   1409      * Return the full height measurement information for this view as computed
   1410      * by the most recent call to {@link android.view.View#measure(int, int)}.
   1411      * This result is a bit mask as defined by {@link #MEASURED_SIZE_MASK} and
   1412      * {@link #MEASURED_STATE_TOO_SMALL}.
   1413      * This should be used during measurement and layout calculations only. Use
   1414      * {@link android.view.View#getHeight()} to see how wide a view is after layout.
   1415      *
   1416      * @return The measured width of this view as a bit mask.
   1417      *
   1418      * @deprecated Use {@link View#getMeasuredHeightAndState()} directly.
   1419      */
   1420     @Deprecated
   1421     public static int getMeasuredHeightAndState(View view) {
   1422         return view.getMeasuredHeightAndState();
   1423     }
   1424 
   1425     /**
   1426      * Return only the state bits of {@link #getMeasuredWidthAndState}
   1427      * and {@link #getMeasuredHeightAndState}, combined into one integer.
   1428      * The width component is in the regular bits {@link #MEASURED_STATE_MASK}
   1429      * and the height component is at the shifted bits
   1430      * {@link #MEASURED_HEIGHT_STATE_SHIFT}>>{@link #MEASURED_STATE_MASK}.
   1431      *
   1432      * @deprecated Use {@link View#getMeasuredState()} directly.
   1433      */
   1434     @Deprecated
   1435     public static int getMeasuredState(View view) {
   1436         return view.getMeasuredState();
   1437     }
   1438 
   1439     /**
   1440      * Merge two states as returned by {@link #getMeasuredState(View)}.
   1441      * @param curState The current state as returned from a view or the result
   1442      * of combining multiple views.
   1443      * @param newState The new view state to combine.
   1444      * @return Returns a new integer reflecting the combination of the two
   1445      * states.
   1446      *
   1447      * @deprecated Use {@link View#combineMeasuredStates(int, int)} directly.
   1448      */
   1449     @Deprecated
   1450     public static int combineMeasuredStates(int curState, int newState) {
   1451         return View.combineMeasuredStates(curState, newState);
   1452     }
   1453 
   1454     /**
   1455      * Gets the live region mode for the specified View.
   1456      *
   1457      * @param view The view from which to obtain the live region mode
   1458      * @return The live region mode for the view.
   1459      *
   1460      * @see ViewCompat#setAccessibilityLiveRegion(View, int)
   1461      */
   1462     @AccessibilityLiveRegion
   1463     public static int getAccessibilityLiveRegion(@NonNull View view) {
   1464         if (Build.VERSION.SDK_INT >= 19) {
   1465             return view.getAccessibilityLiveRegion();
   1466         }
   1467         return ACCESSIBILITY_LIVE_REGION_NONE;
   1468     }
   1469 
   1470     /**
   1471      * Sets the live region mode for the specified view. This indicates to
   1472      * accessibility services whether they should automatically notify the user
   1473      * about changes to the view's content description or text, or to the
   1474      * content descriptions or text of the view's children (where applicable).
   1475      * <p>
   1476      * For example, in a login screen with a TextView that displays an "incorrect
   1477      * password" notification, that view should be marked as a live region with
   1478      * mode {@link #ACCESSIBILITY_LIVE_REGION_POLITE}.
   1479      * <p>
   1480      * To disable change notifications for this view, use
   1481      * {@link #ACCESSIBILITY_LIVE_REGION_NONE}. This is the default live region
   1482      * mode for most views.
   1483      * <p>
   1484      * To indicate that the user should be notified of changes, use
   1485      * {@link #ACCESSIBILITY_LIVE_REGION_POLITE}.
   1486      * <p>
   1487      * If the view's changes should interrupt ongoing speech and notify the user
   1488      * immediately, use {@link #ACCESSIBILITY_LIVE_REGION_ASSERTIVE}.
   1489      *
   1490      * @param view The view on which to set the live region mode
   1491      * @param mode The live region mode for this view, one of:
   1492      *        <ul>
   1493      *        <li>{@link #ACCESSIBILITY_LIVE_REGION_NONE}
   1494      *        <li>{@link #ACCESSIBILITY_LIVE_REGION_POLITE}
   1495      *        <li>{@link #ACCESSIBILITY_LIVE_REGION_ASSERTIVE}
   1496      *        </ul>
   1497      */
   1498     public static void setAccessibilityLiveRegion(@NonNull View view,
   1499             @AccessibilityLiveRegion int mode) {
   1500         if (Build.VERSION.SDK_INT >= 19) {
   1501             view.setAccessibilityLiveRegion(mode);
   1502         }
   1503     }
   1504 
   1505     /**
   1506      * Returns the start padding of the specified view depending on its resolved layout direction.
   1507      * If there are inset and enabled scrollbars, this value may include the space
   1508      * required to display the scrollbars as well.
   1509      *
   1510      * @param view The view to get padding for
   1511      * @return the start padding in pixels
   1512      */
   1513     @Px
   1514     public static int getPaddingStart(@NonNull View view) {
   1515         if (Build.VERSION.SDK_INT >= 17) {
   1516             return view.getPaddingStart();
   1517         }
   1518         return view.getPaddingLeft();
   1519     }
   1520 
   1521     /**
   1522      * Returns the end padding of the specified view depending on its resolved layout direction.
   1523      * If there are inset and enabled scrollbars, this value may include the space
   1524      * required to display the scrollbars as well.
   1525      *
   1526      * @param view The view to get padding for
   1527      * @return the end padding in pixels
   1528      */
   1529     @Px
   1530     public static int getPaddingEnd(@NonNull View view) {
   1531         if (Build.VERSION.SDK_INT >= 17) {
   1532             return view.getPaddingEnd();
   1533         }
   1534         return view.getPaddingRight();
   1535     }
   1536 
   1537     /**
   1538      * Sets the relative padding. The view may add on the space required to display
   1539      * the scrollbars, depending on the style and visibility of the scrollbars.
   1540      * So the values returned from {@link #getPaddingStart}, {@link View#getPaddingTop},
   1541      * {@link #getPaddingEnd} and {@link View#getPaddingBottom} may be different
   1542      * from the values set in this call.
   1543      *
   1544      * @param view The view on which to set relative padding
   1545      * @param start the start padding in pixels
   1546      * @param top the top padding in pixels
   1547      * @param end the end padding in pixels
   1548      * @param bottom the bottom padding in pixels
   1549      */
   1550     public static void setPaddingRelative(@NonNull View view, @Px int start, @Px int top,
   1551             @Px int end, @Px int bottom) {
   1552         if (Build.VERSION.SDK_INT >= 17) {
   1553             view.setPaddingRelative(start, top, end, bottom);
   1554         } else {
   1555             view.setPadding(start, top, end, bottom);
   1556         }
   1557     }
   1558 
   1559     private static void bindTempDetach() {
   1560         try {
   1561             sDispatchStartTemporaryDetach = View.class.getDeclaredMethod(
   1562                     "dispatchStartTemporaryDetach");
   1563             sDispatchFinishTemporaryDetach = View.class.getDeclaredMethod(
   1564                     "dispatchFinishTemporaryDetach");
   1565         } catch (NoSuchMethodException e) {
   1566             Log.e(TAG, "Couldn't find method", e);
   1567         }
   1568         sTempDetachBound = true;
   1569     }
   1570 
   1571     /**
   1572      * Notify a view that it is being temporarily detached.
   1573      */
   1574     public static void dispatchStartTemporaryDetach(@NonNull View view) {
   1575         if (Build.VERSION.SDK_INT >= 24) {
   1576             view.dispatchStartTemporaryDetach();
   1577         } else {
   1578             if (!sTempDetachBound) {
   1579                 bindTempDetach();
   1580             }
   1581             if (sDispatchStartTemporaryDetach != null) {
   1582                 try {
   1583                     sDispatchStartTemporaryDetach.invoke(view);
   1584                 } catch (Exception e) {
   1585                     Log.d(TAG, "Error calling dispatchStartTemporaryDetach", e);
   1586                 }
   1587             } else {
   1588                 // Try this instead
   1589                 view.onStartTemporaryDetach();
   1590             }
   1591         }
   1592     }
   1593 
   1594     /**
   1595      * Notify a view that its temporary detach has ended; the view is now reattached.
   1596      */
   1597     public static void dispatchFinishTemporaryDetach(@NonNull View view) {
   1598         if (Build.VERSION.SDK_INT >= 24) {
   1599             view.dispatchFinishTemporaryDetach();
   1600         } else {
   1601             if (!sTempDetachBound) {
   1602                 bindTempDetach();
   1603             }
   1604             if (sDispatchFinishTemporaryDetach != null) {
   1605                 try {
   1606                     sDispatchFinishTemporaryDetach.invoke(view);
   1607                 } catch (Exception e) {
   1608                     Log.d(TAG, "Error calling dispatchFinishTemporaryDetach", e);
   1609                 }
   1610             } else {
   1611                 // Try this instead
   1612                 view.onFinishTemporaryDetach();
   1613             }
   1614         }
   1615     }
   1616 
   1617     /**
   1618      * The horizontal location of this view relative to its {@link View#getLeft() left} position.
   1619      * This position is post-layout, in addition to wherever the object's
   1620      * layout placed it.
   1621      *
   1622      * @return The horizontal position of this view relative to its left position, in pixels.
   1623      *
   1624      * @deprecated Use {@link View#getTranslationX()} directly.
   1625      */
   1626     @Deprecated
   1627     public static float getTranslationX(View view) {
   1628         return view.getTranslationX();
   1629     }
   1630 
   1631     /**
   1632      * The vertical location of this view relative to its {@link View#getTop() top} position.
   1633      * This position is post-layout, in addition to wherever the object's
   1634      * layout placed it.
   1635      *
   1636      * @return The vertical position of this view relative to its top position, in pixels.
   1637      *
   1638      * @deprecated Use {@link View#getTranslationY()} directly.
   1639      */
   1640     @Deprecated
   1641     public static float getTranslationY(View view) {
   1642         return view.getTranslationY();
   1643     }
   1644 
   1645     /**
   1646      * The transform matrix of this view, which is calculated based on the current
   1647      * rotation, scale, and pivot properties.
   1648      * <p>
   1649      *
   1650      * @param view The view whose Matrix will be returned
   1651      * @return The current transform matrix for the view
   1652      *
   1653      * @see #getRotation(View)
   1654      * @see #getScaleX(View)
   1655      * @see #getScaleY(View)
   1656      * @see #getPivotX(View)
   1657      * @see #getPivotY(View)
   1658      *
   1659      * @deprecated Use {@link View#getMatrix()} directly.
   1660      */
   1661     @Deprecated
   1662     @Nullable
   1663     public static Matrix getMatrix(View view) {
   1664         return view.getMatrix();
   1665     }
   1666 
   1667     /**
   1668      * Returns the minimum width of the view.
   1669      *
   1670      * <p>Prior to API 16, this method may return 0 on some platforms.</p>
   1671      *
   1672      * @return the minimum width the view will try to be.
   1673      */
   1674     public static int getMinimumWidth(@NonNull View view) {
   1675         if (Build.VERSION.SDK_INT >= 16) {
   1676             return view.getMinimumWidth();
   1677         }
   1678 
   1679         if (!sMinWidthFieldFetched) {
   1680             try {
   1681                 sMinWidthField = View.class.getDeclaredField("mMinWidth");
   1682                 sMinWidthField.setAccessible(true);
   1683             } catch (NoSuchFieldException e) {
   1684                 // Couldn't find the field. Abort!
   1685             }
   1686             sMinWidthFieldFetched = true;
   1687         }
   1688 
   1689         if (sMinWidthField != null) {
   1690             try {
   1691                 return (int) sMinWidthField.get(view);
   1692             } catch (Exception e) {
   1693                 // Field get failed. Oh well...
   1694             }
   1695         }
   1696 
   1697         // We failed, return 0
   1698         return 0;
   1699     }
   1700 
   1701     /**
   1702      * Returns the minimum height of the view.
   1703      *
   1704      * <p>Prior to API 16, this method may return 0 on some platforms.</p>
   1705      *
   1706      * @return the minimum height the view will try to be.
   1707      */
   1708     public static int getMinimumHeight(@NonNull View view) {
   1709         if (Build.VERSION.SDK_INT >= 16) {
   1710             return view.getMinimumHeight();
   1711         }
   1712 
   1713         if (!sMinHeightFieldFetched) {
   1714             try {
   1715                 sMinHeightField = View.class.getDeclaredField("mMinHeight");
   1716                 sMinHeightField.setAccessible(true);
   1717             } catch (NoSuchFieldException e) {
   1718                 // Couldn't find the field. Abort!
   1719             }
   1720             sMinHeightFieldFetched = true;
   1721         }
   1722 
   1723         if (sMinHeightField != null) {
   1724             try {
   1725                 return (int) sMinHeightField.get(view);
   1726             } catch (Exception e) {
   1727                 // Field get failed. Oh well...
   1728             }
   1729         }
   1730 
   1731         // We failed, return 0
   1732         return 0;
   1733     }
   1734 
   1735     /**
   1736      * This method returns a ViewPropertyAnimator object, which can be used to animate
   1737      * specific properties on this View.
   1738      *
   1739      * @return ViewPropertyAnimator The ViewPropertyAnimator associated with this View.
   1740      */
   1741     @NonNull
   1742     public static ViewPropertyAnimatorCompat animate(@NonNull View view) {
   1743         if (sViewPropertyAnimatorMap == null) {
   1744             sViewPropertyAnimatorMap = new WeakHashMap<>();
   1745         }
   1746         ViewPropertyAnimatorCompat vpa = sViewPropertyAnimatorMap.get(view);
   1747         if (vpa == null) {
   1748             vpa = new ViewPropertyAnimatorCompat(view);
   1749             sViewPropertyAnimatorMap.put(view, vpa);
   1750         }
   1751         return vpa;
   1752     }
   1753 
   1754     /**
   1755      * Sets the horizontal location of this view relative to its left position.
   1756      * This effectively positions the object post-layout, in addition to wherever the object's
   1757      * layout placed it.
   1758      *
   1759      * @param value The horizontal position of this view relative to its left position,
   1760      * in pixels.
   1761      *
   1762      * @deprecated Use {@link View#setTranslationX(float)} directly.
   1763      */
   1764     @Deprecated
   1765     public static void setTranslationX(View view, float value) {
   1766         view.setTranslationX(value);
   1767     }
   1768 
   1769     /**
   1770      * Sets the vertical location of this view relative to its top position.
   1771      * This effectively positions the object post-layout, in addition to wherever the object's
   1772      * layout placed it.
   1773      *
   1774      * @param value The vertical position of this view relative to its top position,
   1775      * in pixels.
   1776      *
   1777      * @attr name android:translationY
   1778      *
   1779      * @deprecated Use {@link View#setTranslationY(float)} directly.
   1780      */
   1781     @Deprecated
   1782     public static void setTranslationY(View view, float value) {
   1783         view.setTranslationY(value);
   1784     }
   1785 
   1786     /**
   1787      * <p>Sets the opacity of the view. This is a value from 0 to 1, where 0 means the view is
   1788      * completely transparent and 1 means the view is completely opaque.</p>
   1789      *
   1790      * <p> Note that setting alpha to a translucent value (0 < alpha < 1) can have significant
   1791      * performance implications, especially for large views. It is best to use the alpha property
   1792      * sparingly and transiently, as in the case of fading animations.</p>
   1793      *
   1794      * @param value The opacity of the view.
   1795      *
   1796      * @deprecated Use {@link View#setAlpha(float)} directly.
   1797      */
   1798     @Deprecated
   1799     public static void setAlpha(View view, @FloatRange(from=0.0, to=1.0) float value) {
   1800         view.setAlpha(value);
   1801     }
   1802 
   1803     /**
   1804      * Sets the visual x position of this view, in pixels. This is equivalent to setting the
   1805      * {@link #setTranslationX(View, float) translationX} property to be the difference between
   1806      * the x value passed in and the current left property of the view as determined
   1807      * by the layout bounds.
   1808      *
   1809      * @param value The visual x position of this view, in pixels.
   1810      *
   1811      * @deprecated Use {@link View#setX(float)} directly.
   1812      */
   1813     @Deprecated
   1814     public static void setX(View view, float value) {
   1815         view.setX(value);
   1816     }
   1817 
   1818     /**
   1819      * Sets the visual y position of this view, in pixels. This is equivalent to setting the
   1820      * {@link #setTranslationY(View, float) translationY} property to be the difference between
   1821      * the y value passed in and the current top property of the view as determined by the
   1822      * layout bounds.
   1823      *
   1824      * @param value The visual y position of this view, in pixels.
   1825      *
   1826      * @deprecated Use {@link View#setY(float)} directly.
   1827      */
   1828     @Deprecated
   1829     public static void setY(View view, float value) {
   1830         view.setY(value);
   1831     }
   1832 
   1833     /**
   1834      * Sets the degrees that the view is rotated around the pivot point. Increasing values
   1835      * result in clockwise rotation.
   1836      *
   1837      * @param value The degrees of rotation.
   1838      *
   1839      * @deprecated Use {@link View#setRotation(float)} directly.
   1840      */
   1841     @Deprecated
   1842     public static void setRotation(View view, float value) {
   1843         view.setRotation(value);
   1844     }
   1845 
   1846     /**
   1847      * Sets the degrees that the view is rotated around the horizontal axis through the pivot point.
   1848      * Increasing values result in clockwise rotation from the viewpoint of looking down the
   1849      * x axis.
   1850      *
   1851      * @param value The degrees of X rotation.
   1852      *
   1853      * @deprecated Use {@link View#setRotationX(float)} directly.
   1854      */
   1855     @Deprecated
   1856     public static void setRotationX(View view, float value) {
   1857         view.setRotationX(value);
   1858     }
   1859 
   1860     /**
   1861      * Sets the degrees that the view is rotated around the vertical axis through the pivot point.
   1862      * Increasing values result in counter-clockwise rotation from the viewpoint of looking
   1863      * down the y axis.
   1864      *
   1865      * @param value The degrees of Y rotation.
   1866      *
   1867      * @deprecated Use {@link View#setRotationY(float)} directly.
   1868      */
   1869     @Deprecated
   1870     public static void setRotationY(View view, float value) {
   1871         view.setRotationY(value);
   1872     }
   1873 
   1874     /**
   1875      * Sets the amount that the view is scaled in x around the pivot point, as a proportion of
   1876      * the view's unscaled width. A value of 1 means that no scaling is applied.
   1877      *
   1878      * @param value The scaling factor.
   1879      *
   1880      * @deprecated Use {@link View#setScaleX(float)} directly.
   1881      */
   1882     @Deprecated
   1883     public static void setScaleX(View view, float value) {
   1884         view.setScaleX(value);
   1885     }
   1886 
   1887     /**
   1888      * Sets the amount that the view is scaled in Y around the pivot point, as a proportion of
   1889      * the view's unscaled width. A value of 1 means that no scaling is applied.
   1890      *
   1891      * @param value The scaling factor.
   1892      *
   1893      * @deprecated Use {@link View#setScaleY(float)} directly.
   1894      */
   1895     @Deprecated
   1896     public static void setScaleY(View view, float value) {
   1897         view.setScaleY(value);
   1898     }
   1899 
   1900     /**
   1901      * The x location of the point around which the view is
   1902      * {@link #setRotation(View, float) rotated} and {@link #setScaleX(View, float) scaled}.
   1903      *
   1904      * @deprecated Use {@link View#getPivotX()} directly.
   1905      */
   1906     @Deprecated
   1907     public static float getPivotX(View view) {
   1908         return view.getPivotX();
   1909     }
   1910 
   1911     /**
   1912      * Sets the x location of the point around which the view is
   1913      * {@link #setRotation(View, float) rotated} and {@link #setScaleX(View, float) scaled}.
   1914      * By default, the pivot point is centered on the object.
   1915      * Setting this property disables this behavior and causes the view to use only the
   1916      * explicitly set pivotX and pivotY values.
   1917      *
   1918      * @param value The x location of the pivot point.
   1919      *
   1920      * @deprecated Use {@link View#setPivotX(float)} directly.
   1921      */
   1922     @Deprecated
   1923     public static void setPivotX(View view, float value) {
   1924         view.setPivotX(value);
   1925     }
   1926 
   1927     /**
   1928      * The y location of the point around which the view is {@link #setRotation(View,
   1929      * float) rotated} and {@link #setScaleY(View, float) scaled}.
   1930      *
   1931      * @return The y location of the pivot point.
   1932      *
   1933      * @deprecated Use {@link View#getPivotY()} directly.
   1934      */
   1935     @Deprecated
   1936     public static float getPivotY(View view) {
   1937         return view.getPivotY();
   1938     }
   1939 
   1940     /**
   1941      * Sets the y location of the point around which the view is
   1942      * {@link #setRotation(View, float) rotated} and {@link #setScaleY(View, float) scaled}.
   1943      * By default, the pivot point is centered on the object.
   1944      * Setting this property disables this behavior and causes the view to use only the
   1945      * explicitly set pivotX and pivotY values.
   1946      *
   1947      * @param value The y location of the pivot point.
   1948      *
   1949      * @deprecated Use {@link View#setPivotX(float)} directly.
   1950      */
   1951     @Deprecated
   1952     public static void setPivotY(View view, float value) {
   1953         view.setPivotY(value);
   1954     }
   1955 
   1956     /**
   1957      * @deprecated Use {@link View#getRotation()} directly.
   1958      */
   1959     @Deprecated
   1960     public static float getRotation(View view) {
   1961         return view.getRotation();
   1962     }
   1963 
   1964     /**
   1965      * @deprecated Use {@link View#getRotationX()} directly.
   1966      */
   1967     @Deprecated
   1968     public static float getRotationX(View view) {
   1969         return view.getRotationX();
   1970     }
   1971 
   1972     /**
   1973      * @deprecated Use {@link View#getRotationY()} directly.
   1974      */
   1975     @Deprecated
   1976     public static float getRotationY(View view) {
   1977         return view.getRotationY();
   1978     }
   1979 
   1980     /**
   1981      * @deprecated Use {@link View#getScaleX()} directly.
   1982      */
   1983     @Deprecated
   1984     public static float getScaleX(View view) {
   1985         return view.getScaleX();
   1986     }
   1987 
   1988     /**
   1989      * @deprecated Use {@link View#getScaleY()} directly.
   1990      */
   1991     @Deprecated
   1992     public static float getScaleY(View view) {
   1993         return view.getScaleY();
   1994     }
   1995 
   1996     /**
   1997      * @deprecated Use {@link View#getX()} directly.
   1998      */
   1999     @Deprecated
   2000     public static float getX(View view) {
   2001         return view.getX();
   2002     }
   2003 
   2004     /**
   2005      * @deprecated Use {@link View#getY()} directly.
   2006      */
   2007     @Deprecated
   2008     public static float getY(View view) {
   2009         return view.getY();
   2010     }
   2011 
   2012     /**
   2013      * Sets the base elevation of this view, in pixels.
   2014      */
   2015     public static void setElevation(@NonNull View view, float elevation) {
   2016         if (Build.VERSION.SDK_INT >= 21) {
   2017             view.setElevation(elevation);
   2018         }
   2019     }
   2020 
   2021     /**
   2022      * The base elevation of this view relative to its parent, in pixels.
   2023      *
   2024      * @return The base depth position of the view, in pixels.
   2025      */
   2026     public static float getElevation(@NonNull View view) {
   2027         if (Build.VERSION.SDK_INT >= 21) {
   2028             return view.getElevation();
   2029         }
   2030         return 0f;
   2031     }
   2032 
   2033     /**
   2034      * Sets the depth location of this view relative to its {@link #getElevation(View) elevation}.
   2035      */
   2036     public static void setTranslationZ(@NonNull View view, float translationZ) {
   2037         if (Build.VERSION.SDK_INT >= 21) {
   2038             view.setTranslationZ(translationZ);
   2039         }
   2040     }
   2041 
   2042     /**
   2043      * The depth location of this view relative to its {@link #getElevation(View) elevation}.
   2044      *
   2045      * @return The depth of this view relative to its elevation.
   2046      */
   2047     public static float getTranslationZ(@NonNull View view) {
   2048         if (Build.VERSION.SDK_INT >= 21) {
   2049             return view.getTranslationZ();
   2050         }
   2051         return 0f;
   2052     }
   2053 
   2054     /**
   2055      * Sets the name of the View to be used to identify Views in Transitions.
   2056      * Names should be unique in the View hierarchy.
   2057      *
   2058      * @param view The View against which to invoke the method.
   2059      * @param transitionName The name of the View to uniquely identify it for Transitions.
   2060      */
   2061     public static void setTransitionName(@NonNull View view, String transitionName) {
   2062         if (Build.VERSION.SDK_INT >= 21) {
   2063             view.setTransitionName(transitionName);
   2064         } else {
   2065             if (sTransitionNameMap == null) {
   2066                 sTransitionNameMap = new WeakHashMap<>();
   2067             }
   2068             sTransitionNameMap.put(view, transitionName);
   2069         }
   2070     }
   2071 
   2072     /**
   2073      * Returns the name of the View to be used to identify Views in Transitions.
   2074      * Names should be unique in the View hierarchy.
   2075      *
   2076      * <p>This returns null if the View has not been given a name.</p>
   2077      *
   2078      * @param view The View against which to invoke the method.
   2079      * @return The name used of the View to be used to identify Views in Transitions or null
   2080      * if no name has been given.
   2081      */
   2082     @Nullable
   2083     public static String getTransitionName(@NonNull View view) {
   2084         if (Build.VERSION.SDK_INT >= 21) {
   2085             return view.getTransitionName();
   2086         }
   2087         if (sTransitionNameMap == null) {
   2088             return null;
   2089         }
   2090         return sTransitionNameMap.get(view);
   2091     }
   2092 
   2093     /**
   2094      * Returns the current system UI visibility that is currently set for the entire window.
   2095      */
   2096     public static int getWindowSystemUiVisibility(@NonNull View view) {
   2097         if (Build.VERSION.SDK_INT >= 16) {
   2098             return view.getWindowSystemUiVisibility();
   2099         }
   2100         return 0;
   2101     }
   2102 
   2103     /**
   2104      * Ask that a new dispatch of {@code View.onApplyWindowInsets(WindowInsets)} be performed. This
   2105      * falls back to {@code View.requestFitSystemWindows()} where available.
   2106      */
   2107     public static void requestApplyInsets(@NonNull View view) {
   2108         if (Build.VERSION.SDK_INT >= 20) {
   2109             view.requestApplyInsets();
   2110         } else if (Build.VERSION.SDK_INT >= 16) {
   2111             view.requestFitSystemWindows();
   2112         }
   2113     }
   2114 
   2115     /**
   2116      * Tells the ViewGroup whether to draw its children in the order defined by the method
   2117      * {@code ViewGroup.getChildDrawingOrder(int, int)}.
   2118      *
   2119      * @param enabled true if the order of the children when drawing is determined by
   2120      *        {@link ViewGroup#getChildDrawingOrder(int, int)}, false otherwise
   2121      *
   2122      * <p>Prior to API 7 this will have no effect.</p>
   2123      *
   2124      * @deprecated Use {@link ViewGroup#setChildrenDrawingOrderEnabled(boolean)} directly.
   2125      */
   2126     @Deprecated
   2127     public static void setChildrenDrawingOrderEnabled(ViewGroup viewGroup, boolean enabled) {
   2128         if (sChildrenDrawingOrderMethod == null) {
   2129             try {
   2130                 sChildrenDrawingOrderMethod = ViewGroup.class
   2131                         .getDeclaredMethod("setChildrenDrawingOrderEnabled", boolean.class);
   2132             } catch (NoSuchMethodException e) {
   2133                 Log.e(TAG, "Unable to find childrenDrawingOrderEnabled", e);
   2134             }
   2135             sChildrenDrawingOrderMethod.setAccessible(true);
   2136         }
   2137         try {
   2138             sChildrenDrawingOrderMethod.invoke(viewGroup, enabled);
   2139         } catch (IllegalAccessException e) {
   2140             Log.e(TAG, "Unable to invoke childrenDrawingOrderEnabled", e);
   2141         } catch (IllegalArgumentException e) {
   2142             Log.e(TAG, "Unable to invoke childrenDrawingOrderEnabled", e);
   2143         } catch (InvocationTargetException e) {
   2144             Log.e(TAG, "Unable to invoke childrenDrawingOrderEnabled", e);
   2145         }
   2146     }
   2147 
   2148     /**
   2149      * Returns true if this view should adapt to fit system window insets. This method will always
   2150      * return false before API 16 (Jellybean).
   2151      */
   2152     public static boolean getFitsSystemWindows(@NonNull View v) {
   2153         if (Build.VERSION.SDK_INT >= 16) {
   2154             return v.getFitsSystemWindows();
   2155         }
   2156         return false;
   2157     }
   2158 
   2159     /**
   2160      * Sets whether or not this view should account for system screen decorations
   2161      * such as the status bar and inset its content; that is, controlling whether
   2162      * the default implementation of {@link View#fitSystemWindows(Rect)} will be
   2163      * executed. See that method for more details.
   2164      *
   2165      * @deprecated Use {@link View#setFitsSystemWindows(boolean)} directly.
   2166      */
   2167     @Deprecated
   2168     public static void setFitsSystemWindows(View view, boolean fitSystemWindows) {
   2169         view.setFitsSystemWindows(fitSystemWindows);
   2170     }
   2171 
   2172     /**
   2173      * On API 11 devices and above, call <code>Drawable.jumpToCurrentState()</code>
   2174      * on all Drawable objects associated with this view.
   2175      * <p>
   2176      * On API 21 and above, also calls <code>StateListAnimator#jumpToCurrentState()</code>
   2177      * if there is a StateListAnimator attached to this view.
   2178      *
   2179      * @deprecated Use {@link View#jumpDrawablesToCurrentState()} directly.
   2180      */
   2181     @Deprecated
   2182     public static void jumpDrawablesToCurrentState(View v) {
   2183         v.jumpDrawablesToCurrentState();
   2184     }
   2185 
   2186     /**
   2187      * Set an {@link OnApplyWindowInsetsListener} to take over the policy for applying
   2188      * window insets to this view. This will only take effect on devices with API 21 or above.
   2189      */
   2190     public static void setOnApplyWindowInsetsListener(@NonNull View v,
   2191             final OnApplyWindowInsetsListener listener) {
   2192         if (Build.VERSION.SDK_INT >= 21) {
   2193             if (listener == null) {
   2194                 v.setOnApplyWindowInsetsListener(null);
   2195                 return;
   2196             }
   2197 
   2198             v.setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() {
   2199                 @Override
   2200                 @RequiresApi(21) // TODO remove https://issuetracker.google.com/issues/76458979
   2201                 public WindowInsets onApplyWindowInsets(View view, WindowInsets insets) {
   2202                     WindowInsetsCompat compatInsets = WindowInsetsCompat.wrap(insets);
   2203                     compatInsets = listener.onApplyWindowInsets(view, compatInsets);
   2204                     return (WindowInsets) WindowInsetsCompat.unwrap(compatInsets);
   2205                 }
   2206             });
   2207         }
   2208     }
   2209 
   2210     /**
   2211      * Called when the view should apply {@link WindowInsetsCompat} according to its internal policy.
   2212      *
   2213      * <p>Clients may supply an {@link OnApplyWindowInsetsListener} to a view. If one is set
   2214      * it will be called during dispatch instead of this method. The listener may optionally
   2215      * call this method from its own implementation if it wishes to apply the view's default
   2216      * insets policy in addition to its own.</p>
   2217      *
   2218      * @param view The View against which to invoke the method.
   2219      * @param insets Insets to apply
   2220      * @return The supplied insets with any applied insets consumed
   2221      */
   2222     public static WindowInsetsCompat onApplyWindowInsets(@NonNull View view,
   2223             WindowInsetsCompat insets) {
   2224         if (Build.VERSION.SDK_INT >= 21) {
   2225             WindowInsets unwrapped = (WindowInsets)  WindowInsetsCompat.unwrap(insets);
   2226             WindowInsets result = view.onApplyWindowInsets(unwrapped);
   2227             if (result != unwrapped) {
   2228                 unwrapped = new WindowInsets(result);
   2229             }
   2230             return WindowInsetsCompat.wrap(unwrapped);
   2231         }
   2232         return insets;
   2233     }
   2234 
   2235     /**
   2236      * Request to apply the given window insets to this view or another view in its subtree.
   2237      *
   2238      * <p>This method should be called by clients wishing to apply insets corresponding to areas
   2239      * obscured by window decorations or overlays. This can include the status and navigation bars,
   2240      * action bars, input methods and more. New inset categories may be added in the future.
   2241      * The method returns the insets provided minus any that were applied by this view or its
   2242      * children.</p>
   2243      *
   2244      * @param insets Insets to apply
   2245      * @return The provided insets minus the insets that were consumed
   2246      */
   2247     public static WindowInsetsCompat dispatchApplyWindowInsets(@NonNull View view,
   2248             WindowInsetsCompat insets) {
   2249         if (Build.VERSION.SDK_INT >= 21) {
   2250             WindowInsets unwrapped = (WindowInsets) WindowInsetsCompat.unwrap(insets);
   2251             WindowInsets result = view.dispatchApplyWindowInsets(unwrapped);
   2252             if (result != unwrapped) {
   2253                 unwrapped = new WindowInsets(result);
   2254             }
   2255             return WindowInsetsCompat.wrap(unwrapped);
   2256         }
   2257         return insets;
   2258     }
   2259 
   2260     /**
   2261      * Controls whether the entire hierarchy under this view will save its
   2262      * state when a state saving traversal occurs from its parent.
   2263      *
   2264      * @param enabled Set to false to <em>disable</em> state saving, or true
   2265      * (the default) to allow it.
   2266      *
   2267      * @deprecated Use {@link View#setSaveFromParentEnabled(boolean)} directly.
   2268      */
   2269     @Deprecated
   2270     public static void setSaveFromParentEnabled(View v, boolean enabled) {
   2271         v.setSaveFromParentEnabled(enabled);
   2272     }
   2273 
   2274     /**
   2275      * Changes the activated state of this view. A view can be activated or not.
   2276      * Note that activation is not the same as selection.  Selection is
   2277      * a transient property, representing the view (hierarchy) the user is
   2278      * currently interacting with.  Activation is a longer-term state that the
   2279      * user can move views in and out of.
   2280      *
   2281      * @param activated true if the view must be activated, false otherwise
   2282      *
   2283      * @deprecated Use {@link View#setActivated(boolean)} directly.
   2284      */
   2285     @Deprecated
   2286     public static void setActivated(View view, boolean activated) {
   2287         view.setActivated(activated);
   2288     }
   2289 
   2290     /**
   2291      * Returns whether this View has content which overlaps.
   2292      *
   2293      * <p>This function, intended to be overridden by specific View types, is an optimization when
   2294      * alpha is set on a view. If rendering overlaps in a view with alpha < 1, that view is drawn to
   2295      * an offscreen buffer and then composited into place, which can be expensive. If the view has
   2296      * no overlapping rendering, the view can draw each primitive with the appropriate alpha value
   2297      * directly. An example of overlapping rendering is a TextView with a background image, such as
   2298      * a Button. An example of non-overlapping rendering is a TextView with no background, or an
   2299      * ImageView with only the foreground image. The default implementation returns true; subclasses
   2300      * should override if they have cases which can be optimized.</p>
   2301      *
   2302      * @return true if the content in this view might overlap, false otherwise.
   2303      */
   2304     public static boolean hasOverlappingRendering(@NonNull View view) {
   2305         if (Build.VERSION.SDK_INT >= 16) {
   2306             return view.hasOverlappingRendering();
   2307         }
   2308         return true;
   2309     }
   2310 
   2311     /**
   2312      * Return if the padding as been set through relative values
   2313      * {@code View.setPaddingRelative(int, int, int, int)} or thru
   2314      *
   2315      * @return true if the padding is relative or false if it is not.
   2316      */
   2317     public static boolean isPaddingRelative(@NonNull View view) {
   2318         if (Build.VERSION.SDK_INT >= 17) {
   2319             return view.isPaddingRelative();
   2320         }
   2321         return false;
   2322     }
   2323 
   2324     /**
   2325      * Set the background of the {@code view} to a given Drawable, or remove the background. If the
   2326      * background has padding, {@code view}'s padding is set to the background's padding. However,
   2327      * when a background is removed, this View's padding isn't touched. If setting the padding is
   2328      * desired, please use{@code setPadding(int, int, int, int)}.
   2329      */
   2330     public static void setBackground(@NonNull View view, @Nullable Drawable background) {
   2331         if (Build.VERSION.SDK_INT >= 16) {
   2332             view.setBackground(background);
   2333         } else {
   2334             view.setBackgroundDrawable(background);
   2335         }
   2336     }
   2337 
   2338     /**
   2339      * Return the tint applied to the background drawable, if specified.
   2340      * <p>
   2341      * Only returns meaningful info when running on API v21 or newer, or if {@code view}
   2342      * implements the {@code TintableBackgroundView} interface.
   2343      */
   2344     public static ColorStateList getBackgroundTintList(@NonNull View view) {
   2345         if (Build.VERSION.SDK_INT >= 21) {
   2346             return view.getBackgroundTintList();
   2347         }
   2348         return (view instanceof TintableBackgroundView)
   2349                 ? ((TintableBackgroundView) view).getSupportBackgroundTintList()
   2350                 : null;
   2351     }
   2352 
   2353     /**
   2354      * Applies a tint to the background drawable.
   2355      * <p>
   2356      * This will always take effect when running on API v21 or newer. When running on platforms
   2357      * previous to API v21, it will only take effect if {@code view} implements the
   2358      * {@code TintableBackgroundView} interface.
   2359      */
   2360     public static void setBackgroundTintList(@NonNull View view, ColorStateList tintList) {
   2361         if (Build.VERSION.SDK_INT >= 21) {
   2362             view.setBackgroundTintList(tintList);
   2363 
   2364             if (Build.VERSION.SDK_INT == 21) {
   2365                 // Work around a bug in L that did not update the state of the background
   2366                 // after applying the tint
   2367                 Drawable background = view.getBackground();
   2368                 boolean hasTint = (view.getBackgroundTintList() != null)
   2369                         || (view.getBackgroundTintMode() != null);
   2370                 if ((background != null) && hasTint) {
   2371                     if (background.isStateful()) {
   2372                         background.setState(view.getDrawableState());
   2373                     }
   2374                     view.setBackground(background);
   2375                 }
   2376             }
   2377         } else if (view instanceof TintableBackgroundView) {
   2378             ((TintableBackgroundView) view).setSupportBackgroundTintList(tintList);
   2379         }
   2380     }
   2381 
   2382     /**
   2383      * Return the blending mode used to apply the tint to the background
   2384      * drawable, if specified.
   2385      * <p>
   2386      * Only returns meaningful info when running on API v21 or newer, or if {@code view}
   2387      * implements the {@code TintableBackgroundView} interface.
   2388      */
   2389     public static PorterDuff.Mode getBackgroundTintMode(@NonNull View view) {
   2390         if (Build.VERSION.SDK_INT >= 21) {
   2391             return view.getBackgroundTintMode();
   2392         }
   2393         return (view instanceof TintableBackgroundView)
   2394                 ? ((TintableBackgroundView) view).getSupportBackgroundTintMode()
   2395                 : null;
   2396     }
   2397 
   2398     /**
   2399      * Specifies the blending mode used to apply the tint specified by
   2400      * {@link #setBackgroundTintList(android.view.View, android.content.res.ColorStateList)} to
   2401      * the background drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}.
   2402      * <p>
   2403      * This will always take effect when running on API v21 or newer. When running on platforms
   2404      * previous to API v21, it will only take effect if {@code view} implement the
   2405      * {@code TintableBackgroundView} interface.
   2406      */
   2407     public static void setBackgroundTintMode(@NonNull View view, PorterDuff.Mode mode) {
   2408         if (Build.VERSION.SDK_INT >= 21) {
   2409             view.setBackgroundTintMode(mode);
   2410 
   2411             if (Build.VERSION.SDK_INT == 21) {
   2412                 // Work around a bug in L that did not update the state of the background
   2413                 // after applying the tint
   2414                 Drawable background = view.getBackground();
   2415                 boolean hasTint = (view.getBackgroundTintList() != null)
   2416                         || (view.getBackgroundTintMode() != null);
   2417                 if ((background != null) && hasTint) {
   2418                     if (background.isStateful()) {
   2419                         background.setState(view.getDrawableState());
   2420                     }
   2421                     view.setBackground(background);
   2422                 }
   2423             }
   2424         } else if (view instanceof TintableBackgroundView) {
   2425             ((TintableBackgroundView) view).setSupportBackgroundTintMode(mode);
   2426         }
   2427     }
   2428 
   2429     // TODO: getters for various view properties (rotation, etc)
   2430 
   2431     /**
   2432      * Enable or disable nested scrolling for this view.
   2433      *
   2434      * <p>If this property is set to true the view will be permitted to initiate nested
   2435      * scrolling operations with a compatible parent view in the current hierarchy. If this
   2436      * view does not implement nested scrolling this will have no effect. Disabling nested scrolling
   2437      * while a nested scroll is in progress has the effect of
   2438      * {@link #stopNestedScroll(View) stopping} the nested scroll.</p>
   2439      *
   2440      * @param enabled true to enable nested scrolling, false to disable
   2441      *
   2442      * @see #isNestedScrollingEnabled(View)
   2443      */
   2444     @SuppressWarnings("RedundantCast") // Intentionally invoking interface method.
   2445     public static void setNestedScrollingEnabled(@NonNull View view, boolean enabled) {
   2446         if (Build.VERSION.SDK_INT >= 21) {
   2447             view.setNestedScrollingEnabled(enabled);
   2448         } else {
   2449             if (view instanceof NestedScrollingChild) {
   2450                 ((NestedScrollingChild) view).setNestedScrollingEnabled(enabled);
   2451             }
   2452         }
   2453     }
   2454 
   2455     /**
   2456      * Returns true if nested scrolling is enabled for this view.
   2457      *
   2458      * <p>If nested scrolling is enabled and this View class implementation supports it,
   2459      * this view will act as a nested scrolling child view when applicable, forwarding data
   2460      * about the scroll operation in progress to a compatible and cooperating nested scrolling
   2461      * parent.</p>
   2462      *
   2463      * @return true if nested scrolling is enabled
   2464      *
   2465      * @see #setNestedScrollingEnabled(View, boolean)
   2466      */
   2467     @SuppressWarnings("RedundantCast") // Intentionally invoking interface method.
   2468     public static boolean isNestedScrollingEnabled(@NonNull View view) {
   2469         if (Build.VERSION.SDK_INT >= 21) {
   2470             return view.isNestedScrollingEnabled();
   2471         }
   2472         if (view instanceof NestedScrollingChild) {
   2473             return ((NestedScrollingChild) view).isNestedScrollingEnabled();
   2474         }
   2475         return false;
   2476     }
   2477 
   2478     /**
   2479      * Begin a nestable scroll operation along the given axes.
   2480      *
   2481      * <p>This version of the method just calls {@link #startNestedScroll(View, int, int)} using
   2482      * the touch input type.</p>
   2483      *
   2484      * @param axes Flags consisting of a combination of {@link ViewCompat#SCROLL_AXIS_HORIZONTAL}
   2485      *             and/or {@link ViewCompat#SCROLL_AXIS_VERTICAL}.
   2486      * @return true if a cooperative parent was found and nested scrolling has been enabled for
   2487      *         the current gesture.
   2488      */
   2489     @SuppressWarnings("RedundantCast") // Intentionally invoking interface method.
   2490     public static boolean startNestedScroll(@NonNull View view, @ScrollAxis int axes) {
   2491         if (Build.VERSION.SDK_INT >= 21) {
   2492             return view.startNestedScroll(axes);
   2493         }
   2494         if (view instanceof NestedScrollingChild) {
   2495             return ((NestedScrollingChild) view).startNestedScroll(axes);
   2496         }
   2497         return false;
   2498     }
   2499 
   2500     /**
   2501      * Stop a nested scroll in progress.
   2502      *
   2503      * <p>This version of the method just calls {@link #stopNestedScroll(View, int)} using the
   2504      * touch input type.</p>
   2505      *
   2506      * @see #startNestedScroll(View, int)
   2507      */
   2508     @SuppressWarnings("RedundantCast") // Intentionally invoking interface method.
   2509     public static void stopNestedScroll(@NonNull View view) {
   2510         if (Build.VERSION.SDK_INT >= 21) {
   2511             view.stopNestedScroll();
   2512         } else if (view instanceof NestedScrollingChild) {
   2513             ((NestedScrollingChild) view).stopNestedScroll();
   2514         }
   2515     }
   2516 
   2517     /**
   2518      * Returns true if this view has a nested scrolling parent.
   2519      *
   2520      * <p>This version of the method just calls {@link #hasNestedScrollingParent(View, int)}
   2521      * using the touch input type.</p>
   2522      *
   2523      * @return whether this view has a nested scrolling parent
   2524      */
   2525     @SuppressWarnings("RedundantCast") // Intentionally invoking interface method.
   2526     public static boolean hasNestedScrollingParent(@NonNull View view) {
   2527         if (Build.VERSION.SDK_INT >= 21) {
   2528             return view.hasNestedScrollingParent();
   2529         }
   2530         if (view instanceof NestedScrollingChild) {
   2531             return ((NestedScrollingChild) view).hasNestedScrollingParent();
   2532         }
   2533         return false;
   2534     }
   2535 
   2536     /**
   2537      * Dispatch one step of a nested scroll in progress.
   2538      *
   2539      * <p>This version of the method just calls
   2540      * {@link #dispatchNestedScroll(View, int, int, int, int, int[], int)} using the touch input
   2541      * type.</p>
   2542      *
   2543      * @param dxConsumed Horizontal distance in pixels consumed by this view during this scroll step
   2544      * @param dyConsumed Vertical distance in pixels consumed by this view during this scroll step
   2545      * @param dxUnconsumed Horizontal scroll distance in pixels not consumed by this view
   2546      * @param dyUnconsumed Horizontal scroll distance in pixels not consumed by this view
   2547      * @param offsetInWindow Optional. If not null, on return this will contain the offset
   2548      *                       in local view coordinates of this view from before this operation
   2549      *                       to after it completes. View implementations may use this to adjust
   2550      *                       expected input coordinate tracking.
   2551      * @return true if the event was dispatched, false if it could not be dispatched.
   2552      */
   2553     @SuppressWarnings("RedundantCast") // Intentionally invoking interface method.
   2554     public static boolean dispatchNestedScroll(@NonNull View view, int dxConsumed, int dyConsumed,
   2555             int dxUnconsumed, int dyUnconsumed, @Nullable int[] offsetInWindow) {
   2556         if (Build.VERSION.SDK_INT >= 21) {
   2557             return view.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed,
   2558                     offsetInWindow);
   2559         }
   2560         if (view instanceof NestedScrollingChild) {
   2561             return ((NestedScrollingChild) view).dispatchNestedScroll(dxConsumed, dyConsumed,
   2562                     dxUnconsumed, dyUnconsumed, offsetInWindow);
   2563         }
   2564         return false;
   2565     }
   2566 
   2567     /**
   2568      * Dispatch one step of a nested scroll in progress before this view consumes any portion of it.
   2569      *
   2570      * <p>This version of the method just calls
   2571      * {@link #dispatchNestedPreScroll(View, int, int, int[], int[], int)} using the touch input
   2572      * type.</p>
   2573      *
   2574      * @param dx Horizontal scroll distance in pixels
   2575      * @param dy Vertical scroll distance in pixels
   2576      * @param consumed Output. If not null, consumed[0] will contain the consumed component of dx
   2577      *                 and consumed[1] the consumed dy.
   2578      * @param offsetInWindow Optional. If not null, on return this will contain the offset
   2579      *                       in local view coordinates of this view from before this operation
   2580      *                       to after it completes. View implementations may use this to adjust
   2581      *                       expected input coordinate tracking.
   2582      * @return true if the parent consumed some or all of the scroll delta
   2583      */
   2584     @SuppressWarnings("RedundantCast") // Intentionally invoking interface method.
   2585     public static boolean dispatchNestedPreScroll(@NonNull View view, int dx, int dy,
   2586             @Nullable int[] consumed, @Nullable int[] offsetInWindow) {
   2587         if (Build.VERSION.SDK_INT >= 21) {
   2588             return view.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow);
   2589         }
   2590         if (view instanceof NestedScrollingChild) {
   2591             return ((NestedScrollingChild) view).dispatchNestedPreScroll(dx, dy, consumed,
   2592                     offsetInWindow);
   2593         }
   2594         return false;
   2595     }
   2596 
   2597     /**
   2598      * Begin a nestable scroll operation along the given axes.
   2599      *
   2600      * <p>A view starting a nested scroll promises to abide by the following contract:</p>
   2601      *
   2602      * <p>The view will call startNestedScroll upon initiating a scroll operation. In the case
   2603      * of a touch scroll this corresponds to the initial {@link MotionEvent#ACTION_DOWN}.
   2604      * In the case of touch scrolling the nested scroll will be terminated automatically in
   2605      * the same manner as {@link ViewParent#requestDisallowInterceptTouchEvent(boolean)}.
   2606      * In the event of programmatic scrolling the caller must explicitly call
   2607      * {@link #stopNestedScroll(View)} to indicate the end of the nested scroll.</p>
   2608      *
   2609      * <p>If <code>startNestedScroll</code> returns true, a cooperative parent was found.
   2610      * If it returns false the caller may ignore the rest of this contract until the next scroll.
   2611      * Calling startNestedScroll while a nested scroll is already in progress will return true.</p>
   2612      *
   2613      * <p>At each incremental step of the scroll the caller should invoke
   2614      * {@link #dispatchNestedPreScroll(View, int, int, int[], int[]) dispatchNestedPreScroll}
   2615      * once it has calculated the requested scrolling delta. If it returns true the nested scrolling
   2616      * parent at least partially consumed the scroll and the caller should adjust the amount it
   2617      * scrolls by.</p>
   2618      *
   2619      * <p>After applying the remainder of the scroll delta the caller should invoke
   2620      * {@link #dispatchNestedScroll(View, int, int, int, int, int[]) dispatchNestedScroll}, passing
   2621      * both the delta consumed and the delta unconsumed. A nested scrolling parent may treat
   2622      * these values differently. See
   2623      * {@link NestedScrollingParent#onNestedScroll(View, int, int, int, int)}.
   2624      * </p>
   2625      *
   2626      * @param axes Flags consisting of a combination of {@link ViewCompat#SCROLL_AXIS_HORIZONTAL}
   2627      *             and/or {@link ViewCompat#SCROLL_AXIS_VERTICAL}.
   2628      * @param type the type of input which cause this scroll event
   2629      * @return true if a cooperative parent was found and nested scrolling has been enabled for
   2630      *         the current gesture.
   2631      *
   2632      * @see #stopNestedScroll(View)
   2633      * @see #dispatchNestedPreScroll(View, int, int, int[], int[])
   2634      * @see #dispatchNestedScroll(View, int, int, int, int, int[])
   2635      */
   2636     public static boolean startNestedScroll(@NonNull View view, @ScrollAxis int axes,
   2637             @NestedScrollType int type) {
   2638         if (view instanceof NestedScrollingChild2) {
   2639             return ((NestedScrollingChild2) view).startNestedScroll(axes, type);
   2640         } else if (type == ViewCompat.TYPE_TOUCH) {
   2641             return startNestedScroll(view, axes);
   2642         }
   2643         return false;
   2644     }
   2645 
   2646     /**
   2647      * Stop a nested scroll in progress.
   2648      *
   2649      * <p>Calling this method when a nested scroll is not currently in progress is harmless.</p>
   2650      *
   2651      * @param type the type of input which cause this scroll event
   2652      * @see #startNestedScroll(View, int)
   2653      */
   2654     public static void stopNestedScroll(@NonNull View view, @NestedScrollType int type) {
   2655         if (view instanceof NestedScrollingChild2) {
   2656             ((NestedScrollingChild2) view).stopNestedScroll(type);
   2657         } else if (type == ViewCompat.TYPE_TOUCH) {
   2658             stopNestedScroll(view);
   2659         }
   2660     }
   2661 
   2662     /**
   2663      * Returns true if this view has a nested scrolling parent.
   2664      *
   2665      * <p>The presence of a nested scrolling parent indicates that this view has initiated
   2666      * a nested scroll and it was accepted by an ancestor view further up the view hierarchy.</p>
   2667      *
   2668      * @param type the type of input which cause this scroll event
   2669      * @return whether this view has a nested scrolling parent
   2670      */
   2671     public static boolean hasNestedScrollingParent(@NonNull View view, @NestedScrollType int type) {
   2672         if (view instanceof NestedScrollingChild2) {
   2673             ((NestedScrollingChild2) view).hasNestedScrollingParent(type);
   2674         } else if (type == ViewCompat.TYPE_TOUCH) {
   2675             return hasNestedScrollingParent(view);
   2676         }
   2677         return false;
   2678     }
   2679 
   2680     /**
   2681      * Dispatch one step of a nested scroll in progress.
   2682      *
   2683      * <p>Implementations of views that support nested scrolling should call this to report
   2684      * info about a scroll in progress to the current nested scrolling parent. If a nested scroll
   2685      * is not currently in progress or nested scrolling is not
   2686      * {@link #isNestedScrollingEnabled(View) enabled} for this view this method does nothing.</p>
   2687      *
   2688      * <p>Compatible View implementations should also call
   2689      * {@link #dispatchNestedPreScroll(View, int, int, int[], int[]) dispatchNestedPreScroll} before
   2690      * consuming a component of the scroll event themselves.</p>
   2691      *
   2692      * @param dxConsumed Horizontal distance in pixels consumed by this view during this scroll step
   2693      * @param dyConsumed Vertical distance in pixels consumed by this view during this scroll step
   2694      * @param dxUnconsumed Horizontal scroll distance in pixels not consumed by this view
   2695      * @param dyUnconsumed Horizontal scroll distance in pixels not consumed by this view
   2696      * @param offsetInWindow Optional. If not null, on return this will contain the offset
   2697      *                       in local view coordinates of this view from before this operation
   2698      *                       to after it completes. View implementations may use this to adjust
   2699      *                       expected input coordinate tracking.
   2700      * @param type the type of input which cause this scroll event
   2701      * @return true if the event was dispatched, false if it could not be dispatched.
   2702      * @see #dispatchNestedPreScroll(View, int, int, int[], int[])
   2703      */
   2704     public static boolean dispatchNestedScroll(@NonNull View view, int dxConsumed, int dyConsumed,
   2705             int dxUnconsumed, int dyUnconsumed, @Nullable int[] offsetInWindow,
   2706             @NestedScrollType int type) {
   2707         if (view instanceof NestedScrollingChild2) {
   2708             return ((NestedScrollingChild2) view).dispatchNestedScroll(dxConsumed, dyConsumed,
   2709                     dxUnconsumed, dyUnconsumed, offsetInWindow, type);
   2710         } else if (type == ViewCompat.TYPE_TOUCH) {
   2711             return dispatchNestedScroll(view, dxConsumed, dyConsumed, dxUnconsumed,
   2712                     dyUnconsumed, offsetInWindow);
   2713         }
   2714         return false;
   2715     }
   2716 
   2717     /**
   2718      * Dispatch one step of a nested scroll in progress before this view consumes any portion of it.
   2719      *
   2720      * <p>Nested pre-scroll events are to nested scroll events what touch intercept is to touch.
   2721      * <code>dispatchNestedPreScroll</code> offers an opportunity for the parent view in a nested
   2722      * scrolling operation to consume some or all of the scroll operation before the child view
   2723      * consumes it.</p>
   2724      *
   2725      * @param dx Horizontal scroll distance in pixels
   2726      * @param dy Vertical scroll distance in pixels
   2727      * @param consumed Output. If not null, consumed[0] will contain the consumed component of dx
   2728      *                 and consumed[1] the consumed dy.
   2729      * @param offsetInWindow Optional. If not null, on return this will contain the offset
   2730      *                       in local view coordinates of this view from before this operation
   2731      *                       to after it completes. View implementations may use this to adjust
   2732      *                       expected input coordinate tracking.
   2733      * @param type the type of input which cause this scroll event
   2734      * @return true if the parent consumed some or all of the scroll delta
   2735      * @see #dispatchNestedScroll(View, int, int, int, int, int[])
   2736      */
   2737     public static boolean dispatchNestedPreScroll(@NonNull View view, int dx, int dy,
   2738             @Nullable int[] consumed, @Nullable int[] offsetInWindow, @NestedScrollType int type) {
   2739         if (view instanceof NestedScrollingChild2) {
   2740             return ((NestedScrollingChild2) view).dispatchNestedPreScroll(dx, dy, consumed,
   2741                     offsetInWindow, type);
   2742         } else if (type == ViewCompat.TYPE_TOUCH) {
   2743             return dispatchNestedPreScroll(view, dx, dy, consumed, offsetInWindow);
   2744         }
   2745         return false;
   2746     }
   2747 
   2748     /**
   2749      * Dispatch a fling to a nested scrolling parent.
   2750      *
   2751      * <p>This method should be used to indicate that a nested scrolling child has detected
   2752      * suitable conditions for a fling. Generally this means that a touch scroll has ended with a
   2753      * {@link VelocityTracker velocity} in the direction of scrolling that meets or exceeds
   2754      * the {@link ViewConfiguration#getScaledMinimumFlingVelocity() minimum fling velocity}
   2755      * along a scrollable axis.</p>
   2756      *
   2757      * <p>If a nested scrolling child view would normally fling but it is at the edge of
   2758      * its own content, it can use this method to delegate the fling to its nested scrolling
   2759      * parent instead. The parent may optionally consume the fling or observe a child fling.</p>
   2760      *
   2761      * @param velocityX Horizontal fling velocity in pixels per second
   2762      * @param velocityY Vertical fling velocity in pixels per second
   2763      * @param consumed true if the child consumed the fling, false otherwise
   2764      * @return true if the nested scrolling parent consumed or otherwise reacted to the fling
   2765      */
   2766     @SuppressWarnings("RedundantCast") // Intentionally invoking interface method.
   2767     public static boolean dispatchNestedFling(@NonNull View view, float velocityX, float velocityY,
   2768             boolean consumed) {
   2769         if (Build.VERSION.SDK_INT >= 21) {
   2770             return view.dispatchNestedFling(velocityX, velocityY, consumed);
   2771         }
   2772         if (view instanceof NestedScrollingChild) {
   2773             return ((NestedScrollingChild) view).dispatchNestedFling(velocityX, velocityY,
   2774                     consumed);
   2775         }
   2776         return false;
   2777     }
   2778 
   2779     /**
   2780      * Dispatch a fling to a nested scrolling parent before it is processed by this view.
   2781      *
   2782      * <p>Nested pre-fling events are to nested fling events what touch intercept is to touch
   2783      * and what nested pre-scroll is to nested scroll. <code>dispatchNestedPreFling</code>
   2784      * offsets an opportunity for the parent view in a nested fling to fully consume the fling
   2785      * before the child view consumes it. If this method returns <code>true</code>, a nested
   2786      * parent view consumed the fling and this view should not scroll as a result.</p>
   2787      *
   2788      * <p>For a better user experience, only one view in a nested scrolling chain should consume
   2789      * the fling at a time. If a parent view consumed the fling this method will return false.
   2790      * Custom view implementations should account for this in two ways:</p>
   2791      *
   2792      * <ul>
   2793      *     <li>If a custom view is paged and needs to settle to a fixed page-point, do not
   2794      *     call <code>dispatchNestedPreFling</code>; consume the fling and settle to a valid
   2795      *     position regardless.</li>
   2796      *     <li>If a nested parent does consume the fling, this view should not scroll at all,
   2797      *     even to settle back to a valid idle position.</li>
   2798      * </ul>
   2799      *
   2800      * <p>Views should also not offer fling velocities to nested parent views along an axis
   2801      * where scrolling is not currently supported; a {@link android.widget.ScrollView ScrollView}
   2802      * should not offer a horizontal fling velocity to its parents since scrolling along that
   2803      * axis is not permitted and carrying velocity along that motion does not make sense.</p>
   2804      *
   2805      * @param velocityX Horizontal fling velocity in pixels per second
   2806      * @param velocityY Vertical fling velocity in pixels per second
   2807      * @return true if a nested scrolling parent consumed the fling
   2808      */
   2809     @SuppressWarnings("RedundantCast") // Intentionally invoking interface method.
   2810     public static boolean dispatchNestedPreFling(@NonNull View view, float velocityX,
   2811             float velocityY) {
   2812         if (Build.VERSION.SDK_INT >= 21) {
   2813             return view.dispatchNestedPreFling(velocityX, velocityY);
   2814         }
   2815         if (view instanceof NestedScrollingChild) {
   2816             return ((NestedScrollingChild) view).dispatchNestedPreFling(velocityX, velocityY);
   2817         }
   2818         return false;
   2819     }
   2820 
   2821     /**
   2822      * Returns whether the view hierarchy is currently undergoing a layout pass. This
   2823      * information is useful to avoid situations such as calling {@link View#requestLayout()}
   2824      * during a layout pass.
   2825      * <p>
   2826      * Compatibility:
   2827      * <ul>
   2828      *     <li>API &lt; 18: Always returns {@code false}</li>
   2829      * </ul>
   2830      *
   2831      * @return whether the view hierarchy is currently undergoing a layout pass
   2832      */
   2833     public static boolean isInLayout(@NonNull View view) {
   2834         if (Build.VERSION.SDK_INT >= 18) {
   2835             return view.isInLayout();
   2836         }
   2837         return false;
   2838     }
   2839 
   2840     /**
   2841      * Returns true if {@code view} has been through at least one layout since it
   2842      * was last attached to or detached from a window.
   2843      */
   2844     public static boolean isLaidOut(@NonNull View view) {
   2845         if (Build.VERSION.SDK_INT >= 19) {
   2846             return view.isLaidOut();
   2847         }
   2848         return view.getWidth() > 0 && view.getHeight() > 0;
   2849     }
   2850 
   2851     /**
   2852      * Returns whether layout direction has been resolved.
   2853      * <p>
   2854      * Compatibility:
   2855      * <ul>
   2856      *     <li>API &lt; 19: Always returns {@code false}</li>
   2857      * </ul>
   2858      *
   2859      * @return true if layout direction has been resolved.
   2860      */
   2861     public static boolean isLayoutDirectionResolved(@NonNull View view) {
   2862         if (Build.VERSION.SDK_INT >= 19) {
   2863             return view.isLayoutDirectionResolved();
   2864         }
   2865         return false;
   2866     }
   2867 
   2868     /**
   2869      * The visual z position of this view, in pixels. This is equivalent to the
   2870      * {@link #setTranslationZ(View, float) translationZ} property plus the current
   2871      * {@link #getElevation(View) elevation} property.
   2872      *
   2873      * @return The visual z position of this view, in pixels.
   2874      */
   2875     public static float getZ(@NonNull View view) {
   2876         if (Build.VERSION.SDK_INT >= 21) {
   2877             return view.getZ();
   2878         }
   2879         return 0f;
   2880     }
   2881 
   2882     /**
   2883      * Sets the visual z position of this view, in pixels. This is equivalent to setting the
   2884      * {@link #setTranslationZ(View, float) translationZ} property to be the difference between
   2885      * the x value passed in and the current {@link #getElevation(View) elevation} property.
   2886      * <p>
   2887      * Compatibility:
   2888      * <ul>
   2889      *     <li>API &lt; 21: No-op
   2890      * </ul>
   2891      *
   2892      * @param z The visual z position of this view, in pixels.
   2893      */
   2894     public static void setZ(@NonNull View view, float z) {
   2895         if (Build.VERSION.SDK_INT >= 21) {
   2896             view.setZ(z);
   2897         }
   2898     }
   2899 
   2900     /**
   2901      * Offset this view's vertical location by the specified number of pixels.
   2902      *
   2903      * @param offset the number of pixels to offset the view by
   2904      */
   2905     public static void offsetTopAndBottom(@NonNull View view, int offset) {
   2906         if (Build.VERSION.SDK_INT >= 23) {
   2907             view.offsetTopAndBottom(offset);
   2908         } else if (Build.VERSION.SDK_INT >= 21) {
   2909             final Rect parentRect = getEmptyTempRect();
   2910             boolean needInvalidateWorkaround = false;
   2911 
   2912             final ViewParent parent = view.getParent();
   2913             if (parent instanceof View) {
   2914                 final View p = (View) parent;
   2915                 parentRect.set(p.getLeft(), p.getTop(), p.getRight(), p.getBottom());
   2916                 // If the view currently does not currently intersect the parent (and is therefore
   2917                 // not displayed) we may need need to invalidate
   2918                 needInvalidateWorkaround = !parentRect.intersects(view.getLeft(), view.getTop(),
   2919                         view.getRight(), view.getBottom());
   2920             }
   2921 
   2922             // Now offset, invoking the API 14+ implementation (which contains its own workarounds)
   2923             compatOffsetTopAndBottom(view, offset);
   2924 
   2925             // The view has now been offset, so let's intersect the Rect and invalidate where
   2926             // the View is now displayed
   2927             if (needInvalidateWorkaround && parentRect.intersect(view.getLeft(), view.getTop(),
   2928                     view.getRight(), view.getBottom())) {
   2929                 ((View) parent).invalidate(parentRect);
   2930             }
   2931         } else {
   2932             compatOffsetTopAndBottom(view, offset);
   2933         }
   2934     }
   2935 
   2936     private static void compatOffsetTopAndBottom(View view, int offset) {
   2937         view.offsetTopAndBottom(offset);
   2938         if (view.getVisibility() == View.VISIBLE) {
   2939             tickleInvalidationFlag(view);
   2940 
   2941             ViewParent parent = view.getParent();
   2942             if (parent instanceof View) {
   2943                 tickleInvalidationFlag((View) parent);
   2944             }
   2945         }
   2946     }
   2947 
   2948     /**
   2949      * Offset this view's horizontal location by the specified amount of pixels.
   2950      *
   2951      * @param offset the number of pixels to offset the view by
   2952      */
   2953     public static void offsetLeftAndRight(@NonNull View view, int offset) {
   2954         if (Build.VERSION.SDK_INT >= 23) {
   2955             view.offsetLeftAndRight(offset);
   2956         } else if (Build.VERSION.SDK_INT >= 21) {
   2957             final Rect parentRect = getEmptyTempRect();
   2958             boolean needInvalidateWorkaround = false;
   2959 
   2960             final ViewParent parent = view.getParent();
   2961             if (parent instanceof View) {
   2962                 final View p = (View) parent;
   2963                 parentRect.set(p.getLeft(), p.getTop(), p.getRight(), p.getBottom());
   2964                 // If the view currently does not currently intersect the parent (and is therefore
   2965                 // not displayed) we may need need to invalidate
   2966                 needInvalidateWorkaround = !parentRect.intersects(view.getLeft(), view.getTop(),
   2967                         view.getRight(), view.getBottom());
   2968             }
   2969 
   2970             // Now offset, invoking the API 14+ implementation (which contains its own workarounds)
   2971             compatOffsetLeftAndRight(view, offset);
   2972 
   2973             // The view has now been offset, so let's intersect the Rect and invalidate where
   2974             // the View is now displayed
   2975             if (needInvalidateWorkaround && parentRect.intersect(view.getLeft(), view.getTop(),
   2976                     view.getRight(), view.getBottom())) {
   2977                 ((View) parent).invalidate(parentRect);
   2978             }
   2979         } else {
   2980             compatOffsetLeftAndRight(view, offset);
   2981         }
   2982     }
   2983 
   2984     private static void compatOffsetLeftAndRight(View view, int offset) {
   2985         view.offsetLeftAndRight(offset);
   2986         if (view.getVisibility() == View.VISIBLE) {
   2987             tickleInvalidationFlag(view);
   2988 
   2989             ViewParent parent = view.getParent();
   2990             if (parent instanceof View) {
   2991                 tickleInvalidationFlag((View) parent);
   2992             }
   2993         }
   2994     }
   2995 
   2996     private static void tickleInvalidationFlag(View view) {
   2997         final float y = view.getTranslationY();
   2998         view.setTranslationY(y + 1);
   2999         view.setTranslationY(y);
   3000     }
   3001 
   3002     /**
   3003      * Sets a rectangular area on this view to which the view will be clipped
   3004      * when it is drawn. Setting the value to null will remove the clip bounds
   3005      * and the view will draw normally, using its full bounds.
   3006      *
   3007      * <p>Prior to API 18 this does nothing.</p>
   3008      *
   3009      * @param view       The view to set clipBounds.
   3010      * @param clipBounds The rectangular area, in the local coordinates of
   3011      * this view, to which future drawing operations will be clipped.
   3012      */
   3013     public static void setClipBounds(@NonNull View view, Rect clipBounds) {
   3014         if (Build.VERSION.SDK_INT >= 18) {
   3015             view.setClipBounds(clipBounds);
   3016         }
   3017     }
   3018 
   3019     /**
   3020      * Returns a copy of the current {@link #setClipBounds(View, Rect)}.
   3021      *
   3022      * <p>Prior to API 18 this will return null.</p>
   3023      *
   3024      * @return A copy of the current clip bounds if clip bounds are set,
   3025      * otherwise null.
   3026      */
   3027     @Nullable
   3028     public static Rect getClipBounds(@NonNull View view) {
   3029         if (Build.VERSION.SDK_INT >= 18) {
   3030             return view.getClipBounds();
   3031         }
   3032         return null;
   3033     }
   3034 
   3035     /**
   3036      * Returns true if the provided view is currently attached to a window.
   3037      */
   3038     public static boolean isAttachedToWindow(@NonNull View view) {
   3039         if (Build.VERSION.SDK_INT >= 19) {
   3040             return view.isAttachedToWindow();
   3041         }
   3042         return view.getWindowToken() != null;
   3043     }
   3044 
   3045     /**
   3046      * Returns whether the provided view has an attached {@link View.OnClickListener}.
   3047      *
   3048      * @return true if there is a listener, false if there is none.
   3049      */
   3050     public static boolean hasOnClickListeners(@NonNull View view) {
   3051         if (Build.VERSION.SDK_INT >= 15) {
   3052             return view.hasOnClickListeners();
   3053         }
   3054         return false;
   3055     }
   3056 
   3057     /**
   3058      * Sets the state of all scroll indicators.
   3059      * <p>
   3060      * See {@link #setScrollIndicators(View, int, int)} for usage information.
   3061      *
   3062      * @param indicators a bitmask of indicators that should be enabled, or
   3063      *                   {@code 0} to disable all indicators
   3064      *
   3065      * @see #setScrollIndicators(View, int, int)
   3066      * @see #getScrollIndicators(View)
   3067      */
   3068     public static void setScrollIndicators(@NonNull View view, @ScrollIndicators int indicators) {
   3069         if (Build.VERSION.SDK_INT >= 23) {
   3070             view.setScrollIndicators(indicators);
   3071         }
   3072     }
   3073 
   3074     /**
   3075      * Sets the state of the scroll indicators specified by the mask. To change
   3076      * all scroll indicators at once, see {@link #setScrollIndicators(View, int)}.
   3077      * <p>
   3078      * When a scroll indicator is enabled, it will be displayed if the view
   3079      * can scroll in the direction of the indicator.
   3080      * <p>
   3081      * Multiple indicator types may be enabled or disabled by passing the
   3082      * logical OR of the desired types. If multiple types are specified, they
   3083      * will all be set to the same enabled state.
   3084      * <p>
   3085      * For example, to enable the top scroll indicatorExample: {@code setScrollIndicators}
   3086      *
   3087      * @param indicators the indicator direction, or the logical OR of multiple
   3088      *             indicator directions. One or more of:
   3089      *             <ul>
   3090      *               <li>{@link #SCROLL_INDICATOR_TOP}</li>
   3091      *               <li>{@link #SCROLL_INDICATOR_BOTTOM}</li>
   3092      *               <li>{@link #SCROLL_INDICATOR_LEFT}</li>
   3093      *               <li>{@link #SCROLL_INDICATOR_RIGHT}</li>
   3094      *               <li>{@link #SCROLL_INDICATOR_START}</li>
   3095      *               <li>{@link #SCROLL_INDICATOR_END}</li>
   3096      *             </ul>
   3097      *
   3098      * @see #setScrollIndicators(View, int)
   3099      * @see #getScrollIndicators(View)
   3100      */
   3101     public static void setScrollIndicators(@NonNull View view, @ScrollIndicators int indicators,
   3102             @ScrollIndicators int mask) {
   3103         if (Build.VERSION.SDK_INT >= 23) {
   3104             view.setScrollIndicators(indicators, mask);
   3105         }
   3106     }
   3107 
   3108     /**
   3109      * Returns a bitmask representing the enabled scroll indicators.
   3110      * <p>
   3111      * For example, if the top and left scroll indicators are enabled and all
   3112      * other indicators are disabled, the return value will be
   3113      * {@code ViewCompat.SCROLL_INDICATOR_TOP | ViewCompat.SCROLL_INDICATOR_LEFT}.
   3114      * <p>
   3115      * To check whether the bottom scroll indicator is enabled, use the value
   3116      * of {@code (ViewCompat.getScrollIndicators(view) & ViewCompat.SCROLL_INDICATOR_BOTTOM) != 0}.
   3117      *
   3118      * @return a bitmask representing the enabled scroll indicators
   3119      */
   3120     public static int getScrollIndicators(@NonNull View view) {
   3121         if (Build.VERSION.SDK_INT >= 23) {
   3122             return view.getScrollIndicators();
   3123         }
   3124         return 0;
   3125     }
   3126 
   3127     /**
   3128      * Set the pointer icon for the current view.
   3129      * @param pointerIcon A PointerIconCompat instance which will be shown when the mouse hovers.
   3130      */
   3131     public static void setPointerIcon(@NonNull View view, PointerIconCompat pointerIcon) {
   3132         if (Build.VERSION.SDK_INT >= 24) {
   3133             view.setPointerIcon((PointerIcon) (pointerIcon != null
   3134                     ? pointerIcon.getPointerIcon() : null));
   3135         }
   3136     }
   3137 
   3138     /**
   3139      * Gets the logical display to which the view's window has been attached.
   3140      * <p>
   3141      * Compatibility:
   3142      * <ul>
   3143      * <li>API &lt; 17: Returns the default display when the view is attached. Otherwise, null.
   3144      * </ul>
   3145      *
   3146      * @return The logical display, or null if the view is not currently attached to a window.
   3147      */
   3148     @Nullable
   3149     public static Display getDisplay(@NonNull View view) {
   3150         if (Build.VERSION.SDK_INT >= 17) {
   3151             return view.getDisplay();
   3152         }
   3153         if (isAttachedToWindow(view)) {
   3154             final WindowManager wm = (WindowManager) view.getContext().getSystemService(
   3155                     Context.WINDOW_SERVICE);
   3156             return wm.getDefaultDisplay();
   3157         }
   3158         return null;
   3159     }
   3160 
   3161     /**
   3162      * Sets the tooltip for the view.
   3163      *
   3164      * <p>Prior to API 26 this does nothing. Use TooltipCompat class from v7 appcompat library
   3165      * for a compatible tooltip implementation.</p>
   3166      *
   3167      * @param tooltipText the tooltip text
   3168      */
   3169     public static void setTooltipText(@NonNull View view, @Nullable CharSequence tooltipText) {
   3170         if (Build.VERSION.SDK_INT >= 26) {
   3171             view.setTooltipText(tooltipText);
   3172         }
   3173     }
   3174 
   3175     /**
   3176      * Start the drag and drop operation.
   3177      */
   3178     public static boolean startDragAndDrop(@NonNull View v, ClipData data,
   3179             View.DragShadowBuilder shadowBuilder, Object localState, int flags) {
   3180         if (Build.VERSION.SDK_INT >= 24) {
   3181             return v.startDragAndDrop(data, shadowBuilder, localState, flags);
   3182         } else {
   3183             return v.startDrag(data, shadowBuilder, localState, flags);
   3184         }
   3185     }
   3186 
   3187     /**
   3188      * Cancel the drag and drop operation.
   3189      */
   3190     public static void cancelDragAndDrop(@NonNull View v) {
   3191         if (Build.VERSION.SDK_INT >= 24) {
   3192             v.cancelDragAndDrop();
   3193         }
   3194     }
   3195 
   3196     /**
   3197      * Update the drag shadow while drag and drop is in progress.
   3198      */
   3199     public static void updateDragShadow(@NonNull View v, View.DragShadowBuilder shadowBuilder) {
   3200         if (Build.VERSION.SDK_INT >= 24) {
   3201             v.updateDragShadow(shadowBuilder);
   3202         }
   3203     }
   3204 
   3205     /**
   3206      * Gets the ID of the next keyboard navigation cluster root.
   3207      *
   3208      * @return the next keyboard navigation cluster ID, or {@link View#NO_ID} if the framework
   3209      *         should decide automatically or API < 26.
   3210      */
   3211     public static int getNextClusterForwardId(@NonNull View view) {
   3212         if (Build.VERSION.SDK_INT >= 26) {
   3213             return view.getNextClusterForwardId();
   3214         }
   3215         return View.NO_ID;
   3216     }
   3217 
   3218     /**
   3219      * Sets the ID of the next keyboard navigation cluster root view. Does nothing if {@code view}
   3220      * is not a keyboard navigation cluster or if API < 26.
   3221      *
   3222      * @param nextClusterForwardId next cluster ID, or {@link View#NO_ID} if the framework
   3223      *                             should decide automatically.
   3224      */
   3225     public static void setNextClusterForwardId(@NonNull View view, int nextClusterForwardId) {
   3226         if (Build.VERSION.SDK_INT >= 26) {
   3227             view.setNextClusterForwardId(nextClusterForwardId);
   3228         }
   3229     }
   3230 
   3231     /**
   3232      * Returns whether {@code view} is a root of a keyboard navigation cluster. Always returns
   3233      * {@code false} on API < 26.
   3234      *
   3235      * @return {@code true} if this view is a root of a cluster, or {@code false} otherwise.
   3236      */
   3237     public static boolean isKeyboardNavigationCluster(@NonNull View view) {
   3238         if (Build.VERSION.SDK_INT >= 26) {
   3239             return view.isKeyboardNavigationCluster();
   3240         }
   3241         return false;
   3242     }
   3243 
   3244     /**
   3245      * Set whether {@code view} is a root of a keyboard navigation cluster. Does nothing if
   3246      * API < 26.
   3247      *
   3248      * @param isCluster {@code true} to mark {@code view} as the root of a cluster, {@code false}
   3249      *                  to unmark.
   3250      */
   3251     public static void setKeyboardNavigationCluster(@NonNull View view, boolean isCluster) {
   3252         if (Build.VERSION.SDK_INT >= 26) {
   3253             view.setKeyboardNavigationCluster(isCluster);
   3254         }
   3255     }
   3256 
   3257     /**
   3258      * Returns whether {@code view} should receive focus when the focus is restored for the view
   3259      * hierarchy containing it. Returns {@code false} on API < 26.
   3260      * <p>
   3261      * Focus gets restored for a view hierarchy when the root of the hierarchy gets added to a
   3262      * window or serves as a target of cluster navigation.
   3263      *
   3264      * @return {@code true} if {@code view} is the default-focus view, {@code false} otherwise.
   3265      */
   3266     public static boolean isFocusedByDefault(@NonNull View view) {
   3267         if (Build.VERSION.SDK_INT >= 26) {
   3268             return view.isFocusedByDefault();
   3269         }
   3270         return false;
   3271     }
   3272 
   3273     /**
   3274      * Sets whether {@code view} should receive focus when the focus is restored for the view
   3275      * hierarchy containing it.
   3276      * <p>
   3277      * Focus gets restored for a view hierarchy when the root of the hierarchy gets added to a
   3278      * window or serves as a target of cluster navigation.
   3279      * <p>
   3280      * Does nothing on API < 26.
   3281      *
   3282      * @param isFocusedByDefault {@code true} to set {@code view} as the default-focus view,
   3283      *                           {@code false} otherwise.
   3284      */
   3285     public static void setFocusedByDefault(@NonNull View view, boolean isFocusedByDefault) {
   3286         if (Build.VERSION.SDK_INT >= 26) {
   3287             view.setFocusedByDefault(isFocusedByDefault);
   3288         }
   3289     }
   3290 
   3291     /**
   3292      * Find the nearest keyboard navigation cluster in the specified direction.
   3293      * This does not actually give focus to that cluster.
   3294      *
   3295      * @param currentCluster The starting point of the search. {@code null} means the current
   3296      *                       cluster is not found yet.
   3297      * @param direction Direction to look.
   3298      *
   3299      * @return the nearest keyboard navigation cluster in the specified direction, or {@code null}
   3300      *         if one can't be found or if API < 26.
   3301      */
   3302     public static View keyboardNavigationClusterSearch(@NonNull View view, View currentCluster,
   3303             @FocusDirection int direction) {
   3304         if (Build.VERSION.SDK_INT >= 26) {
   3305             return view.keyboardNavigationClusterSearch(currentCluster, direction);
   3306         }
   3307         return null;
   3308     }
   3309 
   3310     /**
   3311      * Adds any keyboard navigation cluster roots that are descendants of {@code view} (
   3312      * including {@code view} if it is a cluster root itself) to {@code views}. Does nothing
   3313      * on API < 26.
   3314      *
   3315      * @param views collection of keyboard navigation cluster roots found so far.
   3316      * @param direction direction to look.
   3317      */
   3318     public static void addKeyboardNavigationClusters(@NonNull View view,
   3319             @NonNull Collection<View> views, int direction) {
   3320         if (Build.VERSION.SDK_INT >= 26) {
   3321             view.addKeyboardNavigationClusters(views, direction);
   3322         }
   3323     }
   3324 
   3325     /**
   3326      * Gives focus to the default-focus view in the view hierarchy rooted at {@code view}.
   3327      * If the default-focus view cannot be found or if API < 26, this falls back to calling
   3328      * {@link View#requestFocus(int)}.
   3329      *
   3330      * @return {@code true} if {@code view} or one of its descendants took focus, {@code false}
   3331      *         otherwise.
   3332      */
   3333     public static boolean restoreDefaultFocus(@NonNull View view) {
   3334         if (Build.VERSION.SDK_INT >= 26) {
   3335             return view.restoreDefaultFocus();
   3336         }
   3337         return view.requestFocus();
   3338     }
   3339 
   3340     /**
   3341      * Returns true if this view is focusable or if it contains a reachable View
   3342      * for which {@link View#hasExplicitFocusable()} returns {@code true}.
   3343      * A "reachable hasExplicitFocusable()" is a view whose parents do not block descendants focus.
   3344      * Only {@link View#VISIBLE} views for which {@link View#getFocusable()} would return
   3345      * {@link View#FOCUSABLE} are considered focusable.
   3346      *
   3347      * <p>This method preserves the pre-{@link Build.VERSION_CODES#O} behavior of
   3348      * {@link View#hasFocusable()} in that only views explicitly set focusable will cause
   3349      * this method to return true. A view set to {@link View#FOCUSABLE_AUTO} that resolves
   3350      * to focusable will not.</p>
   3351      *
   3352      * @return {@code true} if the view is focusable or if the view contains a focusable
   3353      *         view, {@code false} otherwise
   3354      */
   3355     public static boolean hasExplicitFocusable(@NonNull View view) {
   3356         if (Build.VERSION.SDK_INT >= 26) {
   3357             return view.hasExplicitFocusable();
   3358         }
   3359         return view.hasFocusable();
   3360     }
   3361 
   3362     /**
   3363      * Generate a value suitable for use in {@link View#setId(int)}.
   3364      * This value will not collide with ID values generated at build time by aapt for R.id.
   3365      *
   3366      * @return a generated ID value
   3367      */
   3368     public static int generateViewId() {
   3369         if (Build.VERSION.SDK_INT >= 17) {
   3370             return View.generateViewId();
   3371         }
   3372         for (;;) {
   3373             final int result = sNextGeneratedId.get();
   3374             // aapt-generated IDs have the high byte nonzero; clamp to the range under that.
   3375             int newValue = result + 1;
   3376             if (newValue > 0x00FFFFFF) newValue = 1; // Roll over to 1, not 0.
   3377             if (sNextGeneratedId.compareAndSet(result, newValue)) {
   3378                 return result;
   3379             }
   3380         }
   3381     }
   3382 
   3383     protected ViewCompat() {}
   3384 }
   3385