Home | History | Annotate | Download | only in view
      1 /*
      2  * Copyright (C) 2006 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 android.view;
     18 
     19 import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
     20 
     21 import android.animation.LayoutTransition;
     22 import android.annotation.CallSuper;
     23 import android.annotation.IdRes;
     24 import android.annotation.NonNull;
     25 import android.annotation.TestApi;
     26 import android.annotation.UiThread;
     27 import android.annotation.UnsupportedAppUsage;
     28 import android.content.ClipData;
     29 import android.content.Context;
     30 import android.content.Intent;
     31 import android.content.pm.PackageManager;
     32 import android.content.res.Configuration;
     33 import android.content.res.TypedArray;
     34 import android.graphics.Bitmap;
     35 import android.graphics.Canvas;
     36 import android.graphics.Color;
     37 import android.graphics.Insets;
     38 import android.graphics.Matrix;
     39 import android.graphics.Paint;
     40 import android.graphics.PointF;
     41 import android.graphics.Rect;
     42 import android.graphics.RectF;
     43 import android.graphics.Region;
     44 import android.os.Build;
     45 import android.os.Bundle;
     46 import android.os.Parcelable;
     47 import android.os.SystemClock;
     48 import android.util.AttributeSet;
     49 import android.util.Log;
     50 import android.util.Pools;
     51 import android.util.Pools.SynchronizedPool;
     52 import android.util.SparseArray;
     53 import android.util.SparseBooleanArray;
     54 import android.view.WindowInsetsAnimationListener.InsetsAnimation;
     55 import android.view.accessibility.AccessibilityEvent;
     56 import android.view.accessibility.AccessibilityManager;
     57 import android.view.accessibility.AccessibilityNodeInfo;
     58 import android.view.animation.Animation;
     59 import android.view.animation.AnimationUtils;
     60 import android.view.animation.LayoutAnimationController;
     61 import android.view.animation.Transformation;
     62 import android.view.autofill.Helper;
     63 import android.view.inspector.InspectableProperty;
     64 import android.view.inspector.InspectableProperty.EnumEntry;
     65 
     66 import com.android.internal.R;
     67 
     68 import java.util.ArrayList;
     69 import java.util.Collection;
     70 import java.util.Collections;
     71 import java.util.HashSet;
     72 import java.util.List;
     73 import java.util.Map;
     74 import java.util.function.Predicate;
     75 
     76 /**
     77  * <p>
     78  * A <code>ViewGroup</code> is a special view that can contain other views
     79  * (called children.) The view group is the base class for layouts and views
     80  * containers. This class also defines the
     81  * {@link android.view.ViewGroup.LayoutParams} class which serves as the base
     82  * class for layouts parameters.
     83  * </p>
     84  *
     85  * <p>
     86  * Also see {@link LayoutParams} for layout attributes.
     87  * </p>
     88  *
     89  * <div class="special reference">
     90  * <h3>Developer Guides</h3>
     91  * <p>For more information about creating user interface layouts, read the
     92  * <a href="{@docRoot}guide/topics/ui/declaring-layout.html">XML Layouts</a> developer
     93  * guide.</p></div>
     94  *
     95  * <p>Here is a complete implementation of a custom ViewGroup that implements
     96  * a simple {@link android.widget.FrameLayout} along with the ability to stack
     97  * children in left and right gutters.</p>
     98  *
     99  * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/CustomLayout.java
    100  *      Complete}
    101  *
    102  * <p>If you are implementing XML layout attributes as shown in the example, this is the
    103  * corresponding definition for them that would go in <code>res/values/attrs.xml</code>:</p>
    104  *
    105  * {@sample development/samples/ApiDemos/res/values/attrs.xml CustomLayout}
    106  *
    107  * <p>Finally the layout manager can be used in an XML layout like so:</p>
    108  *
    109  * {@sample development/samples/ApiDemos/res/layout/custom_layout.xml Complete}
    110  *
    111  * @attr ref android.R.styleable#ViewGroup_clipChildren
    112  * @attr ref android.R.styleable#ViewGroup_clipToPadding
    113  * @attr ref android.R.styleable#ViewGroup_layoutAnimation
    114  * @attr ref android.R.styleable#ViewGroup_animationCache
    115  * @attr ref android.R.styleable#ViewGroup_persistentDrawingCache
    116  * @attr ref android.R.styleable#ViewGroup_alwaysDrawnWithCache
    117  * @attr ref android.R.styleable#ViewGroup_addStatesFromChildren
    118  * @attr ref android.R.styleable#ViewGroup_descendantFocusability
    119  * @attr ref android.R.styleable#ViewGroup_animateLayoutChanges
    120  * @attr ref android.R.styleable#ViewGroup_splitMotionEvents
    121  * @attr ref android.R.styleable#ViewGroup_layoutMode
    122  */
    123 @UiThread
    124 public abstract class ViewGroup extends View implements ViewParent, ViewManager {
    125     private static final String TAG = "ViewGroup";
    126 
    127     @UnsupportedAppUsage
    128     private static final boolean DBG = false;
    129 
    130     /**
    131      * Views which have been hidden or removed which need to be animated on
    132      * their way out.
    133      * This field should be made private, so it is hidden from the SDK.
    134      * {@hide}
    135      */
    136     @UnsupportedAppUsage
    137     protected ArrayList<View> mDisappearingChildren;
    138 
    139     /**
    140      * Listener used to propagate events indicating when children are added
    141      * and/or removed from a view group.
    142      * This field should be made private, so it is hidden from the SDK.
    143      * {@hide}
    144      */
    145     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768704)
    146     protected OnHierarchyChangeListener mOnHierarchyChangeListener;
    147 
    148     // The view contained within this ViewGroup that has or contains focus.
    149     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
    150     private View mFocused;
    151     // The view contained within this ViewGroup (excluding nested keyboard navigation clusters)
    152     // that is or contains a default-focus view.
    153     private View mDefaultFocus;
    154     // The last child of this ViewGroup which held focus within the current cluster
    155     View mFocusedInCluster;
    156 
    157     /**
    158      * A Transformation used when drawing children, to
    159      * apply on the child being drawn.
    160      */
    161     private Transformation mChildTransformation;
    162 
    163     /**
    164      * Used to track the current invalidation region.
    165      */
    166     RectF mInvalidateRegion;
    167 
    168     /**
    169      * A Transformation used to calculate a correct
    170      * invalidation area when the application is autoscaled.
    171      */
    172     Transformation mInvalidationTransformation;
    173 
    174     // Current frontmost child that can accept drag and lies under the drag location.
    175     // Used only to generate ENTER/EXIT events for pre-Nougat aps.
    176     private View mCurrentDragChild;
    177 
    178     // Metadata about the ongoing drag
    179     private DragEvent mCurrentDragStartEvent;
    180     private boolean mIsInterestedInDrag;
    181     private HashSet<View> mChildrenInterestedInDrag;
    182 
    183     // Used during drag dispatch
    184     private PointF mLocalPoint;
    185 
    186     // Lazily-created holder for point computations.
    187     private float[] mTempPoint;
    188 
    189     // Layout animation
    190     private LayoutAnimationController mLayoutAnimationController;
    191     private Animation.AnimationListener mAnimationListener;
    192 
    193     // First touch target in the linked list of touch targets.
    194     @UnsupportedAppUsage
    195     private TouchTarget mFirstTouchTarget;
    196 
    197     // For debugging only.  You can see these in hierarchyviewer.
    198     @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"})
    199     @ViewDebug.ExportedProperty(category = "events")
    200     private long mLastTouchDownTime;
    201     @ViewDebug.ExportedProperty(category = "events")
    202     private int mLastTouchDownIndex = -1;
    203     @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"})
    204     @ViewDebug.ExportedProperty(category = "events")
    205     private float mLastTouchDownX;
    206     @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"})
    207     @ViewDebug.ExportedProperty(category = "events")
    208     private float mLastTouchDownY;
    209 
    210     // First hover target in the linked list of hover targets.
    211     // The hover targets are children which have received ACTION_HOVER_ENTER.
    212     // They might not have actually handled the hover event, but we will
    213     // continue sending hover events to them as long as the pointer remains over
    214     // their bounds and the view group does not intercept hover.
    215     private HoverTarget mFirstHoverTarget;
    216 
    217     // True if the view group itself received a hover event.
    218     // It might not have actually handled the hover event.
    219     private boolean mHoveredSelf;
    220 
    221     // The child capable of showing a tooltip and currently under the pointer.
    222     private View mTooltipHoverTarget;
    223 
    224     // True if the view group is capable of showing a tooltip and the pointer is directly
    225     // over the view group but not one of its child views.
    226     private boolean mTooltipHoveredSelf;
    227 
    228     /**
    229      * Internal flags.
    230      *
    231      * This field should be made private, so it is hidden from the SDK.
    232      * {@hide}
    233      */
    234     @ViewDebug.ExportedProperty(flagMapping = {
    235             @ViewDebug.FlagToString(mask = FLAG_CLIP_CHILDREN, equals = FLAG_CLIP_CHILDREN,
    236                     name = "CLIP_CHILDREN"),
    237             @ViewDebug.FlagToString(mask = FLAG_CLIP_TO_PADDING, equals = FLAG_CLIP_TO_PADDING,
    238                     name = "CLIP_TO_PADDING"),
    239             @ViewDebug.FlagToString(mask = FLAG_PADDING_NOT_NULL, equals = FLAG_PADDING_NOT_NULL,
    240                     name = "PADDING_NOT_NULL")
    241     }, formatToHexString = true)
    242     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769411)
    243     protected int mGroupFlags;
    244 
    245     /**
    246      * Either {@link #LAYOUT_MODE_CLIP_BOUNDS} or {@link #LAYOUT_MODE_OPTICAL_BOUNDS}.
    247      */
    248     private int mLayoutMode = LAYOUT_MODE_UNDEFINED;
    249 
    250     /**
    251      * NOTE: If you change the flags below make sure to reflect the changes
    252      *       the DisplayList class
    253      */
    254 
    255     // When set, ViewGroup invalidates only the child's rectangle
    256     // Set by default
    257     static final int FLAG_CLIP_CHILDREN = 0x1;
    258 
    259     // When set, ViewGroup excludes the padding area from the invalidate rectangle
    260     // Set by default
    261     private static final int FLAG_CLIP_TO_PADDING = 0x2;
    262 
    263     // When set, dispatchDraw() will invoke invalidate(); this is set by drawChild() when
    264     // a child needs to be invalidated and FLAG_OPTIMIZE_INVALIDATE is set
    265     static final int FLAG_INVALIDATE_REQUIRED  = 0x4;
    266 
    267     // When set, dispatchDraw() will run the layout animation and unset the flag
    268     private static final int FLAG_RUN_ANIMATION = 0x8;
    269 
    270     // When set, there is either no layout animation on the ViewGroup or the layout
    271     // animation is over
    272     // Set by default
    273     static final int FLAG_ANIMATION_DONE = 0x10;
    274 
    275     // If set, this ViewGroup has padding; if unset there is no padding and we don't need
    276     // to clip it, even if FLAG_CLIP_TO_PADDING is set
    277     private static final int FLAG_PADDING_NOT_NULL = 0x20;
    278 
    279     /** @deprecated - functionality removed */
    280     @Deprecated
    281     private static final int FLAG_ANIMATION_CACHE = 0x40;
    282 
    283     // When set, this ViewGroup converts calls to invalidate(Rect) to invalidate() during a
    284     // layout animation; this avoid clobbering the hierarchy
    285     // Automatically set when the layout animation starts, depending on the animation's
    286     // characteristics
    287     static final int FLAG_OPTIMIZE_INVALIDATE = 0x80;
    288 
    289     // When set, the next call to drawChild() will clear mChildTransformation's matrix
    290     static final int FLAG_CLEAR_TRANSFORMATION = 0x100;
    291 
    292     // When set, this ViewGroup invokes mAnimationListener.onAnimationEnd() and removes
    293     // the children's Bitmap caches if necessary
    294     // This flag is set when the layout animation is over (after FLAG_ANIMATION_DONE is set)
    295     private static final int FLAG_NOTIFY_ANIMATION_LISTENER = 0x200;
    296 
    297     /**
    298      * When set, the drawing method will call {@link #getChildDrawingOrder(int, int)}
    299      * to get the index of the child to draw for that iteration.
    300      *
    301      * @hide
    302      */
    303     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769377)
    304     protected static final int FLAG_USE_CHILD_DRAWING_ORDER = 0x400;
    305 
    306     /**
    307      * When set, this ViewGroup supports static transformations on children; this causes
    308      * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} to be
    309      * invoked when a child is drawn.
    310      *
    311      * Any subclass overriding
    312      * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} should
    313      * set this flags in {@link #mGroupFlags}.
    314      *
    315      * {@hide}
    316      */
    317     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769647)
    318     protected static final int FLAG_SUPPORT_STATIC_TRANSFORMATIONS = 0x800;
    319 
    320     // UNUSED FLAG VALUE: 0x1000;
    321 
    322     /**
    323      * When set, this ViewGroup's drawable states also include those
    324      * of its children.
    325      */
    326     private static final int FLAG_ADD_STATES_FROM_CHILDREN = 0x2000;
    327 
    328     /** @deprecated functionality removed */
    329     @Deprecated
    330     private static final int FLAG_ALWAYS_DRAWN_WITH_CACHE = 0x4000;
    331 
    332     /** @deprecated functionality removed */
    333     @Deprecated
    334     private static final int FLAG_CHILDREN_DRAWN_WITH_CACHE = 0x8000;
    335 
    336     /**
    337      * When set, this group will go through its list of children to notify them of
    338      * any drawable state change.
    339      */
    340     private static final int FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE = 0x10000;
    341 
    342     private static final int FLAG_MASK_FOCUSABILITY = 0x60000;
    343 
    344     /**
    345      * This view will get focus before any of its descendants.
    346      */
    347     public static final int FOCUS_BEFORE_DESCENDANTS = 0x20000;
    348 
    349     /**
    350      * This view will get focus only if none of its descendants want it.
    351      */
    352     public static final int FOCUS_AFTER_DESCENDANTS = 0x40000;
    353 
    354     /**
    355      * This view will block any of its descendants from getting focus, even
    356      * if they are focusable.
    357      */
    358     public static final int FOCUS_BLOCK_DESCENDANTS = 0x60000;
    359 
    360     /**
    361      * Used to map between enum in attrubutes and flag values.
    362      */
    363     private static final int[] DESCENDANT_FOCUSABILITY_FLAGS =
    364             {FOCUS_BEFORE_DESCENDANTS, FOCUS_AFTER_DESCENDANTS,
    365                     FOCUS_BLOCK_DESCENDANTS};
    366 
    367     /**
    368      * When set, this ViewGroup should not intercept touch events.
    369      * {@hide}
    370      */
    371     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123983692)
    372     protected static final int FLAG_DISALLOW_INTERCEPT = 0x80000;
    373 
    374     /**
    375      * When set, this ViewGroup will split MotionEvents to multiple child Views when appropriate.
    376      */
    377     private static final int FLAG_SPLIT_MOTION_EVENTS = 0x200000;
    378 
    379     /**
    380      * When set, this ViewGroup will not dispatch onAttachedToWindow calls
    381      * to children when adding new views. This is used to prevent multiple
    382      * onAttached calls when a ViewGroup adds children in its own onAttached method.
    383      */
    384     private static final int FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW = 0x400000;
    385 
    386     /**
    387      * When true, indicates that a layoutMode has been explicitly set, either with
    388      * an explicit call to {@link #setLayoutMode(int)} in code or from an XML resource.
    389      * This distinguishes the situation in which a layout mode was inherited from
    390      * one of the ViewGroup's ancestors and cached locally.
    391      */
    392     private static final int FLAG_LAYOUT_MODE_WAS_EXPLICITLY_SET = 0x800000;
    393 
    394     static final int FLAG_IS_TRANSITION_GROUP = 0x1000000;
    395 
    396     static final int FLAG_IS_TRANSITION_GROUP_SET = 0x2000000;
    397 
    398     /**
    399      * When set, focus will not be permitted to enter this group if a touchscreen is present.
    400      */
    401     static final int FLAG_TOUCHSCREEN_BLOCKS_FOCUS = 0x4000000;
    402 
    403     /**
    404      * When true, indicates that a call to startActionModeForChild was made with the type parameter
    405      * and should not be ignored. This helps in backwards compatibility with the existing method
    406      * without a type.
    407      *
    408      * @see #startActionModeForChild(View, android.view.ActionMode.Callback)
    409      * @see #startActionModeForChild(View, android.view.ActionMode.Callback, int)
    410      */
    411     private static final int FLAG_START_ACTION_MODE_FOR_CHILD_IS_TYPED = 0x8000000;
    412 
    413     /**
    414      * When true, indicates that a call to startActionModeForChild was made without the type
    415      * parameter. This helps in backwards compatibility with the existing method
    416      * without a type.
    417      *
    418      * @see #startActionModeForChild(View, android.view.ActionMode.Callback)
    419      * @see #startActionModeForChild(View, android.view.ActionMode.Callback, int)
    420      */
    421     private static final int FLAG_START_ACTION_MODE_FOR_CHILD_IS_NOT_TYPED = 0x10000000;
    422 
    423     /**
    424      * When set, indicates that a call to showContextMenuForChild was made with explicit
    425      * coordinates within the initiating child view.
    426      */
    427     private static final int FLAG_SHOW_CONTEXT_MENU_WITH_COORDS = 0x20000000;
    428 
    429     /**
    430      * Indicates which types of drawing caches are to be kept in memory.
    431      * This field should be made private, so it is hidden from the SDK.
    432      * {@hide}
    433      */
    434     @UnsupportedAppUsage
    435     protected int mPersistentDrawingCache;
    436 
    437     /**
    438      * Used to indicate that no drawing cache should be kept in memory.
    439      *
    440      * @deprecated The view drawing cache was largely made obsolete with the introduction of
    441      * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache
    442      * layers are largely unnecessary and can easily result in a net loss in performance due to the
    443      * cost of creating and updating the layer. In the rare cases where caching layers are useful,
    444      * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware
    445      * rendering. For software-rendered snapshots of a small part of the View hierarchy or
    446      * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or
    447      * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these
    448      * software-rendered usages are discouraged and have compatibility issues with hardware-only
    449      * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE}
    450      * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback
    451      * reports or unit testing the {@link PixelCopy} API is recommended.
    452      */
    453     @Deprecated
    454     public static final int PERSISTENT_NO_CACHE = 0x0;
    455 
    456     /**
    457      * Used to indicate that the animation drawing cache should be kept in memory.
    458      *
    459      * @deprecated The view drawing cache was largely made obsolete with the introduction of
    460      * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache
    461      * layers are largely unnecessary and can easily result in a net loss in performance due to the
    462      * cost of creating and updating the layer. In the rare cases where caching layers are useful,
    463      * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware
    464      * rendering. For software-rendered snapshots of a small part of the View hierarchy or
    465      * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or
    466      * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these
    467      * software-rendered usages are discouraged and have compatibility issues with hardware-only
    468      * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE}
    469      * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback
    470      * reports or unit testing the {@link PixelCopy} API is recommended.
    471      */
    472     @Deprecated
    473     public static final int PERSISTENT_ANIMATION_CACHE = 0x1;
    474 
    475     /**
    476      * Used to indicate that the scrolling drawing cache should be kept in memory.
    477      *
    478      * @deprecated The view drawing cache was largely made obsolete with the introduction of
    479      * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache
    480      * layers are largely unnecessary and can easily result in a net loss in performance due to the
    481      * cost of creating and updating the layer. In the rare cases where caching layers are useful,
    482      * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware
    483      * rendering. For software-rendered snapshots of a small part of the View hierarchy or
    484      * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or
    485      * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these
    486      * software-rendered usages are discouraged and have compatibility issues with hardware-only
    487      * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE}
    488      * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback
    489      * reports or unit testing the {@link PixelCopy} API is recommended.
    490      */
    491     @Deprecated
    492     public static final int PERSISTENT_SCROLLING_CACHE = 0x2;
    493 
    494     /**
    495      * Used to indicate that all drawing caches should be kept in memory.
    496      *
    497      * @deprecated The view drawing cache was largely made obsolete with the introduction of
    498      * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache
    499      * layers are largely unnecessary and can easily result in a net loss in performance due to the
    500      * cost of creating and updating the layer. In the rare cases where caching layers are useful,
    501      * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware
    502      * rendering. For software-rendered snapshots of a small part of the View hierarchy or
    503      * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or
    504      * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these
    505      * software-rendered usages are discouraged and have compatibility issues with hardware-only
    506      * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE}
    507      * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback
    508      * reports or unit testing the {@link PixelCopy} API is recommended.
    509      */
    510     @Deprecated
    511     public static final int PERSISTENT_ALL_CACHES = 0x3;
    512 
    513     // Layout Modes
    514 
    515     private static final int LAYOUT_MODE_UNDEFINED = -1;
    516 
    517     /**
    518      * This constant is a {@link #setLayoutMode(int) layoutMode}.
    519      * Clip bounds are the raw values of {@link #getLeft() left}, {@link #getTop() top},
    520      * {@link #getRight() right} and {@link #getBottom() bottom}.
    521      */
    522     public static final int LAYOUT_MODE_CLIP_BOUNDS = 0;
    523 
    524     /**
    525      * This constant is a {@link #setLayoutMode(int) layoutMode}.
    526      * Optical bounds describe where a widget appears to be. They sit inside the clip
    527      * bounds which need to cover a larger area to allow other effects,
    528      * such as shadows and glows, to be drawn.
    529      */
    530     public static final int LAYOUT_MODE_OPTICAL_BOUNDS = 1;
    531 
    532     /** @hide */
    533     public static int LAYOUT_MODE_DEFAULT = LAYOUT_MODE_CLIP_BOUNDS;
    534 
    535     /**
    536      * We clip to padding when FLAG_CLIP_TO_PADDING and FLAG_PADDING_NOT_NULL
    537      * are set at the same time.
    538      */
    539     protected static final int CLIP_TO_PADDING_MASK = FLAG_CLIP_TO_PADDING | FLAG_PADDING_NOT_NULL;
    540 
    541     // Index of the child's left position in the mLocation array
    542     private static final int CHILD_LEFT_INDEX = 0;
    543     // Index of the child's top position in the mLocation array
    544     private static final int CHILD_TOP_INDEX = 1;
    545 
    546     // Child views of this ViewGroup
    547     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
    548     private View[] mChildren;
    549     // Number of valid children in the mChildren array, the rest should be null or not
    550     // considered as children
    551     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
    552     private int mChildrenCount;
    553 
    554     // Whether layout calls are currently being suppressed, controlled by calls to
    555     // suppressLayout()
    556     boolean mSuppressLayout = false;
    557 
    558     // Whether any layout calls have actually been suppressed while mSuppressLayout
    559     // has been true. This tracks whether we need to issue a requestLayout() when
    560     // layout is later re-enabled.
    561     private boolean mLayoutCalledWhileSuppressed = false;
    562 
    563     private static final int ARRAY_INITIAL_CAPACITY = 12;
    564     private static final int ARRAY_CAPACITY_INCREMENT = 12;
    565 
    566     private static float[] sDebugLines;
    567 
    568     // Used to draw cached views
    569     Paint mCachePaint;
    570 
    571     // Used to animate add/remove changes in layout
    572     private LayoutTransition mTransition;
    573 
    574     // The set of views that are currently being transitioned. This list is used to track views
    575     // being removed that should not actually be removed from the parent yet because they are
    576     // being animated.
    577     private ArrayList<View> mTransitioningViews;
    578 
    579     // List of children changing visibility. This is used to potentially keep rendering
    580     // views during a transition when they otherwise would have become gone/invisible
    581     private ArrayList<View> mVisibilityChangingChildren;
    582 
    583     // Temporary holder of presorted children, only used for
    584     // input/software draw dispatch for correctly Z ordering.
    585     private ArrayList<View> mPreSortedChildren;
    586 
    587     // Indicates how many of this container's child subtrees contain transient state
    588     @ViewDebug.ExportedProperty(category = "layout")
    589     private int mChildCountWithTransientState = 0;
    590 
    591     /**
    592      * Currently registered axes for nested scrolling. Flag set consisting of
    593      * {@link #SCROLL_AXIS_HORIZONTAL} {@link #SCROLL_AXIS_VERTICAL} or {@link #SCROLL_AXIS_NONE}
    594      * for null.
    595      */
    596     private int mNestedScrollAxes;
    597 
    598     // Used to manage the list of transient views, added by addTransientView()
    599     private List<Integer> mTransientIndices = null;
    600     private List<View> mTransientViews = null;
    601 
    602     /**
    603      * Keeps track of how many child views have UnhandledKeyEventListeners. This should only be
    604      * updated on the UI thread so shouldn't require explicit synchronization.
    605      */
    606     int mChildUnhandledKeyListeners = 0;
    607 
    608     /**
    609      * Empty ActionMode used as a sentinel in recursive entries to startActionModeForChild.
    610      *
    611      * @see #startActionModeForChild(View, android.view.ActionMode.Callback)
    612      * @see #startActionModeForChild(View, android.view.ActionMode.Callback, int)
    613      */
    614     private static final ActionMode SENTINEL_ACTION_MODE = new ActionMode() {
    615         @Override
    616         public void setTitle(CharSequence title) {}
    617 
    618         @Override
    619         public void setTitle(int resId) {}
    620 
    621         @Override
    622         public void setSubtitle(CharSequence subtitle) {}
    623 
    624         @Override
    625         public void setSubtitle(int resId) {}
    626 
    627         @Override
    628         public void setCustomView(View view) {}
    629 
    630         @Override
    631         public void invalidate() {}
    632 
    633         @Override
    634         public void finish() {}
    635 
    636         @Override
    637         public Menu getMenu() {
    638             return null;
    639         }
    640 
    641         @Override
    642         public CharSequence getTitle() {
    643             return null;
    644         }
    645 
    646         @Override
    647         public CharSequence getSubtitle() {
    648             return null;
    649         }
    650 
    651         @Override
    652         public View getCustomView() {
    653             return null;
    654         }
    655 
    656         @Override
    657         public MenuInflater getMenuInflater() {
    658             return null;
    659         }
    660     };
    661 
    662     public ViewGroup(Context context) {
    663         this(context, null);
    664     }
    665 
    666     public ViewGroup(Context context, AttributeSet attrs) {
    667         this(context, attrs, 0);
    668     }
    669 
    670     public ViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {
    671         this(context, attrs, defStyleAttr, 0);
    672     }
    673 
    674     public ViewGroup(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
    675         super(context, attrs, defStyleAttr, defStyleRes);
    676 
    677         initViewGroup();
    678         initFromAttributes(context, attrs, defStyleAttr, defStyleRes);
    679     }
    680 
    681     private void initViewGroup() {
    682         // ViewGroup doesn't draw by default
    683         if (!debugDraw()) {
    684             setFlags(WILL_NOT_DRAW, DRAW_MASK);
    685         }
    686         mGroupFlags |= FLAG_CLIP_CHILDREN;
    687         mGroupFlags |= FLAG_CLIP_TO_PADDING;
    688         mGroupFlags |= FLAG_ANIMATION_DONE;
    689         mGroupFlags |= FLAG_ANIMATION_CACHE;
    690         mGroupFlags |= FLAG_ALWAYS_DRAWN_WITH_CACHE;
    691 
    692         if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB) {
    693             mGroupFlags |= FLAG_SPLIT_MOTION_EVENTS;
    694         }
    695 
    696         setDescendantFocusability(FOCUS_BEFORE_DESCENDANTS);
    697 
    698         mChildren = new View[ARRAY_INITIAL_CAPACITY];
    699         mChildrenCount = 0;
    700 
    701         mPersistentDrawingCache = PERSISTENT_SCROLLING_CACHE;
    702     }
    703 
    704     private void initFromAttributes(
    705             Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
    706         final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ViewGroup,
    707                 defStyleAttr, defStyleRes);
    708         saveAttributeDataForStyleable(context, R.styleable.ViewGroup, attrs, a, defStyleAttr,
    709                 defStyleRes);
    710 
    711         final int N = a.getIndexCount();
    712         for (int i = 0; i < N; i++) {
    713             int attr = a.getIndex(i);
    714             switch (attr) {
    715                 case R.styleable.ViewGroup_clipChildren:
    716                     setClipChildren(a.getBoolean(attr, true));
    717                     break;
    718                 case R.styleable.ViewGroup_clipToPadding:
    719                     setClipToPadding(a.getBoolean(attr, true));
    720                     break;
    721                 case R.styleable.ViewGroup_animationCache:
    722                     setAnimationCacheEnabled(a.getBoolean(attr, true));
    723                     break;
    724                 case R.styleable.ViewGroup_persistentDrawingCache:
    725                     setPersistentDrawingCache(a.getInt(attr, PERSISTENT_SCROLLING_CACHE));
    726                     break;
    727                 case R.styleable.ViewGroup_addStatesFromChildren:
    728                     setAddStatesFromChildren(a.getBoolean(attr, false));
    729                     break;
    730                 case R.styleable.ViewGroup_alwaysDrawnWithCache:
    731                     setAlwaysDrawnWithCacheEnabled(a.getBoolean(attr, true));
    732                     break;
    733                 case R.styleable.ViewGroup_layoutAnimation:
    734                     int id = a.getResourceId(attr, -1);
    735                     if (id > 0) {
    736                         setLayoutAnimation(AnimationUtils.loadLayoutAnimation(mContext, id));
    737                     }
    738                     break;
    739                 case R.styleable.ViewGroup_descendantFocusability:
    740                     setDescendantFocusability(DESCENDANT_FOCUSABILITY_FLAGS[a.getInt(attr, 0)]);
    741                     break;
    742                 case R.styleable.ViewGroup_splitMotionEvents:
    743                     setMotionEventSplittingEnabled(a.getBoolean(attr, false));
    744                     break;
    745                 case R.styleable.ViewGroup_animateLayoutChanges:
    746                     boolean animateLayoutChanges = a.getBoolean(attr, false);
    747                     if (animateLayoutChanges) {
    748                         setLayoutTransition(new LayoutTransition());
    749                     }
    750                     break;
    751                 case R.styleable.ViewGroup_layoutMode:
    752                     setLayoutMode(a.getInt(attr, LAYOUT_MODE_UNDEFINED));
    753                     break;
    754                 case R.styleable.ViewGroup_transitionGroup:
    755                     setTransitionGroup(a.getBoolean(attr, false));
    756                     break;
    757                 case R.styleable.ViewGroup_touchscreenBlocksFocus:
    758                     setTouchscreenBlocksFocus(a.getBoolean(attr, false));
    759                     break;
    760             }
    761         }
    762 
    763         a.recycle();
    764     }
    765 
    766     /**
    767      * Gets the descendant focusability of this view group.  The descendant
    768      * focusability defines the relationship between this view group and its
    769      * descendants when looking for a view to take focus in
    770      * {@link #requestFocus(int, android.graphics.Rect)}.
    771      *
    772      * @return one of {@link #FOCUS_BEFORE_DESCENDANTS}, {@link #FOCUS_AFTER_DESCENDANTS},
    773      *   {@link #FOCUS_BLOCK_DESCENDANTS}.
    774      */
    775     @ViewDebug.ExportedProperty(category = "focus", mapping = {
    776         @ViewDebug.IntToString(from = FOCUS_BEFORE_DESCENDANTS, to = "FOCUS_BEFORE_DESCENDANTS"),
    777         @ViewDebug.IntToString(from = FOCUS_AFTER_DESCENDANTS, to = "FOCUS_AFTER_DESCENDANTS"),
    778         @ViewDebug.IntToString(from = FOCUS_BLOCK_DESCENDANTS, to = "FOCUS_BLOCK_DESCENDANTS")
    779     })
    780     @InspectableProperty(enumMapping = {
    781             @EnumEntry(value = FOCUS_BEFORE_DESCENDANTS, name = "beforeDescendants"),
    782             @EnumEntry(value = FOCUS_AFTER_DESCENDANTS, name = "afterDescendants"),
    783             @EnumEntry(value = FOCUS_BLOCK_DESCENDANTS, name = "blocksDescendants")
    784     })
    785     public int getDescendantFocusability() {
    786         return mGroupFlags & FLAG_MASK_FOCUSABILITY;
    787     }
    788 
    789     /**
    790      * Set the descendant focusability of this view group. This defines the relationship
    791      * between this view group and its descendants when looking for a view to
    792      * take focus in {@link #requestFocus(int, android.graphics.Rect)}.
    793      *
    794      * @param focusability one of {@link #FOCUS_BEFORE_DESCENDANTS}, {@link #FOCUS_AFTER_DESCENDANTS},
    795      *   {@link #FOCUS_BLOCK_DESCENDANTS}.
    796      */
    797     public void setDescendantFocusability(int focusability) {
    798         switch (focusability) {
    799             case FOCUS_BEFORE_DESCENDANTS:
    800             case FOCUS_AFTER_DESCENDANTS:
    801             case FOCUS_BLOCK_DESCENDANTS:
    802                 break;
    803             default:
    804                 throw new IllegalArgumentException("must be one of FOCUS_BEFORE_DESCENDANTS, "
    805                         + "FOCUS_AFTER_DESCENDANTS, FOCUS_BLOCK_DESCENDANTS");
    806         }
    807         mGroupFlags &= ~FLAG_MASK_FOCUSABILITY;
    808         mGroupFlags |= (focusability & FLAG_MASK_FOCUSABILITY);
    809     }
    810 
    811     @Override
    812     void handleFocusGainInternal(int direction, Rect previouslyFocusedRect) {
    813         if (mFocused != null) {
    814             mFocused.unFocus(this);
    815             mFocused = null;
    816             mFocusedInCluster = null;
    817         }
    818         super.handleFocusGainInternal(direction, previouslyFocusedRect);
    819     }
    820 
    821     @Override
    822     public void requestChildFocus(View child, View focused) {
    823         if (DBG) {
    824             System.out.println(this + " requestChildFocus()");
    825         }
    826         if (getDescendantFocusability() == FOCUS_BLOCK_DESCENDANTS) {
    827             return;
    828         }
    829 
    830         // Unfocus us, if necessary
    831         super.unFocus(focused);
    832 
    833         // We had a previous notion of who had focus. Clear it.
    834         if (mFocused != child) {
    835             if (mFocused != null) {
    836                 mFocused.unFocus(focused);
    837             }
    838 
    839             mFocused = child;
    840         }
    841         if (mParent != null) {
    842             mParent.requestChildFocus(this, focused);
    843         }
    844     }
    845 
    846     void setDefaultFocus(View child) {
    847         // Stop at any higher view which is explicitly focused-by-default
    848         if (mDefaultFocus != null && mDefaultFocus.isFocusedByDefault()) {
    849             return;
    850         }
    851 
    852         mDefaultFocus = child;
    853 
    854         if (mParent instanceof ViewGroup) {
    855             ((ViewGroup) mParent).setDefaultFocus(this);
    856         }
    857     }
    858 
    859     /**
    860      * Clears the default-focus chain from {@param child} up to the first parent which has another
    861      * default-focusable branch below it or until there is no default-focus chain.
    862      *
    863      * @param child
    864      */
    865     void clearDefaultFocus(View child) {
    866         // Stop at any higher view which is explicitly focused-by-default
    867         if (mDefaultFocus != child && mDefaultFocus != null
    868                 && mDefaultFocus.isFocusedByDefault()) {
    869             return;
    870         }
    871 
    872         mDefaultFocus = null;
    873 
    874         // Search child siblings for default focusables.
    875         for (int i = 0; i < mChildrenCount; ++i) {
    876             View sibling = mChildren[i];
    877             if (sibling.isFocusedByDefault()) {
    878                 mDefaultFocus = sibling;
    879                 return;
    880             } else if (mDefaultFocus == null && sibling.hasDefaultFocus()) {
    881                 mDefaultFocus = sibling;
    882             }
    883         }
    884 
    885         if (mParent instanceof ViewGroup) {
    886             ((ViewGroup) mParent).clearDefaultFocus(this);
    887         }
    888     }
    889 
    890     @Override
    891     boolean hasDefaultFocus() {
    892         return mDefaultFocus != null || super.hasDefaultFocus();
    893     }
    894 
    895     /**
    896      * Removes {@code child} (and associated focusedInCluster chain) from the cluster containing
    897      * it.
    898      * <br>
    899      * This is intended to be run on {@code child}'s immediate parent. This is necessary because
    900      * the chain is sometimes cleared after {@code child} has been detached.
    901      */
    902     void clearFocusedInCluster(View child) {
    903         if (mFocusedInCluster != child) {
    904             return;
    905         }
    906         clearFocusedInCluster();
    907     }
    908 
    909     /**
    910      * Removes the focusedInCluster chain from this up to the cluster containing it.
    911      */
    912     void clearFocusedInCluster() {
    913         View top = findKeyboardNavigationCluster();
    914         ViewParent parent = this;
    915         do {
    916             ((ViewGroup) parent).mFocusedInCluster = null;
    917             if (parent == top) {
    918                 break;
    919             }
    920             parent = parent.getParent();
    921         } while (parent instanceof ViewGroup);
    922     }
    923 
    924     @Override
    925     public void focusableViewAvailable(View v) {
    926         if (mParent != null
    927                 // shortcut: don't report a new focusable view if we block our descendants from
    928                 // getting focus or if we're not visible
    929                 && (getDescendantFocusability() != FOCUS_BLOCK_DESCENDANTS)
    930                 && ((mViewFlags & VISIBILITY_MASK) == VISIBLE)
    931                 && (isFocusableInTouchMode() || !shouldBlockFocusForTouchscreen())
    932                 // shortcut: don't report a new focusable view if we already are focused
    933                 // (and we don't prefer our descendants)
    934                 //
    935                 // note: knowing that mFocused is non-null is not a good enough reason
    936                 // to break the traversal since in that case we'd actually have to find
    937                 // the focused view and make sure it wasn't FOCUS_AFTER_DESCENDANTS and
    938                 // an ancestor of v; this will get checked for at ViewAncestor
    939                 && !(isFocused() && getDescendantFocusability() != FOCUS_AFTER_DESCENDANTS)) {
    940             mParent.focusableViewAvailable(v);
    941         }
    942     }
    943 
    944     @Override
    945     public boolean showContextMenuForChild(View originalView) {
    946         if (isShowingContextMenuWithCoords()) {
    947             // We're being called for compatibility. Return false and let the version
    948             // with coordinates recurse up.
    949             return false;
    950         }
    951         return mParent != null && mParent.showContextMenuForChild(originalView);
    952     }
    953 
    954     /**
    955      * @hide used internally for compatibility with existing app code only
    956      */
    957     public final boolean isShowingContextMenuWithCoords() {
    958         return (mGroupFlags & FLAG_SHOW_CONTEXT_MENU_WITH_COORDS) != 0;
    959     }
    960 
    961     @Override
    962     public boolean showContextMenuForChild(View originalView, float x, float y) {
    963         try {
    964             mGroupFlags |= FLAG_SHOW_CONTEXT_MENU_WITH_COORDS;
    965             if (showContextMenuForChild(originalView)) {
    966                 return true;
    967             }
    968         } finally {
    969             mGroupFlags &= ~FLAG_SHOW_CONTEXT_MENU_WITH_COORDS;
    970         }
    971         return mParent != null && mParent.showContextMenuForChild(originalView, x, y);
    972     }
    973 
    974     @Override
    975     public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback) {
    976         if ((mGroupFlags & FLAG_START_ACTION_MODE_FOR_CHILD_IS_TYPED) == 0) {
    977             // This is the original call.
    978             try {
    979                 mGroupFlags |= FLAG_START_ACTION_MODE_FOR_CHILD_IS_NOT_TYPED;
    980                 return startActionModeForChild(originalView, callback, ActionMode.TYPE_PRIMARY);
    981             } finally {
    982                 mGroupFlags &= ~FLAG_START_ACTION_MODE_FOR_CHILD_IS_NOT_TYPED;
    983             }
    984         } else {
    985             // We are being called from the new method with type.
    986             return SENTINEL_ACTION_MODE;
    987         }
    988     }
    989 
    990     @Override
    991     public ActionMode startActionModeForChild(
    992             View originalView, ActionMode.Callback callback, int type) {
    993         if ((mGroupFlags & FLAG_START_ACTION_MODE_FOR_CHILD_IS_NOT_TYPED) == 0
    994                 && type == ActionMode.TYPE_PRIMARY) {
    995             ActionMode mode;
    996             try {
    997                 mGroupFlags |= FLAG_START_ACTION_MODE_FOR_CHILD_IS_TYPED;
    998                 mode = startActionModeForChild(originalView, callback);
    999             } finally {
   1000                 mGroupFlags &= ~FLAG_START_ACTION_MODE_FOR_CHILD_IS_TYPED;
   1001             }
   1002             if (mode != SENTINEL_ACTION_MODE) {
   1003                 return mode;
   1004             }
   1005         }
   1006         if (mParent != null) {
   1007             try {
   1008                 return mParent.startActionModeForChild(originalView, callback, type);
   1009             } catch (AbstractMethodError ame) {
   1010                 // Custom view parents might not implement this method.
   1011                 return mParent.startActionModeForChild(originalView, callback);
   1012             }
   1013         }
   1014         return null;
   1015     }
   1016 
   1017     /**
   1018      * @hide
   1019      */
   1020     @Override
   1021     public boolean dispatchActivityResult(
   1022             String who, int requestCode, int resultCode, Intent data) {
   1023         if (super.dispatchActivityResult(who, requestCode, resultCode, data)) {
   1024             return true;
   1025         }
   1026         int childCount = getChildCount();
   1027         for (int i = 0; i < childCount; i++) {
   1028             View child = getChildAt(i);
   1029             if (child.dispatchActivityResult(who, requestCode, resultCode, data)) {
   1030                 return true;
   1031             }
   1032         }
   1033         return false;
   1034     }
   1035 
   1036     /**
   1037      * Find the nearest view in the specified direction that wants to take
   1038      * focus.
   1039      *
   1040      * @param focused The view that currently has focus
   1041      * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and
   1042      *        FOCUS_RIGHT, or 0 for not applicable.
   1043      */
   1044     @Override
   1045     public View focusSearch(View focused, int direction) {
   1046         if (isRootNamespace()) {
   1047             // root namespace means we should consider ourselves the top of the
   1048             // tree for focus searching; otherwise we could be focus searching
   1049             // into other tabs.  see LocalActivityManager and TabHost for more info.
   1050             return FocusFinder.getInstance().findNextFocus(this, focused, direction);
   1051         } else if (mParent != null) {
   1052             return mParent.focusSearch(focused, direction);
   1053         }
   1054         return null;
   1055     }
   1056 
   1057     @Override
   1058     public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
   1059         return false;
   1060     }
   1061 
   1062     @Override
   1063     public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event) {
   1064         ViewParent parent = mParent;
   1065         if (parent == null) {
   1066             return false;
   1067         }
   1068         final boolean propagate = onRequestSendAccessibilityEvent(child, event);
   1069         if (!propagate) {
   1070             return false;
   1071         }
   1072         return parent.requestSendAccessibilityEvent(this, event);
   1073     }
   1074 
   1075     /**
   1076      * Called when a child has requested sending an {@link AccessibilityEvent} and
   1077      * gives an opportunity to its parent to augment the event.
   1078      * <p>
   1079      * If an {@link android.view.View.AccessibilityDelegate} has been specified via calling
   1080      * {@link android.view.View#setAccessibilityDelegate(android.view.View.AccessibilityDelegate)} its
   1081      * {@link android.view.View.AccessibilityDelegate#onRequestSendAccessibilityEvent(ViewGroup, View, AccessibilityEvent)}
   1082      * is responsible for handling this call.
   1083      * </p>
   1084      *
   1085      * @param child The child which requests sending the event.
   1086      * @param event The event to be sent.
   1087      * @return True if the event should be sent.
   1088      *
   1089      * @see #requestSendAccessibilityEvent(View, AccessibilityEvent)
   1090      */
   1091     public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
   1092         if (mAccessibilityDelegate != null) {
   1093             return mAccessibilityDelegate.onRequestSendAccessibilityEvent(this, child, event);
   1094         } else {
   1095             return onRequestSendAccessibilityEventInternal(child, event);
   1096         }
   1097     }
   1098 
   1099     /**
   1100      * @see #onRequestSendAccessibilityEvent(View, AccessibilityEvent)
   1101      *
   1102      * Note: Called from the default {@link View.AccessibilityDelegate}.
   1103      *
   1104      * @hide
   1105      */
   1106     public boolean onRequestSendAccessibilityEventInternal(View child, AccessibilityEvent event) {
   1107         return true;
   1108     }
   1109 
   1110     /**
   1111      * Called when a child view has changed whether or not it is tracking transient state.
   1112      */
   1113     @Override
   1114     public void childHasTransientStateChanged(View child, boolean childHasTransientState) {
   1115         final boolean oldHasTransientState = hasTransientState();
   1116         if (childHasTransientState) {
   1117             mChildCountWithTransientState++;
   1118         } else {
   1119             mChildCountWithTransientState--;
   1120         }
   1121 
   1122         final boolean newHasTransientState = hasTransientState();
   1123         if (mParent != null && oldHasTransientState != newHasTransientState) {
   1124             try {
   1125                 mParent.childHasTransientStateChanged(this, newHasTransientState);
   1126             } catch (AbstractMethodError e) {
   1127                 Log.e(TAG, mParent.getClass().getSimpleName() +
   1128                         " does not fully implement ViewParent", e);
   1129             }
   1130         }
   1131     }
   1132 
   1133     @Override
   1134     public boolean hasTransientState() {
   1135         return mChildCountWithTransientState > 0 || super.hasTransientState();
   1136     }
   1137 
   1138     @Override
   1139     public boolean dispatchUnhandledMove(View focused, int direction) {
   1140         return mFocused != null &&
   1141                 mFocused.dispatchUnhandledMove(focused, direction);
   1142     }
   1143 
   1144     @Override
   1145     public void clearChildFocus(View child) {
   1146         if (DBG) {
   1147             System.out.println(this + " clearChildFocus()");
   1148         }
   1149 
   1150         mFocused = null;
   1151         if (mParent != null) {
   1152             mParent.clearChildFocus(this);
   1153         }
   1154     }
   1155 
   1156     @Override
   1157     public void clearFocus() {
   1158         if (DBG) {
   1159             System.out.println(this + " clearFocus()");
   1160         }
   1161         if (mFocused == null) {
   1162             super.clearFocus();
   1163         } else {
   1164             View focused = mFocused;
   1165             mFocused = null;
   1166             focused.clearFocus();
   1167         }
   1168     }
   1169 
   1170     @Override
   1171     void unFocus(View focused) {
   1172         if (DBG) {
   1173             System.out.println(this + " unFocus()");
   1174         }
   1175         if (mFocused == null) {
   1176             super.unFocus(focused);
   1177         } else {
   1178             mFocused.unFocus(focused);
   1179             mFocused = null;
   1180         }
   1181     }
   1182 
   1183     /**
   1184      * Returns the focused child of this view, if any. The child may have focus
   1185      * or contain focus.
   1186      *
   1187      * @return the focused child or null.
   1188      */
   1189     public View getFocusedChild() {
   1190         return mFocused;
   1191     }
   1192 
   1193     View getDeepestFocusedChild() {
   1194         View v = this;
   1195         while (v != null) {
   1196             if (v.isFocused()) {
   1197                 return v;
   1198             }
   1199             v = v instanceof ViewGroup ? ((ViewGroup) v).getFocusedChild() : null;
   1200         }
   1201         return null;
   1202     }
   1203 
   1204     /**
   1205      * Returns true if this view has or contains focus
   1206      *
   1207      * @return true if this view has or contains focus
   1208      */
   1209     @Override
   1210     public boolean hasFocus() {
   1211         return (mPrivateFlags & PFLAG_FOCUSED) != 0 || mFocused != null;
   1212     }
   1213 
   1214     /*
   1215      * (non-Javadoc)
   1216      *
   1217      * @see android.view.View#findFocus()
   1218      */
   1219     @Override
   1220     public View findFocus() {
   1221         if (DBG) {
   1222             System.out.println("Find focus in " + this + ": flags="
   1223                     + isFocused() + ", child=" + mFocused);
   1224         }
   1225 
   1226         if (isFocused()) {
   1227             return this;
   1228         }
   1229 
   1230         if (mFocused != null) {
   1231             return mFocused.findFocus();
   1232         }
   1233         return null;
   1234     }
   1235 
   1236     @Override
   1237     boolean hasFocusable(boolean allowAutoFocus, boolean dispatchExplicit) {
   1238         // This should probably be super.hasFocusable, but that would change
   1239         // behavior. Historically, we have not checked the ancestor views for
   1240         // shouldBlockFocusForTouchscreen() in ViewGroup.hasFocusable.
   1241 
   1242         // Invisible and gone views are never focusable.
   1243         if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) {
   1244             return false;
   1245         }
   1246 
   1247         // Only use effective focusable value when allowed.
   1248         if ((allowAutoFocus || getFocusable() != FOCUSABLE_AUTO) && isFocusable()) {
   1249             return true;
   1250         }
   1251 
   1252         // Determine whether we have a focused descendant.
   1253         final int descendantFocusability = getDescendantFocusability();
   1254         if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS) {
   1255             return hasFocusableChild(dispatchExplicit);
   1256         }
   1257 
   1258         return false;
   1259     }
   1260 
   1261     boolean hasFocusableChild(boolean dispatchExplicit) {
   1262         // Determine whether we have a focusable descendant.
   1263         final int count = mChildrenCount;
   1264         final View[] children = mChildren;
   1265 
   1266         for (int i = 0; i < count; i++) {
   1267             final View child = children[i];
   1268 
   1269             // In case the subclass has overridden has[Explicit]Focusable, dispatch
   1270             // to the expected one for each child even though we share logic here.
   1271             if ((dispatchExplicit && child.hasExplicitFocusable())
   1272                     || (!dispatchExplicit && child.hasFocusable())) {
   1273                 return true;
   1274             }
   1275         }
   1276 
   1277         return false;
   1278     }
   1279 
   1280     @Override
   1281     public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
   1282         final int focusableCount = views.size();
   1283 
   1284         final int descendantFocusability = getDescendantFocusability();
   1285         final boolean blockFocusForTouchscreen = shouldBlockFocusForTouchscreen();
   1286         final boolean focusSelf = (isFocusableInTouchMode() || !blockFocusForTouchscreen);
   1287 
   1288         if (descendantFocusability == FOCUS_BLOCK_DESCENDANTS) {
   1289             if (focusSelf) {
   1290                 super.addFocusables(views, direction, focusableMode);
   1291             }
   1292             return;
   1293         }
   1294 
   1295         if (blockFocusForTouchscreen) {
   1296             focusableMode |= FOCUSABLES_TOUCH_MODE;
   1297         }
   1298 
   1299         if ((descendantFocusability == FOCUS_BEFORE_DESCENDANTS) && focusSelf) {
   1300             super.addFocusables(views, direction, focusableMode);
   1301         }
   1302 
   1303         int count = 0;
   1304         final View[] children = new View[mChildrenCount];
   1305         for (int i = 0; i < mChildrenCount; ++i) {
   1306             View child = mChildren[i];
   1307             if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
   1308                 children[count++] = child;
   1309             }
   1310         }
   1311         FocusFinder.sort(children, 0, count, this, isLayoutRtl());
   1312         for (int i = 0; i < count; ++i) {
   1313             children[i].addFocusables(views, direction, focusableMode);
   1314         }
   1315 
   1316         // When set to FOCUS_AFTER_DESCENDANTS, we only add ourselves if
   1317         // there aren't any focusable descendants.  this is
   1318         // to avoid the focus search finding layouts when a more precise search
   1319         // among the focusable children would be more interesting.
   1320         if ((descendantFocusability == FOCUS_AFTER_DESCENDANTS) && focusSelf
   1321                 && focusableCount == views.size()) {
   1322             super.addFocusables(views, direction, focusableMode);
   1323         }
   1324     }
   1325 
   1326     @Override
   1327     public void addKeyboardNavigationClusters(Collection<View> views, int direction) {
   1328         final int focusableCount = views.size();
   1329 
   1330         if (isKeyboardNavigationCluster()) {
   1331             // Cluster-navigation can enter a touchscreenBlocksFocus cluster, so temporarily
   1332             // disable touchscreenBlocksFocus to evaluate whether it contains focusables.
   1333             final boolean blockedFocus = getTouchscreenBlocksFocus();
   1334             try {
   1335                 setTouchscreenBlocksFocusNoRefocus(false);
   1336                 super.addKeyboardNavigationClusters(views, direction);
   1337             } finally {
   1338                 setTouchscreenBlocksFocusNoRefocus(blockedFocus);
   1339             }
   1340         } else {
   1341             super.addKeyboardNavigationClusters(views, direction);
   1342         }
   1343 
   1344         if (focusableCount != views.size()) {
   1345             // No need to look for groups inside a group.
   1346             return;
   1347         }
   1348 
   1349         if (getDescendantFocusability() == FOCUS_BLOCK_DESCENDANTS) {
   1350             return;
   1351         }
   1352 
   1353         int count = 0;
   1354         final View[] visibleChildren = new View[mChildrenCount];
   1355         for (int i = 0; i < mChildrenCount; ++i) {
   1356             final View child = mChildren[i];
   1357             if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
   1358                 visibleChildren[count++] = child;
   1359             }
   1360         }
   1361         FocusFinder.sort(visibleChildren, 0, count, this, isLayoutRtl());
   1362         for (int i = 0; i < count; ++i) {
   1363             visibleChildren[i].addKeyboardNavigationClusters(views, direction);
   1364         }
   1365     }
   1366 
   1367     /**
   1368      * Set whether this ViewGroup should ignore focus requests for itself and its children.
   1369      * If this option is enabled and the ViewGroup or a descendant currently has focus, focus
   1370      * will proceed forward.
   1371      *
   1372      * @param touchscreenBlocksFocus true to enable blocking focus in the presence of a touchscreen
   1373      */
   1374     public void setTouchscreenBlocksFocus(boolean touchscreenBlocksFocus) {
   1375         if (touchscreenBlocksFocus) {
   1376             mGroupFlags |= FLAG_TOUCHSCREEN_BLOCKS_FOCUS;
   1377             if (hasFocus() && !isKeyboardNavigationCluster()) {
   1378                 final View focusedChild = getDeepestFocusedChild();
   1379                 if (!focusedChild.isFocusableInTouchMode()) {
   1380                     final View newFocus = focusSearch(FOCUS_FORWARD);
   1381                     if (newFocus != null) {
   1382                         newFocus.requestFocus();
   1383                     }
   1384                 }
   1385             }
   1386         } else {
   1387             mGroupFlags &= ~FLAG_TOUCHSCREEN_BLOCKS_FOCUS;
   1388         }
   1389     }
   1390 
   1391     private void setTouchscreenBlocksFocusNoRefocus(boolean touchscreenBlocksFocus) {
   1392         if (touchscreenBlocksFocus) {
   1393             mGroupFlags |= FLAG_TOUCHSCREEN_BLOCKS_FOCUS;
   1394         } else {
   1395             mGroupFlags &= ~FLAG_TOUCHSCREEN_BLOCKS_FOCUS;
   1396         }
   1397     }
   1398 
   1399     /**
   1400      * Check whether this ViewGroup should ignore focus requests for itself and its children.
   1401      */
   1402     @ViewDebug.ExportedProperty(category = "focus")
   1403     @InspectableProperty
   1404     public boolean getTouchscreenBlocksFocus() {
   1405         return (mGroupFlags & FLAG_TOUCHSCREEN_BLOCKS_FOCUS) != 0;
   1406     }
   1407 
   1408     boolean shouldBlockFocusForTouchscreen() {
   1409         // There is a special case for keyboard-navigation clusters. We allow cluster navigation
   1410         // to jump into blockFocusForTouchscreen ViewGroups which are clusters. Once in the
   1411         // cluster, focus is free to move around within it.
   1412         return getTouchscreenBlocksFocus() &&
   1413                 mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN)
   1414                 && !(isKeyboardNavigationCluster()
   1415                         && (hasFocus() || (findKeyboardNavigationCluster() != this)));
   1416     }
   1417 
   1418     @Override
   1419     public void findViewsWithText(ArrayList<View> outViews, CharSequence text, int flags) {
   1420         super.findViewsWithText(outViews, text, flags);
   1421         final int childrenCount = mChildrenCount;
   1422         final View[] children = mChildren;
   1423         for (int i = 0; i < childrenCount; i++) {
   1424             View child = children[i];
   1425             if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE
   1426                     && (child.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) {
   1427                 child.findViewsWithText(outViews, text, flags);
   1428             }
   1429         }
   1430     }
   1431 
   1432     /** @hide */
   1433     @Override
   1434     public View findViewByAccessibilityIdTraversal(int accessibilityId) {
   1435         View foundView = super.findViewByAccessibilityIdTraversal(accessibilityId);
   1436         if (foundView != null) {
   1437             return foundView;
   1438         }
   1439 
   1440         if (getAccessibilityNodeProvider() != null) {
   1441             return null;
   1442         }
   1443 
   1444         final int childrenCount = mChildrenCount;
   1445         final View[] children = mChildren;
   1446         for (int i = 0; i < childrenCount; i++) {
   1447             View child = children[i];
   1448             foundView = child.findViewByAccessibilityIdTraversal(accessibilityId);
   1449             if (foundView != null) {
   1450                 return foundView;
   1451             }
   1452         }
   1453 
   1454         return null;
   1455     }
   1456 
   1457     /** @hide */
   1458     @Override
   1459     public View findViewByAutofillIdTraversal(int autofillId) {
   1460         View foundView = super.findViewByAutofillIdTraversal(autofillId);
   1461         if (foundView != null) {
   1462             return foundView;
   1463         }
   1464 
   1465         final int childrenCount = mChildrenCount;
   1466         final View[] children = mChildren;
   1467         for (int i = 0; i < childrenCount; i++) {
   1468             View child = children[i];
   1469             foundView = child.findViewByAutofillIdTraversal(autofillId);
   1470             if (foundView != null) {
   1471                 return foundView;
   1472             }
   1473         }
   1474 
   1475         return null;
   1476     }
   1477 
   1478     @Override
   1479     public void dispatchWindowFocusChanged(boolean hasFocus) {
   1480         super.dispatchWindowFocusChanged(hasFocus);
   1481         final int count = mChildrenCount;
   1482         final View[] children = mChildren;
   1483         for (int i = 0; i < count; i++) {
   1484             children[i].dispatchWindowFocusChanged(hasFocus);
   1485         }
   1486     }
   1487 
   1488     @Override
   1489     public void addTouchables(ArrayList<View> views) {
   1490         super.addTouchables(views);
   1491 
   1492         final int count = mChildrenCount;
   1493         final View[] children = mChildren;
   1494 
   1495         for (int i = 0; i < count; i++) {
   1496             final View child = children[i];
   1497             if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
   1498                 child.addTouchables(views);
   1499             }
   1500         }
   1501     }
   1502 
   1503     /**
   1504      * @hide
   1505      */
   1506     @Override
   1507     @UnsupportedAppUsage
   1508     public void makeOptionalFitsSystemWindows() {
   1509         super.makeOptionalFitsSystemWindows();
   1510         final int count = mChildrenCount;
   1511         final View[] children = mChildren;
   1512         for (int i = 0; i < count; i++) {
   1513             children[i].makeOptionalFitsSystemWindows();
   1514         }
   1515     }
   1516 
   1517     @Override
   1518     public void dispatchDisplayHint(int hint) {
   1519         super.dispatchDisplayHint(hint);
   1520         final int count = mChildrenCount;
   1521         final View[] children = mChildren;
   1522         for (int i = 0; i < count; i++) {
   1523             children[i].dispatchDisplayHint(hint);
   1524         }
   1525     }
   1526 
   1527     /**
   1528      * Called when a view's visibility has changed. Notify the parent to take any appropriate
   1529      * action.
   1530      *
   1531      * @param child The view whose visibility has changed
   1532      * @param oldVisibility The previous visibility value (GONE, INVISIBLE, or VISIBLE).
   1533      * @param newVisibility The new visibility value (GONE, INVISIBLE, or VISIBLE).
   1534      * @hide
   1535      */
   1536     @UnsupportedAppUsage
   1537     protected void onChildVisibilityChanged(View child, int oldVisibility, int newVisibility) {
   1538         if (mTransition != null) {
   1539             if (newVisibility == VISIBLE) {
   1540                 mTransition.showChild(this, child, oldVisibility);
   1541             } else {
   1542                 mTransition.hideChild(this, child, newVisibility);
   1543                 if (mTransitioningViews != null && mTransitioningViews.contains(child)) {
   1544                     // Only track this on disappearing views - appearing views are already visible
   1545                     // and don't need special handling during drawChild()
   1546                     if (mVisibilityChangingChildren == null) {
   1547                         mVisibilityChangingChildren = new ArrayList<View>();
   1548                     }
   1549                     mVisibilityChangingChildren.add(child);
   1550                     addDisappearingView(child);
   1551                 }
   1552             }
   1553         }
   1554 
   1555         // in all cases, for drags
   1556         if (newVisibility == VISIBLE && mCurrentDragStartEvent != null) {
   1557             if (!mChildrenInterestedInDrag.contains(child)) {
   1558                 notifyChildOfDragStart(child);
   1559             }
   1560         }
   1561     }
   1562 
   1563     @Override
   1564     protected void dispatchVisibilityChanged(View changedView, int visibility) {
   1565         super.dispatchVisibilityChanged(changedView, visibility);
   1566         final int count = mChildrenCount;
   1567         final View[] children = mChildren;
   1568         for (int i = 0; i < count; i++) {
   1569             children[i].dispatchVisibilityChanged(changedView, visibility);
   1570         }
   1571     }
   1572 
   1573     @Override
   1574     public void dispatchWindowVisibilityChanged(int visibility) {
   1575         super.dispatchWindowVisibilityChanged(visibility);
   1576         final int count = mChildrenCount;
   1577         final View[] children = mChildren;
   1578         for (int i = 0; i < count; i++) {
   1579             children[i].dispatchWindowVisibilityChanged(visibility);
   1580         }
   1581     }
   1582 
   1583     @Override
   1584     boolean dispatchVisibilityAggregated(boolean isVisible) {
   1585         isVisible = super.dispatchVisibilityAggregated(isVisible);
   1586         final int count = mChildrenCount;
   1587         final View[] children = mChildren;
   1588         for (int i = 0; i < count; i++) {
   1589             // Only dispatch to visible children. Not visible children and their subtrees already
   1590             // know that they aren't visible and that's not going to change as a result of
   1591             // whatever triggered this dispatch.
   1592             if (children[i].getVisibility() == VISIBLE) {
   1593                 children[i].dispatchVisibilityAggregated(isVisible);
   1594             }
   1595         }
   1596         return isVisible;
   1597     }
   1598 
   1599     @Override
   1600     public void dispatchConfigurationChanged(Configuration newConfig) {
   1601         super.dispatchConfigurationChanged(newConfig);
   1602         final int count = mChildrenCount;
   1603         final View[] children = mChildren;
   1604         for (int i = 0; i < count; i++) {
   1605             children[i].dispatchConfigurationChanged(newConfig);
   1606         }
   1607     }
   1608 
   1609     @Override
   1610     public void recomputeViewAttributes(View child) {
   1611         if (mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) {
   1612             ViewParent parent = mParent;
   1613             if (parent != null) parent.recomputeViewAttributes(this);
   1614         }
   1615     }
   1616 
   1617     @Override
   1618     void dispatchCollectViewAttributes(AttachInfo attachInfo, int visibility) {
   1619         if ((visibility & VISIBILITY_MASK) == VISIBLE) {
   1620             super.dispatchCollectViewAttributes(attachInfo, visibility);
   1621             final int count = mChildrenCount;
   1622             final View[] children = mChildren;
   1623             for (int i = 0; i < count; i++) {
   1624                 final View child = children[i];
   1625                 child.dispatchCollectViewAttributes(attachInfo,
   1626                         visibility | (child.mViewFlags&VISIBILITY_MASK));
   1627             }
   1628         }
   1629     }
   1630 
   1631     @Override
   1632     public void bringChildToFront(View child) {
   1633         final int index = indexOfChild(child);
   1634         if (index >= 0) {
   1635             removeFromArray(index);
   1636             addInArray(child, mChildrenCount);
   1637             child.mParent = this;
   1638             requestLayout();
   1639             invalidate();
   1640         }
   1641     }
   1642 
   1643     private PointF getLocalPoint() {
   1644         if (mLocalPoint == null) mLocalPoint = new PointF();
   1645         return mLocalPoint;
   1646     }
   1647 
   1648     @Override
   1649     boolean dispatchDragEnterExitInPreN(DragEvent event) {
   1650         if (event.mAction == DragEvent.ACTION_DRAG_EXITED && mCurrentDragChild != null) {
   1651             // The drag exited a sub-tree of views; notify of the exit all descendants that are in
   1652             // entered state.
   1653             // We don't need this recursive delivery for ENTERED events because they get generated
   1654             // from the recursive delivery of LOCATION/DROP events, and hence, don't need their own
   1655             // recursion.
   1656             mCurrentDragChild.dispatchDragEnterExitInPreN(event);
   1657             mCurrentDragChild = null;
   1658         }
   1659         return mIsInterestedInDrag && super.dispatchDragEnterExitInPreN(event);
   1660     }
   1661 
   1662     // TODO: Write real docs
   1663     @Override
   1664     public boolean dispatchDragEvent(DragEvent event) {
   1665         boolean retval = false;
   1666         final float tx = event.mX;
   1667         final float ty = event.mY;
   1668         final ClipData td = event.mClipData;
   1669 
   1670         // Dispatch down the view hierarchy
   1671         final PointF localPoint = getLocalPoint();
   1672 
   1673         switch (event.mAction) {
   1674         case DragEvent.ACTION_DRAG_STARTED: {
   1675             // Clear the state to recalculate which views we drag over.
   1676             mCurrentDragChild = null;
   1677 
   1678             // Set up our tracking of drag-started notifications
   1679             mCurrentDragStartEvent = DragEvent.obtain(event);
   1680             if (mChildrenInterestedInDrag == null) {
   1681                 mChildrenInterestedInDrag = new HashSet<View>();
   1682             } else {
   1683                 mChildrenInterestedInDrag.clear();
   1684             }
   1685 
   1686             // Now dispatch down to our children, caching the responses
   1687             final int count = mChildrenCount;
   1688             final View[] children = mChildren;
   1689             for (int i = 0; i < count; i++) {
   1690                 final View child = children[i];
   1691                 child.mPrivateFlags2 &= ~View.DRAG_MASK;
   1692                 if (child.getVisibility() == VISIBLE) {
   1693                     if (notifyChildOfDragStart(children[i])) {
   1694                         retval = true;
   1695                     }
   1696                 }
   1697             }
   1698 
   1699             // Notify itself of the drag start.
   1700             mIsInterestedInDrag = super.dispatchDragEvent(event);
   1701             if (mIsInterestedInDrag) {
   1702                 retval = true;
   1703             }
   1704 
   1705             if (!retval) {
   1706                 // Neither us nor any of our children are interested in this drag, so stop tracking
   1707                 // the current drag event.
   1708                 mCurrentDragStartEvent.recycle();
   1709                 mCurrentDragStartEvent = null;
   1710             }
   1711         } break;
   1712 
   1713         case DragEvent.ACTION_DRAG_ENDED: {
   1714             // Release the bookkeeping now that the drag lifecycle has ended
   1715             final HashSet<View> childrenInterestedInDrag = mChildrenInterestedInDrag;
   1716             if (childrenInterestedInDrag != null) {
   1717                 for (View child : childrenInterestedInDrag) {
   1718                     // If a child was interested in the ongoing drag, it's told that it's over
   1719                     if (child.dispatchDragEvent(event)) {
   1720                         retval = true;
   1721                     }
   1722                 }
   1723                 childrenInterestedInDrag.clear();
   1724             }
   1725             if (mCurrentDragStartEvent != null) {
   1726                 mCurrentDragStartEvent.recycle();
   1727                 mCurrentDragStartEvent = null;
   1728             }
   1729 
   1730             if (mIsInterestedInDrag) {
   1731                 if (super.dispatchDragEvent(event)) {
   1732                     retval = true;
   1733                 }
   1734                 mIsInterestedInDrag = false;
   1735             }
   1736         } break;
   1737 
   1738         case DragEvent.ACTION_DRAG_LOCATION:
   1739         case DragEvent.ACTION_DROP: {
   1740             // Find the [possibly new] drag target
   1741             View target = findFrontmostDroppableChildAt(event.mX, event.mY, localPoint);
   1742 
   1743             if (target != mCurrentDragChild) {
   1744                 if (sCascadedDragDrop) {
   1745                     // For pre-Nougat apps, make sure that the whole hierarchy of views that contain
   1746                     // the drag location is kept in the state between ENTERED and EXITED events.
   1747                     // (Starting with N, only the innermost view will be in that state).
   1748 
   1749                     final int action = event.mAction;
   1750                     // Position should not be available for ACTION_DRAG_ENTERED and
   1751                     // ACTION_DRAG_EXITED.
   1752                     event.mX = 0;
   1753                     event.mY = 0;
   1754                     event.mClipData = null;
   1755 
   1756                     if (mCurrentDragChild != null) {
   1757                         event.mAction = DragEvent.ACTION_DRAG_EXITED;
   1758                         mCurrentDragChild.dispatchDragEnterExitInPreN(event);
   1759                     }
   1760 
   1761                     if (target != null) {
   1762                         event.mAction = DragEvent.ACTION_DRAG_ENTERED;
   1763                         target.dispatchDragEnterExitInPreN(event);
   1764                     }
   1765 
   1766                     event.mAction = action;
   1767                     event.mX = tx;
   1768                     event.mY = ty;
   1769                     event.mClipData = td;
   1770                 }
   1771                 mCurrentDragChild = target;
   1772             }
   1773 
   1774             if (target == null && mIsInterestedInDrag) {
   1775                 target = this;
   1776             }
   1777 
   1778             // Dispatch the actual drag notice, localized into the target coordinates.
   1779             if (target != null) {
   1780                 if (target != this) {
   1781                     event.mX = localPoint.x;
   1782                     event.mY = localPoint.y;
   1783 
   1784                     retval = target.dispatchDragEvent(event);
   1785 
   1786                     event.mX = tx;
   1787                     event.mY = ty;
   1788 
   1789                     if (mIsInterestedInDrag) {
   1790                         final boolean eventWasConsumed;
   1791                         if (sCascadedDragDrop) {
   1792                             eventWasConsumed = retval;
   1793                         } else {
   1794                             eventWasConsumed = event.mEventHandlerWasCalled;
   1795                         }
   1796 
   1797                         if (!eventWasConsumed) {
   1798                             retval = super.dispatchDragEvent(event);
   1799                         }
   1800                     }
   1801                 } else {
   1802                     retval = super.dispatchDragEvent(event);
   1803                 }
   1804             }
   1805         } break;
   1806         }
   1807 
   1808         return retval;
   1809     }
   1810 
   1811     // Find the frontmost child view that lies under the given point, and calculate
   1812     // the position within its own local coordinate system.
   1813     View findFrontmostDroppableChildAt(float x, float y, PointF outLocalPoint) {
   1814         final int count = mChildrenCount;
   1815         final View[] children = mChildren;
   1816         for (int i = count - 1; i >= 0; i--) {
   1817             final View child = children[i];
   1818             if (!child.canAcceptDrag()) {
   1819                 continue;
   1820             }
   1821 
   1822             if (isTransformedTouchPointInView(x, y, child, outLocalPoint)) {
   1823                 return child;
   1824             }
   1825         }
   1826         return null;
   1827     }
   1828 
   1829     boolean notifyChildOfDragStart(View child) {
   1830         // The caller guarantees that the child is not in mChildrenInterestedInDrag yet.
   1831 
   1832         if (ViewDebug.DEBUG_DRAG) {
   1833             Log.d(View.VIEW_LOG_TAG, "Sending drag-started to view: " + child);
   1834         }
   1835 
   1836         final float tx = mCurrentDragStartEvent.mX;
   1837         final float ty = mCurrentDragStartEvent.mY;
   1838 
   1839         final float[] point = getTempPoint();
   1840         point[0] = tx;
   1841         point[1] = ty;
   1842         transformPointToViewLocal(point, child);
   1843 
   1844         mCurrentDragStartEvent.mX = point[0];
   1845         mCurrentDragStartEvent.mY = point[1];
   1846         final boolean canAccept = child.dispatchDragEvent(mCurrentDragStartEvent);
   1847         mCurrentDragStartEvent.mX = tx;
   1848         mCurrentDragStartEvent.mY = ty;
   1849         mCurrentDragStartEvent.mEventHandlerWasCalled = false;
   1850         if (canAccept) {
   1851             mChildrenInterestedInDrag.add(child);
   1852             if (!child.canAcceptDrag()) {
   1853                 child.mPrivateFlags2 |= View.PFLAG2_DRAG_CAN_ACCEPT;
   1854                 child.refreshDrawableState();
   1855             }
   1856         }
   1857         return canAccept;
   1858     }
   1859 
   1860     @Override
   1861     public void dispatchWindowSystemUiVisiblityChanged(int visible) {
   1862         super.dispatchWindowSystemUiVisiblityChanged(visible);
   1863 
   1864         final int count = mChildrenCount;
   1865         final View[] children = mChildren;
   1866         for (int i=0; i <count; i++) {
   1867             final View child = children[i];
   1868             child.dispatchWindowSystemUiVisiblityChanged(visible);
   1869         }
   1870     }
   1871 
   1872     @Override
   1873     public void dispatchSystemUiVisibilityChanged(int visible) {
   1874         super.dispatchSystemUiVisibilityChanged(visible);
   1875 
   1876         final int count = mChildrenCount;
   1877         final View[] children = mChildren;
   1878         for (int i=0; i <count; i++) {
   1879             final View child = children[i];
   1880             child.dispatchSystemUiVisibilityChanged(visible);
   1881         }
   1882     }
   1883 
   1884     @Override
   1885     boolean updateLocalSystemUiVisibility(int localValue, int localChanges) {
   1886         boolean changed = super.updateLocalSystemUiVisibility(localValue, localChanges);
   1887 
   1888         final int count = mChildrenCount;
   1889         final View[] children = mChildren;
   1890         for (int i=0; i <count; i++) {
   1891             final View child = children[i];
   1892             changed |= child.updateLocalSystemUiVisibility(localValue, localChanges);
   1893         }
   1894         return changed;
   1895     }
   1896 
   1897     @Override
   1898     public boolean dispatchKeyEventPreIme(KeyEvent event) {
   1899         if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
   1900                 == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
   1901             return super.dispatchKeyEventPreIme(event);
   1902         } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
   1903                 == PFLAG_HAS_BOUNDS) {
   1904             return mFocused.dispatchKeyEventPreIme(event);
   1905         }
   1906         return false;
   1907     }
   1908 
   1909     @Override
   1910     public boolean dispatchKeyEvent(KeyEvent event) {
   1911         if (mInputEventConsistencyVerifier != null) {
   1912             mInputEventConsistencyVerifier.onKeyEvent(event, 1);
   1913         }
   1914 
   1915         if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
   1916                 == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
   1917             if (super.dispatchKeyEvent(event)) {
   1918                 return true;
   1919             }
   1920         } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
   1921                 == PFLAG_HAS_BOUNDS) {
   1922             if (mFocused.dispatchKeyEvent(event)) {
   1923                 return true;
   1924             }
   1925         }
   1926 
   1927         if (mInputEventConsistencyVerifier != null) {
   1928             mInputEventConsistencyVerifier.onUnhandledEvent(event, 1);
   1929         }
   1930         return false;
   1931     }
   1932 
   1933     @Override
   1934     public boolean dispatchKeyShortcutEvent(KeyEvent event) {
   1935         if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
   1936                 == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
   1937             return super.dispatchKeyShortcutEvent(event);
   1938         } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
   1939                 == PFLAG_HAS_BOUNDS) {
   1940             return mFocused.dispatchKeyShortcutEvent(event);
   1941         }
   1942         return false;
   1943     }
   1944 
   1945     @Override
   1946     public boolean dispatchTrackballEvent(MotionEvent event) {
   1947         if (mInputEventConsistencyVerifier != null) {
   1948             mInputEventConsistencyVerifier.onTrackballEvent(event, 1);
   1949         }
   1950 
   1951         if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
   1952                 == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
   1953             if (super.dispatchTrackballEvent(event)) {
   1954                 return true;
   1955             }
   1956         } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
   1957                 == PFLAG_HAS_BOUNDS) {
   1958             if (mFocused.dispatchTrackballEvent(event)) {
   1959                 return true;
   1960             }
   1961         }
   1962 
   1963         if (mInputEventConsistencyVerifier != null) {
   1964             mInputEventConsistencyVerifier.onUnhandledEvent(event, 1);
   1965         }
   1966         return false;
   1967     }
   1968 
   1969     @Override
   1970     public boolean dispatchCapturedPointerEvent(MotionEvent event) {
   1971         if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
   1972                 == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
   1973             if (super.dispatchCapturedPointerEvent(event)) {
   1974                 return true;
   1975             }
   1976         } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
   1977                 == PFLAG_HAS_BOUNDS) {
   1978             if (mFocused.dispatchCapturedPointerEvent(event)) {
   1979                 return true;
   1980             }
   1981         }
   1982         return false;
   1983     }
   1984 
   1985     @Override
   1986     public void dispatchPointerCaptureChanged(boolean hasCapture) {
   1987         exitHoverTargets();
   1988 
   1989         super.dispatchPointerCaptureChanged(hasCapture);
   1990         final int count = mChildrenCount;
   1991         final View[] children = mChildren;
   1992         for (int i = 0; i < count; i++) {
   1993             children[i].dispatchPointerCaptureChanged(hasCapture);
   1994         }
   1995     }
   1996 
   1997     @Override
   1998     public PointerIcon onResolvePointerIcon(MotionEvent event, int pointerIndex) {
   1999         final float x = event.getX(pointerIndex);
   2000         final float y = event.getY(pointerIndex);
   2001         if (isOnScrollbarThumb(x, y) || isDraggingScrollBar()) {
   2002             return PointerIcon.getSystemIcon(mContext, PointerIcon.TYPE_ARROW);
   2003         }
   2004         // Check what the child under the pointer says about the pointer.
   2005         final int childrenCount = mChildrenCount;
   2006         if (childrenCount != 0) {
   2007             final ArrayList<View> preorderedList = buildOrderedChildList();
   2008             final boolean customOrder = preorderedList == null
   2009                     && isChildrenDrawingOrderEnabled();
   2010             final View[] children = mChildren;
   2011             for (int i = childrenCount - 1; i >= 0; i--) {
   2012                 final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
   2013                 final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex);
   2014                 if (!child.canReceivePointerEvents()
   2015                         || !isTransformedTouchPointInView(x, y, child, null)) {
   2016                     continue;
   2017                 }
   2018                 final PointerIcon pointerIcon =
   2019                         dispatchResolvePointerIcon(event, pointerIndex, child);
   2020                 if (pointerIcon != null) {
   2021                     if (preorderedList != null) preorderedList.clear();
   2022                     return pointerIcon;
   2023                 }
   2024             }
   2025             if (preorderedList != null) preorderedList.clear();
   2026         }
   2027 
   2028         // The pointer is not a child or the child has no preferences, returning the default
   2029         // implementation.
   2030         return super.onResolvePointerIcon(event, pointerIndex);
   2031     }
   2032 
   2033     private PointerIcon dispatchResolvePointerIcon(MotionEvent event, int pointerIndex,
   2034             View child) {
   2035         final PointerIcon pointerIcon;
   2036         if (!child.hasIdentityMatrix()) {
   2037             MotionEvent transformedEvent = getTransformedMotionEvent(event, child);
   2038             pointerIcon = child.onResolvePointerIcon(transformedEvent, pointerIndex);
   2039             transformedEvent.recycle();
   2040         } else {
   2041             final float offsetX = mScrollX - child.mLeft;
   2042             final float offsetY = mScrollY - child.mTop;
   2043             event.offsetLocation(offsetX, offsetY);
   2044             pointerIcon = child.onResolvePointerIcon(event, pointerIndex);
   2045             event.offsetLocation(-offsetX, -offsetY);
   2046         }
   2047         return pointerIcon;
   2048     }
   2049 
   2050     private int getAndVerifyPreorderedIndex(int childrenCount, int i, boolean customOrder) {
   2051         final int childIndex;
   2052         if (customOrder) {
   2053             final int childIndex1 = getChildDrawingOrder(childrenCount, i);
   2054             if (childIndex1 >= childrenCount) {
   2055                 throw new IndexOutOfBoundsException("getChildDrawingOrder() "
   2056                         + "returned invalid index " + childIndex1
   2057                         + " (child count is " + childrenCount + ")");
   2058             }
   2059             childIndex = childIndex1;
   2060         } else {
   2061             childIndex = i;
   2062         }
   2063         return childIndex;
   2064     }
   2065 
   2066     @SuppressWarnings({"ConstantConditions"})
   2067     @Override
   2068     protected boolean dispatchHoverEvent(MotionEvent event) {
   2069         final int action = event.getAction();
   2070 
   2071         // First check whether the view group wants to intercept the hover event.
   2072         final boolean interceptHover = onInterceptHoverEvent(event);
   2073         event.setAction(action); // restore action in case it was changed
   2074 
   2075         MotionEvent eventNoHistory = event;
   2076         boolean handled = false;
   2077 
   2078         // Send events to the hovered children and build a new list of hover targets until
   2079         // one is found that handles the event.
   2080         HoverTarget firstOldHoverTarget = mFirstHoverTarget;
   2081         mFirstHoverTarget = null;
   2082         if (!interceptHover && action != MotionEvent.ACTION_HOVER_EXIT) {
   2083             final float x = event.getX();
   2084             final float y = event.getY();
   2085             final int childrenCount = mChildrenCount;
   2086             if (childrenCount != 0) {
   2087                 final ArrayList<View> preorderedList = buildOrderedChildList();
   2088                 final boolean customOrder = preorderedList == null
   2089                         && isChildrenDrawingOrderEnabled();
   2090                 final View[] children = mChildren;
   2091                 HoverTarget lastHoverTarget = null;
   2092                 for (int i = childrenCount - 1; i >= 0; i--) {
   2093                     final int childIndex = getAndVerifyPreorderedIndex(
   2094                             childrenCount, i, customOrder);
   2095                     final View child = getAndVerifyPreorderedView(
   2096                             preorderedList, children, childIndex);
   2097                     if (!child.canReceivePointerEvents()
   2098                             || !isTransformedTouchPointInView(x, y, child, null)) {
   2099                         continue;
   2100                     }
   2101 
   2102                     // Obtain a hover target for this child.  Dequeue it from the
   2103                     // old hover target list if the child was previously hovered.
   2104                     HoverTarget hoverTarget = firstOldHoverTarget;
   2105                     final boolean wasHovered;
   2106                     for (HoverTarget predecessor = null; ;) {
   2107                         if (hoverTarget == null) {
   2108                             hoverTarget = HoverTarget.obtain(child);
   2109                             wasHovered = false;
   2110                             break;
   2111                         }
   2112 
   2113                         if (hoverTarget.child == child) {
   2114                             if (predecessor != null) {
   2115                                 predecessor.next = hoverTarget.next;
   2116                             } else {
   2117                                 firstOldHoverTarget = hoverTarget.next;
   2118                             }
   2119                             hoverTarget.next = null;
   2120                             wasHovered = true;
   2121                             break;
   2122                         }
   2123 
   2124                         predecessor = hoverTarget;
   2125                         hoverTarget = hoverTarget.next;
   2126                     }
   2127 
   2128                     // Enqueue the hover target onto the new hover target list.
   2129                     if (lastHoverTarget != null) {
   2130                         lastHoverTarget.next = hoverTarget;
   2131                     } else {
   2132                         mFirstHoverTarget = hoverTarget;
   2133                     }
   2134                     lastHoverTarget = hoverTarget;
   2135 
   2136                     // Dispatch the event to the child.
   2137                     if (action == MotionEvent.ACTION_HOVER_ENTER) {
   2138                         if (!wasHovered) {
   2139                             // Send the enter as is.
   2140                             handled |= dispatchTransformedGenericPointerEvent(
   2141                                     event, child); // enter
   2142                         }
   2143                     } else if (action == MotionEvent.ACTION_HOVER_MOVE) {
   2144                         if (!wasHovered) {
   2145                             // Synthesize an enter from a move.
   2146                             eventNoHistory = obtainMotionEventNoHistoryOrSelf(eventNoHistory);
   2147                             eventNoHistory.setAction(MotionEvent.ACTION_HOVER_ENTER);
   2148                             handled |= dispatchTransformedGenericPointerEvent(
   2149                                     eventNoHistory, child); // enter
   2150                             eventNoHistory.setAction(action);
   2151 
   2152                             handled |= dispatchTransformedGenericPointerEvent(
   2153                                     eventNoHistory, child); // move
   2154                         } else {
   2155                             // Send the move as is.
   2156                             handled |= dispatchTransformedGenericPointerEvent(event, child);
   2157                         }
   2158                     }
   2159                     if (handled) {
   2160                         break;
   2161                     }
   2162                 }
   2163                 if (preorderedList != null) preorderedList.clear();
   2164             }
   2165         }
   2166 
   2167         // Send exit events to all previously hovered children that are no longer hovered.
   2168         while (firstOldHoverTarget != null) {
   2169             final View child = firstOldHoverTarget.child;
   2170 
   2171             // Exit the old hovered child.
   2172             if (action == MotionEvent.ACTION_HOVER_EXIT) {
   2173                 // Send the exit as is.
   2174                 handled |= dispatchTransformedGenericPointerEvent(
   2175                         event, child); // exit
   2176             } else {
   2177                 // Synthesize an exit from a move or enter.
   2178                 // Ignore the result because hover focus has moved to a different view.
   2179                 if (action == MotionEvent.ACTION_HOVER_MOVE) {
   2180                     final boolean hoverExitPending = event.isHoverExitPending();
   2181                     event.setHoverExitPending(true);
   2182                     dispatchTransformedGenericPointerEvent(
   2183                             event, child); // move
   2184                     event.setHoverExitPending(hoverExitPending);
   2185                 }
   2186                 eventNoHistory = obtainMotionEventNoHistoryOrSelf(eventNoHistory);
   2187                 eventNoHistory.setAction(MotionEvent.ACTION_HOVER_EXIT);
   2188                 dispatchTransformedGenericPointerEvent(
   2189                         eventNoHistory, child); // exit
   2190                 eventNoHistory.setAction(action);
   2191             }
   2192 
   2193             final HoverTarget nextOldHoverTarget = firstOldHoverTarget.next;
   2194             firstOldHoverTarget.recycle();
   2195             firstOldHoverTarget = nextOldHoverTarget;
   2196         }
   2197 
   2198         // Send events to the view group itself if no children have handled it and the view group
   2199         // itself is not currently being hover-exited.
   2200         boolean newHoveredSelf = !handled &&
   2201                 (action != MotionEvent.ACTION_HOVER_EXIT) && !event.isHoverExitPending();
   2202         if (newHoveredSelf == mHoveredSelf) {
   2203             if (newHoveredSelf) {
   2204                 // Send event to the view group as before.
   2205                 handled |= super.dispatchHoverEvent(event);
   2206             }
   2207         } else {
   2208             if (mHoveredSelf) {
   2209                 // Exit the view group.
   2210                 if (action == MotionEvent.ACTION_HOVER_EXIT) {
   2211                     // Send the exit as is.
   2212                     handled |= super.dispatchHoverEvent(event); // exit
   2213                 } else {
   2214                     // Synthesize an exit from a move or enter.
   2215                     // Ignore the result because hover focus is moving to a different view.
   2216                     if (action == MotionEvent.ACTION_HOVER_MOVE) {
   2217                         super.dispatchHoverEvent(event); // move
   2218                     }
   2219                     eventNoHistory = obtainMotionEventNoHistoryOrSelf(eventNoHistory);
   2220                     eventNoHistory.setAction(MotionEvent.ACTION_HOVER_EXIT);
   2221                     super.dispatchHoverEvent(eventNoHistory); // exit
   2222                     eventNoHistory.setAction(action);
   2223                 }
   2224                 mHoveredSelf = false;
   2225             }
   2226 
   2227             if (newHoveredSelf) {
   2228                 // Enter the view group.
   2229                 if (action == MotionEvent.ACTION_HOVER_ENTER) {
   2230                     // Send the enter as is.
   2231                     handled |= super.dispatchHoverEvent(event); // enter
   2232                     mHoveredSelf = true;
   2233                 } else if (action == MotionEvent.ACTION_HOVER_MOVE) {
   2234                     // Synthesize an enter from a move.
   2235                     eventNoHistory = obtainMotionEventNoHistoryOrSelf(eventNoHistory);
   2236                     eventNoHistory.setAction(MotionEvent.ACTION_HOVER_ENTER);
   2237                     handled |= super.dispatchHoverEvent(eventNoHistory); // enter
   2238                     eventNoHistory.setAction(action);
   2239 
   2240                     handled |= super.dispatchHoverEvent(eventNoHistory); // move
   2241                     mHoveredSelf = true;
   2242                 }
   2243             }
   2244         }
   2245 
   2246         // Recycle the copy of the event that we made.
   2247         if (eventNoHistory != event) {
   2248             eventNoHistory.recycle();
   2249         }
   2250 
   2251         // Done.
   2252         return handled;
   2253     }
   2254 
   2255     private void exitHoverTargets() {
   2256         if (mHoveredSelf || mFirstHoverTarget != null) {
   2257             final long now = SystemClock.uptimeMillis();
   2258             MotionEvent event = MotionEvent.obtain(now, now,
   2259                     MotionEvent.ACTION_HOVER_EXIT, 0.0f, 0.0f, 0);
   2260             event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
   2261             dispatchHoverEvent(event);
   2262             event.recycle();
   2263         }
   2264     }
   2265 
   2266     private void cancelHoverTarget(View view) {
   2267         HoverTarget predecessor = null;
   2268         HoverTarget target = mFirstHoverTarget;
   2269         while (target != null) {
   2270             final HoverTarget next = target.next;
   2271             if (target.child == view) {
   2272                 if (predecessor == null) {
   2273                     mFirstHoverTarget = next;
   2274                 } else {
   2275                     predecessor.next = next;
   2276                 }
   2277                 target.recycle();
   2278 
   2279                 final long now = SystemClock.uptimeMillis();
   2280                 MotionEvent event = MotionEvent.obtain(now, now,
   2281                         MotionEvent.ACTION_HOVER_EXIT, 0.0f, 0.0f, 0);
   2282                 event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
   2283                 view.dispatchHoverEvent(event);
   2284                 event.recycle();
   2285                 return;
   2286             }
   2287             predecessor = target;
   2288             target = next;
   2289         }
   2290     }
   2291 
   2292     @Override
   2293     boolean dispatchTooltipHoverEvent(MotionEvent event) {
   2294         final int action = event.getAction();
   2295         switch (action) {
   2296             case MotionEvent.ACTION_HOVER_ENTER:
   2297                 break;
   2298 
   2299             case MotionEvent.ACTION_HOVER_MOVE:
   2300                 View newTarget = null;
   2301 
   2302                 // Check what the child under the pointer says about the tooltip.
   2303                 final int childrenCount = mChildrenCount;
   2304                 if (childrenCount != 0) {
   2305                     final float x = event.getX();
   2306                     final float y = event.getY();
   2307 
   2308                     final ArrayList<View> preorderedList = buildOrderedChildList();
   2309                     final boolean customOrder = preorderedList == null
   2310                             && isChildrenDrawingOrderEnabled();
   2311                     final View[] children = mChildren;
   2312                     for (int i = childrenCount - 1; i >= 0; i--) {
   2313                         final int childIndex =
   2314                                 getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
   2315                         final View child =
   2316                                 getAndVerifyPreorderedView(preorderedList, children, childIndex);
   2317                         if (!child.canReceivePointerEvents()
   2318                                 || !isTransformedTouchPointInView(x, y, child, null)) {
   2319                             continue;
   2320                         }
   2321                         if (dispatchTooltipHoverEvent(event, child)) {
   2322                             newTarget = child;
   2323                             break;
   2324                         }
   2325                     }
   2326                     if (preorderedList != null) preorderedList.clear();
   2327                 }
   2328 
   2329                 if (mTooltipHoverTarget != newTarget) {
   2330                     if (mTooltipHoverTarget != null) {
   2331                         event.setAction(MotionEvent.ACTION_HOVER_EXIT);
   2332                         mTooltipHoverTarget.dispatchTooltipHoverEvent(event);
   2333                         event.setAction(action);
   2334                     }
   2335                     mTooltipHoverTarget = newTarget;
   2336                 }
   2337 
   2338                 if (mTooltipHoverTarget != null) {
   2339                     if (mTooltipHoveredSelf) {
   2340                         mTooltipHoveredSelf = false;
   2341                         event.setAction(MotionEvent.ACTION_HOVER_EXIT);
   2342                         super.dispatchTooltipHoverEvent(event);
   2343                         event.setAction(action);
   2344                     }
   2345                     return true;
   2346                 }
   2347 
   2348                 mTooltipHoveredSelf = super.dispatchTooltipHoverEvent(event);
   2349                 return mTooltipHoveredSelf;
   2350 
   2351             case MotionEvent.ACTION_HOVER_EXIT:
   2352                 if (mTooltipHoverTarget != null) {
   2353                     mTooltipHoverTarget.dispatchTooltipHoverEvent(event);
   2354                     mTooltipHoverTarget = null;
   2355                 } else if (mTooltipHoveredSelf) {
   2356                     super.dispatchTooltipHoverEvent(event);
   2357                     mTooltipHoveredSelf = false;
   2358                 }
   2359                 break;
   2360         }
   2361         return false;
   2362     }
   2363 
   2364     private boolean dispatchTooltipHoverEvent(MotionEvent event, View child) {
   2365         final boolean result;
   2366         if (!child.hasIdentityMatrix()) {
   2367             MotionEvent transformedEvent = getTransformedMotionEvent(event, child);
   2368             result = child.dispatchTooltipHoverEvent(transformedEvent);
   2369             transformedEvent.recycle();
   2370         } else {
   2371             final float offsetX = mScrollX - child.mLeft;
   2372             final float offsetY = mScrollY - child.mTop;
   2373             event.offsetLocation(offsetX, offsetY);
   2374             result = child.dispatchTooltipHoverEvent(event);
   2375             event.offsetLocation(-offsetX, -offsetY);
   2376         }
   2377         return result;
   2378     }
   2379 
   2380     private void exitTooltipHoverTargets() {
   2381         if (mTooltipHoveredSelf || mTooltipHoverTarget != null) {
   2382             final long now = SystemClock.uptimeMillis();
   2383             MotionEvent event = MotionEvent.obtain(now, now,
   2384                     MotionEvent.ACTION_HOVER_EXIT, 0.0f, 0.0f, 0);
   2385             event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
   2386             dispatchTooltipHoverEvent(event);
   2387             event.recycle();
   2388         }
   2389     }
   2390 
   2391     /** @hide */
   2392     @Override
   2393     protected boolean hasHoveredChild() {
   2394         return mFirstHoverTarget != null;
   2395     }
   2396 
   2397     /** @hide */
   2398     @Override
   2399     protected boolean pointInHoveredChild(MotionEvent event) {
   2400         if (mFirstHoverTarget != null) {
   2401             return isTransformedTouchPointInView(event.getX(), event.getY(),
   2402                 mFirstHoverTarget.child, null);
   2403         }
   2404         return false;
   2405     }
   2406 
   2407     @Override
   2408     public void addChildrenForAccessibility(ArrayList<View> outChildren) {
   2409         if (getAccessibilityNodeProvider() != null) {
   2410             return;
   2411         }
   2412         ChildListForAccessibility children = ChildListForAccessibility.obtain(this, true);
   2413         try {
   2414             final int childrenCount = children.getChildCount();
   2415             for (int i = 0; i < childrenCount; i++) {
   2416                 View child = children.getChildAt(i);
   2417                 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
   2418                     if (child.includeForAccessibility()) {
   2419                         outChildren.add(child);
   2420                     } else {
   2421                         child.addChildrenForAccessibility(outChildren);
   2422                     }
   2423                 }
   2424             }
   2425         } finally {
   2426             children.recycle();
   2427         }
   2428     }
   2429 
   2430     /**
   2431      * Implement this method to intercept hover events before they are handled
   2432      * by child views.
   2433      * <p>
   2434      * This method is called before dispatching a hover event to a child of
   2435      * the view group or to the view group's own {@link #onHoverEvent} to allow
   2436      * the view group a chance to intercept the hover event.
   2437      * This method can also be used to watch all pointer motions that occur within
   2438      * the bounds of the view group even when the pointer is hovering over
   2439      * a child of the view group rather than over the view group itself.
   2440      * </p><p>
   2441      * The view group can prevent its children from receiving hover events by
   2442      * implementing this method and returning <code>true</code> to indicate
   2443      * that it would like to intercept hover events.  The view group must
   2444      * continuously return <code>true</code> from {@link #onInterceptHoverEvent}
   2445      * for as long as it wishes to continue intercepting hover events from
   2446      * its children.
   2447      * </p><p>
   2448      * Interception preserves the invariant that at most one view can be
   2449      * hovered at a time by transferring hover focus from the currently hovered
   2450      * child to the view group or vice-versa as needed.
   2451      * </p><p>
   2452      * If this method returns <code>true</code> and a child is already hovered, then the
   2453      * child view will first receive a hover exit event and then the view group
   2454      * itself will receive a hover enter event in {@link #onHoverEvent}.
   2455      * Likewise, if this method had previously returned <code>true</code> to intercept hover
   2456      * events and instead returns <code>false</code> while the pointer is hovering
   2457      * within the bounds of one of a child, then the view group will first receive a
   2458      * hover exit event in {@link #onHoverEvent} and then the hovered child will
   2459      * receive a hover enter event.
   2460      * </p><p>
   2461      * The default implementation handles mouse hover on the scroll bars.
   2462      * </p>
   2463      *
   2464      * @param event The motion event that describes the hover.
   2465      * @return True if the view group would like to intercept the hover event
   2466      * and prevent its children from receiving it.
   2467      */
   2468     public boolean onInterceptHoverEvent(MotionEvent event) {
   2469         if (event.isFromSource(InputDevice.SOURCE_MOUSE)) {
   2470             final int action = event.getAction();
   2471             final float x = event.getX();
   2472             final float y = event.getY();
   2473             if ((action == MotionEvent.ACTION_HOVER_MOVE
   2474                     || action == MotionEvent.ACTION_HOVER_ENTER) && isOnScrollbar(x, y)) {
   2475                 return true;
   2476             }
   2477         }
   2478         return false;
   2479     }
   2480 
   2481     private static MotionEvent obtainMotionEventNoHistoryOrSelf(MotionEvent event) {
   2482         if (event.getHistorySize() == 0) {
   2483             return event;
   2484         }
   2485         return MotionEvent.obtainNoHistory(event);
   2486     }
   2487 
   2488     @Override
   2489     protected boolean dispatchGenericPointerEvent(MotionEvent event) {
   2490         // Send the event to the child under the pointer.
   2491         final int childrenCount = mChildrenCount;
   2492         if (childrenCount != 0) {
   2493             final float x = event.getX();
   2494             final float y = event.getY();
   2495 
   2496             final ArrayList<View> preorderedList = buildOrderedChildList();
   2497             final boolean customOrder = preorderedList == null
   2498                     && isChildrenDrawingOrderEnabled();
   2499             final View[] children = mChildren;
   2500             for (int i = childrenCount - 1; i >= 0; i--) {
   2501                 final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
   2502                 final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex);
   2503                 if (!child.canReceivePointerEvents()
   2504                         || !isTransformedTouchPointInView(x, y, child, null)) {
   2505                     continue;
   2506                 }
   2507 
   2508                 if (dispatchTransformedGenericPointerEvent(event, child)) {
   2509                     if (preorderedList != null) preorderedList.clear();
   2510                     return true;
   2511                 }
   2512             }
   2513             if (preorderedList != null) preorderedList.clear();
   2514         }
   2515 
   2516         // No child handled the event.  Send it to this view group.
   2517         return super.dispatchGenericPointerEvent(event);
   2518     }
   2519 
   2520     @Override
   2521     protected boolean dispatchGenericFocusedEvent(MotionEvent event) {
   2522         // Send the event to the focused child or to this view group if it has focus.
   2523         if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
   2524                 == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
   2525             return super.dispatchGenericFocusedEvent(event);
   2526         } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
   2527                 == PFLAG_HAS_BOUNDS) {
   2528             return mFocused.dispatchGenericMotionEvent(event);
   2529         }
   2530         return false;
   2531     }
   2532 
   2533     /**
   2534      * Dispatches a generic pointer event to a child, taking into account
   2535      * transformations that apply to the child.
   2536      *
   2537      * @param event The event to send.
   2538      * @param child The view to send the event to.
   2539      * @return {@code true} if the child handled the event.
   2540      */
   2541     private boolean dispatchTransformedGenericPointerEvent(MotionEvent event, View child) {
   2542         boolean handled;
   2543         if (!child.hasIdentityMatrix()) {
   2544             MotionEvent transformedEvent = getTransformedMotionEvent(event, child);
   2545             handled = child.dispatchGenericMotionEvent(transformedEvent);
   2546             transformedEvent.recycle();
   2547         } else {
   2548             final float offsetX = mScrollX - child.mLeft;
   2549             final float offsetY = mScrollY - child.mTop;
   2550             event.offsetLocation(offsetX, offsetY);
   2551             handled = child.dispatchGenericMotionEvent(event);
   2552             event.offsetLocation(-offsetX, -offsetY);
   2553         }
   2554         return handled;
   2555     }
   2556 
   2557     /**
   2558      * Returns a MotionEvent that's been transformed into the child's local coordinates.
   2559      *
   2560      * It's the responsibility of the caller to recycle it once they're finished with it.
   2561      * @param event The event to transform.
   2562      * @param child The view whose coordinate space is to be used.
   2563      * @return A copy of the the given MotionEvent, transformed into the given View's coordinate
   2564      *         space.
   2565      */
   2566     private MotionEvent getTransformedMotionEvent(MotionEvent event, View child) {
   2567         final float offsetX = mScrollX - child.mLeft;
   2568         final float offsetY = mScrollY - child.mTop;
   2569         final MotionEvent transformedEvent = MotionEvent.obtain(event);
   2570         transformedEvent.offsetLocation(offsetX, offsetY);
   2571         if (!child.hasIdentityMatrix()) {
   2572             transformedEvent.transform(child.getInverseMatrix());
   2573         }
   2574         return transformedEvent;
   2575     }
   2576 
   2577     @Override
   2578     public boolean dispatchTouchEvent(MotionEvent ev) {
   2579         if (mInputEventConsistencyVerifier != null) {
   2580             mInputEventConsistencyVerifier.onTouchEvent(ev, 1);
   2581         }
   2582 
   2583         // If the event targets the accessibility focused view and this is it, start
   2584         // normal event dispatch. Maybe a descendant is what will handle the click.
   2585         if (ev.isTargetAccessibilityFocus() && isAccessibilityFocusedViewOrHost()) {
   2586             ev.setTargetAccessibilityFocus(false);
   2587         }
   2588 
   2589         boolean handled = false;
   2590         if (onFilterTouchEventForSecurity(ev)) {
   2591             final int action = ev.getAction();
   2592             final int actionMasked = action & MotionEvent.ACTION_MASK;
   2593 
   2594             // Handle an initial down.
   2595             if (actionMasked == MotionEvent.ACTION_DOWN) {
   2596                 // Throw away all previous state when starting a new touch gesture.
   2597                 // The framework may have dropped the up or cancel event for the previous gesture
   2598                 // due to an app switch, ANR, or some other state change.
   2599                 cancelAndClearTouchTargets(ev);
   2600                 resetTouchState();
   2601             }
   2602 
   2603             // Check for interception.
   2604             final boolean intercepted;
   2605             if (actionMasked == MotionEvent.ACTION_DOWN
   2606                     || mFirstTouchTarget != null) {
   2607                 final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
   2608                 if (!disallowIntercept) {
   2609                     intercepted = onInterceptTouchEvent(ev);
   2610                     ev.setAction(action); // restore action in case it was changed
   2611                 } else {
   2612                     intercepted = false;
   2613                 }
   2614             } else {
   2615                 // There are no touch targets and this action is not an initial down
   2616                 // so this view group continues to intercept touches.
   2617                 intercepted = true;
   2618             }
   2619 
   2620             // If intercepted, start normal event dispatch. Also if there is already
   2621             // a view that is handling the gesture, do normal event dispatch.
   2622             if (intercepted || mFirstTouchTarget != null) {
   2623                 ev.setTargetAccessibilityFocus(false);
   2624             }
   2625 
   2626             // Check for cancelation.
   2627             final boolean canceled = resetCancelNextUpFlag(this)
   2628                     || actionMasked == MotionEvent.ACTION_CANCEL;
   2629 
   2630             // Update list of touch targets for pointer down, if needed.
   2631             final boolean split = (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) != 0;
   2632             TouchTarget newTouchTarget = null;
   2633             boolean alreadyDispatchedToNewTouchTarget = false;
   2634             if (!canceled && !intercepted) {
   2635 
   2636                 // If the event is targeting accessibility focus we give it to the
   2637                 // view that has accessibility focus and if it does not handle it
   2638                 // we clear the flag and dispatch the event to all children as usual.
   2639                 // We are looking up the accessibility focused host to avoid keeping
   2640                 // state since these events are very rare.
   2641                 View childWithAccessibilityFocus = ev.isTargetAccessibilityFocus()
   2642                         ? findChildWithAccessibilityFocus() : null;
   2643 
   2644                 if (actionMasked == MotionEvent.ACTION_DOWN
   2645                         || (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN)
   2646                         || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
   2647                     final int actionIndex = ev.getActionIndex(); // always 0 for down
   2648                     final int idBitsToAssign = split ? 1 << ev.getPointerId(actionIndex)
   2649                             : TouchTarget.ALL_POINTER_IDS;
   2650 
   2651                     // Clean up earlier touch targets for this pointer id in case they
   2652                     // have become out of sync.
   2653                     removePointersFromTouchTargets(idBitsToAssign);
   2654 
   2655                     final int childrenCount = mChildrenCount;
   2656                     if (newTouchTarget == null && childrenCount != 0) {
   2657                         final float x = ev.getX(actionIndex);
   2658                         final float y = ev.getY(actionIndex);
   2659                         // Find a child that can receive the event.
   2660                         // Scan children from front to back.
   2661                         final ArrayList<View> preorderedList = buildTouchDispatchChildList();
   2662                         final boolean customOrder = preorderedList == null
   2663                                 && isChildrenDrawingOrderEnabled();
   2664                         final View[] children = mChildren;
   2665                         for (int i = childrenCount - 1; i >= 0; i--) {
   2666                             final int childIndex = getAndVerifyPreorderedIndex(
   2667                                     childrenCount, i, customOrder);
   2668                             final View child = getAndVerifyPreorderedView(
   2669                                     preorderedList, children, childIndex);
   2670 
   2671                             // If there is a view that has accessibility focus we want it
   2672                             // to get the event first and if not handled we will perform a
   2673                             // normal dispatch. We may do a double iteration but this is
   2674                             // safer given the timeframe.
   2675                             if (childWithAccessibilityFocus != null) {
   2676                                 if (childWithAccessibilityFocus != child) {
   2677                                     continue;
   2678                                 }
   2679                                 childWithAccessibilityFocus = null;
   2680                                 i = childrenCount - 1;
   2681                             }
   2682 
   2683                             if (!child.canReceivePointerEvents()
   2684                                     || !isTransformedTouchPointInView(x, y, child, null)) {
   2685                                 ev.setTargetAccessibilityFocus(false);
   2686                                 continue;
   2687                             }
   2688 
   2689                             newTouchTarget = getTouchTarget(child);
   2690                             if (newTouchTarget != null) {
   2691                                 // Child is already receiving touch within its bounds.
   2692                                 // Give it the new pointer in addition to the ones it is handling.
   2693                                 newTouchTarget.pointerIdBits |= idBitsToAssign;
   2694                                 break;
   2695                             }
   2696 
   2697                             resetCancelNextUpFlag(child);
   2698                             if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
   2699                                 // Child wants to receive touch within its bounds.
   2700                                 mLastTouchDownTime = ev.getDownTime();
   2701                                 if (preorderedList != null) {
   2702                                     // childIndex points into presorted list, find original index
   2703                                     for (int j = 0; j < childrenCount; j++) {
   2704                                         if (children[childIndex] == mChildren[j]) {
   2705                                             mLastTouchDownIndex = j;
   2706                                             break;
   2707                                         }
   2708                                     }
   2709                                 } else {
   2710                                     mLastTouchDownIndex = childIndex;
   2711                                 }
   2712                                 mLastTouchDownX = ev.getX();
   2713                                 mLastTouchDownY = ev.getY();
   2714                                 newTouchTarget = addTouchTarget(child, idBitsToAssign);
   2715                                 alreadyDispatchedToNewTouchTarget = true;
   2716                                 break;
   2717                             }
   2718 
   2719                             // The accessibility focus didn't handle the event, so clear
   2720                             // the flag and do a normal dispatch to all children.
   2721                             ev.setTargetAccessibilityFocus(false);
   2722                         }
   2723                         if (preorderedList != null) preorderedList.clear();
   2724                     }
   2725 
   2726                     if (newTouchTarget == null && mFirstTouchTarget != null) {
   2727                         // Did not find a child to receive the event.
   2728                         // Assign the pointer to the least recently added target.
   2729                         newTouchTarget = mFirstTouchTarget;
   2730                         while (newTouchTarget.next != null) {
   2731                             newTouchTarget = newTouchTarget.next;
   2732                         }
   2733                         newTouchTarget.pointerIdBits |= idBitsToAssign;
   2734                     }
   2735                 }
   2736             }
   2737 
   2738             // Dispatch to touch targets.
   2739             if (mFirstTouchTarget == null) {
   2740                 // No touch targets so treat this as an ordinary view.
   2741                 handled = dispatchTransformedTouchEvent(ev, canceled, null,
   2742                         TouchTarget.ALL_POINTER_IDS);
   2743             } else {
   2744                 // Dispatch to touch targets, excluding the new touch target if we already
   2745                 // dispatched to it.  Cancel touch targets if necessary.
   2746                 TouchTarget predecessor = null;
   2747                 TouchTarget target = mFirstTouchTarget;
   2748                 while (target != null) {
   2749                     final TouchTarget next = target.next;
   2750                     if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) {
   2751                         handled = true;
   2752                     } else {
   2753                         final boolean cancelChild = resetCancelNextUpFlag(target.child)
   2754                                 || intercepted;
   2755                         if (dispatchTransformedTouchEvent(ev, cancelChild,
   2756                                 target.child, target.pointerIdBits)) {
   2757                             handled = true;
   2758                         }
   2759                         if (cancelChild) {
   2760                             if (predecessor == null) {
   2761                                 mFirstTouchTarget = next;
   2762                             } else {
   2763                                 predecessor.next = next;
   2764                             }
   2765                             target.recycle();
   2766                             target = next;
   2767                             continue;
   2768                         }
   2769                     }
   2770                     predecessor = target;
   2771                     target = next;
   2772                 }
   2773             }
   2774 
   2775             // Update list of touch targets for pointer up or cancel, if needed.
   2776             if (canceled
   2777                     || actionMasked == MotionEvent.ACTION_UP
   2778                     || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
   2779                 resetTouchState();
   2780             } else if (split && actionMasked == MotionEvent.ACTION_POINTER_UP) {
   2781                 final int actionIndex = ev.getActionIndex();
   2782                 final int idBitsToRemove = 1 << ev.getPointerId(actionIndex);
   2783                 removePointersFromTouchTargets(idBitsToRemove);
   2784             }
   2785         }
   2786 
   2787         if (!handled && mInputEventConsistencyVerifier != null) {
   2788             mInputEventConsistencyVerifier.onUnhandledEvent(ev, 1);
   2789         }
   2790         return handled;
   2791     }
   2792 
   2793     /**
   2794      * Provide custom ordering of views in which the touch will be dispatched.
   2795      *
   2796      * This is called within a tight loop, so you are not allowed to allocate objects, including
   2797      * the return array. Instead, you should return a pre-allocated list that will be cleared
   2798      * after the dispatch is finished.
   2799      * @hide
   2800      */
   2801     public ArrayList<View> buildTouchDispatchChildList() {
   2802         return buildOrderedChildList();
   2803     }
   2804 
   2805     /**
   2806      * Finds the child which has accessibility focus.
   2807      *
   2808      * @return The child that has focus.
   2809      */
   2810     private View findChildWithAccessibilityFocus() {
   2811         ViewRootImpl viewRoot = getViewRootImpl();
   2812         if (viewRoot == null) {
   2813             return null;
   2814         }
   2815 
   2816         View current = viewRoot.getAccessibilityFocusedHost();
   2817         if (current == null) {
   2818             return null;
   2819         }
   2820 
   2821         ViewParent parent = current.getParent();
   2822         while (parent instanceof View) {
   2823             if (parent == this) {
   2824                 return current;
   2825             }
   2826             current = (View) parent;
   2827             parent = current.getParent();
   2828         }
   2829 
   2830         return null;
   2831     }
   2832 
   2833     /**
   2834      * Resets all touch state in preparation for a new cycle.
   2835      */
   2836     private void resetTouchState() {
   2837         clearTouchTargets();
   2838         resetCancelNextUpFlag(this);
   2839         mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
   2840         mNestedScrollAxes = SCROLL_AXIS_NONE;
   2841     }
   2842 
   2843     /**
   2844      * Resets the cancel next up flag.
   2845      * Returns true if the flag was previously set.
   2846      */
   2847     private static boolean resetCancelNextUpFlag(@NonNull View view) {
   2848         if ((view.mPrivateFlags & PFLAG_CANCEL_NEXT_UP_EVENT) != 0) {
   2849             view.mPrivateFlags &= ~PFLAG_CANCEL_NEXT_UP_EVENT;
   2850             return true;
   2851         }
   2852         return false;
   2853     }
   2854 
   2855     /**
   2856      * Clears all touch targets.
   2857      */
   2858     private void clearTouchTargets() {
   2859         TouchTarget target = mFirstTouchTarget;
   2860         if (target != null) {
   2861             do {
   2862                 TouchTarget next = target.next;
   2863                 target.recycle();
   2864                 target = next;
   2865             } while (target != null);
   2866             mFirstTouchTarget = null;
   2867         }
   2868     }
   2869 
   2870     /**
   2871      * Cancels and clears all touch targets.
   2872      */
   2873     private void cancelAndClearTouchTargets(MotionEvent event) {
   2874         if (mFirstTouchTarget != null) {
   2875             boolean syntheticEvent = false;
   2876             if (event == null) {
   2877                 final long now = SystemClock.uptimeMillis();
   2878                 event = MotionEvent.obtain(now, now,
   2879                         MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
   2880                 event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
   2881                 syntheticEvent = true;
   2882             }
   2883 
   2884             for (TouchTarget target = mFirstTouchTarget; target != null; target = target.next) {
   2885                 resetCancelNextUpFlag(target.child);
   2886                 dispatchTransformedTouchEvent(event, true, target.child, target.pointerIdBits);
   2887             }
   2888             clearTouchTargets();
   2889 
   2890             if (syntheticEvent) {
   2891                 event.recycle();
   2892             }
   2893         }
   2894     }
   2895 
   2896     /**
   2897      * Gets the touch target for specified child view.
   2898      * Returns null if not found.
   2899      */
   2900     private TouchTarget getTouchTarget(@NonNull View child) {
   2901         for (TouchTarget target = mFirstTouchTarget; target != null; target = target.next) {
   2902             if (target.child == child) {
   2903                 return target;
   2904             }
   2905         }
   2906         return null;
   2907     }
   2908 
   2909     /**
   2910      * Adds a touch target for specified child to the beginning of the list.
   2911      * Assumes the target child is not already present.
   2912      */
   2913     private TouchTarget addTouchTarget(@NonNull View child, int pointerIdBits) {
   2914         final TouchTarget target = TouchTarget.obtain(child, pointerIdBits);
   2915         target.next = mFirstTouchTarget;
   2916         mFirstTouchTarget = target;
   2917         return target;
   2918     }
   2919 
   2920     /**
   2921      * Removes the pointer ids from consideration.
   2922      */
   2923     private void removePointersFromTouchTargets(int pointerIdBits) {
   2924         TouchTarget predecessor = null;
   2925         TouchTarget target = mFirstTouchTarget;
   2926         while (target != null) {
   2927             final TouchTarget next = target.next;
   2928             if ((target.pointerIdBits & pointerIdBits) != 0) {
   2929                 target.pointerIdBits &= ~pointerIdBits;
   2930                 if (target.pointerIdBits == 0) {
   2931                     if (predecessor == null) {
   2932                         mFirstTouchTarget = next;
   2933                     } else {
   2934                         predecessor.next = next;
   2935                     }
   2936                     target.recycle();
   2937                     target = next;
   2938                     continue;
   2939                 }
   2940             }
   2941             predecessor = target;
   2942             target = next;
   2943         }
   2944     }
   2945 
   2946     @UnsupportedAppUsage
   2947     private void cancelTouchTarget(View view) {
   2948         TouchTarget predecessor = null;
   2949         TouchTarget target = mFirstTouchTarget;
   2950         while (target != null) {
   2951             final TouchTarget next = target.next;
   2952             if (target.child == view) {
   2953                 if (predecessor == null) {
   2954                     mFirstTouchTarget = next;
   2955                 } else {
   2956                     predecessor.next = next;
   2957                 }
   2958                 target.recycle();
   2959 
   2960                 final long now = SystemClock.uptimeMillis();
   2961                 MotionEvent event = MotionEvent.obtain(now, now,
   2962                         MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
   2963                 event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
   2964                 view.dispatchTouchEvent(event);
   2965                 event.recycle();
   2966                 return;
   2967             }
   2968             predecessor = target;
   2969             target = next;
   2970         }
   2971     }
   2972 
   2973     private float[] getTempPoint() {
   2974         if (mTempPoint == null) {
   2975             mTempPoint = new float[2];
   2976         }
   2977         return mTempPoint;
   2978     }
   2979 
   2980     /**
   2981      * Returns true if a child view contains the specified point when transformed
   2982      * into its coordinate space.
   2983      * Child must not be null.
   2984      * @hide
   2985      */
   2986     @UnsupportedAppUsage
   2987     protected boolean isTransformedTouchPointInView(float x, float y, View child,
   2988             PointF outLocalPoint) {
   2989         final float[] point = getTempPoint();
   2990         point[0] = x;
   2991         point[1] = y;
   2992         transformPointToViewLocal(point, child);
   2993         final boolean isInView = child.pointInView(point[0], point[1]);
   2994         if (isInView && outLocalPoint != null) {
   2995             outLocalPoint.set(point[0], point[1]);
   2996         }
   2997         return isInView;
   2998     }
   2999 
   3000     /**
   3001      * @hide
   3002      */
   3003     @UnsupportedAppUsage
   3004     public void transformPointToViewLocal(float[] point, View child) {
   3005         point[0] += mScrollX - child.mLeft;
   3006         point[1] += mScrollY - child.mTop;
   3007 
   3008         if (!child.hasIdentityMatrix()) {
   3009             child.getInverseMatrix().mapPoints(point);
   3010         }
   3011     }
   3012 
   3013     /**
   3014      * Transforms a motion event into the coordinate space of a particular child view,
   3015      * filters out irrelevant pointer ids, and overrides its action if necessary.
   3016      * If child is null, assumes the MotionEvent will be sent to this ViewGroup instead.
   3017      */
   3018     private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,
   3019             View child, int desiredPointerIdBits) {
   3020         final boolean handled;
   3021 
   3022         // Canceling motions is a special case.  We don't need to perform any transformations
   3023         // or filtering.  The important part is the action, not the contents.
   3024         final int oldAction = event.getAction();
   3025         if (cancel || oldAction == MotionEvent.ACTION_CANCEL) {
   3026             event.setAction(MotionEvent.ACTION_CANCEL);
   3027             if (child == null) {
   3028                 handled = super.dispatchTouchEvent(event);
   3029             } else {
   3030                 handled = child.dispatchTouchEvent(event);
   3031             }
   3032             event.setAction(oldAction);
   3033             return handled;
   3034         }
   3035 
   3036         // Calculate the number of pointers to deliver.
   3037         final int oldPointerIdBits = event.getPointerIdBits();
   3038         final int newPointerIdBits = oldPointerIdBits & desiredPointerIdBits;
   3039 
   3040         // If for some reason we ended up in an inconsistent state where it looks like we
   3041         // might produce a motion event with no pointers in it, then drop the event.
   3042         if (newPointerIdBits == 0) {
   3043             return false;
   3044         }
   3045 
   3046         // If the number of pointers is the same and we don't need to perform any fancy
   3047         // irreversible transformations, then we can reuse the motion event for this
   3048         // dispatch as long as we are careful to revert any changes we make.
   3049         // Otherwise we need to make a copy.
   3050         final MotionEvent transformedEvent;
   3051         if (newPointerIdBits == oldPointerIdBits) {
   3052             if (child == null || child.hasIdentityMatrix()) {
   3053                 if (child == null) {
   3054                     handled = super.dispatchTouchEvent(event);
   3055                 } else {
   3056                     final float offsetX = mScrollX - child.mLeft;
   3057                     final float offsetY = mScrollY - child.mTop;
   3058                     event.offsetLocation(offsetX, offsetY);
   3059 
   3060                     handled = child.dispatchTouchEvent(event);
   3061 
   3062                     event.offsetLocation(-offsetX, -offsetY);
   3063                 }
   3064                 return handled;
   3065             }
   3066             transformedEvent = MotionEvent.obtain(event);
   3067         } else {
   3068             transformedEvent = event.split(newPointerIdBits);
   3069         }
   3070 
   3071         // Perform any necessary transformations and dispatch.
   3072         if (child == null) {
   3073             handled = super.dispatchTouchEvent(transformedEvent);
   3074         } else {
   3075             final float offsetX = mScrollX - child.mLeft;
   3076             final float offsetY = mScrollY - child.mTop;
   3077             transformedEvent.offsetLocation(offsetX, offsetY);
   3078             if (! child.hasIdentityMatrix()) {
   3079                 transformedEvent.transform(child.getInverseMatrix());
   3080             }
   3081 
   3082             handled = child.dispatchTouchEvent(transformedEvent);
   3083         }
   3084 
   3085         // Done.
   3086         transformedEvent.recycle();
   3087         return handled;
   3088     }
   3089 
   3090     /**
   3091      * Enable or disable the splitting of MotionEvents to multiple children during touch event
   3092      * dispatch. This behavior is enabled by default for applications that target an
   3093      * SDK version of {@link Build.VERSION_CODES#HONEYCOMB} or newer.
   3094      *
   3095      * <p>When this option is enabled MotionEvents may be split and dispatched to different child
   3096      * views depending on where each pointer initially went down. This allows for user interactions
   3097      * such as scrolling two panes of content independently, chording of buttons, and performing
   3098      * independent gestures on different pieces of content.
   3099      *
   3100      * @param split <code>true</code> to allow MotionEvents to be split and dispatched to multiple
   3101      *              child views. <code>false</code> to only allow one child view to be the target of
   3102      *              any MotionEvent received by this ViewGroup.
   3103      * @attr ref android.R.styleable#ViewGroup_splitMotionEvents
   3104      */
   3105     public void setMotionEventSplittingEnabled(boolean split) {
   3106         // TODO Applications really shouldn't change this setting mid-touch event,
   3107         // but perhaps this should handle that case and send ACTION_CANCELs to any child views
   3108         // with gestures in progress when this is changed.
   3109         if (split) {
   3110             mGroupFlags |= FLAG_SPLIT_MOTION_EVENTS;
   3111         } else {
   3112             mGroupFlags &= ~FLAG_SPLIT_MOTION_EVENTS;
   3113         }
   3114     }
   3115 
   3116     /**
   3117      * Returns true if MotionEvents dispatched to this ViewGroup can be split to multiple children.
   3118      * @return true if MotionEvents dispatched to this ViewGroup can be split to multiple children.
   3119      */
   3120     @InspectableProperty(name = "splitMotionEvents")
   3121     public boolean isMotionEventSplittingEnabled() {
   3122         return (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) == FLAG_SPLIT_MOTION_EVENTS;
   3123     }
   3124 
   3125     /**
   3126      * Returns true if this ViewGroup should be considered as a single entity for removal
   3127      * when executing an Activity transition. If this is false, child elements will move
   3128      * individually during the transition.
   3129      *
   3130      * @return True if the ViewGroup should be acted on together during an Activity transition.
   3131      * The default value is true when there is a non-null background or if
   3132      * {@link #getTransitionName()} is not null or if a
   3133      * non-null {@link android.view.ViewOutlineProvider} other than
   3134      * {@link android.view.ViewOutlineProvider#BACKGROUND} was given to
   3135      * {@link #setOutlineProvider(ViewOutlineProvider)} and false otherwise.
   3136      */
   3137     @InspectableProperty
   3138     public boolean isTransitionGroup() {
   3139         if ((mGroupFlags & FLAG_IS_TRANSITION_GROUP_SET) != 0) {
   3140             return ((mGroupFlags & FLAG_IS_TRANSITION_GROUP) != 0);
   3141         } else {
   3142             final ViewOutlineProvider outlineProvider = getOutlineProvider();
   3143             return getBackground() != null || getTransitionName() != null ||
   3144                     (outlineProvider != null && outlineProvider != ViewOutlineProvider.BACKGROUND);
   3145         }
   3146     }
   3147 
   3148     /**
   3149      * Changes whether or not this ViewGroup should be treated as a single entity during
   3150      * Activity Transitions.
   3151      * @param isTransitionGroup Whether or not the ViewGroup should be treated as a unit
   3152      *                          in Activity transitions. If false, the ViewGroup won't transition,
   3153      *                          only its children. If true, the entire ViewGroup will transition
   3154      *                          together.
   3155      * @see android.app.ActivityOptions#makeSceneTransitionAnimation(android.app.Activity,
   3156      * android.util.Pair[])
   3157      */
   3158     public void setTransitionGroup(boolean isTransitionGroup) {
   3159         mGroupFlags |= FLAG_IS_TRANSITION_GROUP_SET;
   3160         if (isTransitionGroup) {
   3161             mGroupFlags |= FLAG_IS_TRANSITION_GROUP;
   3162         } else {
   3163             mGroupFlags &= ~FLAG_IS_TRANSITION_GROUP;
   3164         }
   3165     }
   3166 
   3167     @Override
   3168     public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
   3169 
   3170         if (disallowIntercept == ((mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0)) {
   3171             // We're already in this state, assume our ancestors are too
   3172             return;
   3173         }
   3174 
   3175         if (disallowIntercept) {
   3176             mGroupFlags |= FLAG_DISALLOW_INTERCEPT;
   3177         } else {
   3178             mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
   3179         }
   3180 
   3181         // Pass it up to our parent
   3182         if (mParent != null) {
   3183             mParent.requestDisallowInterceptTouchEvent(disallowIntercept);
   3184         }
   3185     }
   3186 
   3187     /**
   3188      * Implement this method to intercept all touch screen motion events.  This
   3189      * allows you to watch events as they are dispatched to your children, and
   3190      * take ownership of the current gesture at any point.
   3191      *
   3192      * <p>Using this function takes some care, as it has a fairly complicated
   3193      * interaction with {@link View#onTouchEvent(MotionEvent)
   3194      * View.onTouchEvent(MotionEvent)}, and using it requires implementing
   3195      * that method as well as this one in the correct way.  Events will be
   3196      * received in the following order:
   3197      *
   3198      * <ol>
   3199      * <li> You will receive the down event here.
   3200      * <li> The down event will be handled either by a child of this view
   3201      * group, or given to your own onTouchEvent() method to handle; this means
   3202      * you should implement onTouchEvent() to return true, so you will
   3203      * continue to see the rest of the gesture (instead of looking for
   3204      * a parent view to handle it).  Also, by returning true from
   3205      * onTouchEvent(), you will not receive any following
   3206      * events in onInterceptTouchEvent() and all touch processing must
   3207      * happen in onTouchEvent() like normal.
   3208      * <li> For as long as you return false from this function, each following
   3209      * event (up to and including the final up) will be delivered first here
   3210      * and then to the target's onTouchEvent().
   3211      * <li> If you return true from here, you will not receive any
   3212      * following events: the target view will receive the same event but
   3213      * with the action {@link MotionEvent#ACTION_CANCEL}, and all further
   3214      * events will be delivered to your onTouchEvent() method and no longer
   3215      * appear here.
   3216      * </ol>
   3217      *
   3218      * @param ev The motion event being dispatched down the hierarchy.
   3219      * @return Return true to steal motion events from the children and have
   3220      * them dispatched to this ViewGroup through onTouchEvent().
   3221      * The current target will receive an ACTION_CANCEL event, and no further
   3222      * messages will be delivered here.
   3223      */
   3224     public boolean onInterceptTouchEvent(MotionEvent ev) {
   3225         if (ev.isFromSource(InputDevice.SOURCE_MOUSE)
   3226                 && ev.getAction() == MotionEvent.ACTION_DOWN
   3227                 && ev.isButtonPressed(MotionEvent.BUTTON_PRIMARY)
   3228                 && isOnScrollbarThumb(ev.getX(), ev.getY())) {
   3229             return true;
   3230         }
   3231         return false;
   3232     }
   3233 
   3234     /**
   3235      * {@inheritDoc}
   3236      *
   3237      * Looks for a view to give focus to respecting the setting specified by
   3238      * {@link #getDescendantFocusability()}.
   3239      *
   3240      * Uses {@link #onRequestFocusInDescendants(int, android.graphics.Rect)} to
   3241      * find focus within the children of this group when appropriate.
   3242      *
   3243      * @see #FOCUS_BEFORE_DESCENDANTS
   3244      * @see #FOCUS_AFTER_DESCENDANTS
   3245      * @see #FOCUS_BLOCK_DESCENDANTS
   3246      * @see #onRequestFocusInDescendants(int, android.graphics.Rect)
   3247      */
   3248     @Override
   3249     public boolean requestFocus(int direction, Rect previouslyFocusedRect) {
   3250         if (DBG) {
   3251             System.out.println(this + " ViewGroup.requestFocus direction="
   3252                     + direction);
   3253         }
   3254         int descendantFocusability = getDescendantFocusability();
   3255 
   3256         boolean result;
   3257         switch (descendantFocusability) {
   3258             case FOCUS_BLOCK_DESCENDANTS:
   3259                 result = super.requestFocus(direction, previouslyFocusedRect);
   3260                 break;
   3261             case FOCUS_BEFORE_DESCENDANTS: {
   3262                 final boolean took = super.requestFocus(direction, previouslyFocusedRect);
   3263                 result = took ? took : onRequestFocusInDescendants(direction,
   3264                         previouslyFocusedRect);
   3265                 break;
   3266             }
   3267             case FOCUS_AFTER_DESCENDANTS: {
   3268                 final boolean took = onRequestFocusInDescendants(direction, previouslyFocusedRect);
   3269                 result = took ? took : super.requestFocus(direction, previouslyFocusedRect);
   3270                 break;
   3271             }
   3272             default:
   3273                 throw new IllegalStateException("descendant focusability must be "
   3274                         + "one of FOCUS_BEFORE_DESCENDANTS, FOCUS_AFTER_DESCENDANTS, FOCUS_BLOCK_DESCENDANTS "
   3275                         + "but is " + descendantFocusability);
   3276         }
   3277         if (result && !isLayoutValid() && ((mPrivateFlags & PFLAG_WANTS_FOCUS) == 0)) {
   3278             mPrivateFlags |= PFLAG_WANTS_FOCUS;
   3279         }
   3280         return result;
   3281     }
   3282 
   3283     /**
   3284      * Look for a descendant to call {@link View#requestFocus} on.
   3285      * Called by {@link ViewGroup#requestFocus(int, android.graphics.Rect)}
   3286      * when it wants to request focus within its children.  Override this to
   3287      * customize how your {@link ViewGroup} requests focus within its children.
   3288      * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT
   3289      * @param previouslyFocusedRect The rectangle (in this View's coordinate system)
   3290      *        to give a finer grained hint about where focus is coming from.  May be null
   3291      *        if there is no hint.
   3292      * @return Whether focus was taken.
   3293      */
   3294     @SuppressWarnings({"ConstantConditions"})
   3295     protected boolean onRequestFocusInDescendants(int direction,
   3296             Rect previouslyFocusedRect) {
   3297         int index;
   3298         int increment;
   3299         int end;
   3300         int count = mChildrenCount;
   3301         if ((direction & FOCUS_FORWARD) != 0) {
   3302             index = 0;
   3303             increment = 1;
   3304             end = count;
   3305         } else {
   3306             index = count - 1;
   3307             increment = -1;
   3308             end = -1;
   3309         }
   3310         final View[] children = mChildren;
   3311         for (int i = index; i != end; i += increment) {
   3312             View child = children[i];
   3313             if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
   3314                 if (child.requestFocus(direction, previouslyFocusedRect)) {
   3315                     return true;
   3316                 }
   3317             }
   3318         }
   3319         return false;
   3320     }
   3321 
   3322     @Override
   3323     public boolean restoreDefaultFocus() {
   3324         if (mDefaultFocus != null
   3325                 && getDescendantFocusability() != FOCUS_BLOCK_DESCENDANTS
   3326                 && (mDefaultFocus.mViewFlags & VISIBILITY_MASK) == VISIBLE
   3327                 && mDefaultFocus.restoreDefaultFocus()) {
   3328             return true;
   3329         }
   3330         return super.restoreDefaultFocus();
   3331     }
   3332 
   3333     /**
   3334      * @hide
   3335      */
   3336     @TestApi
   3337     @Override
   3338     public boolean restoreFocusInCluster(@FocusRealDirection int direction) {
   3339         // Allow cluster-navigation to enter touchscreenBlocksFocus ViewGroups.
   3340         if (isKeyboardNavigationCluster()) {
   3341             final boolean blockedFocus = getTouchscreenBlocksFocus();
   3342             try {
   3343                 setTouchscreenBlocksFocusNoRefocus(false);
   3344                 return restoreFocusInClusterInternal(direction);
   3345             } finally {
   3346                 setTouchscreenBlocksFocusNoRefocus(blockedFocus);
   3347             }
   3348         } else {
   3349             return restoreFocusInClusterInternal(direction);
   3350         }
   3351     }
   3352 
   3353     private boolean restoreFocusInClusterInternal(@FocusRealDirection int direction) {
   3354         if (mFocusedInCluster != null && getDescendantFocusability() != FOCUS_BLOCK_DESCENDANTS
   3355                 && (mFocusedInCluster.mViewFlags & VISIBILITY_MASK) == VISIBLE
   3356                 && mFocusedInCluster.restoreFocusInCluster(direction)) {
   3357             return true;
   3358         }
   3359         return super.restoreFocusInCluster(direction);
   3360     }
   3361 
   3362     /**
   3363      * @hide
   3364      */
   3365     @Override
   3366     public boolean restoreFocusNotInCluster() {
   3367         if (mFocusedInCluster != null) {
   3368             // since clusters don't nest; we can assume that a non-null mFocusedInCluster
   3369             // will refer to a view not-in a cluster.
   3370             return restoreFocusInCluster(View.FOCUS_DOWN);
   3371         }
   3372         if (isKeyboardNavigationCluster() || (mViewFlags & VISIBILITY_MASK) != VISIBLE) {
   3373             return false;
   3374         }
   3375         int descendentFocusability = getDescendantFocusability();
   3376         if (descendentFocusability == FOCUS_BLOCK_DESCENDANTS) {
   3377             return super.requestFocus(FOCUS_DOWN, null);
   3378         }
   3379         if (descendentFocusability == FOCUS_BEFORE_DESCENDANTS
   3380                 && super.requestFocus(FOCUS_DOWN, null)) {
   3381             return true;
   3382         }
   3383         for (int i = 0; i < mChildrenCount; ++i) {
   3384             View child = mChildren[i];
   3385             if (!child.isKeyboardNavigationCluster()
   3386                     && child.restoreFocusNotInCluster()) {
   3387                 return true;
   3388             }
   3389         }
   3390         if (descendentFocusability == FOCUS_AFTER_DESCENDANTS && !hasFocusableChild(false)) {
   3391             return super.requestFocus(FOCUS_DOWN, null);
   3392         }
   3393         return false;
   3394     }
   3395 
   3396     /**
   3397      * {@inheritDoc}
   3398      *
   3399      * @hide
   3400      */
   3401     @Override
   3402     public void dispatchStartTemporaryDetach() {
   3403         super.dispatchStartTemporaryDetach();
   3404         final int count = mChildrenCount;
   3405         final View[] children = mChildren;
   3406         for (int i = 0; i < count; i++) {
   3407             children[i].dispatchStartTemporaryDetach();
   3408         }
   3409     }
   3410 
   3411     /**
   3412      * {@inheritDoc}
   3413      *
   3414      * @hide
   3415      */
   3416     @Override
   3417     public void dispatchFinishTemporaryDetach() {
   3418         super.dispatchFinishTemporaryDetach();
   3419         final int count = mChildrenCount;
   3420         final View[] children = mChildren;
   3421         for (int i = 0; i < count; i++) {
   3422             children[i].dispatchFinishTemporaryDetach();
   3423         }
   3424     }
   3425 
   3426     @Override
   3427     @UnsupportedAppUsage
   3428     void dispatchAttachedToWindow(AttachInfo info, int visibility) {
   3429         mGroupFlags |= FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW;
   3430         super.dispatchAttachedToWindow(info, visibility);
   3431         mGroupFlags &= ~FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW;
   3432 
   3433         final int count = mChildrenCount;
   3434         final View[] children = mChildren;
   3435         for (int i = 0; i < count; i++) {
   3436             final View child = children[i];
   3437             child.dispatchAttachedToWindow(info,
   3438                     combineVisibility(visibility, child.getVisibility()));
   3439         }
   3440         final int transientCount = mTransientIndices == null ? 0 : mTransientIndices.size();
   3441         for (int i = 0; i < transientCount; ++i) {
   3442             View view = mTransientViews.get(i);
   3443             view.dispatchAttachedToWindow(info,
   3444                     combineVisibility(visibility, view.getVisibility()));
   3445         }
   3446     }
   3447 
   3448     @Override
   3449     void dispatchScreenStateChanged(int screenState) {
   3450         super.dispatchScreenStateChanged(screenState);
   3451 
   3452         final int count = mChildrenCount;
   3453         final View[] children = mChildren;
   3454         for (int i = 0; i < count; i++) {
   3455             children[i].dispatchScreenStateChanged(screenState);
   3456         }
   3457     }
   3458 
   3459     @Override
   3460     void dispatchMovedToDisplay(Display display, Configuration config) {
   3461         super.dispatchMovedToDisplay(display, config);
   3462 
   3463         final int count = mChildrenCount;
   3464         final View[] children = mChildren;
   3465         for (int i = 0; i < count; i++) {
   3466             children[i].dispatchMovedToDisplay(display, config);
   3467         }
   3468     }
   3469 
   3470     /** @hide */
   3471     @Override
   3472     public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) {
   3473         boolean handled = false;
   3474         if (includeForAccessibility()) {
   3475             handled = super.dispatchPopulateAccessibilityEventInternal(event);
   3476             if (handled) {
   3477                 return handled;
   3478             }
   3479         }
   3480         // Let our children have a shot in populating the event.
   3481         ChildListForAccessibility children = ChildListForAccessibility.obtain(this, true);
   3482         try {
   3483             final int childCount = children.getChildCount();
   3484             for (int i = 0; i < childCount; i++) {
   3485                 View child = children.getChildAt(i);
   3486                 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
   3487                     handled = child.dispatchPopulateAccessibilityEvent(event);
   3488                     if (handled) {
   3489                         return handled;
   3490                     }
   3491                 }
   3492             }
   3493         } finally {
   3494             children.recycle();
   3495         }
   3496         return false;
   3497     }
   3498 
   3499     /**
   3500      * Dispatch creation of {@link ViewStructure} down the hierarchy.  This implementation
   3501      * adds in all child views of the view group, in addition to calling the default View
   3502      * implementation.
   3503      */
   3504     @Override
   3505     public void dispatchProvideStructure(ViewStructure structure) {
   3506         super.dispatchProvideStructure(structure);
   3507         if (isAssistBlocked() || structure.getChildCount() != 0) {
   3508             return;
   3509         }
   3510         final int childrenCount = mChildrenCount;
   3511         if (childrenCount <= 0) {
   3512             return;
   3513         }
   3514 
   3515         if (!isLaidOut()) {
   3516             if (Helper.sVerbose) {
   3517                 Log.v(VIEW_LOG_TAG, "dispatchProvideStructure(): not laid out, ignoring "
   3518                         + childrenCount + " children of " + getAccessibilityViewId());
   3519             }
   3520             return;
   3521         }
   3522 
   3523         structure.setChildCount(childrenCount);
   3524         ArrayList<View> preorderedList = buildOrderedChildList();
   3525         boolean customOrder = preorderedList == null
   3526                 && isChildrenDrawingOrderEnabled();
   3527         for (int i = 0; i < childrenCount; i++) {
   3528             int childIndex;
   3529             try {
   3530                 childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
   3531             } catch (IndexOutOfBoundsException e) {
   3532                 childIndex = i;
   3533                 if (mContext.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.M) {
   3534                     Log.w(TAG, "Bad getChildDrawingOrder while collecting assist @ "
   3535                             + i + " of " + childrenCount, e);
   3536                     // At least one app is failing when we call getChildDrawingOrder
   3537                     // at this point, so deal semi-gracefully with it by falling back
   3538                     // on the basic order.
   3539                     customOrder = false;
   3540                     if (i > 0) {
   3541                         // If we failed at the first index, there really isn't
   3542                         // anything to do -- we will just proceed with the simple
   3543                         // sequence order.
   3544                         // Otherwise, we failed in the middle, so need to come up
   3545                         // with an order for the remaining indices and use that.
   3546                         // Failed at the first one, easy peasy.
   3547                         int[] permutation = new int[childrenCount];
   3548                         SparseBooleanArray usedIndices = new SparseBooleanArray();
   3549                         // Go back and collected the indices we have done so far.
   3550                         for (int j = 0; j < i; j++) {
   3551                             permutation[j] = getChildDrawingOrder(childrenCount, j);
   3552                             usedIndices.put(permutation[j], true);
   3553                         }
   3554                         // Fill in the remaining indices with indices that have not
   3555                         // yet been used.
   3556                         int nextIndex = 0;
   3557                         for (int j = i; j < childrenCount; j++) {
   3558                             while (usedIndices.get(nextIndex, false)) {
   3559                                 nextIndex++;
   3560                             }
   3561                             permutation[j] = nextIndex;
   3562                             nextIndex++;
   3563                         }
   3564                         // Build the final view list.
   3565                         preorderedList = new ArrayList<>(childrenCount);
   3566                         for (int j = 0; j < childrenCount; j++) {
   3567                             final int index = permutation[j];
   3568                             final View child = mChildren[index];
   3569                             preorderedList.add(child);
   3570                         }
   3571                     }
   3572                 } else {
   3573                     throw e;
   3574                 }
   3575             }
   3576             final View child = getAndVerifyPreorderedView(preorderedList, mChildren,
   3577                     childIndex);
   3578             final ViewStructure cstructure = structure.newChild(i);
   3579             child.dispatchProvideStructure(cstructure);
   3580         }
   3581         if (preorderedList != null) {
   3582             preorderedList.clear();
   3583         }
   3584     }
   3585 
   3586     /**
   3587      * {@inheritDoc}
   3588      *
   3589      * <p>This implementation adds in all child views of the view group, in addition to calling the
   3590      * default {@link View} implementation.
   3591      */
   3592     @Override
   3593     public void dispatchProvideAutofillStructure(ViewStructure structure,
   3594             @AutofillFlags int flags) {
   3595         super.dispatchProvideAutofillStructure(structure, flags);
   3596 
   3597         if (structure.getChildCount() != 0) {
   3598             return;
   3599         }
   3600 
   3601         if (!isLaidOut()) {
   3602             if (Helper.sVerbose) {
   3603                 Log.v(VIEW_LOG_TAG, "dispatchProvideAutofillStructure(): not laid out, ignoring "
   3604                         + mChildrenCount + " children of " + getAutofillId());
   3605             }
   3606             return;
   3607         }
   3608 
   3609         final ChildListForAutofill children = getChildrenForAutofill(flags);
   3610         final int childrenCount = children.size();
   3611         structure.setChildCount(childrenCount);
   3612         for (int i = 0; i < childrenCount; i++) {
   3613             final View child = children.get(i);
   3614             final ViewStructure cstructure = structure.newChild(i);
   3615             child.dispatchProvideAutofillStructure(cstructure, flags);
   3616         }
   3617         children.recycle();
   3618     }
   3619 
   3620     /**
   3621      * Gets the children for autofill. Children for autofill are the first
   3622      * level descendants that are important for autofill. The returned
   3623      * child list object is pooled and the caller must recycle it once done.
   3624      * @hide */
   3625     private @NonNull ChildListForAutofill getChildrenForAutofill(
   3626             @AutofillFlags int flags) {
   3627         final ChildListForAutofill children = ChildListForAutofill
   3628                 .obtain();
   3629         populateChildrenForAutofill(children, flags);
   3630         return children;
   3631     }
   3632 
   3633     /** @hide */
   3634     private void populateChildrenForAutofill(ArrayList<View> list, @AutofillFlags int flags) {
   3635         final int childrenCount = mChildrenCount;
   3636         if (childrenCount <= 0) {
   3637             return;
   3638         }
   3639         final ArrayList<View> preorderedList = buildOrderedChildList();
   3640         final boolean customOrder = preorderedList == null
   3641                 && isChildrenDrawingOrderEnabled();
   3642         for (int i = 0; i < childrenCount; i++) {
   3643             final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
   3644             final View child = (preorderedList == null)
   3645                     ? mChildren[childIndex] : preorderedList.get(childIndex);
   3646             if ((flags & AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) != 0
   3647                     || child.isImportantForAutofill()) {
   3648                 list.add(child);
   3649             } else if (child instanceof ViewGroup) {
   3650                 ((ViewGroup) child).populateChildrenForAutofill(list, flags);
   3651             }
   3652         }
   3653     }
   3654 
   3655     private static View getAndVerifyPreorderedView(ArrayList<View> preorderedList, View[] children,
   3656             int childIndex) {
   3657         final View child;
   3658         if (preorderedList != null) {
   3659             child = preorderedList.get(childIndex);
   3660             if (child == null) {
   3661                 throw new RuntimeException("Invalid preorderedList contained null child at index "
   3662                         + childIndex);
   3663             }
   3664         } else {
   3665             child = children[childIndex];
   3666         }
   3667         return child;
   3668     }
   3669 
   3670     /** @hide */
   3671     @Override
   3672     @UnsupportedAppUsage
   3673     public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
   3674         super.onInitializeAccessibilityNodeInfoInternal(info);
   3675         if (getAccessibilityNodeProvider() != null) {
   3676             return;
   3677         }
   3678         if (mAttachInfo != null) {
   3679             final ArrayList<View> childrenForAccessibility = mAttachInfo.mTempArrayList;
   3680             childrenForAccessibility.clear();
   3681             addChildrenForAccessibility(childrenForAccessibility);
   3682             final int childrenForAccessibilityCount = childrenForAccessibility.size();
   3683             for (int i = 0; i < childrenForAccessibilityCount; i++) {
   3684                 final View child = childrenForAccessibility.get(i);
   3685                 info.addChildUnchecked(child);
   3686             }
   3687             childrenForAccessibility.clear();
   3688         }
   3689     }
   3690 
   3691     @Override
   3692     public CharSequence getAccessibilityClassName() {
   3693         return ViewGroup.class.getName();
   3694     }
   3695 
   3696     @Override
   3697     public void notifySubtreeAccessibilityStateChanged(View child, View source, int changeType) {
   3698         // If this is a live region, we should send a subtree change event
   3699         // from this view. Otherwise, we can let it propagate up.
   3700         if (getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE) {
   3701             notifyViewAccessibilityStateChangedIfNeeded(
   3702                     AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE);
   3703         } else if (mParent != null) {
   3704             try {
   3705                 mParent.notifySubtreeAccessibilityStateChanged(this, source, changeType);
   3706             } catch (AbstractMethodError e) {
   3707                 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() +
   3708                         " does not fully implement ViewParent", e);
   3709             }
   3710         }
   3711     }
   3712 
   3713     /** @hide */
   3714     @Override
   3715     public void notifySubtreeAccessibilityStateChangedIfNeeded() {
   3716         if (!AccessibilityManager.getInstance(mContext).isEnabled() || mAttachInfo == null) {
   3717             return;
   3718         }
   3719         // If something important for a11y is happening in this subtree, make sure it's dispatched
   3720         // from a view that is important for a11y so it doesn't get lost.
   3721         if ((getImportantForAccessibility() != IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS)
   3722                 && !isImportantForAccessibility() && (getChildCount() > 0)) {
   3723             ViewParent a11yParent = getParentForAccessibility();
   3724             if (a11yParent instanceof View) {
   3725                 ((View) a11yParent).notifySubtreeAccessibilityStateChangedIfNeeded();
   3726                 return;
   3727             }
   3728         }
   3729         super.notifySubtreeAccessibilityStateChangedIfNeeded();
   3730     }
   3731 
   3732     @Override
   3733     void resetSubtreeAccessibilityStateChanged() {
   3734         super.resetSubtreeAccessibilityStateChanged();
   3735         View[] children = mChildren;
   3736         final int childCount = mChildrenCount;
   3737         for (int i = 0; i < childCount; i++) {
   3738             children[i].resetSubtreeAccessibilityStateChanged();
   3739         }
   3740     }
   3741 
   3742     /**
   3743      * Counts the number of children of this View that will be sent to an accessibility service.
   3744      *
   3745      * @return The number of children an {@code AccessibilityNodeInfo} rooted at this View
   3746      * would have.
   3747      */
   3748     int getNumChildrenForAccessibility() {
   3749         int numChildrenForAccessibility = 0;
   3750         for (int i = 0; i < getChildCount(); i++) {
   3751             View child = getChildAt(i);
   3752             if (child.includeForAccessibility()) {
   3753                 numChildrenForAccessibility++;
   3754             } else if (child instanceof ViewGroup) {
   3755                 numChildrenForAccessibility += ((ViewGroup) child)
   3756                         .getNumChildrenForAccessibility();
   3757             }
   3758         }
   3759         return numChildrenForAccessibility;
   3760     }
   3761 
   3762     /**
   3763      * {@inheritDoc}
   3764      *
   3765      * <p>Subclasses should always call <code>super.onNestedPrePerformAccessibilityAction</code></p>
   3766      *
   3767      * @param target The target view dispatching this action
   3768      * @param action Action being performed; see
   3769      *               {@link android.view.accessibility.AccessibilityNodeInfo}
   3770      * @param args Optional action arguments
   3771      * @return false by default. Subclasses should return true if they handle the event.
   3772      */
   3773     @Override
   3774     public boolean onNestedPrePerformAccessibilityAction(View target, int action, Bundle args) {
   3775         return false;
   3776     }
   3777 
   3778     @Override
   3779     @UnsupportedAppUsage
   3780     void dispatchDetachedFromWindow() {
   3781         // If we still have a touch target, we are still in the process of
   3782         // dispatching motion events to a child; we need to get rid of that
   3783         // child to avoid dispatching events to it after the window is torn
   3784         // down. To make sure we keep the child in a consistent state, we
   3785         // first send it an ACTION_CANCEL motion event.
   3786         cancelAndClearTouchTargets(null);
   3787 
   3788         // Similarly, set ACTION_EXIT to all hover targets and clear them.
   3789         exitHoverTargets();
   3790         exitTooltipHoverTargets();
   3791 
   3792         // In case view is detached while transition is running
   3793         mLayoutCalledWhileSuppressed = false;
   3794 
   3795         // Tear down our drag tracking
   3796         mChildrenInterestedInDrag = null;
   3797         mIsInterestedInDrag = false;
   3798         if (mCurrentDragStartEvent != null) {
   3799             mCurrentDragStartEvent.recycle();
   3800             mCurrentDragStartEvent = null;
   3801         }
   3802 
   3803         final int count = mChildrenCount;
   3804         final View[] children = mChildren;
   3805         for (int i = 0; i < count; i++) {
   3806             children[i].dispatchDetachedFromWindow();
   3807         }
   3808         clearDisappearingChildren();
   3809         final int transientCount = mTransientViews == null ? 0 : mTransientIndices.size();
   3810         for (int i = 0; i < transientCount; ++i) {
   3811             View view = mTransientViews.get(i);
   3812             view.dispatchDetachedFromWindow();
   3813         }
   3814         super.dispatchDetachedFromWindow();
   3815     }
   3816 
   3817     /**
   3818      * @hide
   3819      */
   3820     @Override
   3821     protected void internalSetPadding(int left, int top, int right, int bottom) {
   3822         super.internalSetPadding(left, top, right, bottom);
   3823 
   3824         if ((mPaddingLeft | mPaddingTop | mPaddingRight | mPaddingBottom) != 0) {
   3825             mGroupFlags |= FLAG_PADDING_NOT_NULL;
   3826         } else {
   3827             mGroupFlags &= ~FLAG_PADDING_NOT_NULL;
   3828         }
   3829     }
   3830 
   3831     @Override
   3832     protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {
   3833         super.dispatchSaveInstanceState(container);
   3834         final int count = mChildrenCount;
   3835         final View[] children = mChildren;
   3836         for (int i = 0; i < count; i++) {
   3837             View c = children[i];
   3838             if ((c.mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED) {
   3839                 c.dispatchSaveInstanceState(container);
   3840             }
   3841         }
   3842     }
   3843 
   3844     /**
   3845      * Perform dispatching of a {@link #saveHierarchyState(android.util.SparseArray)}  freeze()}
   3846      * to only this view, not to its children.  For use when overriding
   3847      * {@link #dispatchSaveInstanceState(android.util.SparseArray)}  dispatchFreeze()} to allow
   3848      * subclasses to freeze their own state but not the state of their children.
   3849      *
   3850      * @param container the container
   3851      */
   3852     protected void dispatchFreezeSelfOnly(SparseArray<Parcelable> container) {
   3853         super.dispatchSaveInstanceState(container);
   3854     }
   3855 
   3856     @Override
   3857     protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {
   3858         super.dispatchRestoreInstanceState(container);
   3859         final int count = mChildrenCount;
   3860         final View[] children = mChildren;
   3861         for (int i = 0; i < count; i++) {
   3862             View c = children[i];
   3863             if ((c.mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED) {
   3864                 c.dispatchRestoreInstanceState(container);
   3865             }
   3866         }
   3867     }
   3868 
   3869     /**
   3870      * Perform dispatching of a {@link #restoreHierarchyState(android.util.SparseArray)}
   3871      * to only this view, not to its children.  For use when overriding
   3872      * {@link #dispatchRestoreInstanceState(android.util.SparseArray)} to allow
   3873      * subclasses to thaw their own state but not the state of their children.
   3874      *
   3875      * @param container the container
   3876      */
   3877     protected void dispatchThawSelfOnly(SparseArray<Parcelable> container) {
   3878         super.dispatchRestoreInstanceState(container);
   3879     }
   3880 
   3881     /**
   3882      * Enables or disables the drawing cache for each child of this view group.
   3883      *
   3884      * @param enabled true to enable the cache, false to dispose of it
   3885      *
   3886      * @deprecated The view drawing cache was largely made obsolete with the introduction of
   3887      * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache
   3888      * layers are largely unnecessary and can easily result in a net loss in performance due to the
   3889      * cost of creating and updating the layer. In the rare cases where caching layers are useful,
   3890      * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware
   3891      * rendering. For software-rendered snapshots of a small part of the View hierarchy or
   3892      * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or
   3893      * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these
   3894      * software-rendered usages are discouraged and have compatibility issues with hardware-only
   3895      * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE}
   3896      * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback
   3897      * reports or unit testing the {@link PixelCopy} API is recommended.
   3898      */
   3899     @Deprecated
   3900     protected void setChildrenDrawingCacheEnabled(boolean enabled) {
   3901         if (enabled || (mPersistentDrawingCache & PERSISTENT_ALL_CACHES) != PERSISTENT_ALL_CACHES) {
   3902             final View[] children = mChildren;
   3903             final int count = mChildrenCount;
   3904             for (int i = 0; i < count; i++) {
   3905                 children[i].setDrawingCacheEnabled(enabled);
   3906             }
   3907         }
   3908     }
   3909 
   3910     /**
   3911      * @hide
   3912      */
   3913     @Override
   3914     public Bitmap createSnapshot(ViewDebug.CanvasProvider canvasProvider, boolean skipChildren) {
   3915         int count = mChildrenCount;
   3916         int[] visibilities = null;
   3917 
   3918         if (skipChildren) {
   3919             visibilities = new int[count];
   3920             for (int i = 0; i < count; i++) {
   3921                 View child = getChildAt(i);
   3922                 visibilities[i] = child.getVisibility();
   3923                 if (visibilities[i] == View.VISIBLE) {
   3924                     child.mViewFlags = (child.mViewFlags & ~View.VISIBILITY_MASK)
   3925                             | (View.INVISIBLE & View.VISIBILITY_MASK);
   3926                 }
   3927             }
   3928         }
   3929 
   3930         try {
   3931             return super.createSnapshot(canvasProvider, skipChildren);
   3932         } finally {
   3933             if (skipChildren) {
   3934                 for (int i = 0; i < count; i++) {
   3935                     View child = getChildAt(i);
   3936                     child.mViewFlags = (child.mViewFlags & ~View.VISIBILITY_MASK)
   3937                             | (visibilities[i] & View.VISIBILITY_MASK);
   3938                 }
   3939             }
   3940         }
   3941     }
   3942 
   3943     /** Return true if this ViewGroup is laying out using optical bounds. */
   3944     boolean isLayoutModeOptical() {
   3945         return mLayoutMode == LAYOUT_MODE_OPTICAL_BOUNDS;
   3946     }
   3947 
   3948     @Override
   3949     Insets computeOpticalInsets() {
   3950         if (isLayoutModeOptical()) {
   3951             int left = 0;
   3952             int top = 0;
   3953             int right = 0;
   3954             int bottom = 0;
   3955             for (int i = 0; i < mChildrenCount; i++) {
   3956                 View child = getChildAt(i);
   3957                 if (child.getVisibility() == VISIBLE) {
   3958                     Insets insets = child.getOpticalInsets();
   3959                     left =   Math.max(left,   insets.left);
   3960                     top =    Math.max(top,    insets.top);
   3961                     right =  Math.max(right,  insets.right);
   3962                     bottom = Math.max(bottom, insets.bottom);
   3963                 }
   3964             }
   3965             return Insets.of(left, top, right, bottom);
   3966         } else {
   3967             return Insets.NONE;
   3968         }
   3969     }
   3970 
   3971     private static void fillRect(Canvas canvas, Paint paint, int x1, int y1, int x2, int y2) {
   3972         if (x1 != x2 && y1 != y2) {
   3973             if (x1 > x2) {
   3974                 int tmp = x1; x1 = x2; x2 = tmp;
   3975             }
   3976             if (y1 > y2) {
   3977                 int tmp = y1; y1 = y2; y2 = tmp;
   3978             }
   3979             canvas.drawRect(x1, y1, x2, y2, paint);
   3980         }
   3981     }
   3982 
   3983     private static int sign(int x) {
   3984         return (x >= 0) ? 1 : -1;
   3985     }
   3986 
   3987     private static void drawCorner(Canvas c, Paint paint, int x1, int y1, int dx, int dy, int lw) {
   3988         fillRect(c, paint, x1, y1, x1 + dx, y1 + lw * sign(dy));
   3989         fillRect(c, paint, x1, y1, x1 + lw * sign(dx), y1 + dy);
   3990     }
   3991 
   3992     private static void drawRectCorners(Canvas canvas, int x1, int y1, int x2, int y2, Paint paint,
   3993             int lineLength, int lineWidth) {
   3994         drawCorner(canvas, paint, x1, y1, lineLength, lineLength, lineWidth);
   3995         drawCorner(canvas, paint, x1, y2, lineLength, -lineLength, lineWidth);
   3996         drawCorner(canvas, paint, x2, y1, -lineLength, lineLength, lineWidth);
   3997         drawCorner(canvas, paint, x2, y2, -lineLength, -lineLength, lineWidth);
   3998     }
   3999 
   4000     private static void fillDifference(Canvas canvas,
   4001             int x2, int y2, int x3, int y3,
   4002             int dx1, int dy1, int dx2, int dy2, Paint paint) {
   4003         int x1 = x2 - dx1;
   4004         int y1 = y2 - dy1;
   4005 
   4006         int x4 = x3 + dx2;
   4007         int y4 = y3 + dy2;
   4008 
   4009         fillRect(canvas, paint, x1, y1, x4, y2);
   4010         fillRect(canvas, paint, x1, y2, x2, y3);
   4011         fillRect(canvas, paint, x3, y2, x4, y3);
   4012         fillRect(canvas, paint, x1, y3, x4, y4);
   4013     }
   4014 
   4015     /**
   4016      * @hide
   4017      */
   4018     protected void onDebugDrawMargins(Canvas canvas, Paint paint) {
   4019         for (int i = 0; i < getChildCount(); i++) {
   4020             View c = getChildAt(i);
   4021             c.getLayoutParams().onDebugDraw(c, canvas, paint);
   4022         }
   4023     }
   4024 
   4025     /**
   4026      * @hide
   4027      */
   4028     protected void onDebugDraw(Canvas canvas) {
   4029         Paint paint = getDebugPaint();
   4030 
   4031         // Draw optical bounds
   4032         {
   4033             paint.setColor(Color.RED);
   4034             paint.setStyle(Paint.Style.STROKE);
   4035 
   4036             for (int i = 0; i < getChildCount(); i++) {
   4037                 View c = getChildAt(i);
   4038                 if (c.getVisibility() != View.GONE) {
   4039                     Insets insets = c.getOpticalInsets();
   4040 
   4041                     drawRect(canvas, paint,
   4042                             c.getLeft() + insets.left,
   4043                             c.getTop() + insets.top,
   4044                             c.getRight() - insets.right - 1,
   4045                             c.getBottom() - insets.bottom - 1);
   4046                 }
   4047             }
   4048         }
   4049 
   4050         // Draw margins
   4051         {
   4052             paint.setColor(Color.argb(63, 255, 0, 255));
   4053             paint.setStyle(Paint.Style.FILL);
   4054 
   4055             onDebugDrawMargins(canvas, paint);
   4056         }
   4057 
   4058         // Draw clip bounds
   4059         {
   4060             paint.setColor(DEBUG_CORNERS_COLOR);
   4061             paint.setStyle(Paint.Style.FILL);
   4062 
   4063             int lineLength = dipsToPixels(DEBUG_CORNERS_SIZE_DIP);
   4064             int lineWidth = dipsToPixels(1);
   4065             for (int i = 0; i < getChildCount(); i++) {
   4066                 View c = getChildAt(i);
   4067                 if (c.getVisibility() != View.GONE) {
   4068                     drawRectCorners(canvas, c.getLeft(), c.getTop(), c.getRight(), c.getBottom(),
   4069                             paint, lineLength, lineWidth);
   4070                 }
   4071             }
   4072         }
   4073     }
   4074 
   4075     @Override
   4076     protected void dispatchDraw(Canvas canvas) {
   4077         boolean usingRenderNodeProperties = canvas.isRecordingFor(mRenderNode);
   4078         final int childrenCount = mChildrenCount;
   4079         final View[] children = mChildren;
   4080         int flags = mGroupFlags;
   4081 
   4082         if ((flags & FLAG_RUN_ANIMATION) != 0 && canAnimate()) {
   4083             final boolean buildCache = !isHardwareAccelerated();
   4084             for (int i = 0; i < childrenCount; i++) {
   4085                 final View child = children[i];
   4086                 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
   4087                     final LayoutParams params = child.getLayoutParams();
   4088                     attachLayoutAnimationParameters(child, params, i, childrenCount);
   4089                     bindLayoutAnimation(child);
   4090                 }
   4091             }
   4092 
   4093             final LayoutAnimationController controller = mLayoutAnimationController;
   4094             if (controller.willOverlap()) {
   4095                 mGroupFlags |= FLAG_OPTIMIZE_INVALIDATE;
   4096             }
   4097 
   4098             controller.start();
   4099 
   4100             mGroupFlags &= ~FLAG_RUN_ANIMATION;
   4101             mGroupFlags &= ~FLAG_ANIMATION_DONE;
   4102 
   4103             if (mAnimationListener != null) {
   4104                 mAnimationListener.onAnimationStart(controller.getAnimation());
   4105             }
   4106         }
   4107 
   4108         int clipSaveCount = 0;
   4109         final boolean clipToPadding = (flags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK;
   4110         if (clipToPadding) {
   4111             clipSaveCount = canvas.save(Canvas.CLIP_SAVE_FLAG);
   4112             canvas.clipRect(mScrollX + mPaddingLeft, mScrollY + mPaddingTop,
   4113                     mScrollX + mRight - mLeft - mPaddingRight,
   4114                     mScrollY + mBottom - mTop - mPaddingBottom);
   4115         }
   4116 
   4117         // We will draw our child's animation, let's reset the flag
   4118         mPrivateFlags &= ~PFLAG_DRAW_ANIMATION;
   4119         mGroupFlags &= ~FLAG_INVALIDATE_REQUIRED;
   4120 
   4121         boolean more = false;
   4122         final long drawingTime = getDrawingTime();
   4123 
   4124         if (usingRenderNodeProperties) canvas.insertReorderBarrier();
   4125         final int transientCount = mTransientIndices == null ? 0 : mTransientIndices.size();
   4126         int transientIndex = transientCount != 0 ? 0 : -1;
   4127         // Only use the preordered list if not HW accelerated, since the HW pipeline will do the
   4128         // draw reordering internally
   4129         final ArrayList<View> preorderedList = usingRenderNodeProperties
   4130                 ? null : buildOrderedChildList();
   4131         final boolean customOrder = preorderedList == null
   4132                 && isChildrenDrawingOrderEnabled();
   4133         for (int i = 0; i < childrenCount; i++) {
   4134             while (transientIndex >= 0 && mTransientIndices.get(transientIndex) == i) {
   4135                 final View transientChild = mTransientViews.get(transientIndex);
   4136                 if ((transientChild.mViewFlags & VISIBILITY_MASK) == VISIBLE ||
   4137                         transientChild.getAnimation() != null) {
   4138                     more |= drawChild(canvas, transientChild, drawingTime);
   4139                 }
   4140                 transientIndex++;
   4141                 if (transientIndex >= transientCount) {
   4142                     transientIndex = -1;
   4143                 }
   4144             }
   4145 
   4146             final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
   4147             final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex);
   4148             if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
   4149                 more |= drawChild(canvas, child, drawingTime);
   4150             }
   4151         }
   4152         while (transientIndex >= 0) {
   4153             // there may be additional transient views after the normal views
   4154             final View transientChild = mTransientViews.get(transientIndex);
   4155             if ((transientChild.mViewFlags & VISIBILITY_MASK) == VISIBLE ||
   4156                     transientChild.getAnimation() != null) {
   4157                 more |= drawChild(canvas, transientChild, drawingTime);
   4158             }
   4159             transientIndex++;
   4160             if (transientIndex >= transientCount) {
   4161                 break;
   4162             }
   4163         }
   4164         if (preorderedList != null) preorderedList.clear();
   4165 
   4166         // Draw any disappearing views that have animations
   4167         if (mDisappearingChildren != null) {
   4168             final ArrayList<View> disappearingChildren = mDisappearingChildren;
   4169             final int disappearingCount = disappearingChildren.size() - 1;
   4170             // Go backwards -- we may delete as animations finish
   4171             for (int i = disappearingCount; i >= 0; i--) {
   4172                 final View child = disappearingChildren.get(i);
   4173                 more |= drawChild(canvas, child, drawingTime);
   4174             }
   4175         }
   4176         if (usingRenderNodeProperties) canvas.insertInorderBarrier();
   4177 
   4178         if (debugDraw()) {
   4179             onDebugDraw(canvas);
   4180         }
   4181 
   4182         if (clipToPadding) {
   4183             canvas.restoreToCount(clipSaveCount);
   4184         }
   4185 
   4186         // mGroupFlags might have been updated by drawChild()
   4187         flags = mGroupFlags;
   4188 
   4189         if ((flags & FLAG_INVALIDATE_REQUIRED) == FLAG_INVALIDATE_REQUIRED) {
   4190             invalidate(true);
   4191         }
   4192 
   4193         if ((flags & FLAG_ANIMATION_DONE) == 0 && (flags & FLAG_NOTIFY_ANIMATION_LISTENER) == 0 &&
   4194                 mLayoutAnimationController.isDone() && !more) {
   4195             // We want to erase the drawing cache and notify the listener after the
   4196             // next frame is drawn because one extra invalidate() is caused by
   4197             // drawChild() after the animation is over
   4198             mGroupFlags |= FLAG_NOTIFY_ANIMATION_LISTENER;
   4199             final Runnable end = new Runnable() {
   4200                @Override
   4201                public void run() {
   4202                    notifyAnimationListener();
   4203                }
   4204             };
   4205             post(end);
   4206         }
   4207     }
   4208 
   4209     /**
   4210      * Returns the ViewGroupOverlay for this view group, creating it if it does
   4211      * not yet exist. In addition to {@link ViewOverlay}'s support for drawables,
   4212      * {@link ViewGroupOverlay} allows views to be added to the overlay. These
   4213      * views, like overlay drawables, are visual-only; they do not receive input
   4214      * events and should not be used as anything other than a temporary
   4215      * representation of a view in a parent container, such as might be used
   4216      * by an animation effect.
   4217      *
   4218      * <p>Note: Overlays do not currently work correctly with {@link
   4219      * SurfaceView} or {@link TextureView}; contents in overlays for these
   4220      * types of views may not display correctly.</p>
   4221      *
   4222      * @return The ViewGroupOverlay object for this view.
   4223      * @see ViewGroupOverlay
   4224      */
   4225     @Override
   4226     public ViewGroupOverlay getOverlay() {
   4227         if (mOverlay == null) {
   4228             mOverlay = new ViewGroupOverlay(mContext, this);
   4229         }
   4230         return (ViewGroupOverlay) mOverlay;
   4231     }
   4232 
   4233     /**
   4234      * Converts drawing order position to container position. Override this
   4235      * if you want to change the drawing order of children. By default, it
   4236      * returns drawingPosition.
   4237      * <p>
   4238      * NOTE: In order for this method to be called, you must enable child ordering
   4239      * first by calling {@link #setChildrenDrawingOrderEnabled(boolean)}.
   4240      *
   4241      * @param drawingPosition the drawing order position.
   4242      * @return the container position of a child for this drawing order position.
   4243      *
   4244      * @see #setChildrenDrawingOrderEnabled(boolean)
   4245      * @see #isChildrenDrawingOrderEnabled()
   4246      */
   4247     protected int getChildDrawingOrder(int childCount, int drawingPosition) {
   4248         return drawingPosition;
   4249     }
   4250 
   4251     /**
   4252      * Converts drawing order position to container position.
   4253      * <p>
   4254      * Children are not necessarily drawn in the order in which they appear in the container.
   4255      * ViewGroups can enable a custom ordering via {@link #setChildrenDrawingOrderEnabled(boolean)}.
   4256      * This method returns the container position of a child that appears in the given position
   4257      * in the current drawing order.
   4258      *
   4259      * @param drawingPosition the drawing order position.
   4260      * @return the container position of a child for this drawing order position.
   4261      *
   4262      * @see #getChildDrawingOrder(int, int)}
   4263      */
   4264     public final int getChildDrawingOrder(int drawingPosition) {
   4265         return getChildDrawingOrder(getChildCount(), drawingPosition);
   4266     }
   4267 
   4268     private boolean hasChildWithZ() {
   4269         for (int i = 0; i < mChildrenCount; i++) {
   4270             if (mChildren[i].getZ() != 0) return true;
   4271         }
   4272         return false;
   4273     }
   4274 
   4275     /**
   4276      * Populates (and returns) mPreSortedChildren with a pre-ordered list of the View's children,
   4277      * sorted first by Z, then by child drawing order (if applicable). This list must be cleared
   4278      * after use to avoid leaking child Views.
   4279      *
   4280      * Uses a stable, insertion sort which is commonly O(n) for ViewGroups with very few elevated
   4281      * children.
   4282      */
   4283     ArrayList<View> buildOrderedChildList() {
   4284         final int childrenCount = mChildrenCount;
   4285         if (childrenCount <= 1 || !hasChildWithZ()) return null;
   4286 
   4287         if (mPreSortedChildren == null) {
   4288             mPreSortedChildren = new ArrayList<>(childrenCount);
   4289         } else {
   4290             // callers should clear, so clear shouldn't be necessary, but for safety...
   4291             mPreSortedChildren.clear();
   4292             mPreSortedChildren.ensureCapacity(childrenCount);
   4293         }
   4294 
   4295         final boolean customOrder = isChildrenDrawingOrderEnabled();
   4296         for (int i = 0; i < childrenCount; i++) {
   4297             // add next child (in child order) to end of list
   4298             final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
   4299             final View nextChild = mChildren[childIndex];
   4300             final float currentZ = nextChild.getZ();
   4301 
   4302             // insert ahead of any Views with greater Z
   4303             int insertIndex = i;
   4304             while (insertIndex > 0 && mPreSortedChildren.get(insertIndex - 1).getZ() > currentZ) {
   4305                 insertIndex--;
   4306             }
   4307             mPreSortedChildren.add(insertIndex, nextChild);
   4308         }
   4309         return mPreSortedChildren;
   4310     }
   4311 
   4312     private void notifyAnimationListener() {
   4313         mGroupFlags &= ~FLAG_NOTIFY_ANIMATION_LISTENER;
   4314         mGroupFlags |= FLAG_ANIMATION_DONE;
   4315 
   4316         if (mAnimationListener != null) {
   4317            final Runnable end = new Runnable() {
   4318                @Override
   4319                public void run() {
   4320                    mAnimationListener.onAnimationEnd(mLayoutAnimationController.getAnimation());
   4321                }
   4322            };
   4323            post(end);
   4324         }
   4325 
   4326         invalidate(true);
   4327     }
   4328 
   4329     /**
   4330      * This method is used to cause children of this ViewGroup to restore or recreate their
   4331      * display lists. It is called by getDisplayList() when the parent ViewGroup does not need
   4332      * to recreate its own display list, which would happen if it went through the normal
   4333      * draw/dispatchDraw mechanisms.
   4334      *
   4335      * @hide
   4336      */
   4337     @Override
   4338     @UnsupportedAppUsage
   4339     protected void dispatchGetDisplayList() {
   4340         final int count = mChildrenCount;
   4341         final View[] children = mChildren;
   4342         for (int i = 0; i < count; i++) {
   4343             final View child = children[i];
   4344             if (((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null)) {
   4345                 recreateChildDisplayList(child);
   4346             }
   4347         }
   4348         final int transientCount = mTransientViews == null ? 0 : mTransientIndices.size();
   4349         for (int i = 0; i < transientCount; ++i) {
   4350             View child = mTransientViews.get(i);
   4351             if (((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null)) {
   4352                 recreateChildDisplayList(child);
   4353             }
   4354         }
   4355         if (mOverlay != null) {
   4356             View overlayView = mOverlay.getOverlayView();
   4357             recreateChildDisplayList(overlayView);
   4358         }
   4359         if (mDisappearingChildren != null) {
   4360             final ArrayList<View> disappearingChildren = mDisappearingChildren;
   4361             final int disappearingCount = disappearingChildren.size();
   4362             for (int i = 0; i < disappearingCount; ++i) {
   4363                 final View child = disappearingChildren.get(i);
   4364                 recreateChildDisplayList(child);
   4365             }
   4366         }
   4367     }
   4368 
   4369     private void recreateChildDisplayList(View child) {
   4370         child.mRecreateDisplayList = (child.mPrivateFlags & PFLAG_INVALIDATED) != 0;
   4371         child.mPrivateFlags &= ~PFLAG_INVALIDATED;
   4372         child.updateDisplayListIfDirty();
   4373         child.mRecreateDisplayList = false;
   4374     }
   4375 
   4376     /**
   4377      * Draw one child of this View Group. This method is responsible for getting
   4378      * the canvas in the right state. This includes clipping, translating so
   4379      * that the child's scrolled origin is at 0, 0, and applying any animation
   4380      * transformations.
   4381      *
   4382      * @param canvas The canvas on which to draw the child
   4383      * @param child Who to draw
   4384      * @param drawingTime The time at which draw is occurring
   4385      * @return True if an invalidate() was issued
   4386      */
   4387     protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
   4388         return child.draw(canvas, this, drawingTime);
   4389     }
   4390 
   4391     @Override
   4392     void getScrollIndicatorBounds(@NonNull Rect out) {
   4393         super.getScrollIndicatorBounds(out);
   4394 
   4395         // If we have padding and we're supposed to clip children to that
   4396         // padding, offset the scroll indicators to match our clip bounds.
   4397         final boolean clipToPadding = (mGroupFlags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK;
   4398         if (clipToPadding) {
   4399             out.left += mPaddingLeft;
   4400             out.right -= mPaddingRight;
   4401             out.top += mPaddingTop;
   4402             out.bottom -= mPaddingBottom;
   4403         }
   4404     }
   4405 
   4406     /**
   4407      * Returns whether this group's children are clipped to their bounds before drawing.
   4408      * The default value is true.
   4409      * @see #setClipChildren(boolean)
   4410      *
   4411      * @return True if the group's children will be clipped to their bounds,
   4412      * false otherwise.
   4413      */
   4414     @ViewDebug.ExportedProperty(category = "drawing")
   4415     @InspectableProperty
   4416     public boolean getClipChildren() {
   4417         return ((mGroupFlags & FLAG_CLIP_CHILDREN) != 0);
   4418     }
   4419 
   4420     /**
   4421      * By default, children are clipped to their bounds before drawing. This
   4422      * allows view groups to override this behavior for animations, etc.
   4423      *
   4424      * @param clipChildren true to clip children to their bounds,
   4425      *        false otherwise
   4426      * @attr ref android.R.styleable#ViewGroup_clipChildren
   4427      */
   4428     public void setClipChildren(boolean clipChildren) {
   4429         boolean previousValue = (mGroupFlags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN;
   4430         if (clipChildren != previousValue) {
   4431             setBooleanFlag(FLAG_CLIP_CHILDREN, clipChildren);
   4432             for (int i = 0; i < mChildrenCount; ++i) {
   4433                 View child = getChildAt(i);
   4434                 if (child.mRenderNode != null) {
   4435                     child.mRenderNode.setClipToBounds(clipChildren);
   4436                 }
   4437             }
   4438             invalidate(true);
   4439         }
   4440     }
   4441 
   4442     /**
   4443      * Sets whether this ViewGroup will clip its children to its padding and resize (but not
   4444      * clip) any EdgeEffect to the padded region, if padding is present.
   4445      * <p>
   4446      * By default, children are clipped to the padding of their parent
   4447      * ViewGroup. This clipping behavior is only enabled if padding is non-zero.
   4448      *
   4449      * @param clipToPadding true to clip children to the padding of the group, and resize (but
   4450      *        not clip) any EdgeEffect to the padded region. False otherwise.
   4451      * @attr ref android.R.styleable#ViewGroup_clipToPadding
   4452      */
   4453     public void setClipToPadding(boolean clipToPadding) {
   4454         if (hasBooleanFlag(FLAG_CLIP_TO_PADDING) != clipToPadding) {
   4455             setBooleanFlag(FLAG_CLIP_TO_PADDING, clipToPadding);
   4456             invalidate(true);
   4457         }
   4458     }
   4459 
   4460     /**
   4461      * Returns whether this ViewGroup will clip its children to its padding, and resize (but
   4462      * not clip) any EdgeEffect to the padded region, if padding is present.
   4463      * <p>
   4464      * By default, children are clipped to the padding of their parent
   4465      * Viewgroup. This clipping behavior is only enabled if padding is non-zero.
   4466      *
   4467      * @return true if this ViewGroup clips children to its padding and resizes (but doesn't
   4468      *         clip) any EdgeEffect to the padded region, false otherwise.
   4469      *
   4470      * @attr ref android.R.styleable#ViewGroup_clipToPadding
   4471      */
   4472     @ViewDebug.ExportedProperty(category = "drawing")
   4473     @InspectableProperty
   4474     public boolean getClipToPadding() {
   4475         return hasBooleanFlag(FLAG_CLIP_TO_PADDING);
   4476     }
   4477 
   4478     @Override
   4479     public void dispatchSetSelected(boolean selected) {
   4480         final View[] children = mChildren;
   4481         final int count = mChildrenCount;
   4482         for (int i = 0; i < count; i++) {
   4483             children[i].setSelected(selected);
   4484         }
   4485     }
   4486 
   4487     @Override
   4488     public void dispatchSetActivated(boolean activated) {
   4489         final View[] children = mChildren;
   4490         final int count = mChildrenCount;
   4491         for (int i = 0; i < count; i++) {
   4492             children[i].setActivated(activated);
   4493         }
   4494     }
   4495 
   4496     @Override
   4497     protected void dispatchSetPressed(boolean pressed) {
   4498         final View[] children = mChildren;
   4499         final int count = mChildrenCount;
   4500         for (int i = 0; i < count; i++) {
   4501             final View child = children[i];
   4502             // Children that are clickable on their own should not
   4503             // show a pressed state when their parent view does.
   4504             // Clearing a pressed state always propagates.
   4505             if (!pressed || (!child.isClickable() && !child.isLongClickable())) {
   4506                 child.setPressed(pressed);
   4507             }
   4508         }
   4509     }
   4510 
   4511     /**
   4512      * Dispatches drawable hotspot changes to child views that meet at least
   4513      * one of the following criteria:
   4514      * <ul>
   4515      *     <li>Returns {@code false} from both {@link View#isClickable()} and
   4516      *     {@link View#isLongClickable()}</li>
   4517      *     <li>Requests duplication of parent state via
   4518      *     {@link View#setDuplicateParentStateEnabled(boolean)}</li>
   4519      * </ul>
   4520      *
   4521      * @param x hotspot x coordinate
   4522      * @param y hotspot y coordinate
   4523      * @see #drawableHotspotChanged(float, float)
   4524      */
   4525     @Override
   4526     public void dispatchDrawableHotspotChanged(float x, float y) {
   4527         final int count = mChildrenCount;
   4528         if (count == 0) {
   4529             return;
   4530         }
   4531 
   4532         final View[] children = mChildren;
   4533         for (int i = 0; i < count; i++) {
   4534             final View child = children[i];
   4535             // Children that are clickable on their own should not
   4536             // receive hotspots when their parent view does.
   4537             final boolean nonActionable = !child.isClickable() && !child.isLongClickable();
   4538             final boolean duplicatesState = (child.mViewFlags & DUPLICATE_PARENT_STATE) != 0;
   4539             if (nonActionable || duplicatesState) {
   4540                 final float[] point = getTempPoint();
   4541                 point[0] = x;
   4542                 point[1] = y;
   4543                 transformPointToViewLocal(point, child);
   4544                 child.drawableHotspotChanged(point[0], point[1]);
   4545             }
   4546         }
   4547     }
   4548 
   4549     @Override
   4550     void dispatchCancelPendingInputEvents() {
   4551         super.dispatchCancelPendingInputEvents();
   4552 
   4553         final View[] children = mChildren;
   4554         final int count = mChildrenCount;
   4555         for (int i = 0; i < count; i++) {
   4556             children[i].dispatchCancelPendingInputEvents();
   4557         }
   4558     }
   4559 
   4560     /**
   4561      * When this property is set to true, this ViewGroup supports static transformations on
   4562      * children; this causes
   4563      * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} to be
   4564      * invoked when a child is drawn.
   4565      *
   4566      * Any subclass overriding
   4567      * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} should
   4568      * set this property to true.
   4569      *
   4570      * @param enabled True to enable static transformations on children, false otherwise.
   4571      *
   4572      * @see #getChildStaticTransformation(View, android.view.animation.Transformation)
   4573      */
   4574     protected void setStaticTransformationsEnabled(boolean enabled) {
   4575         setBooleanFlag(FLAG_SUPPORT_STATIC_TRANSFORMATIONS, enabled);
   4576     }
   4577 
   4578     /**
   4579      * Sets  <code>t</code> to be the static transformation of the child, if set, returning a
   4580      * boolean to indicate whether a static transform was set. The default implementation
   4581      * simply returns <code>false</code>; subclasses may override this method for different
   4582      * behavior. {@link #setStaticTransformationsEnabled(boolean)} must be set to true
   4583      * for this method to be called.
   4584      *
   4585      * @param child The child view whose static transform is being requested
   4586      * @param t The Transformation which will hold the result
   4587      * @return true if the transformation was set, false otherwise
   4588      * @see #setStaticTransformationsEnabled(boolean)
   4589      */
   4590     protected boolean getChildStaticTransformation(View child, Transformation t) {
   4591         return false;
   4592     }
   4593 
   4594     Transformation getChildTransformation() {
   4595         if (mChildTransformation == null) {
   4596             mChildTransformation = new Transformation();
   4597         }
   4598         return mChildTransformation;
   4599     }
   4600 
   4601     /**
   4602      * {@hide}
   4603      */
   4604     @Override
   4605     protected <T extends View> T findViewTraversal(@IdRes int id) {
   4606         if (id == mID) {
   4607             return (T) this;
   4608         }
   4609 
   4610         final View[] where = mChildren;
   4611         final int len = mChildrenCount;
   4612 
   4613         for (int i = 0; i < len; i++) {
   4614             View v = where[i];
   4615 
   4616             if ((v.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) {
   4617                 v = v.findViewById(id);
   4618 
   4619                 if (v != null) {
   4620                     return (T) v;
   4621                 }
   4622             }
   4623         }
   4624 
   4625         return null;
   4626     }
   4627 
   4628     /**
   4629      * {@hide}
   4630      */
   4631     @Override
   4632     protected <T extends View> T findViewWithTagTraversal(Object tag) {
   4633         if (tag != null && tag.equals(mTag)) {
   4634             return (T) this;
   4635         }
   4636 
   4637         final View[] where = mChildren;
   4638         final int len = mChildrenCount;
   4639 
   4640         for (int i = 0; i < len; i++) {
   4641             View v = where[i];
   4642 
   4643             if ((v.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) {
   4644                 v = v.findViewWithTag(tag);
   4645 
   4646                 if (v != null) {
   4647                     return (T) v;
   4648                 }
   4649             }
   4650         }
   4651 
   4652         return null;
   4653     }
   4654 
   4655     /**
   4656      * {@hide}
   4657      */
   4658     @Override
   4659     protected <T extends View> T findViewByPredicateTraversal(Predicate<View> predicate,
   4660             View childToSkip) {
   4661         if (predicate.test(this)) {
   4662             return (T) this;
   4663         }
   4664 
   4665         final View[] where = mChildren;
   4666         final int len = mChildrenCount;
   4667 
   4668         for (int i = 0; i < len; i++) {
   4669             View v = where[i];
   4670 
   4671             if (v != childToSkip && (v.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) {
   4672                 v = v.findViewByPredicate(predicate);
   4673 
   4674                 if (v != null) {
   4675                     return (T) v;
   4676                 }
   4677             }
   4678         }
   4679 
   4680         return null;
   4681     }
   4682 
   4683     /**
   4684      * This method adds a view to this container at the specified index purely for the
   4685      * purposes of allowing that view to draw even though it is not a normal child of
   4686      * the container. That is, the view does not participate in layout, focus, accessibility,
   4687      * input, or other normal view operations; it is purely an item to be drawn during the normal
   4688      * rendering operation of this container. The index that it is added at is the order
   4689      * in which it will be drawn, with respect to the other views in the container.
   4690      * For example, a transient view added at index 0 will be drawn before all other views
   4691      * in the container because it will be drawn first (including before any real view
   4692      * at index 0). There can be more than one transient view at any particular index;
   4693      * these views will be drawn in the order in which they were added to the list of
   4694      * transient views. The index of transient views can also be greater than the number
   4695      * of normal views in the container; that just means that they will be drawn after all
   4696      * other views are drawn.
   4697      *
   4698      * <p>Note that since transient views do not participate in layout, they must be sized
   4699      * manually or, more typically, they should just use the size that they had before they
   4700      * were removed from their container.</p>
   4701      *
   4702      * <p>Transient views are useful for handling animations of views that have been removed
   4703      * from the container, but which should be animated out after the removal. Adding these
   4704      * views as transient views allows them to participate in drawing without side-effecting
   4705      * the layout of the container.</p>
   4706      *
   4707      * <p>Transient views must always be explicitly {@link #removeTransientView(View) removed}
   4708      * from the container when they are no longer needed. For example, a transient view
   4709      * which is added in order to fade it out in its old location should be removed
   4710      * once the animation is complete.</p>
   4711      *
   4712      * @param view The view to be added. The view must not have a parent.
   4713      * @param index The index at which this view should be drawn, must be >= 0.
   4714      * This value is relative to the {@link #getChildAt(int) index} values in the normal
   4715      * child list of this container, where any transient view at a particular index will
   4716      * be drawn before any normal child at that same index.
   4717      *
   4718      * @hide
   4719      */
   4720     @UnsupportedAppUsage
   4721     public void addTransientView(View view, int index) {
   4722         if (index < 0 || view == null) {
   4723             return;
   4724         }
   4725         if (view.mParent != null) {
   4726             throw new IllegalStateException("The specified view already has a parent "
   4727                     + view.mParent);
   4728         }
   4729 
   4730         if (mTransientIndices == null) {
   4731             mTransientIndices = new ArrayList<Integer>();
   4732             mTransientViews = new ArrayList<View>();
   4733         }
   4734         final int oldSize = mTransientIndices.size();
   4735         if (oldSize > 0) {
   4736             int insertionIndex;
   4737             for (insertionIndex = 0; insertionIndex < oldSize; ++insertionIndex) {
   4738                 if (index < mTransientIndices.get(insertionIndex)) {
   4739                     break;
   4740                 }
   4741             }
   4742             mTransientIndices.add(insertionIndex, index);
   4743             mTransientViews.add(insertionIndex, view);
   4744         } else {
   4745             mTransientIndices.add(index);
   4746             mTransientViews.add(view);
   4747         }
   4748         view.mParent = this;
   4749         if (mAttachInfo != null) {
   4750             view.dispatchAttachedToWindow(mAttachInfo, (mViewFlags & VISIBILITY_MASK));
   4751         }
   4752         invalidate(true);
   4753     }
   4754 
   4755     /**
   4756      * Removes a view from the list of transient views in this container. If there is no
   4757      * such transient view, this method does nothing.
   4758      *
   4759      * @param view The transient view to be removed
   4760      *
   4761      * @hide
   4762      */
   4763     @UnsupportedAppUsage
   4764     public void removeTransientView(View view) {
   4765         if (mTransientViews == null) {
   4766             return;
   4767         }
   4768         final int size = mTransientViews.size();
   4769         for (int i = 0; i < size; ++i) {
   4770             if (view == mTransientViews.get(i)) {
   4771                 mTransientViews.remove(i);
   4772                 mTransientIndices.remove(i);
   4773                 view.mParent = null;
   4774                 if (view.mAttachInfo != null) {
   4775                     view.dispatchDetachedFromWindow();
   4776                 }
   4777                 invalidate(true);
   4778                 return;
   4779             }
   4780         }
   4781     }
   4782 
   4783     /**
   4784      * Returns the number of transient views in this container. Specific transient
   4785      * views and the index at which they were added can be retrieved via
   4786      * {@link #getTransientView(int)} and {@link #getTransientViewIndex(int)}.
   4787      *
   4788      * @see #addTransientView(View, int)
   4789      * @return The number of transient views in this container
   4790      *
   4791      * @hide
   4792      */
   4793     @UnsupportedAppUsage
   4794     public int getTransientViewCount() {
   4795         return mTransientIndices == null ? 0 : mTransientIndices.size();
   4796     }
   4797 
   4798     /**
   4799      * Given a valid position within the list of transient views, returns the index of
   4800      * the transient view at that position.
   4801      *
   4802      * @param position The position of the index being queried. Must be at least 0
   4803      * and less than the value returned by {@link #getTransientViewCount()}.
   4804      * @return The index of the transient view stored in the given position if the
   4805      * position is valid, otherwise -1
   4806      *
   4807      * @hide
   4808      */
   4809     public int getTransientViewIndex(int position) {
   4810         if (position < 0 || mTransientIndices == null || position >= mTransientIndices.size()) {
   4811             return -1;
   4812         }
   4813         return mTransientIndices.get(position);
   4814     }
   4815 
   4816     /**
   4817      * Given a valid position within the list of transient views, returns the
   4818      * transient view at that position.
   4819      *
   4820      * @param position The position of the view being queried. Must be at least 0
   4821      * and less than the value returned by {@link #getTransientViewCount()}.
   4822      * @return The transient view stored in the given position if the
   4823      * position is valid, otherwise null
   4824      *
   4825      * @hide
   4826      */
   4827     @UnsupportedAppUsage
   4828     public View getTransientView(int position) {
   4829         if (mTransientViews == null || position >= mTransientViews.size()) {
   4830             return null;
   4831         }
   4832         return mTransientViews.get(position);
   4833     }
   4834 
   4835     /**
   4836      * <p>Adds a child view. If no layout parameters are already set on the child, the
   4837      * default parameters for this ViewGroup are set on the child.</p>
   4838      *
   4839      * <p><strong>Note:</strong> do not invoke this method from
   4840      * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
   4841      * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
   4842      *
   4843      * @param child the child view to add
   4844      *
   4845      * @see #generateDefaultLayoutParams()
   4846      */
   4847     public void addView(View child) {
   4848         addView(child, -1);
   4849     }
   4850 
   4851     /**
   4852      * Adds a child view. If no layout parameters are already set on the child, the
   4853      * default parameters for this ViewGroup are set on the child.
   4854      *
   4855      * <p><strong>Note:</strong> do not invoke this method from
   4856      * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
   4857      * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
   4858      *
   4859      * @param child the child view to add
   4860      * @param index the position at which to add the child
   4861      *
   4862      * @see #generateDefaultLayoutParams()
   4863      */
   4864     public void addView(View child, int index) {
   4865         if (child == null) {
   4866             throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup");
   4867         }
   4868         LayoutParams params = child.getLayoutParams();
   4869         if (params == null) {
   4870             params = generateDefaultLayoutParams();
   4871             if (params == null) {
   4872                 throw new IllegalArgumentException("generateDefaultLayoutParams() cannot return null");
   4873             }
   4874         }
   4875         addView(child, index, params);
   4876     }
   4877 
   4878     /**
   4879      * Adds a child view with this ViewGroup's default layout parameters and the
   4880      * specified width and height.
   4881      *
   4882      * <p><strong>Note:</strong> do not invoke this method from
   4883      * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
   4884      * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
   4885      *
   4886      * @param child the child view to add
   4887      */
   4888     public void addView(View child, int width, int height) {
   4889         final LayoutParams params = generateDefaultLayoutParams();
   4890         params.width = width;
   4891         params.height = height;
   4892         addView(child, -1, params);
   4893     }
   4894 
   4895     /**
   4896      * Adds a child view with the specified layout parameters.
   4897      *
   4898      * <p><strong>Note:</strong> do not invoke this method from
   4899      * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
   4900      * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
   4901      *
   4902      * @param child the child view to add
   4903      * @param params the layout parameters to set on the child
   4904      */
   4905     @Override
   4906     public void addView(View child, LayoutParams params) {
   4907         addView(child, -1, params);
   4908     }
   4909 
   4910     /**
   4911      * Adds a child view with the specified layout parameters.
   4912      *
   4913      * <p><strong>Note:</strong> do not invoke this method from
   4914      * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
   4915      * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
   4916      *
   4917      * @param child the child view to add
   4918      * @param index the position at which to add the child or -1 to add last
   4919      * @param params the layout parameters to set on the child
   4920      */
   4921     public void addView(View child, int index, LayoutParams params) {
   4922         if (DBG) {
   4923             System.out.println(this + " addView");
   4924         }
   4925 
   4926         if (child == null) {
   4927             throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup");
   4928         }
   4929 
   4930         // addViewInner() will call child.requestLayout() when setting the new LayoutParams
   4931         // therefore, we call requestLayout() on ourselves before, so that the child's request
   4932         // will be blocked at our level
   4933         requestLayout();
   4934         invalidate(true);
   4935         addViewInner(child, index, params, false);
   4936     }
   4937 
   4938     @Override
   4939     public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
   4940         if (!checkLayoutParams(params)) {
   4941             throw new IllegalArgumentException("Invalid LayoutParams supplied to " + this);
   4942         }
   4943         if (view.mParent != this) {
   4944             throw new IllegalArgumentException("Given view not a child of " + this);
   4945         }
   4946         view.setLayoutParams(params);
   4947     }
   4948 
   4949     protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
   4950         return  p != null;
   4951     }
   4952 
   4953     /**
   4954      * Interface definition for a callback to be invoked when the hierarchy
   4955      * within this view changed. The hierarchy changes whenever a child is added
   4956      * to or removed from this view.
   4957      */
   4958     public interface OnHierarchyChangeListener {
   4959         /**
   4960          * Called when a new child is added to a parent view.
   4961          *
   4962          * @param parent the view in which a child was added
   4963          * @param child the new child view added in the hierarchy
   4964          */
   4965         void onChildViewAdded(View parent, View child);
   4966 
   4967         /**
   4968          * Called when a child is removed from a parent view.
   4969          *
   4970          * @param parent the view from which the child was removed
   4971          * @param child the child removed from the hierarchy
   4972          */
   4973         void onChildViewRemoved(View parent, View child);
   4974     }
   4975 
   4976     /**
   4977      * Register a callback to be invoked when a child is added to or removed
   4978      * from this view.
   4979      *
   4980      * @param listener the callback to invoke on hierarchy change
   4981      */
   4982     public void setOnHierarchyChangeListener(OnHierarchyChangeListener listener) {
   4983         mOnHierarchyChangeListener = listener;
   4984     }
   4985 
   4986     @UnsupportedAppUsage
   4987     void dispatchViewAdded(View child) {
   4988         onViewAdded(child);
   4989         if (mOnHierarchyChangeListener != null) {
   4990             mOnHierarchyChangeListener.onChildViewAdded(this, child);
   4991         }
   4992     }
   4993 
   4994     /**
   4995      * Called when a new child is added to this ViewGroup. Overrides should always
   4996      * call super.onViewAdded.
   4997      *
   4998      * @param child the added child view
   4999      */
   5000     public void onViewAdded(View child) {
   5001     }
   5002 
   5003     @UnsupportedAppUsage
   5004     void dispatchViewRemoved(View child) {
   5005         onViewRemoved(child);
   5006         if (mOnHierarchyChangeListener != null) {
   5007             mOnHierarchyChangeListener.onChildViewRemoved(this, child);
   5008         }
   5009     }
   5010 
   5011     /**
   5012      * Called when a child view is removed from this ViewGroup. Overrides should always
   5013      * call super.onViewRemoved.
   5014      *
   5015      * @param child the removed child view
   5016      */
   5017     public void onViewRemoved(View child) {
   5018     }
   5019 
   5020     private void clearCachedLayoutMode() {
   5021         if (!hasBooleanFlag(FLAG_LAYOUT_MODE_WAS_EXPLICITLY_SET)) {
   5022            mLayoutMode = LAYOUT_MODE_UNDEFINED;
   5023         }
   5024     }
   5025 
   5026     @Override
   5027     protected void onAttachedToWindow() {
   5028         super.onAttachedToWindow();
   5029         clearCachedLayoutMode();
   5030     }
   5031 
   5032     @Override
   5033     protected void onDetachedFromWindow() {
   5034         super.onDetachedFromWindow();
   5035         clearCachedLayoutMode();
   5036     }
   5037 
   5038     /** @hide */
   5039     @Override
   5040     protected void destroyHardwareResources() {
   5041         super.destroyHardwareResources();
   5042         int count = getChildCount();
   5043         for (int i = 0; i < count; i++) {
   5044             getChildAt(i).destroyHardwareResources();
   5045         }
   5046     }
   5047 
   5048     /**
   5049      * Adds a view during layout. This is useful if in your onLayout() method,
   5050      * you need to add more views (as does the list view for example).
   5051      *
   5052      * If index is negative, it means put it at the end of the list.
   5053      *
   5054      * @param child the view to add to the group
   5055      * @param index the index at which the child must be added or -1 to add last
   5056      * @param params the layout parameters to associate with the child
   5057      * @return true if the child was added, false otherwise
   5058      */
   5059     protected boolean addViewInLayout(View child, int index, LayoutParams params) {
   5060         return addViewInLayout(child, index, params, false);
   5061     }
   5062 
   5063     /**
   5064      * Adds a view during layout. This is useful if in your onLayout() method,
   5065      * you need to add more views (as does the list view for example).
   5066      *
   5067      * If index is negative, it means put it at the end of the list.
   5068      *
   5069      * @param child the view to add to the group
   5070      * @param index the index at which the child must be added or -1 to add last
   5071      * @param params the layout parameters to associate with the child
   5072      * @param preventRequestLayout if true, calling this method will not trigger a
   5073      *        layout request on child
   5074      * @return true if the child was added, false otherwise
   5075      */
   5076     protected boolean addViewInLayout(View child, int index, LayoutParams params,
   5077             boolean preventRequestLayout) {
   5078         if (child == null) {
   5079             throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup");
   5080         }
   5081         child.mParent = null;
   5082         addViewInner(child, index, params, preventRequestLayout);
   5083         child.mPrivateFlags = (child.mPrivateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN;
   5084         return true;
   5085     }
   5086 
   5087     /**
   5088      * Prevents the specified child to be laid out during the next layout pass.
   5089      *
   5090      * @param child the child on which to perform the cleanup
   5091      */
   5092     protected void cleanupLayoutState(View child) {
   5093         child.mPrivateFlags &= ~View.PFLAG_FORCE_LAYOUT;
   5094     }
   5095 
   5096     private void addViewInner(View child, int index, LayoutParams params,
   5097             boolean preventRequestLayout) {
   5098 
   5099         if (mTransition != null) {
   5100             // Don't prevent other add transitions from completing, but cancel remove
   5101             // transitions to let them complete the process before we add to the container
   5102             mTransition.cancel(LayoutTransition.DISAPPEARING);
   5103         }
   5104 
   5105         if (child.getParent() != null) {
   5106             throw new IllegalStateException("The specified child already has a parent. " +
   5107                     "You must call removeView() on the child's parent first.");
   5108         }
   5109 
   5110         if (mTransition != null) {
   5111             mTransition.addChild(this, child);
   5112         }
   5113 
   5114         if (!checkLayoutParams(params)) {
   5115             params = generateLayoutParams(params);
   5116         }
   5117 
   5118         if (preventRequestLayout) {
   5119             child.mLayoutParams = params;
   5120         } else {
   5121             child.setLayoutParams(params);
   5122         }
   5123 
   5124         if (index < 0) {
   5125             index = mChildrenCount;
   5126         }
   5127 
   5128         addInArray(child, index);
   5129 
   5130         // tell our children
   5131         if (preventRequestLayout) {
   5132             child.assignParent(this);
   5133         } else {
   5134             child.mParent = this;
   5135         }
   5136         if (child.hasUnhandledKeyListener()) {
   5137             incrementChildUnhandledKeyListeners();
   5138         }
   5139 
   5140         final boolean childHasFocus = child.hasFocus();
   5141         if (childHasFocus) {
   5142             requestChildFocus(child, child.findFocus());
   5143         }
   5144 
   5145         AttachInfo ai = mAttachInfo;
   5146         if (ai != null && (mGroupFlags & FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW) == 0) {
   5147             boolean lastKeepOn = ai.mKeepScreenOn;
   5148             ai.mKeepScreenOn = false;
   5149             child.dispatchAttachedToWindow(mAttachInfo, (mViewFlags&VISIBILITY_MASK));
   5150             if (ai.mKeepScreenOn) {
   5151                 needGlobalAttributesUpdate(true);
   5152             }
   5153             ai.mKeepScreenOn = lastKeepOn;
   5154         }
   5155 
   5156         if (child.isLayoutDirectionInherited()) {
   5157             child.resetRtlProperties();
   5158         }
   5159 
   5160         dispatchViewAdded(child);
   5161 
   5162         if ((child.mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE) {
   5163             mGroupFlags |= FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE;
   5164         }
   5165 
   5166         if (child.hasTransientState()) {
   5167             childHasTransientStateChanged(child, true);
   5168         }
   5169 
   5170         if (child.getVisibility() != View.GONE) {
   5171             notifySubtreeAccessibilityStateChangedIfNeeded();
   5172         }
   5173 
   5174         if (mTransientIndices != null) {
   5175             final int transientCount = mTransientIndices.size();
   5176             for (int i = 0; i < transientCount; ++i) {
   5177                 final int oldIndex = mTransientIndices.get(i);
   5178                 if (index <= oldIndex) {
   5179                     mTransientIndices.set(i, oldIndex + 1);
   5180                 }
   5181             }
   5182         }
   5183 
   5184         if (mCurrentDragStartEvent != null && child.getVisibility() == VISIBLE) {
   5185             notifyChildOfDragStart(child);
   5186         }
   5187 
   5188         if (child.hasDefaultFocus()) {
   5189             // When adding a child that contains default focus, either during inflation or while
   5190             // manually assembling the hierarchy, update the ancestor default-focus chain.
   5191             setDefaultFocus(child);
   5192         }
   5193 
   5194         touchAccessibilityNodeProviderIfNeeded(child);
   5195     }
   5196 
   5197     /**
   5198      * We may need to touch the provider to bring up the a11y layer. In a11y mode
   5199      * clients inspect the screen or the user touches it which triggers bringing up
   5200      * of the a11y infrastructure while in autofill mode we want the infra up and
   5201      * running from the beginning since we watch for a11y events to drive autofill.
   5202      */
   5203     private void touchAccessibilityNodeProviderIfNeeded(View child) {
   5204         if (mContext.isAutofillCompatibilityEnabled()) {
   5205             child.getAccessibilityNodeProvider();
   5206         }
   5207     }
   5208 
   5209     private void addInArray(View child, int index) {
   5210         View[] children = mChildren;
   5211         final int count = mChildrenCount;
   5212         final int size = children.length;
   5213         if (index == count) {
   5214             if (size == count) {
   5215                 mChildren = new View[size + ARRAY_CAPACITY_INCREMENT];
   5216                 System.arraycopy(children, 0, mChildren, 0, size);
   5217                 children = mChildren;
   5218             }
   5219             children[mChildrenCount++] = child;
   5220         } else if (index < count) {
   5221             if (size == count) {
   5222                 mChildren = new View[size + ARRAY_CAPACITY_INCREMENT];
   5223                 System.arraycopy(children, 0, mChildren, 0, index);
   5224                 System.arraycopy(children, index, mChildren, index + 1, count - index);
   5225                 children = mChildren;
   5226             } else {
   5227                 System.arraycopy(children, index, children, index + 1, count - index);
   5228             }
   5229             children[index] = child;
   5230             mChildrenCount++;
   5231             if (mLastTouchDownIndex >= index) {
   5232                 mLastTouchDownIndex++;
   5233             }
   5234         } else {
   5235             throw new IndexOutOfBoundsException("index=" + index + " count=" + count);
   5236         }
   5237     }
   5238 
   5239     // This method also sets the child's mParent to null
   5240     private void removeFromArray(int index) {
   5241         final View[] children = mChildren;
   5242         if (!(mTransitioningViews != null && mTransitioningViews.contains(children[index]))) {
   5243             children[index].mParent = null;
   5244         }
   5245         final int count = mChildrenCount;
   5246         if (index == count - 1) {
   5247             children[--mChildrenCount] = null;
   5248         } else if (index >= 0 && index < count) {
   5249             System.arraycopy(children, index + 1, children, index, count - index - 1);
   5250             children[--mChildrenCount] = null;
   5251         } else {
   5252             throw new IndexOutOfBoundsException();
   5253         }
   5254         if (mLastTouchDownIndex == index) {
   5255             mLastTouchDownTime = 0;
   5256             mLastTouchDownIndex = -1;
   5257         } else if (mLastTouchDownIndex > index) {
   5258             mLastTouchDownIndex--;
   5259         }
   5260     }
   5261 
   5262     // This method also sets the children's mParent to null
   5263     private void removeFromArray(int start, int count) {
   5264         final View[] children = mChildren;
   5265         final int childrenCount = mChildrenCount;
   5266 
   5267         start = Math.max(0, start);
   5268         final int end = Math.min(childrenCount, start + count);
   5269 
   5270         if (start == end) {
   5271             return;
   5272         }
   5273 
   5274         if (end == childrenCount) {
   5275             for (int i = start; i < end; i++) {
   5276                 children[i].mParent = null;
   5277                 children[i] = null;
   5278             }
   5279         } else {
   5280             for (int i = start; i < end; i++) {
   5281                 children[i].mParent = null;
   5282             }
   5283 
   5284             // Since we're looping above, we might as well do the copy, but is arraycopy()
   5285             // faster than the extra 2 bounds checks we would do in the loop?
   5286             System.arraycopy(children, end, children, start, childrenCount - end);
   5287 
   5288             for (int i = childrenCount - (end - start); i < childrenCount; i++) {
   5289                 children[i] = null;
   5290             }
   5291         }
   5292 
   5293         mChildrenCount -= (end - start);
   5294     }
   5295 
   5296     private void bindLayoutAnimation(View child) {
   5297         Animation a = mLayoutAnimationController.getAnimationForView(child);
   5298         child.setAnimation(a);
   5299     }
   5300 
   5301     /**
   5302      * Subclasses should override this method to set layout animation
   5303      * parameters on the supplied child.
   5304      *
   5305      * @param child the child to associate with animation parameters
   5306      * @param params the child's layout parameters which hold the animation
   5307      *        parameters
   5308      * @param index the index of the child in the view group
   5309      * @param count the number of children in the view group
   5310      */
   5311     protected void attachLayoutAnimationParameters(View child,
   5312             LayoutParams params, int index, int count) {
   5313         LayoutAnimationController.AnimationParameters animationParams =
   5314                     params.layoutAnimationParameters;
   5315         if (animationParams == null) {
   5316             animationParams = new LayoutAnimationController.AnimationParameters();
   5317             params.layoutAnimationParameters = animationParams;
   5318         }
   5319 
   5320         animationParams.count = count;
   5321         animationParams.index = index;
   5322     }
   5323 
   5324     /**
   5325      * {@inheritDoc}
   5326      *
   5327      * <p><strong>Note:</strong> do not invoke this method from
   5328      * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
   5329      * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
   5330      */
   5331     @Override
   5332     public void removeView(View view) {
   5333         if (removeViewInternal(view)) {
   5334             requestLayout();
   5335             invalidate(true);
   5336         }
   5337     }
   5338 
   5339     /**
   5340      * Removes a view during layout. This is useful if in your onLayout() method,
   5341      * you need to remove more views.
   5342      *
   5343      * <p><strong>Note:</strong> do not invoke this method from
   5344      * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
   5345      * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
   5346      *
   5347      * @param view the view to remove from the group
   5348      */
   5349     public void removeViewInLayout(View view) {
   5350         removeViewInternal(view);
   5351     }
   5352 
   5353     /**
   5354      * Removes a range of views during layout. This is useful if in your onLayout() method,
   5355      * you need to remove more views.
   5356      *
   5357      * <p><strong>Note:</strong> do not invoke this method from
   5358      * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
   5359      * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
   5360      *
   5361      * @param start the index of the first view to remove from the group
   5362      * @param count the number of views to remove from the group
   5363      */
   5364     public void removeViewsInLayout(int start, int count) {
   5365         removeViewsInternal(start, count);
   5366     }
   5367 
   5368     /**
   5369      * Removes the view at the specified position in the group.
   5370      *
   5371      * <p><strong>Note:</strong> do not invoke this method from
   5372      * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
   5373      * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
   5374      *
   5375      * @param index the position in the group of the view to remove
   5376      */
   5377     public void removeViewAt(int index) {
   5378         removeViewInternal(index, getChildAt(index));
   5379         requestLayout();
   5380         invalidate(true);
   5381     }
   5382 
   5383     /**
   5384      * Removes the specified range of views from the group.
   5385      *
   5386      * <p><strong>Note:</strong> do not invoke this method from
   5387      * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
   5388      * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
   5389      *
   5390      * @param start the first position in the group of the range of views to remove
   5391      * @param count the number of views to remove
   5392      */
   5393     public void removeViews(int start, int count) {
   5394         removeViewsInternal(start, count);
   5395         requestLayout();
   5396         invalidate(true);
   5397     }
   5398 
   5399     private boolean removeViewInternal(View view) {
   5400         final int index = indexOfChild(view);
   5401         if (index >= 0) {
   5402             removeViewInternal(index, view);
   5403             return true;
   5404         }
   5405         return false;
   5406     }
   5407 
   5408     private void removeViewInternal(int index, View view) {
   5409         if (mTransition != null) {
   5410             mTransition.removeChild(this, view);
   5411         }
   5412 
   5413         boolean clearChildFocus = false;
   5414         if (view == mFocused) {
   5415             view.unFocus(null);
   5416             clearChildFocus = true;
   5417         }
   5418         if (view == mFocusedInCluster) {
   5419             clearFocusedInCluster(view);
   5420         }
   5421 
   5422         view.clearAccessibilityFocus();
   5423 
   5424         cancelTouchTarget(view);
   5425         cancelHoverTarget(view);
   5426 
   5427         if (view.getAnimation() != null ||
   5428                 (mTransitioningViews != null && mTransitioningViews.contains(view))) {
   5429             addDisappearingView(view);
   5430         } else if (view.mAttachInfo != null) {
   5431            view.dispatchDetachedFromWindow();
   5432         }
   5433 
   5434         if (view.hasTransientState()) {
   5435             childHasTransientStateChanged(view, false);
   5436         }
   5437 
   5438         needGlobalAttributesUpdate(false);
   5439 
   5440         removeFromArray(index);
   5441 
   5442         if (view.hasUnhandledKeyListener()) {
   5443             decrementChildUnhandledKeyListeners();
   5444         }
   5445 
   5446         if (view == mDefaultFocus) {
   5447             clearDefaultFocus(view);
   5448         }
   5449         if (clearChildFocus) {
   5450             clearChildFocus(view);
   5451             if (!rootViewRequestFocus()) {
   5452                 notifyGlobalFocusCleared(this);
   5453             }
   5454         }
   5455 
   5456         dispatchViewRemoved(view);
   5457 
   5458         if (view.getVisibility() != View.GONE) {
   5459             notifySubtreeAccessibilityStateChangedIfNeeded();
   5460         }
   5461 
   5462         int transientCount = mTransientIndices == null ? 0 : mTransientIndices.size();
   5463         for (int i = 0; i < transientCount; ++i) {
   5464             final int oldIndex = mTransientIndices.get(i);
   5465             if (index < oldIndex) {
   5466                 mTransientIndices.set(i, oldIndex - 1);
   5467             }
   5468         }
   5469 
   5470         if (mCurrentDragStartEvent != null) {
   5471             mChildrenInterestedInDrag.remove(view);
   5472         }
   5473     }
   5474 
   5475     /**
   5476      * Sets the LayoutTransition object for this ViewGroup. If the LayoutTransition object is
   5477      * not null, changes in layout which occur because of children being added to or removed from
   5478      * the ViewGroup will be animated according to the animations defined in that LayoutTransition
   5479      * object. By default, the transition object is null (so layout changes are not animated).
   5480      *
   5481      * <p>Replacing a non-null transition will cause that previous transition to be
   5482      * canceled, if it is currently running, to restore this container to
   5483      * its correct post-transition state.</p>
   5484      *
   5485      * @param transition The LayoutTransition object that will animated changes in layout. A value
   5486      * of <code>null</code> means no transition will run on layout changes.
   5487      * @attr ref android.R.styleable#ViewGroup_animateLayoutChanges
   5488      */
   5489     public void setLayoutTransition(LayoutTransition transition) {
   5490         if (mTransition != null) {
   5491             LayoutTransition previousTransition = mTransition;
   5492             previousTransition.cancel();
   5493             previousTransition.removeTransitionListener(mLayoutTransitionListener);
   5494         }
   5495         mTransition = transition;
   5496         if (mTransition != null) {
   5497             mTransition.addTransitionListener(mLayoutTransitionListener);
   5498         }
   5499     }
   5500 
   5501     /**
   5502      * Gets the LayoutTransition object for this ViewGroup. If the LayoutTransition object is
   5503      * not null, changes in layout which occur because of children being added to or removed from
   5504      * the ViewGroup will be animated according to the animations defined in that LayoutTransition
   5505      * object. By default, the transition object is null (so layout changes are not animated).
   5506      *
   5507      * @return LayoutTranstion The LayoutTransition object that will animated changes in layout.
   5508      * A value of <code>null</code> means no transition will run on layout changes.
   5509      */
   5510     public LayoutTransition getLayoutTransition() {
   5511         return mTransition;
   5512     }
   5513 
   5514     private void removeViewsInternal(int start, int count) {
   5515         final int end = start + count;
   5516 
   5517         if (start < 0 || count < 0 || end > mChildrenCount) {
   5518             throw new IndexOutOfBoundsException();
   5519         }
   5520 
   5521         final View focused = mFocused;
   5522         final boolean detach = mAttachInfo != null;
   5523         boolean clearChildFocus = false;
   5524         View clearDefaultFocus = null;
   5525 
   5526         final View[] children = mChildren;
   5527 
   5528         for (int i = start; i < end; i++) {
   5529             final View view = children[i];
   5530 
   5531             if (mTransition != null) {
   5532                 mTransition.removeChild(this, view);
   5533             }
   5534 
   5535             if (view == focused) {
   5536                 view.unFocus(null);
   5537                 clearChildFocus = true;
   5538             }
   5539             if (view == mDefaultFocus) {
   5540                 clearDefaultFocus = view;
   5541             }
   5542             if (view == mFocusedInCluster) {
   5543                 clearFocusedInCluster(view);
   5544             }
   5545 
   5546             view.clearAccessibilityFocus();
   5547 
   5548             cancelTouchTarget(view);
   5549             cancelHoverTarget(view);
   5550 
   5551             if (view.getAnimation() != null ||
   5552                 (mTransitioningViews != null && mTransitioningViews.contains(view))) {
   5553                 addDisappearingView(view);
   5554             } else if (detach) {
   5555                view.dispatchDetachedFromWindow();
   5556             }
   5557 
   5558             if (view.hasTransientState()) {
   5559                 childHasTransientStateChanged(view, false);
   5560             }
   5561 
   5562             needGlobalAttributesUpdate(false);
   5563 
   5564             dispatchViewRemoved(view);
   5565         }
   5566 
   5567         removeFromArray(start, count);
   5568 
   5569         if (clearDefaultFocus != null) {
   5570             clearDefaultFocus(clearDefaultFocus);
   5571         }
   5572         if (clearChildFocus) {
   5573             clearChildFocus(focused);
   5574             if (!rootViewRequestFocus()) {
   5575                 notifyGlobalFocusCleared(focused);
   5576             }
   5577         }
   5578     }
   5579 
   5580     /**
   5581      * Call this method to remove all child views from the
   5582      * ViewGroup.
   5583      *
   5584      * <p><strong>Note:</strong> do not invoke this method from
   5585      * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
   5586      * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
   5587      */
   5588     public void removeAllViews() {
   5589         removeAllViewsInLayout();
   5590         requestLayout();
   5591         invalidate(true);
   5592     }
   5593 
   5594     /**
   5595      * Called by a ViewGroup subclass to remove child views from itself,
   5596      * when it must first know its size on screen before it can calculate how many
   5597      * child views it will render. An example is a Gallery or a ListView, which
   5598      * may "have" 50 children, but actually only render the number of children
   5599      * that can currently fit inside the object on screen. Do not call
   5600      * this method unless you are extending ViewGroup and understand the
   5601      * view measuring and layout pipeline.
   5602      *
   5603      * <p><strong>Note:</strong> do not invoke this method from
   5604      * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
   5605      * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
   5606      */
   5607     public void removeAllViewsInLayout() {
   5608         final int count = mChildrenCount;
   5609         if (count <= 0) {
   5610             return;
   5611         }
   5612 
   5613         final View[] children = mChildren;
   5614         mChildrenCount = 0;
   5615 
   5616         final View focused = mFocused;
   5617         final boolean detach = mAttachInfo != null;
   5618         boolean clearChildFocus = false;
   5619 
   5620         needGlobalAttributesUpdate(false);
   5621 
   5622         for (int i = count - 1; i >= 0; i--) {
   5623             final View view = children[i];
   5624 
   5625             if (mTransition != null) {
   5626                 mTransition.removeChild(this, view);
   5627             }
   5628 
   5629             if (view == focused) {
   5630                 view.unFocus(null);
   5631                 clearChildFocus = true;
   5632             }
   5633 
   5634             view.clearAccessibilityFocus();
   5635 
   5636             cancelTouchTarget(view);
   5637             cancelHoverTarget(view);
   5638 
   5639             if (view.getAnimation() != null ||
   5640                     (mTransitioningViews != null && mTransitioningViews.contains(view))) {
   5641                 addDisappearingView(view);
   5642             } else if (detach) {
   5643                view.dispatchDetachedFromWindow();
   5644             }
   5645 
   5646             if (view.hasTransientState()) {
   5647                 childHasTransientStateChanged(view, false);
   5648             }
   5649 
   5650             dispatchViewRemoved(view);
   5651 
   5652             view.mParent = null;
   5653             children[i] = null;
   5654         }
   5655 
   5656         if (mDefaultFocus != null) {
   5657             clearDefaultFocus(mDefaultFocus);
   5658         }
   5659         if (mFocusedInCluster != null) {
   5660             clearFocusedInCluster(mFocusedInCluster);
   5661         }
   5662         if (clearChildFocus) {
   5663             clearChildFocus(focused);
   5664             if (!rootViewRequestFocus()) {
   5665                 notifyGlobalFocusCleared(focused);
   5666             }
   5667         }
   5668     }
   5669 
   5670     /**
   5671      * Finishes the removal of a detached view. This method will dispatch the detached from
   5672      * window event and notify the hierarchy change listener.
   5673      * <p>
   5674      * This method is intended to be lightweight and makes no assumptions about whether the
   5675      * parent or child should be redrawn. Proper use of this method will include also making
   5676      * any appropriate {@link #requestLayout()} or {@link #invalidate()} calls.
   5677      * For example, callers can {@link #post(Runnable) post} a {@link Runnable}
   5678      * which performs a {@link #requestLayout()} on the next frame, after all detach/remove
   5679      * calls are finished, causing layout to be run prior to redrawing the view hierarchy.
   5680      *
   5681      * @param child the child to be definitely removed from the view hierarchy
   5682      * @param animate if true and the view has an animation, the view is placed in the
   5683      *                disappearing views list, otherwise, it is detached from the window
   5684      *
   5685      * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
   5686      * @see #detachAllViewsFromParent()
   5687      * @see #detachViewFromParent(View)
   5688      * @see #detachViewFromParent(int)
   5689      */
   5690     protected void removeDetachedView(View child, boolean animate) {
   5691         if (mTransition != null) {
   5692             mTransition.removeChild(this, child);
   5693         }
   5694 
   5695         if (child == mFocused) {
   5696             child.clearFocus();
   5697         }
   5698         if (child == mDefaultFocus) {
   5699             clearDefaultFocus(child);
   5700         }
   5701         if (child == mFocusedInCluster) {
   5702             clearFocusedInCluster(child);
   5703         }
   5704 
   5705         child.clearAccessibilityFocus();
   5706 
   5707         cancelTouchTarget(child);
   5708         cancelHoverTarget(child);
   5709 
   5710         if ((animate && child.getAnimation() != null) ||
   5711                 (mTransitioningViews != null && mTransitioningViews.contains(child))) {
   5712             addDisappearingView(child);
   5713         } else if (child.mAttachInfo != null) {
   5714             child.dispatchDetachedFromWindow();
   5715         }
   5716 
   5717         if (child.hasTransientState()) {
   5718             childHasTransientStateChanged(child, false);
   5719         }
   5720 
   5721         dispatchViewRemoved(child);
   5722     }
   5723 
   5724     /**
   5725      * Attaches a view to this view group. Attaching a view assigns this group as the parent,
   5726      * sets the layout parameters and puts the view in the list of children so that
   5727      * it can be retrieved by calling {@link #getChildAt(int)}.
   5728      * <p>
   5729      * This method is intended to be lightweight and makes no assumptions about whether the
   5730      * parent or child should be redrawn. Proper use of this method will include also making
   5731      * any appropriate {@link #requestLayout()} or {@link #invalidate()} calls.
   5732      * For example, callers can {@link #post(Runnable) post} a {@link Runnable}
   5733      * which performs a {@link #requestLayout()} on the next frame, after all detach/attach
   5734      * calls are finished, causing layout to be run prior to redrawing the view hierarchy.
   5735      * <p>
   5736      * This method should be called only for views which were detached from their parent.
   5737      *
   5738      * @param child the child to attach
   5739      * @param index the index at which the child should be attached
   5740      * @param params the layout parameters of the child
   5741      *
   5742      * @see #removeDetachedView(View, boolean)
   5743      * @see #detachAllViewsFromParent()
   5744      * @see #detachViewFromParent(View)
   5745      * @see #detachViewFromParent(int)
   5746      */
   5747     protected void attachViewToParent(View child, int index, LayoutParams params) {
   5748         child.mLayoutParams = params;
   5749 
   5750         if (index < 0) {
   5751             index = mChildrenCount;
   5752         }
   5753 
   5754         addInArray(child, index);
   5755 
   5756         child.mParent = this;
   5757         child.mPrivateFlags = (child.mPrivateFlags & ~PFLAG_DIRTY_MASK
   5758                         & ~PFLAG_DRAWING_CACHE_VALID)
   5759                 | PFLAG_DRAWN | PFLAG_INVALIDATED;
   5760         this.mPrivateFlags |= PFLAG_INVALIDATED;
   5761 
   5762         if (child.hasFocus()) {
   5763             requestChildFocus(child, child.findFocus());
   5764         }
   5765         dispatchVisibilityAggregated(isAttachedToWindow() && getWindowVisibility() == VISIBLE
   5766                 && isShown());
   5767         notifySubtreeAccessibilityStateChangedIfNeeded();
   5768     }
   5769 
   5770     /**
   5771      * Detaches a view from its parent. Detaching a view should be followed
   5772      * either by a call to
   5773      * {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
   5774      * or a call to {@link #removeDetachedView(View, boolean)}. Detachment should only be
   5775      * temporary; reattachment or removal should happen within the same drawing cycle as
   5776      * detachment. When a view is detached, its parent is null and cannot be retrieved by a
   5777      * call to {@link #getChildAt(int)}.
   5778      *
   5779      * @param child the child to detach
   5780      *
   5781      * @see #detachViewFromParent(int)
   5782      * @see #detachViewsFromParent(int, int)
   5783      * @see #detachAllViewsFromParent()
   5784      * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
   5785      * @see #removeDetachedView(View, boolean)
   5786      */
   5787     protected void detachViewFromParent(View child) {
   5788         removeFromArray(indexOfChild(child));
   5789     }
   5790 
   5791     /**
   5792      * Detaches a view from its parent. Detaching a view should be followed
   5793      * either by a call to
   5794      * {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
   5795      * or a call to {@link #removeDetachedView(View, boolean)}. Detachment should only be
   5796      * temporary; reattachment or removal should happen within the same drawing cycle as
   5797      * detachment. When a view is detached, its parent is null and cannot be retrieved by a
   5798      * call to {@link #getChildAt(int)}.
   5799      *
   5800      * @param index the index of the child to detach
   5801      *
   5802      * @see #detachViewFromParent(View)
   5803      * @see #detachAllViewsFromParent()
   5804      * @see #detachViewsFromParent(int, int)
   5805      * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
   5806      * @see #removeDetachedView(View, boolean)
   5807      */
   5808     protected void detachViewFromParent(int index) {
   5809         removeFromArray(index);
   5810     }
   5811 
   5812     /**
   5813      * Detaches a range of views from their parents. Detaching a view should be followed
   5814      * either by a call to
   5815      * {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
   5816      * or a call to {@link #removeDetachedView(View, boolean)}. Detachment should only be
   5817      * temporary; reattachment or removal should happen within the same drawing cycle as
   5818      * detachment. When a view is detached, its parent is null and cannot be retrieved by a
   5819      * call to {@link #getChildAt(int)}.
   5820      *
   5821      * @param start the first index of the childrend range to detach
   5822      * @param count the number of children to detach
   5823      *
   5824      * @see #detachViewFromParent(View)
   5825      * @see #detachViewFromParent(int)
   5826      * @see #detachAllViewsFromParent()
   5827      * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
   5828      * @see #removeDetachedView(View, boolean)
   5829      */
   5830     protected void detachViewsFromParent(int start, int count) {
   5831         removeFromArray(start, count);
   5832     }
   5833 
   5834     /**
   5835      * Detaches all views from the parent. Detaching a view should be followed
   5836      * either by a call to
   5837      * {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
   5838      * or a call to {@link #removeDetachedView(View, boolean)}. Detachment should only be
   5839      * temporary; reattachment or removal should happen within the same drawing cycle as
   5840      * detachment. When a view is detached, its parent is null and cannot be retrieved by a
   5841      * call to {@link #getChildAt(int)}.
   5842      *
   5843      * @see #detachViewFromParent(View)
   5844      * @see #detachViewFromParent(int)
   5845      * @see #detachViewsFromParent(int, int)
   5846      * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
   5847      * @see #removeDetachedView(View, boolean)
   5848      */
   5849     protected void detachAllViewsFromParent() {
   5850         final int count = mChildrenCount;
   5851         if (count <= 0) {
   5852             return;
   5853         }
   5854 
   5855         final View[] children = mChildren;
   5856         mChildrenCount = 0;
   5857 
   5858         for (int i = count - 1; i >= 0; i--) {
   5859             children[i].mParent = null;
   5860             children[i] = null;
   5861         }
   5862     }
   5863 
   5864     @Override
   5865     @CallSuper
   5866     public void onDescendantInvalidated(@NonNull View child, @NonNull View target) {
   5867         /*
   5868          * HW-only, Rect-ignoring damage codepath
   5869          *
   5870          * We don't deal with rectangles here, since RenderThread native code computes damage for
   5871          * everything drawn by HWUI (and SW layer / drawing cache doesn't keep track of damage area)
   5872          */
   5873 
   5874         // if set, combine the animation flag into the parent
   5875         mPrivateFlags |= (target.mPrivateFlags & PFLAG_DRAW_ANIMATION);
   5876 
   5877         if ((target.mPrivateFlags & ~PFLAG_DIRTY_MASK) != 0) {
   5878             // We lazily use PFLAG_DIRTY, since computing opaque isn't worth the potential
   5879             // optimization in provides in a DisplayList world.
   5880             mPrivateFlags = (mPrivateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DIRTY;
   5881 
   5882             // simplified invalidateChildInParent behavior: clear cache validity to be safe...
   5883             mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
   5884         }
   5885 
   5886         // ... and mark inval if in software layer that needs to repaint (hw handled in native)
   5887         if (mLayerType == LAYER_TYPE_SOFTWARE) {
   5888             // Layered parents should be invalidated. Escalate to a full invalidate (and note that
   5889             // we do this after consuming any relevant flags from the originating descendant)
   5890             mPrivateFlags |= PFLAG_INVALIDATED | PFLAG_DIRTY;
   5891             target = this;
   5892         }
   5893 
   5894         if (mParent != null) {
   5895             mParent.onDescendantInvalidated(this, target);
   5896         }
   5897     }
   5898 
   5899 
   5900     /**
   5901      * Don't call or override this method. It is used for the implementation of
   5902      * the view hierarchy.
   5903      *
   5904      * @deprecated Use {@link #onDescendantInvalidated(View, View)} instead to observe updates to
   5905      * draw state in descendants.
   5906      */
   5907     @Deprecated
   5908     @Override
   5909     public final void invalidateChild(View child, final Rect dirty) {
   5910         final AttachInfo attachInfo = mAttachInfo;
   5911         if (attachInfo != null && attachInfo.mHardwareAccelerated) {
   5912             // HW accelerated fast path
   5913             onDescendantInvalidated(child, child);
   5914             return;
   5915         }
   5916 
   5917         ViewParent parent = this;
   5918         if (attachInfo != null) {
   5919             // If the child is drawing an animation, we want to copy this flag onto
   5920             // ourselves and the parent to make sure the invalidate request goes
   5921             // through
   5922             final boolean drawAnimation = (child.mPrivateFlags & PFLAG_DRAW_ANIMATION) != 0;
   5923 
   5924             // Check whether the child that requests the invalidate is fully opaque
   5925             // Views being animated or transformed are not considered opaque because we may
   5926             // be invalidating their old position and need the parent to paint behind them.
   5927             Matrix childMatrix = child.getMatrix();
   5928             // Mark the child as dirty, using the appropriate flag
   5929             // Make sure we do not set both flags at the same time
   5930 
   5931             if (child.mLayerType != LAYER_TYPE_NONE) {
   5932                 mPrivateFlags |= PFLAG_INVALIDATED;
   5933                 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
   5934             }
   5935 
   5936             final int[] location = attachInfo.mInvalidateChildLocation;
   5937             location[CHILD_LEFT_INDEX] = child.mLeft;
   5938             location[CHILD_TOP_INDEX] = child.mTop;
   5939             if (!childMatrix.isIdentity() ||
   5940                     (mGroupFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) {
   5941                 RectF boundingRect = attachInfo.mTmpTransformRect;
   5942                 boundingRect.set(dirty);
   5943                 Matrix transformMatrix;
   5944                 if ((mGroupFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) {
   5945                     Transformation t = attachInfo.mTmpTransformation;
   5946                     boolean transformed = getChildStaticTransformation(child, t);
   5947                     if (transformed) {
   5948                         transformMatrix = attachInfo.mTmpMatrix;
   5949                         transformMatrix.set(t.getMatrix());
   5950                         if (!childMatrix.isIdentity()) {
   5951                             transformMatrix.preConcat(childMatrix);
   5952                         }
   5953                     } else {
   5954                         transformMatrix = childMatrix;
   5955                     }
   5956                 } else {
   5957                     transformMatrix = childMatrix;
   5958                 }
   5959                 transformMatrix.mapRect(boundingRect);
   5960                 dirty.set((int) Math.floor(boundingRect.left),
   5961                         (int) Math.floor(boundingRect.top),
   5962                         (int) Math.ceil(boundingRect.right),
   5963                         (int) Math.ceil(boundingRect.bottom));
   5964             }
   5965 
   5966             do {
   5967                 View view = null;
   5968                 if (parent instanceof View) {
   5969                     view = (View) parent;
   5970                 }
   5971 
   5972                 if (drawAnimation) {
   5973                     if (view != null) {
   5974                         view.mPrivateFlags |= PFLAG_DRAW_ANIMATION;
   5975                     } else if (parent instanceof ViewRootImpl) {
   5976                         ((ViewRootImpl) parent).mIsAnimating = true;
   5977                     }
   5978                 }
   5979 
   5980                 // If the parent is dirty opaque or not dirty, mark it dirty with the opaque
   5981                 // flag coming from the child that initiated the invalidate
   5982                 if (view != null) {
   5983                     if ((view.mPrivateFlags & PFLAG_DIRTY_MASK) != PFLAG_DIRTY) {
   5984                         view.mPrivateFlags = (view.mPrivateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DIRTY;
   5985                     }
   5986                 }
   5987 
   5988                 parent = parent.invalidateChildInParent(location, dirty);
   5989                 if (view != null) {
   5990                     // Account for transform on current parent
   5991                     Matrix m = view.getMatrix();
   5992                     if (!m.isIdentity()) {
   5993                         RectF boundingRect = attachInfo.mTmpTransformRect;
   5994                         boundingRect.set(dirty);
   5995                         m.mapRect(boundingRect);
   5996                         dirty.set((int) Math.floor(boundingRect.left),
   5997                                 (int) Math.floor(boundingRect.top),
   5998                                 (int) Math.ceil(boundingRect.right),
   5999                                 (int) Math.ceil(boundingRect.bottom));
   6000                     }
   6001                 }
   6002             } while (parent != null);
   6003         }
   6004     }
   6005 
   6006     /**
   6007      * Don't call or override this method. It is used for the implementation of
   6008      * the view hierarchy.
   6009      *
   6010      * This implementation returns null if this ViewGroup does not have a parent,
   6011      * if this ViewGroup is already fully invalidated or if the dirty rectangle
   6012      * does not intersect with this ViewGroup's bounds.
   6013      *
   6014      * @deprecated Use {@link #onDescendantInvalidated(View, View)} instead to observe updates to
   6015      * draw state in descendants.
   6016      */
   6017     @Deprecated
   6018     @Override
   6019     public ViewParent invalidateChildInParent(final int[] location, final Rect dirty) {
   6020         if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID)) != 0) {
   6021             // either DRAWN, or DRAWING_CACHE_VALID
   6022             if ((mGroupFlags & (FLAG_OPTIMIZE_INVALIDATE | FLAG_ANIMATION_DONE))
   6023                     != FLAG_OPTIMIZE_INVALIDATE) {
   6024                 dirty.offset(location[CHILD_LEFT_INDEX] - mScrollX,
   6025                         location[CHILD_TOP_INDEX] - mScrollY);
   6026                 if ((mGroupFlags & FLAG_CLIP_CHILDREN) == 0) {
   6027                     dirty.union(0, 0, mRight - mLeft, mBottom - mTop);
   6028                 }
   6029 
   6030                 final int left = mLeft;
   6031                 final int top = mTop;
   6032 
   6033                 if ((mGroupFlags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN) {
   6034                     if (!dirty.intersect(0, 0, mRight - left, mBottom - top)) {
   6035                         dirty.setEmpty();
   6036                     }
   6037                 }
   6038 
   6039                 location[CHILD_LEFT_INDEX] = left;
   6040                 location[CHILD_TOP_INDEX] = top;
   6041             } else {
   6042 
   6043                 if ((mGroupFlags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN) {
   6044                     dirty.set(0, 0, mRight - mLeft, mBottom - mTop);
   6045                 } else {
   6046                     // in case the dirty rect extends outside the bounds of this container
   6047                     dirty.union(0, 0, mRight - mLeft, mBottom - mTop);
   6048                 }
   6049                 location[CHILD_LEFT_INDEX] = mLeft;
   6050                 location[CHILD_TOP_INDEX] = mTop;
   6051 
   6052                 mPrivateFlags &= ~PFLAG_DRAWN;
   6053             }
   6054             mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
   6055             if (mLayerType != LAYER_TYPE_NONE) {
   6056                 mPrivateFlags |= PFLAG_INVALIDATED;
   6057             }
   6058 
   6059             return mParent;
   6060         }
   6061 
   6062         return null;
   6063     }
   6064 
   6065     /**
   6066      * Offset a rectangle that is in a descendant's coordinate
   6067      * space into our coordinate space.
   6068      * @param descendant A descendant of this view
   6069      * @param rect A rectangle defined in descendant's coordinate space.
   6070      */
   6071     public final void offsetDescendantRectToMyCoords(View descendant, Rect rect) {
   6072         offsetRectBetweenParentAndChild(descendant, rect, true, false);
   6073     }
   6074 
   6075     /**
   6076      * Offset a rectangle that is in our coordinate space into an ancestor's
   6077      * coordinate space.
   6078      * @param descendant A descendant of this view
   6079      * @param rect A rectangle defined in descendant's coordinate space.
   6080      */
   6081     public final void offsetRectIntoDescendantCoords(View descendant, Rect rect) {
   6082         offsetRectBetweenParentAndChild(descendant, rect, false, false);
   6083     }
   6084 
   6085     /**
   6086      * Helper method that offsets a rect either from parent to descendant or
   6087      * descendant to parent.
   6088      */
   6089     void offsetRectBetweenParentAndChild(View descendant, Rect rect,
   6090             boolean offsetFromChildToParent, boolean clipToBounds) {
   6091 
   6092         // already in the same coord system :)
   6093         if (descendant == this) {
   6094             return;
   6095         }
   6096 
   6097         ViewParent theParent = descendant.mParent;
   6098 
   6099         // search and offset up to the parent
   6100         while ((theParent != null)
   6101                 && (theParent instanceof View)
   6102                 && (theParent != this)) {
   6103 
   6104             if (offsetFromChildToParent) {
   6105                 rect.offset(descendant.mLeft - descendant.mScrollX,
   6106                         descendant.mTop - descendant.mScrollY);
   6107                 if (clipToBounds) {
   6108                     View p = (View) theParent;
   6109                     boolean intersected = rect.intersect(0, 0, p.mRight - p.mLeft,
   6110                             p.mBottom - p.mTop);
   6111                     if (!intersected) {
   6112                         rect.setEmpty();
   6113                     }
   6114                 }
   6115             } else {
   6116                 if (clipToBounds) {
   6117                     View p = (View) theParent;
   6118                     boolean intersected = rect.intersect(0, 0, p.mRight - p.mLeft,
   6119                             p.mBottom - p.mTop);
   6120                     if (!intersected) {
   6121                         rect.setEmpty();
   6122                     }
   6123                 }
   6124                 rect.offset(descendant.mScrollX - descendant.mLeft,
   6125                         descendant.mScrollY - descendant.mTop);
   6126             }
   6127 
   6128             descendant = (View) theParent;
   6129             theParent = descendant.mParent;
   6130         }
   6131 
   6132         // now that we are up to this view, need to offset one more time
   6133         // to get into our coordinate space
   6134         if (theParent == this) {
   6135             if (offsetFromChildToParent) {
   6136                 rect.offset(descendant.mLeft - descendant.mScrollX,
   6137                         descendant.mTop - descendant.mScrollY);
   6138             } else {
   6139                 rect.offset(descendant.mScrollX - descendant.mLeft,
   6140                         descendant.mScrollY - descendant.mTop);
   6141             }
   6142         } else {
   6143             throw new IllegalArgumentException("parameter must be a descendant of this view");
   6144         }
   6145     }
   6146 
   6147     /**
   6148      * Offset the vertical location of all children of this view by the specified number of pixels.
   6149      *
   6150      * @param offset the number of pixels to offset
   6151      *
   6152      * @hide
   6153      */
   6154     @UnsupportedAppUsage
   6155     public void offsetChildrenTopAndBottom(int offset) {
   6156         final int count = mChildrenCount;
   6157         final View[] children = mChildren;
   6158         boolean invalidate = false;
   6159 
   6160         for (int i = 0; i < count; i++) {
   6161             final View v = children[i];
   6162             v.mTop += offset;
   6163             v.mBottom += offset;
   6164             if (v.mRenderNode != null) {
   6165                 invalidate = true;
   6166                 v.mRenderNode.offsetTopAndBottom(offset);
   6167             }
   6168         }
   6169 
   6170         if (invalidate) {
   6171             invalidateViewProperty(false, false);
   6172         }
   6173         notifySubtreeAccessibilityStateChangedIfNeeded();
   6174     }
   6175 
   6176     @Override
   6177     public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) {
   6178         return getChildVisibleRect(child, r, offset, false);
   6179     }
   6180 
   6181     /**
   6182      * @param forceParentCheck true to guarantee that this call will propagate to all ancestors,
   6183      *      false otherwise
   6184      *
   6185      * @hide
   6186      */
   6187     public boolean getChildVisibleRect(
   6188             View child, Rect r, android.graphics.Point offset, boolean forceParentCheck) {
   6189         // It doesn't make a whole lot of sense to call this on a view that isn't attached,
   6190         // but for some simple tests it can be useful. If we don't have attach info this
   6191         // will allocate memory.
   6192         final RectF rect = mAttachInfo != null ? mAttachInfo.mTmpTransformRect : new RectF();
   6193         rect.set(r);
   6194 
   6195         if (!child.hasIdentityMatrix()) {
   6196             child.getMatrix().mapRect(rect);
   6197         }
   6198 
   6199         final int dx = child.mLeft - mScrollX;
   6200         final int dy = child.mTop - mScrollY;
   6201 
   6202         rect.offset(dx, dy);
   6203 
   6204         if (offset != null) {
   6205             if (!child.hasIdentityMatrix()) {
   6206                 float[] position = mAttachInfo != null ? mAttachInfo.mTmpTransformLocation
   6207                         : new float[2];
   6208                 position[0] = offset.x;
   6209                 position[1] = offset.y;
   6210                 child.getMatrix().mapPoints(position);
   6211                 offset.x = Math.round(position[0]);
   6212                 offset.y = Math.round(position[1]);
   6213             }
   6214             offset.x += dx;
   6215             offset.y += dy;
   6216         }
   6217 
   6218         final int width = mRight - mLeft;
   6219         final int height = mBottom - mTop;
   6220 
   6221         boolean rectIsVisible = true;
   6222         if (mParent == null ||
   6223                 (mParent instanceof ViewGroup && ((ViewGroup) mParent).getClipChildren())) {
   6224             // Clip to bounds.
   6225             rectIsVisible = rect.intersect(0, 0, width, height);
   6226         }
   6227 
   6228         if ((forceParentCheck || rectIsVisible)
   6229                 && (mGroupFlags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK) {
   6230             // Clip to padding.
   6231             rectIsVisible = rect.intersect(mPaddingLeft, mPaddingTop,
   6232                     width - mPaddingRight, height - mPaddingBottom);
   6233         }
   6234 
   6235         if ((forceParentCheck || rectIsVisible) && mClipBounds != null) {
   6236             // Clip to clipBounds.
   6237             rectIsVisible = rect.intersect(mClipBounds.left, mClipBounds.top, mClipBounds.right,
   6238                     mClipBounds.bottom);
   6239         }
   6240         r.set((int) Math.floor(rect.left), (int) Math.floor(rect.top),
   6241                 (int) Math.ceil(rect.right), (int) Math.ceil(rect.bottom));
   6242 
   6243         if ((forceParentCheck || rectIsVisible) && mParent != null) {
   6244             if (mParent instanceof ViewGroup) {
   6245                 rectIsVisible = ((ViewGroup) mParent)
   6246                         .getChildVisibleRect(this, r, offset, forceParentCheck);
   6247             } else {
   6248                 rectIsVisible = mParent.getChildVisibleRect(this, r, offset);
   6249             }
   6250         }
   6251         return rectIsVisible;
   6252     }
   6253 
   6254     @Override
   6255     public final void layout(int l, int t, int r, int b) {
   6256         if (!mSuppressLayout && (mTransition == null || !mTransition.isChangingLayout())) {
   6257             if (mTransition != null) {
   6258                 mTransition.layoutChange(this);
   6259             }
   6260             super.layout(l, t, r, b);
   6261         } else {
   6262             // record the fact that we noop'd it; request layout when transition finishes
   6263             mLayoutCalledWhileSuppressed = true;
   6264         }
   6265     }
   6266 
   6267     @Override
   6268     protected abstract void onLayout(boolean changed,
   6269             int l, int t, int r, int b);
   6270 
   6271     /**
   6272      * Indicates whether the view group has the ability to animate its children
   6273      * after the first layout.
   6274      *
   6275      * @return true if the children can be animated, false otherwise
   6276      */
   6277     protected boolean canAnimate() {
   6278         return mLayoutAnimationController != null;
   6279     }
   6280 
   6281     /**
   6282      * Runs the layout animation. Calling this method triggers a relayout of
   6283      * this view group.
   6284      */
   6285     public void startLayoutAnimation() {
   6286         if (mLayoutAnimationController != null) {
   6287             mGroupFlags |= FLAG_RUN_ANIMATION;
   6288             requestLayout();
   6289         }
   6290     }
   6291 
   6292     /**
   6293      * Schedules the layout animation to be played after the next layout pass
   6294      * of this view group. This can be used to restart the layout animation
   6295      * when the content of the view group changes or when the activity is
   6296      * paused and resumed.
   6297      */
   6298     public void scheduleLayoutAnimation() {
   6299         mGroupFlags |= FLAG_RUN_ANIMATION;
   6300     }
   6301 
   6302     /**
   6303      * Sets the layout animation controller used to animate the group's
   6304      * children after the first layout.
   6305      *
   6306      * @param controller the animation controller
   6307      */
   6308     public void setLayoutAnimation(LayoutAnimationController controller) {
   6309         mLayoutAnimationController = controller;
   6310         if (mLayoutAnimationController != null) {
   6311             mGroupFlags |= FLAG_RUN_ANIMATION;
   6312         }
   6313     }
   6314 
   6315     /**
   6316      * Returns the layout animation controller used to animate the group's
   6317      * children.
   6318      *
   6319      * @return the current animation controller
   6320      */
   6321     @InspectableProperty
   6322     public LayoutAnimationController getLayoutAnimation() {
   6323         return mLayoutAnimationController;
   6324     }
   6325 
   6326     /**
   6327      * Indicates whether the children's drawing cache is used during a layout
   6328      * animation. By default, the drawing cache is enabled but this will prevent
   6329      * nested layout animations from working. To nest animations, you must disable
   6330      * the cache.
   6331      *
   6332      * @return true if the animation cache is enabled, false otherwise
   6333      *
   6334      * @see #setAnimationCacheEnabled(boolean)
   6335      * @see View#setDrawingCacheEnabled(boolean)
   6336      *
   6337      * @deprecated As of {@link android.os.Build.VERSION_CODES#M}, this property is ignored.
   6338      * Caching behavior of children may be controlled through {@link View#setLayerType(int, Paint)}.
   6339      */
   6340     @Deprecated
   6341     @InspectableProperty(name = "animationCache")
   6342     public boolean isAnimationCacheEnabled() {
   6343         return (mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE;
   6344     }
   6345 
   6346     /**
   6347      * Enables or disables the children's drawing cache during a layout animation.
   6348      * By default, the drawing cache is enabled but this will prevent nested
   6349      * layout animations from working. To nest animations, you must disable the
   6350      * cache.
   6351      *
   6352      * @param enabled true to enable the animation cache, false otherwise
   6353      *
   6354      * @see #isAnimationCacheEnabled()
   6355      * @see View#setDrawingCacheEnabled(boolean)
   6356      *
   6357      * @deprecated As of {@link android.os.Build.VERSION_CODES#M}, this property is ignored.
   6358      * Caching behavior of children may be controlled through {@link View#setLayerType(int, Paint)}.
   6359      */
   6360     @Deprecated
   6361     public void setAnimationCacheEnabled(boolean enabled) {
   6362         setBooleanFlag(FLAG_ANIMATION_CACHE, enabled);
   6363     }
   6364 
   6365     /**
   6366      * Indicates whether this ViewGroup will always try to draw its children using their
   6367      * drawing cache. By default this property is enabled.
   6368      *
   6369      * @return true if the animation cache is enabled, false otherwise
   6370      *
   6371      * @see #setAlwaysDrawnWithCacheEnabled(boolean)
   6372      * @see #setChildrenDrawnWithCacheEnabled(boolean)
   6373      * @see View#setDrawingCacheEnabled(boolean)
   6374      *
   6375      * @deprecated As of {@link android.os.Build.VERSION_CODES#M}, this property is ignored.
   6376      * Child views may no longer have their caching behavior disabled by parents.
   6377      */
   6378     @Deprecated
   6379     @InspectableProperty(name = "alwaysDrawnWithCache")
   6380     public boolean isAlwaysDrawnWithCacheEnabled() {
   6381         return (mGroupFlags & FLAG_ALWAYS_DRAWN_WITH_CACHE) == FLAG_ALWAYS_DRAWN_WITH_CACHE;
   6382     }
   6383 
   6384     /**
   6385      * Indicates whether this ViewGroup will always try to draw its children using their
   6386      * drawing cache. This property can be set to true when the cache rendering is
   6387      * slightly different from the children's normal rendering. Renderings can be different,
   6388      * for instance, when the cache's quality is set to low.
   6389      *
   6390      * When this property is disabled, the ViewGroup will use the drawing cache of its
   6391      * children only when asked to. It's usually the task of subclasses to tell ViewGroup
   6392      * when to start using the drawing cache and when to stop using it.
   6393      *
   6394      * @param always true to always draw with the drawing cache, false otherwise
   6395      *
   6396      * @see #isAlwaysDrawnWithCacheEnabled()
   6397      * @see #setChildrenDrawnWithCacheEnabled(boolean)
   6398      * @see View#setDrawingCacheEnabled(boolean)
   6399      * @see View#setDrawingCacheQuality(int)
   6400      *
   6401      * @deprecated As of {@link android.os.Build.VERSION_CODES#M}, this property is ignored.
   6402      * Child views may no longer have their caching behavior disabled by parents.
   6403      */
   6404     @Deprecated
   6405     public void setAlwaysDrawnWithCacheEnabled(boolean always) {
   6406         setBooleanFlag(FLAG_ALWAYS_DRAWN_WITH_CACHE, always);
   6407     }
   6408 
   6409     /**
   6410      * Indicates whether the ViewGroup is currently drawing its children using
   6411      * their drawing cache.
   6412      *
   6413      * @return true if children should be drawn with their cache, false otherwise
   6414      *
   6415      * @see #setAlwaysDrawnWithCacheEnabled(boolean)
   6416      * @see #setChildrenDrawnWithCacheEnabled(boolean)
   6417      *
   6418      * @deprecated As of {@link android.os.Build.VERSION_CODES#M}, this property is ignored.
   6419      * Child views may no longer be forced to cache their rendering state by their parents.
   6420      * Use {@link View#setLayerType(int, Paint)} on individual Views instead.
   6421      */
   6422     @Deprecated
   6423     protected boolean isChildrenDrawnWithCacheEnabled() {
   6424         return (mGroupFlags & FLAG_CHILDREN_DRAWN_WITH_CACHE) == FLAG_CHILDREN_DRAWN_WITH_CACHE;
   6425     }
   6426 
   6427     /**
   6428      * Tells the ViewGroup to draw its children using their drawing cache. This property
   6429      * is ignored when {@link #isAlwaysDrawnWithCacheEnabled()} is true. A child's drawing cache
   6430      * will be used only if it has been enabled.
   6431      *
   6432      * Subclasses should call this method to start and stop using the drawing cache when
   6433      * they perform performance sensitive operations, like scrolling or animating.
   6434      *
   6435      * @param enabled true if children should be drawn with their cache, false otherwise
   6436      *
   6437      * @see #setAlwaysDrawnWithCacheEnabled(boolean)
   6438      * @see #isChildrenDrawnWithCacheEnabled()
   6439      *
   6440      * @deprecated As of {@link android.os.Build.VERSION_CODES#M}, this property is ignored.
   6441      * Child views may no longer be forced to cache their rendering state by their parents.
   6442      * Use {@link View#setLayerType(int, Paint)} on individual Views instead.
   6443      */
   6444     @Deprecated
   6445     protected void setChildrenDrawnWithCacheEnabled(boolean enabled) {
   6446         setBooleanFlag(FLAG_CHILDREN_DRAWN_WITH_CACHE, enabled);
   6447     }
   6448 
   6449     /**
   6450      * Indicates whether the ViewGroup is drawing its children in the order defined by
   6451      * {@link #getChildDrawingOrder(int, int)}.
   6452      *
   6453      * @return true if children drawing order is defined by {@link #getChildDrawingOrder(int, int)},
   6454      *         false otherwise
   6455      *
   6456      * @see #setChildrenDrawingOrderEnabled(boolean)
   6457      * @see #getChildDrawingOrder(int, int)
   6458      */
   6459     @ViewDebug.ExportedProperty(category = "drawing")
   6460     protected boolean isChildrenDrawingOrderEnabled() {
   6461         return (mGroupFlags & FLAG_USE_CHILD_DRAWING_ORDER) == FLAG_USE_CHILD_DRAWING_ORDER;
   6462     }
   6463 
   6464     /**
   6465      * Tells the ViewGroup whether to draw its children in the order defined by the method
   6466      * {@link #getChildDrawingOrder(int, int)}.
   6467      * <p>
   6468      * Note that {@link View#getZ() Z} reordering, done by {@link #dispatchDraw(Canvas)},
   6469      * will override custom child ordering done via this method.
   6470      *
   6471      * @param enabled true if the order of the children when drawing is determined by
   6472      *        {@link #getChildDrawingOrder(int, int)}, false otherwise
   6473      *
   6474      * @see #isChildrenDrawingOrderEnabled()
   6475      * @see #getChildDrawingOrder(int, int)
   6476      */
   6477     protected void setChildrenDrawingOrderEnabled(boolean enabled) {
   6478         setBooleanFlag(FLAG_USE_CHILD_DRAWING_ORDER, enabled);
   6479     }
   6480 
   6481     private boolean hasBooleanFlag(int flag) {
   6482         return (mGroupFlags & flag) == flag;
   6483     }
   6484 
   6485     private void setBooleanFlag(int flag, boolean value) {
   6486         if (value) {
   6487             mGroupFlags |= flag;
   6488         } else {
   6489             mGroupFlags &= ~flag;
   6490         }
   6491     }
   6492 
   6493     /**
   6494      * Returns an integer indicating what types of drawing caches are kept in memory.
   6495      *
   6496      * @see #setPersistentDrawingCache(int)
   6497      * @see #setAnimationCacheEnabled(boolean)
   6498      *
   6499      * @return one or a combination of {@link #PERSISTENT_NO_CACHE},
   6500      *         {@link #PERSISTENT_ANIMATION_CACHE}, {@link #PERSISTENT_SCROLLING_CACHE}
   6501      *         and {@link #PERSISTENT_ALL_CACHES}
   6502      *
   6503      * @deprecated The view drawing cache was largely made obsolete with the introduction of
   6504      * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache
   6505      * layers are largely unnecessary and can easily result in a net loss in performance due to the
   6506      * cost of creating and updating the layer. In the rare cases where caching layers are useful,
   6507      * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware
   6508      * rendering. For software-rendered snapshots of a small part of the View hierarchy or
   6509      * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or
   6510      * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these
   6511      * software-rendered usages are discouraged and have compatibility issues with hardware-only
   6512      * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE}
   6513      * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback
   6514      * reports or unit testing the {@link PixelCopy} API is recommended.
   6515      */
   6516     @Deprecated
   6517     @ViewDebug.ExportedProperty(category = "drawing", mapping = {
   6518         @ViewDebug.IntToString(from = PERSISTENT_NO_CACHE,        to = "NONE"),
   6519         @ViewDebug.IntToString(from = PERSISTENT_ANIMATION_CACHE, to = "ANIMATION"),
   6520         @ViewDebug.IntToString(from = PERSISTENT_SCROLLING_CACHE, to = "SCROLLING"),
   6521         @ViewDebug.IntToString(from = PERSISTENT_ALL_CACHES,      to = "ALL")
   6522     })
   6523     @InspectableProperty(enumMapping = {
   6524             @EnumEntry(value = PERSISTENT_NO_CACHE, name = "none"),
   6525             @EnumEntry(value = PERSISTENT_ANIMATION_CACHE, name = "animation"),
   6526             @EnumEntry(value = PERSISTENT_SCROLLING_CACHE, name = "scrolling"),
   6527             @EnumEntry(value = PERSISTENT_ALL_CACHES, name = "all"),
   6528     })
   6529     public int getPersistentDrawingCache() {
   6530         return mPersistentDrawingCache;
   6531     }
   6532 
   6533     /**
   6534      * Indicates what types of drawing caches should be kept in memory after
   6535      * they have been created.
   6536      *
   6537      * @see #getPersistentDrawingCache()
   6538      * @see #setAnimationCacheEnabled(boolean)
   6539      *
   6540      * @param drawingCacheToKeep one or a combination of {@link #PERSISTENT_NO_CACHE},
   6541      *        {@link #PERSISTENT_ANIMATION_CACHE}, {@link #PERSISTENT_SCROLLING_CACHE}
   6542      *        and {@link #PERSISTENT_ALL_CACHES}
   6543      *
   6544      * @deprecated The view drawing cache was largely made obsolete with the introduction of
   6545      * hardware-accelerated rendering in API 11. With hardware-acceleration, intermediate cache
   6546      * layers are largely unnecessary and can easily result in a net loss in performance due to the
   6547      * cost of creating and updating the layer. In the rare cases where caching layers are useful,
   6548      * such as for alpha animations, {@link #setLayerType(int, Paint)} handles this with hardware
   6549      * rendering. For software-rendered snapshots of a small part of the View hierarchy or
   6550      * individual Views it is recommended to create a {@link Canvas} from either a {@link Bitmap} or
   6551      * {@link android.graphics.Picture} and call {@link #draw(Canvas)} on the View. However these
   6552      * software-rendered usages are discouraged and have compatibility issues with hardware-only
   6553      * rendering features such as {@link android.graphics.Bitmap.Config#HARDWARE Config.HARDWARE}
   6554      * bitmaps, real-time shadows, and outline clipping. For screenshots of the UI for feedback
   6555      * reports or unit testing the {@link PixelCopy} API is recommended.
   6556      */
   6557     @Deprecated
   6558     public void setPersistentDrawingCache(int drawingCacheToKeep) {
   6559         mPersistentDrawingCache = drawingCacheToKeep & PERSISTENT_ALL_CACHES;
   6560     }
   6561 
   6562     private void setLayoutMode(int layoutMode, boolean explicitly) {
   6563         mLayoutMode = layoutMode;
   6564         setBooleanFlag(FLAG_LAYOUT_MODE_WAS_EXPLICITLY_SET, explicitly);
   6565     }
   6566 
   6567     /**
   6568      * Recursively traverse the view hierarchy, resetting the layoutMode of any
   6569      * descendants that had inherited a different layoutMode from a previous parent.
   6570      * Recursion terminates when a descendant's mode is:
   6571      * <ul>
   6572      *     <li>Undefined</li>
   6573      *     <li>The same as the root node's</li>
   6574      *     <li>A mode that had been explicitly set</li>
   6575      * <ul/>
   6576      * The first two clauses are optimizations.
   6577      * @param layoutModeOfRoot
   6578      */
   6579     @Override
   6580     void invalidateInheritedLayoutMode(int layoutModeOfRoot) {
   6581         if (mLayoutMode == LAYOUT_MODE_UNDEFINED ||
   6582             mLayoutMode == layoutModeOfRoot ||
   6583             hasBooleanFlag(FLAG_LAYOUT_MODE_WAS_EXPLICITLY_SET)) {
   6584             return;
   6585         }
   6586         setLayoutMode(LAYOUT_MODE_UNDEFINED, false);
   6587 
   6588         // apply recursively
   6589         for (int i = 0, N = getChildCount(); i < N; i++) {
   6590             getChildAt(i).invalidateInheritedLayoutMode(layoutModeOfRoot);
   6591         }
   6592     }
   6593 
   6594     /**
   6595      * Returns the basis of alignment during layout operations on this ViewGroup:
   6596      * either {@link #LAYOUT_MODE_CLIP_BOUNDS} or {@link #LAYOUT_MODE_OPTICAL_BOUNDS}.
   6597      * <p>
   6598      * If no layoutMode was explicitly set, either programmatically or in an XML resource,
   6599      * the method returns the layoutMode of the view's parent ViewGroup if such a parent exists,
   6600      * otherwise the method returns a default value of {@link #LAYOUT_MODE_CLIP_BOUNDS}.
   6601      *
   6602      * @return the layout mode to use during layout operations
   6603      *
   6604      * @see #setLayoutMode(int)
   6605      */
   6606     @InspectableProperty(enumMapping = {
   6607             @EnumEntry(value = LAYOUT_MODE_CLIP_BOUNDS, name = "clipBounds"),
   6608             @EnumEntry(value = LAYOUT_MODE_OPTICAL_BOUNDS, name = "opticalBounds")
   6609     })
   6610     public int getLayoutMode() {
   6611         if (mLayoutMode == LAYOUT_MODE_UNDEFINED) {
   6612             int inheritedLayoutMode = (mParent instanceof ViewGroup) ?
   6613                     ((ViewGroup) mParent).getLayoutMode() : LAYOUT_MODE_DEFAULT;
   6614             setLayoutMode(inheritedLayoutMode, false);
   6615         }
   6616         return mLayoutMode;
   6617     }
   6618 
   6619     /**
   6620      * Sets the basis of alignment during the layout of this ViewGroup.
   6621      * Valid values are either {@link #LAYOUT_MODE_CLIP_BOUNDS} or
   6622      * {@link #LAYOUT_MODE_OPTICAL_BOUNDS}.
   6623      *
   6624      * @param layoutMode the layout mode to use during layout operations
   6625      *
   6626      * @see #getLayoutMode()
   6627      * @attr ref android.R.styleable#ViewGroup_layoutMode
   6628      */
   6629     public void setLayoutMode(int layoutMode) {
   6630         if (mLayoutMode != layoutMode) {
   6631             invalidateInheritedLayoutMode(layoutMode);
   6632             setLayoutMode(layoutMode, layoutMode != LAYOUT_MODE_UNDEFINED);
   6633             requestLayout();
   6634         }
   6635     }
   6636 
   6637     /**
   6638      * Returns a new set of layout parameters based on the supplied attributes set.
   6639      *
   6640      * @param attrs the attributes to build the layout parameters from
   6641      *
   6642      * @return an instance of {@link android.view.ViewGroup.LayoutParams} or one
   6643      *         of its descendants
   6644      */
   6645     public LayoutParams generateLayoutParams(AttributeSet attrs) {
   6646         return new LayoutParams(getContext(), attrs);
   6647     }
   6648 
   6649     /**
   6650      * Returns a safe set of layout parameters based on the supplied layout params.
   6651      * When a ViewGroup is passed a View whose layout params do not pass the test of
   6652      * {@link #checkLayoutParams(android.view.ViewGroup.LayoutParams)}, this method
   6653      * is invoked. This method should return a new set of layout params suitable for
   6654      * this ViewGroup, possibly by copying the appropriate attributes from the
   6655      * specified set of layout params.
   6656      *
   6657      * @param p The layout parameters to convert into a suitable set of layout parameters
   6658      *          for this ViewGroup.
   6659      *
   6660      * @return an instance of {@link android.view.ViewGroup.LayoutParams} or one
   6661      *         of its descendants
   6662      */
   6663     protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
   6664         return p;
   6665     }
   6666 
   6667     /**
   6668      * Returns a set of default layout parameters. These parameters are requested
   6669      * when the View passed to {@link #addView(View)} has no layout parameters
   6670      * already set. If null is returned, an exception is thrown from addView.
   6671      *
   6672      * @return a set of default layout parameters or null
   6673      */
   6674     protected LayoutParams generateDefaultLayoutParams() {
   6675         return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
   6676     }
   6677 
   6678     @Override
   6679     protected void debug(int depth) {
   6680         super.debug(depth);
   6681         String output;
   6682 
   6683         if (mFocused != null) {
   6684             output = debugIndent(depth);
   6685             output += "mFocused";
   6686             Log.d(VIEW_LOG_TAG, output);
   6687             mFocused.debug(depth + 1);
   6688         }
   6689         if (mDefaultFocus != null) {
   6690             output = debugIndent(depth);
   6691             output += "mDefaultFocus";
   6692             Log.d(VIEW_LOG_TAG, output);
   6693             mDefaultFocus.debug(depth + 1);
   6694         }
   6695         if (mFocusedInCluster != null) {
   6696             output = debugIndent(depth);
   6697             output += "mFocusedInCluster";
   6698             Log.d(VIEW_LOG_TAG, output);
   6699             mFocusedInCluster.debug(depth + 1);
   6700         }
   6701         if (mChildrenCount != 0) {
   6702             output = debugIndent(depth);
   6703             output += "{";
   6704             Log.d(VIEW_LOG_TAG, output);
   6705         }
   6706         int count = mChildrenCount;
   6707         for (int i = 0; i < count; i++) {
   6708             View child = mChildren[i];
   6709             child.debug(depth + 1);
   6710         }
   6711 
   6712         if (mChildrenCount != 0) {
   6713             output = debugIndent(depth);
   6714             output += "}";
   6715             Log.d(VIEW_LOG_TAG, output);
   6716         }
   6717     }
   6718 
   6719     /**
   6720      * Returns the position in the group of the specified child view.
   6721      *
   6722      * @param child the view for which to get the position
   6723      * @return a positive integer representing the position of the view in the
   6724      *         group, or -1 if the view does not exist in the group
   6725      */
   6726     public int indexOfChild(View child) {
   6727         final int count = mChildrenCount;
   6728         final View[] children = mChildren;
   6729         for (int i = 0; i < count; i++) {
   6730             if (children[i] == child) {
   6731                 return i;
   6732             }
   6733         }
   6734         return -1;
   6735     }
   6736 
   6737     /**
   6738      * Returns the number of children in the group.
   6739      *
   6740      * @return a positive integer representing the number of children in
   6741      *         the group
   6742      */
   6743     public int getChildCount() {
   6744         return mChildrenCount;
   6745     }
   6746 
   6747     /**
   6748      * Returns the view at the specified position in the group.
   6749      *
   6750      * @param index the position at which to get the view from
   6751      * @return the view at the specified position or null if the position
   6752      *         does not exist within the group
   6753      */
   6754     public View getChildAt(int index) {
   6755         if (index < 0 || index >= mChildrenCount) {
   6756             return null;
   6757         }
   6758         return mChildren[index];
   6759     }
   6760 
   6761     /**
   6762      * Ask all of the children of this view to measure themselves, taking into
   6763      * account both the MeasureSpec requirements for this view and its padding.
   6764      * We skip children that are in the GONE state The heavy lifting is done in
   6765      * getChildMeasureSpec.
   6766      *
   6767      * @param widthMeasureSpec The width requirements for this view
   6768      * @param heightMeasureSpec The height requirements for this view
   6769      */
   6770     protected void measureChildren(int widthMeasureSpec, int heightMeasureSpec) {
   6771         final int size = mChildrenCount;
   6772         final View[] children = mChildren;
   6773         for (int i = 0; i < size; ++i) {
   6774             final View child = children[i];
   6775             if ((child.mViewFlags & VISIBILITY_MASK) != GONE) {
   6776                 measureChild(child, widthMeasureSpec, heightMeasureSpec);
   6777             }
   6778         }
   6779     }
   6780 
   6781     /**
   6782      * Ask one of the children of this view to measure itself, taking into
   6783      * account both the MeasureSpec requirements for this view and its padding.
   6784      * The heavy lifting is done in getChildMeasureSpec.
   6785      *
   6786      * @param child The child to measure
   6787      * @param parentWidthMeasureSpec The width requirements for this view
   6788      * @param parentHeightMeasureSpec The height requirements for this view
   6789      */
   6790     protected void measureChild(View child, int parentWidthMeasureSpec,
   6791             int parentHeightMeasureSpec) {
   6792         final LayoutParams lp = child.getLayoutParams();
   6793 
   6794         final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
   6795                 mPaddingLeft + mPaddingRight, lp.width);
   6796         final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
   6797                 mPaddingTop + mPaddingBottom, lp.height);
   6798 
   6799         child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
   6800     }
   6801 
   6802     /**
   6803      * Ask one of the children of this view to measure itself, taking into
   6804      * account both the MeasureSpec requirements for this view and its padding
   6805      * and margins. The child must have MarginLayoutParams The heavy lifting is
   6806      * done in getChildMeasureSpec.
   6807      *
   6808      * @param child The child to measure
   6809      * @param parentWidthMeasureSpec The width requirements for this view
   6810      * @param widthUsed Extra space that has been used up by the parent
   6811      *        horizontally (possibly by other children of the parent)
   6812      * @param parentHeightMeasureSpec The height requirements for this view
   6813      * @param heightUsed Extra space that has been used up by the parent
   6814      *        vertically (possibly by other children of the parent)
   6815      */
   6816     protected void measureChildWithMargins(View child,
   6817             int parentWidthMeasureSpec, int widthUsed,
   6818             int parentHeightMeasureSpec, int heightUsed) {
   6819         final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
   6820 
   6821         final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
   6822                 mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin
   6823                         + widthUsed, lp.width);
   6824         final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
   6825                 mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin
   6826                         + heightUsed, lp.height);
   6827 
   6828         child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
   6829     }
   6830 
   6831     /**
   6832      * Does the hard part of measureChildren: figuring out the MeasureSpec to
   6833      * pass to a particular child. This method figures out the right MeasureSpec
   6834      * for one dimension (height or width) of one child view.
   6835      *
   6836      * The goal is to combine information from our MeasureSpec with the
   6837      * LayoutParams of the child to get the best possible results. For example,
   6838      * if the this view knows its size (because its MeasureSpec has a mode of
   6839      * EXACTLY), and the child has indicated in its LayoutParams that it wants
   6840      * to be the same size as the parent, the parent should ask the child to
   6841      * layout given an exact size.
   6842      *
   6843      * @param spec The requirements for this view
   6844      * @param padding The padding of this view for the current dimension and
   6845      *        margins, if applicable
   6846      * @param childDimension How big the child wants to be in the current
   6847      *        dimension
   6848      * @return a MeasureSpec integer for the child
   6849      */
   6850     public static int getChildMeasureSpec(int spec, int padding, int childDimension) {
   6851         int specMode = MeasureSpec.getMode(spec);
   6852         int specSize = MeasureSpec.getSize(spec);
   6853 
   6854         int size = Math.max(0, specSize - padding);
   6855 
   6856         int resultSize = 0;
   6857         int resultMode = 0;
   6858 
   6859         switch (specMode) {
   6860         // Parent has imposed an exact size on us
   6861         case MeasureSpec.EXACTLY:
   6862             if (childDimension >= 0) {
   6863                 resultSize = childDimension;
   6864                 resultMode = MeasureSpec.EXACTLY;
   6865             } else if (childDimension == LayoutParams.MATCH_PARENT) {
   6866                 // Child wants to be our size. So be it.
   6867                 resultSize = size;
   6868                 resultMode = MeasureSpec.EXACTLY;
   6869             } else if (childDimension == LayoutParams.WRAP_CONTENT) {
   6870                 // Child wants to determine its own size. It can't be
   6871                 // bigger than us.
   6872                 resultSize = size;
   6873                 resultMode = MeasureSpec.AT_MOST;
   6874             }
   6875             break;
   6876 
   6877         // Parent has imposed a maximum size on us
   6878         case MeasureSpec.AT_MOST:
   6879             if (childDimension >= 0) {
   6880                 // Child wants a specific size... so be it
   6881                 resultSize = childDimension;
   6882                 resultMode = MeasureSpec.EXACTLY;
   6883             } else if (childDimension == LayoutParams.MATCH_PARENT) {
   6884                 // Child wants to be our size, but our size is not fixed.
   6885                 // Constrain child to not be bigger than us.
   6886                 resultSize = size;
   6887                 resultMode = MeasureSpec.AT_MOST;
   6888             } else if (childDimension == LayoutParams.WRAP_CONTENT) {
   6889                 // Child wants to determine its own size. It can't be
   6890                 // bigger than us.
   6891                 resultSize = size;
   6892                 resultMode = MeasureSpec.AT_MOST;
   6893             }
   6894             break;
   6895 
   6896         // Parent asked to see how big we want to be
   6897         case MeasureSpec.UNSPECIFIED:
   6898             if (childDimension >= 0) {
   6899                 // Child wants a specific size... let him have it
   6900                 resultSize = childDimension;
   6901                 resultMode = MeasureSpec.EXACTLY;
   6902             } else if (childDimension == LayoutParams.MATCH_PARENT) {
   6903                 // Child wants to be our size... find out how big it should
   6904                 // be
   6905                 resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size;
   6906                 resultMode = MeasureSpec.UNSPECIFIED;
   6907             } else if (childDimension == LayoutParams.WRAP_CONTENT) {
   6908                 // Child wants to determine its own size.... find out how
   6909                 // big it should be
   6910                 resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size;
   6911                 resultMode = MeasureSpec.UNSPECIFIED;
   6912             }
   6913             break;
   6914         }
   6915         //noinspection ResourceType
   6916         return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
   6917     }
   6918 
   6919 
   6920     /**
   6921      * Removes any pending animations for views that have been removed. Call
   6922      * this if you don't want animations for exiting views to stack up.
   6923      */
   6924     public void clearDisappearingChildren() {
   6925         final ArrayList<View> disappearingChildren = mDisappearingChildren;
   6926         if (disappearingChildren != null) {
   6927             final int count = disappearingChildren.size();
   6928             for (int i = 0; i < count; i++) {
   6929                 final View view = disappearingChildren.get(i);
   6930                 if (view.mAttachInfo != null) {
   6931                     view.dispatchDetachedFromWindow();
   6932                 }
   6933                 view.clearAnimation();
   6934             }
   6935             disappearingChildren.clear();
   6936             invalidate();
   6937         }
   6938     }
   6939 
   6940     /**
   6941      * Add a view which is removed from mChildren but still needs animation
   6942      *
   6943      * @param v View to add
   6944      */
   6945     private void addDisappearingView(View v) {
   6946         ArrayList<View> disappearingChildren = mDisappearingChildren;
   6947 
   6948         if (disappearingChildren == null) {
   6949             disappearingChildren = mDisappearingChildren = new ArrayList<View>();
   6950         }
   6951 
   6952         disappearingChildren.add(v);
   6953     }
   6954 
   6955     /**
   6956      * Cleanup a view when its animation is done. This may mean removing it from
   6957      * the list of disappearing views.
   6958      *
   6959      * @param view The view whose animation has finished
   6960      * @param animation The animation, cannot be null
   6961      */
   6962     void finishAnimatingView(final View view, Animation animation) {
   6963         final ArrayList<View> disappearingChildren = mDisappearingChildren;
   6964         if (disappearingChildren != null) {
   6965             if (disappearingChildren.contains(view)) {
   6966                 disappearingChildren.remove(view);
   6967 
   6968                 if (view.mAttachInfo != null) {
   6969                     view.dispatchDetachedFromWindow();
   6970                 }
   6971 
   6972                 view.clearAnimation();
   6973                 mGroupFlags |= FLAG_INVALIDATE_REQUIRED;
   6974             }
   6975         }
   6976 
   6977         if (animation != null && !animation.getFillAfter()) {
   6978             view.clearAnimation();
   6979         }
   6980 
   6981         if ((view.mPrivateFlags & PFLAG_ANIMATION_STARTED) == PFLAG_ANIMATION_STARTED) {
   6982             view.onAnimationEnd();
   6983             // Should be performed by onAnimationEnd() but this avoid an infinite loop,
   6984             // so we'd rather be safe than sorry
   6985             view.mPrivateFlags &= ~PFLAG_ANIMATION_STARTED;
   6986             // Draw one more frame after the animation is done
   6987             mGroupFlags |= FLAG_INVALIDATE_REQUIRED;
   6988         }
   6989     }
   6990 
   6991     /**
   6992      * Utility function called by View during invalidation to determine whether a view that
   6993      * is invisible or gone should still be invalidated because it is being transitioned (and
   6994      * therefore still needs to be drawn).
   6995      */
   6996     boolean isViewTransitioning(View view) {
   6997         return (mTransitioningViews != null && mTransitioningViews.contains(view));
   6998     }
   6999 
   7000     /**
   7001      * This method tells the ViewGroup that the given View object, which should have this
   7002      * ViewGroup as its parent,
   7003      * should be kept around  (re-displayed when the ViewGroup draws its children) even if it
   7004      * is removed from its parent. This allows animations, such as those used by
   7005      * {@link android.app.Fragment} and {@link android.animation.LayoutTransition} to animate
   7006      * the removal of views. A call to this method should always be accompanied by a later call
   7007      * to {@link #endViewTransition(View)}, such as after an animation on the View has finished,
   7008      * so that the View finally gets removed.
   7009      *
   7010      * @param view The View object to be kept visible even if it gets removed from its parent.
   7011      */
   7012     public void startViewTransition(View view) {
   7013         if (view.mParent == this) {
   7014             if (mTransitioningViews == null) {
   7015                 mTransitioningViews = new ArrayList<View>();
   7016             }
   7017             mTransitioningViews.add(view);
   7018         }
   7019     }
   7020 
   7021     /**
   7022      * This method should always be called following an earlier call to
   7023      * {@link #startViewTransition(View)}. The given View is finally removed from its parent
   7024      * and will no longer be displayed. Note that this method does not perform the functionality
   7025      * of removing a view from its parent; it just discontinues the display of a View that
   7026      * has previously been removed.
   7027      *
   7028      * @return view The View object that has been removed but is being kept around in the visible
   7029      * hierarchy by an earlier call to {@link #startViewTransition(View)}.
   7030      */
   7031     public void endViewTransition(View view) {
   7032         if (mTransitioningViews != null) {
   7033             mTransitioningViews.remove(view);
   7034             final ArrayList<View> disappearingChildren = mDisappearingChildren;
   7035             if (disappearingChildren != null && disappearingChildren.contains(view)) {
   7036                 disappearingChildren.remove(view);
   7037                 if (mVisibilityChangingChildren != null &&
   7038                         mVisibilityChangingChildren.contains(view)) {
   7039                     mVisibilityChangingChildren.remove(view);
   7040                 } else {
   7041                     if (view.mAttachInfo != null) {
   7042                         view.dispatchDetachedFromWindow();
   7043                     }
   7044                     if (view.mParent != null) {
   7045                         view.mParent = null;
   7046                     }
   7047                 }
   7048                 invalidate();
   7049             }
   7050         }
   7051     }
   7052 
   7053     private LayoutTransition.TransitionListener mLayoutTransitionListener =
   7054             new LayoutTransition.TransitionListener() {
   7055         @Override
   7056         public void startTransition(LayoutTransition transition, ViewGroup container,
   7057                 View view, int transitionType) {
   7058             // We only care about disappearing items, since we need special logic to keep
   7059             // those items visible after they've been 'removed'
   7060             if (transitionType == LayoutTransition.DISAPPEARING) {
   7061                 startViewTransition(view);
   7062             }
   7063         }
   7064 
   7065         @Override
   7066         public void endTransition(LayoutTransition transition, ViewGroup container,
   7067                 View view, int transitionType) {
   7068             if (mLayoutCalledWhileSuppressed && !transition.isChangingLayout()) {
   7069                 requestLayout();
   7070                 mLayoutCalledWhileSuppressed = false;
   7071             }
   7072             if (transitionType == LayoutTransition.DISAPPEARING && mTransitioningViews != null) {
   7073                 endViewTransition(view);
   7074             }
   7075         }
   7076     };
   7077 
   7078     /**
   7079      * Tells this ViewGroup to suppress all layout() calls until layout
   7080      * suppression is disabled with a later call to suppressLayout(false).
   7081      * When layout suppression is disabled, a requestLayout() call is sent
   7082      * if layout() was attempted while layout was being suppressed.
   7083      */
   7084     public void suppressLayout(boolean suppress) {
   7085         mSuppressLayout = suppress;
   7086         if (!suppress) {
   7087             if (mLayoutCalledWhileSuppressed) {
   7088                 requestLayout();
   7089                 mLayoutCalledWhileSuppressed = false;
   7090             }
   7091         }
   7092     }
   7093 
   7094     /**
   7095      * Returns whether layout calls on this container are currently being
   7096      * suppressed, due to an earlier call to {@link #suppressLayout(boolean)}.
   7097      *
   7098      * @return true if layout calls are currently suppressed, false otherwise.
   7099      */
   7100     public boolean isLayoutSuppressed() {
   7101         return mSuppressLayout;
   7102     }
   7103 
   7104     @Override
   7105     public boolean gatherTransparentRegion(Region region) {
   7106         // If no transparent regions requested, we are always opaque.
   7107         final boolean meOpaque = (mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) == 0;
   7108         if (meOpaque && region == null) {
   7109             // The caller doesn't care about the region, so stop now.
   7110             return true;
   7111         }
   7112         super.gatherTransparentRegion(region);
   7113         // Instead of naively traversing the view tree, we have to traverse according to the Z
   7114         // order here. We need to go with the same order as dispatchDraw().
   7115         // One example is that after surfaceView punch a hole, we will still allow other views drawn
   7116         // on top of that hole. In this case, those other views should be able to cut the
   7117         // transparent region into smaller area.
   7118         final int childrenCount = mChildrenCount;
   7119         boolean noneOfTheChildrenAreTransparent = true;
   7120         if (childrenCount > 0) {
   7121             final ArrayList<View> preorderedList = buildOrderedChildList();
   7122             final boolean customOrder = preorderedList == null
   7123                     && isChildrenDrawingOrderEnabled();
   7124             final View[] children = mChildren;
   7125             for (int i = 0; i < childrenCount; i++) {
   7126                 final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
   7127                 final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex);
   7128                 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
   7129                     if (!child.gatherTransparentRegion(region)) {
   7130                         noneOfTheChildrenAreTransparent = false;
   7131                     }
   7132                 }
   7133             }
   7134             if (preorderedList != null) preorderedList.clear();
   7135         }
   7136         return meOpaque || noneOfTheChildrenAreTransparent;
   7137     }
   7138 
   7139     @Override
   7140     public void requestTransparentRegion(View child) {
   7141         if (child != null) {
   7142             child.mPrivateFlags |= View.PFLAG_REQUEST_TRANSPARENT_REGIONS;
   7143             if (mParent != null) {
   7144                 mParent.requestTransparentRegion(this);
   7145             }
   7146         }
   7147     }
   7148 
   7149     /**
   7150      * @hide
   7151      */
   7152     @Override
   7153     public void subtractObscuredTouchableRegion(Region touchableRegion, View view) {
   7154         final int childrenCount = mChildrenCount;
   7155         final ArrayList<View> preorderedList = buildTouchDispatchChildList();
   7156         final boolean customOrder = preorderedList == null && isChildrenDrawingOrderEnabled();
   7157         final View[] children = mChildren;
   7158         for (int i = childrenCount - 1; i >= 0; i--) {
   7159             final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
   7160             final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex);
   7161             if (child == view) {
   7162                 // We've reached the target view.
   7163                 break;
   7164             }
   7165             if (!child.canReceivePointerEvents()) {
   7166                 // This child cannot be touched. Skip it.
   7167                 continue;
   7168             }
   7169             applyOpToRegionByBounds(touchableRegion, child, Region.Op.DIFFERENCE);
   7170         }
   7171 
   7172         // The touchable region should not exceed the bounds of its container.
   7173         applyOpToRegionByBounds(touchableRegion, this, Region.Op.INTERSECT);
   7174 
   7175         final ViewParent parent = getParent();
   7176         if (parent != null) {
   7177             parent.subtractObscuredTouchableRegion(touchableRegion, this);
   7178         }
   7179     }
   7180 
   7181     private static void applyOpToRegionByBounds(Region region, View view, Region.Op op) {
   7182         final int[] locationInWindow = new int[2];
   7183         view.getLocationInWindow(locationInWindow);
   7184         final int x = locationInWindow[0];
   7185         final int y = locationInWindow[1];
   7186         region.op(x, y, x + view.getWidth(), y + view.getHeight(), op);
   7187     }
   7188 
   7189     @Override
   7190     public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) {
   7191         insets = super.dispatchApplyWindowInsets(insets);
   7192         if (View.sBrokenInsetsDispatch) {
   7193             return brokenDispatchApplyWindowInsets(insets);
   7194         } else {
   7195             return newDispatchApplyWindowInsets(insets);
   7196         }
   7197     }
   7198 
   7199     private WindowInsets brokenDispatchApplyWindowInsets(WindowInsets insets) {
   7200         if (!insets.isConsumed()) {
   7201             final int count = getChildCount();
   7202             for (int i = 0; i < count; i++) {
   7203                 insets = getChildAt(i).dispatchApplyWindowInsets(insets);
   7204                 if (insets.isConsumed()) {
   7205                     break;
   7206                 }
   7207             }
   7208         }
   7209         return insets;
   7210     }
   7211 
   7212     private WindowInsets newDispatchApplyWindowInsets(WindowInsets insets) {
   7213         final int count = getChildCount();
   7214         for (int i = 0; i < count; i++) {
   7215             getChildAt(i).dispatchApplyWindowInsets(insets);
   7216         }
   7217         return insets;
   7218     }
   7219 
   7220     @Override
   7221     void dispatchWindowInsetsAnimationStarted(InsetsAnimation animation) {
   7222         super.dispatchWindowInsetsAnimationStarted(animation);
   7223         final int count = getChildCount();
   7224         for (int i = 0; i < count; i++) {
   7225             getChildAt(i).dispatchWindowInsetsAnimationStarted(animation);
   7226         }
   7227     }
   7228 
   7229     @Override
   7230     WindowInsets dispatchWindowInsetsAnimationProgress(WindowInsets insets) {
   7231         insets = super.dispatchWindowInsetsAnimationProgress(insets);
   7232         final int count = getChildCount();
   7233         for (int i = 0; i < count; i++) {
   7234             getChildAt(i).dispatchWindowInsetsAnimationProgress(insets);
   7235         }
   7236         return insets;
   7237     }
   7238 
   7239     @Override
   7240     void dispatchWindowInsetsAnimationFinished(InsetsAnimation animation) {
   7241         super.dispatchWindowInsetsAnimationFinished(animation);
   7242         final int count = getChildCount();
   7243         for (int i = 0; i < count; i++) {
   7244             getChildAt(i).dispatchWindowInsetsAnimationFinished(animation);
   7245         }
   7246     }
   7247 
   7248     /**
   7249      * Returns the animation listener to which layout animation events are
   7250      * sent.
   7251      *
   7252      * @return an {@link android.view.animation.Animation.AnimationListener}
   7253      */
   7254     public Animation.AnimationListener getLayoutAnimationListener() {
   7255         return mAnimationListener;
   7256     }
   7257 
   7258     @Override
   7259     protected void drawableStateChanged() {
   7260         super.drawableStateChanged();
   7261 
   7262         if ((mGroupFlags & FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE) != 0) {
   7263             if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0) {
   7264                 throw new IllegalStateException("addStateFromChildren cannot be enabled if a"
   7265                         + " child has duplicateParentState set to true");
   7266             }
   7267 
   7268             final View[] children = mChildren;
   7269             final int count = mChildrenCount;
   7270 
   7271             for (int i = 0; i < count; i++) {
   7272                 final View child = children[i];
   7273                 if ((child.mViewFlags & DUPLICATE_PARENT_STATE) != 0) {
   7274                     child.refreshDrawableState();
   7275                 }
   7276             }
   7277         }
   7278     }
   7279 
   7280     @Override
   7281     public void jumpDrawablesToCurrentState() {
   7282         super.jumpDrawablesToCurrentState();
   7283         final View[] children = mChildren;
   7284         final int count = mChildrenCount;
   7285         for (int i = 0; i < count; i++) {
   7286             children[i].jumpDrawablesToCurrentState();
   7287         }
   7288     }
   7289 
   7290     @Override
   7291     protected int[] onCreateDrawableState(int extraSpace) {
   7292         if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) == 0) {
   7293             return super.onCreateDrawableState(extraSpace);
   7294         }
   7295 
   7296         int need = 0;
   7297         int n = getChildCount();
   7298         for (int i = 0; i < n; i++) {
   7299             int[] childState = getChildAt(i).getDrawableState();
   7300 
   7301             if (childState != null) {
   7302                 need += childState.length;
   7303             }
   7304         }
   7305 
   7306         int[] state = super.onCreateDrawableState(extraSpace + need);
   7307 
   7308         for (int i = 0; i < n; i++) {
   7309             int[] childState = getChildAt(i).getDrawableState();
   7310 
   7311             if (childState != null) {
   7312                 state = mergeDrawableStates(state, childState);
   7313             }
   7314         }
   7315 
   7316         return state;
   7317     }
   7318 
   7319     /**
   7320      * Sets whether this ViewGroup's drawable states also include
   7321      * its children's drawable states.  This is used, for example, to
   7322      * make a group appear to be focused when its child EditText or button
   7323      * is focused.
   7324      */
   7325     public void setAddStatesFromChildren(boolean addsStates) {
   7326         if (addsStates) {
   7327             mGroupFlags |= FLAG_ADD_STATES_FROM_CHILDREN;
   7328         } else {
   7329             mGroupFlags &= ~FLAG_ADD_STATES_FROM_CHILDREN;
   7330         }
   7331 
   7332         refreshDrawableState();
   7333     }
   7334 
   7335     /**
   7336      * Returns whether this ViewGroup's drawable states also include
   7337      * its children's drawable states.  This is used, for example, to
   7338      * make a group appear to be focused when its child EditText or button
   7339      * is focused.
   7340      */
   7341     @InspectableProperty
   7342     public boolean addStatesFromChildren() {
   7343         return (mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0;
   7344     }
   7345 
   7346     /**
   7347      * If {@link #addStatesFromChildren} is true, refreshes this group's
   7348      * drawable state (to include the states from its children).
   7349      */
   7350     @Override
   7351     public void childDrawableStateChanged(View child) {
   7352         if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0) {
   7353             refreshDrawableState();
   7354         }
   7355     }
   7356 
   7357     /**
   7358      * Specifies the animation listener to which layout animation events must
   7359      * be sent. Only
   7360      * {@link android.view.animation.Animation.AnimationListener#onAnimationStart(Animation)}
   7361      * and
   7362      * {@link android.view.animation.Animation.AnimationListener#onAnimationEnd(Animation)}
   7363      * are invoked.
   7364      *
   7365      * @param animationListener the layout animation listener
   7366      */
   7367     public void setLayoutAnimationListener(Animation.AnimationListener animationListener) {
   7368         mAnimationListener = animationListener;
   7369     }
   7370 
   7371     /**
   7372      * This method is called by LayoutTransition when there are 'changing' animations that need
   7373      * to start after the layout/setup phase. The request is forwarded to the ViewAncestor, who
   7374      * starts all pending transitions prior to the drawing phase in the current traversal.
   7375      *
   7376      * @param transition The LayoutTransition to be started on the next traversal.
   7377      *
   7378      * @hide
   7379      */
   7380     public void requestTransitionStart(LayoutTransition transition) {
   7381         ViewRootImpl viewAncestor = getViewRootImpl();
   7382         if (viewAncestor != null) {
   7383             viewAncestor.requestTransitionStart(transition);
   7384         }
   7385     }
   7386 
   7387     /**
   7388      * @hide
   7389      */
   7390     @Override
   7391     public boolean resolveRtlPropertiesIfNeeded() {
   7392         final boolean result = super.resolveRtlPropertiesIfNeeded();
   7393         // We dont need to resolve the children RTL properties if nothing has changed for the parent
   7394         if (result) {
   7395             int count = getChildCount();
   7396             for (int i = 0; i < count; i++) {
   7397                 final View child = getChildAt(i);
   7398                 if (child.isLayoutDirectionInherited()) {
   7399                     child.resolveRtlPropertiesIfNeeded();
   7400                 }
   7401             }
   7402         }
   7403         return result;
   7404     }
   7405 
   7406     /**
   7407      * @hide
   7408      */
   7409     @Override
   7410     public boolean resolveLayoutDirection() {
   7411         final boolean result = super.resolveLayoutDirection();
   7412         if (result) {
   7413             int count = getChildCount();
   7414             for (int i = 0; i < count; i++) {
   7415                 final View child = getChildAt(i);
   7416                 if (child.isLayoutDirectionInherited()) {
   7417                     child.resolveLayoutDirection();
   7418                 }
   7419             }
   7420         }
   7421         return result;
   7422     }
   7423 
   7424     /**
   7425      * @hide
   7426      */
   7427     @Override
   7428     public boolean resolveTextDirection() {
   7429         final boolean result = super.resolveTextDirection();
   7430         if (result) {
   7431             int count = getChildCount();
   7432             for (int i = 0; i < count; i++) {
   7433                 final View child = getChildAt(i);
   7434                 if (child.isTextDirectionInherited()) {
   7435                     child.resolveTextDirection();
   7436                 }
   7437             }
   7438         }
   7439         return result;
   7440     }
   7441 
   7442     /**
   7443      * @hide
   7444      */
   7445     @Override
   7446     public boolean resolveTextAlignment() {
   7447         final boolean result = super.resolveTextAlignment();
   7448         if (result) {
   7449             int count = getChildCount();
   7450             for (int i = 0; i < count; i++) {
   7451                 final View child = getChildAt(i);
   7452                 if (child.isTextAlignmentInherited()) {
   7453                     child.resolveTextAlignment();
   7454                 }
   7455             }
   7456         }
   7457         return result;
   7458     }
   7459 
   7460     /**
   7461      * @hide
   7462      */
   7463     @Override
   7464     @UnsupportedAppUsage
   7465     public void resolvePadding() {
   7466         super.resolvePadding();
   7467         int count = getChildCount();
   7468         for (int i = 0; i < count; i++) {
   7469             final View child = getChildAt(i);
   7470             if (child.isLayoutDirectionInherited() && !child.isPaddingResolved()) {
   7471                 child.resolvePadding();
   7472             }
   7473         }
   7474     }
   7475 
   7476     /**
   7477      * @hide
   7478      */
   7479     @Override
   7480     protected void resolveDrawables() {
   7481         super.resolveDrawables();
   7482         int count = getChildCount();
   7483         for (int i = 0; i < count; i++) {
   7484             final View child = getChildAt(i);
   7485             if (child.isLayoutDirectionInherited() && !child.areDrawablesResolved()) {
   7486                 child.resolveDrawables();
   7487             }
   7488         }
   7489     }
   7490 
   7491     /**
   7492      * @hide
   7493      */
   7494     @Override
   7495     public void resolveLayoutParams() {
   7496         super.resolveLayoutParams();
   7497         int count = getChildCount();
   7498         for (int i = 0; i < count; i++) {
   7499             final View child = getChildAt(i);
   7500             child.resolveLayoutParams();
   7501         }
   7502     }
   7503 
   7504     /**
   7505      * @hide
   7506      */
   7507     @TestApi
   7508     @Override
   7509     public void resetResolvedLayoutDirection() {
   7510         super.resetResolvedLayoutDirection();
   7511 
   7512         int count = getChildCount();
   7513         for (int i = 0; i < count; i++) {
   7514             final View child = getChildAt(i);
   7515             if (child.isLayoutDirectionInherited()) {
   7516                 child.resetResolvedLayoutDirection();
   7517             }
   7518         }
   7519     }
   7520 
   7521     /**
   7522      * @hide
   7523      */
   7524     @TestApi
   7525     @Override
   7526     public void resetResolvedTextDirection() {
   7527         super.resetResolvedTextDirection();
   7528 
   7529         int count = getChildCount();
   7530         for (int i = 0; i < count; i++) {
   7531             final View child = getChildAt(i);
   7532             if (child.isTextDirectionInherited()) {
   7533                 child.resetResolvedTextDirection();
   7534             }
   7535         }
   7536     }
   7537 
   7538     /**
   7539      * @hide
   7540      */
   7541     @TestApi
   7542     @Override
   7543     public void resetResolvedTextAlignment() {
   7544         super.resetResolvedTextAlignment();
   7545 
   7546         int count = getChildCount();
   7547         for (int i = 0; i < count; i++) {
   7548             final View child = getChildAt(i);
   7549             if (child.isTextAlignmentInherited()) {
   7550                 child.resetResolvedTextAlignment();
   7551             }
   7552         }
   7553     }
   7554 
   7555     /**
   7556      * @hide
   7557      */
   7558     @TestApi
   7559     @Override
   7560     public void resetResolvedPadding() {
   7561         super.resetResolvedPadding();
   7562 
   7563         int count = getChildCount();
   7564         for (int i = 0; i < count; i++) {
   7565             final View child = getChildAt(i);
   7566             if (child.isLayoutDirectionInherited()) {
   7567                 child.resetResolvedPadding();
   7568             }
   7569         }
   7570     }
   7571 
   7572     /**
   7573      * @hide
   7574      */
   7575     @TestApi
   7576     @Override
   7577     protected void resetResolvedDrawables() {
   7578         super.resetResolvedDrawables();
   7579 
   7580         int count = getChildCount();
   7581         for (int i = 0; i < count; i++) {
   7582             final View child = getChildAt(i);
   7583             if (child.isLayoutDirectionInherited()) {
   7584                 child.resetResolvedDrawables();
   7585             }
   7586         }
   7587     }
   7588 
   7589     /**
   7590      * Return true if the pressed state should be delayed for children or descendants of this
   7591      * ViewGroup. Generally, this should be done for containers that can scroll, such as a List.
   7592      * This prevents the pressed state from appearing when the user is actually trying to scroll
   7593      * the content.
   7594      *
   7595      * The default implementation returns true for compatibility reasons. Subclasses that do
   7596      * not scroll should generally override this method and return false.
   7597      */
   7598     public boolean shouldDelayChildPressedState() {
   7599         return true;
   7600     }
   7601 
   7602     /**
   7603      * @inheritDoc
   7604      */
   7605     @Override
   7606     public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
   7607         return false;
   7608     }
   7609 
   7610     /**
   7611      * @inheritDoc
   7612      */
   7613     @Override
   7614     public void onNestedScrollAccepted(View child, View target, int axes) {
   7615         mNestedScrollAxes = axes;
   7616     }
   7617 
   7618     /**
   7619      * @inheritDoc
   7620      *
   7621      * <p>The default implementation of onStopNestedScroll calls
   7622      * {@link #stopNestedScroll()} to halt any recursive nested scrolling in progress.</p>
   7623      */
   7624     @Override
   7625     public void onStopNestedScroll(View child) {
   7626         // Stop any recursive nested scrolling.
   7627         stopNestedScroll();
   7628         mNestedScrollAxes = 0;
   7629     }
   7630 
   7631     /**
   7632      * @inheritDoc
   7633      */
   7634     @Override
   7635     public void onNestedScroll(View target, int dxConsumed, int dyConsumed,
   7636             int dxUnconsumed, int dyUnconsumed) {
   7637         // Re-dispatch up the tree by default
   7638         dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, null);
   7639     }
   7640 
   7641     /**
   7642      * @inheritDoc
   7643      */
   7644     @Override
   7645     public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
   7646         // Re-dispatch up the tree by default
   7647         dispatchNestedPreScroll(dx, dy, consumed, null);
   7648     }
   7649 
   7650     /**
   7651      * @inheritDoc
   7652      */
   7653     @Override
   7654     public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
   7655         // Re-dispatch up the tree by default
   7656         return dispatchNestedFling(velocityX, velocityY, consumed);
   7657     }
   7658 
   7659     /**
   7660      * @inheritDoc
   7661      */
   7662     @Override
   7663     public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
   7664         // Re-dispatch up the tree by default
   7665         return dispatchNestedPreFling(velocityX, velocityY);
   7666     }
   7667 
   7668     /**
   7669      * Return the current axes of nested scrolling for this ViewGroup.
   7670      *
   7671      * <p>A ViewGroup returning something other than {@link #SCROLL_AXIS_NONE} is currently
   7672      * acting as a nested scrolling parent for one or more descendant views in the hierarchy.</p>
   7673      *
   7674      * @return Flags indicating the current axes of nested scrolling
   7675      * @see #SCROLL_AXIS_HORIZONTAL
   7676      * @see #SCROLL_AXIS_VERTICAL
   7677      * @see #SCROLL_AXIS_NONE
   7678      */
   7679     public int getNestedScrollAxes() {
   7680         return mNestedScrollAxes;
   7681     }
   7682 
   7683     /** @hide */
   7684     protected void onSetLayoutParams(View child, LayoutParams layoutParams) {
   7685         requestLayout();
   7686     }
   7687 
   7688     /** @hide */
   7689     @Override
   7690     public void captureTransitioningViews(List<View> transitioningViews) {
   7691         if (getVisibility() != View.VISIBLE) {
   7692             return;
   7693         }
   7694         if (isTransitionGroup()) {
   7695             transitioningViews.add(this);
   7696         } else {
   7697             int count = getChildCount();
   7698             for (int i = 0; i < count; i++) {
   7699                 View child = getChildAt(i);
   7700                 child.captureTransitioningViews(transitioningViews);
   7701             }
   7702         }
   7703     }
   7704 
   7705     /** @hide */
   7706     @Override
   7707     public void findNamedViews(Map<String, View> namedElements) {
   7708         if (getVisibility() != VISIBLE && mGhostView == null) {
   7709             return;
   7710         }
   7711         super.findNamedViews(namedElements);
   7712         int count = getChildCount();
   7713         for (int i = 0; i < count; i++) {
   7714             View child = getChildAt(i);
   7715             child.findNamedViews(namedElements);
   7716         }
   7717     }
   7718 
   7719     @Override
   7720     boolean hasUnhandledKeyListener() {
   7721         return (mChildUnhandledKeyListeners > 0) || super.hasUnhandledKeyListener();
   7722     }
   7723 
   7724     void incrementChildUnhandledKeyListeners() {
   7725         mChildUnhandledKeyListeners += 1;
   7726         if (mChildUnhandledKeyListeners == 1) {
   7727             if (mParent instanceof ViewGroup) {
   7728                 ((ViewGroup) mParent).incrementChildUnhandledKeyListeners();
   7729             }
   7730         }
   7731     }
   7732 
   7733     void decrementChildUnhandledKeyListeners() {
   7734         mChildUnhandledKeyListeners -= 1;
   7735         if (mChildUnhandledKeyListeners == 0) {
   7736             if (mParent instanceof ViewGroup) {
   7737                 ((ViewGroup) mParent).decrementChildUnhandledKeyListeners();
   7738             }
   7739         }
   7740     }
   7741 
   7742     @Override
   7743     View dispatchUnhandledKeyEvent(KeyEvent evt) {
   7744         if (!hasUnhandledKeyListener()) {
   7745             return null;
   7746         }
   7747         ArrayList<View> orderedViews = buildOrderedChildList();
   7748         if (orderedViews != null) {
   7749             try {
   7750                 for (int i = orderedViews.size() - 1; i >= 0; --i) {
   7751                     View v = orderedViews.get(i);
   7752                     View consumer = v.dispatchUnhandledKeyEvent(evt);
   7753                     if (consumer != null) {
   7754                         return consumer;
   7755                     }
   7756                 }
   7757             } finally {
   7758                 orderedViews.clear();
   7759             }
   7760         } else {
   7761             for (int i = getChildCount() - 1; i >= 0; --i) {
   7762                 View v = getChildAt(i);
   7763                 View consumer = v.dispatchUnhandledKeyEvent(evt);
   7764                 if (consumer != null) {
   7765                     return consumer;
   7766                 }
   7767             }
   7768         }
   7769         if (onUnhandledKeyEvent(evt)) {
   7770             return this;
   7771         }
   7772         return null;
   7773     }
   7774 
   7775     /**
   7776      * LayoutParams are used by views to tell their parents how they want to be
   7777      * laid out. See
   7778      * {@link android.R.styleable#ViewGroup_Layout ViewGroup Layout Attributes}
   7779      * for a list of all child view attributes that this class supports.
   7780      *
   7781      * <p>
   7782      * The base LayoutParams class just describes how big the view wants to be
   7783      * for both width and height. For each dimension, it can specify one of:
   7784      * <ul>
   7785      * <li>FILL_PARENT (renamed MATCH_PARENT in API Level 8 and higher), which
   7786      * means that the view wants to be as big as its parent (minus padding)
   7787      * <li> WRAP_CONTENT, which means that the view wants to be just big enough
   7788      * to enclose its content (plus padding)
   7789      * <li> an exact number
   7790      * </ul>
   7791      * There are subclasses of LayoutParams for different subclasses of
   7792      * ViewGroup. For example, AbsoluteLayout has its own subclass of
   7793      * LayoutParams which adds an X and Y value.</p>
   7794      *
   7795      * <div class="special reference">
   7796      * <h3>Developer Guides</h3>
   7797      * <p>For more information about creating user interface layouts, read the
   7798      * <a href="{@docRoot}guide/topics/ui/declaring-layout.html">XML Layouts</a> developer
   7799      * guide.</p></div>
   7800      *
   7801      * @attr ref android.R.styleable#ViewGroup_Layout_layout_height
   7802      * @attr ref android.R.styleable#ViewGroup_Layout_layout_width
   7803      */
   7804     public static class LayoutParams {
   7805         /**
   7806          * Special value for the height or width requested by a View.
   7807          * FILL_PARENT means that the view wants to be as big as its parent,
   7808          * minus the parent's padding, if any. This value is deprecated
   7809          * starting in API Level 8 and replaced by {@link #MATCH_PARENT}.
   7810          */
   7811         @SuppressWarnings({"UnusedDeclaration"})
   7812         @Deprecated
   7813         public static final int FILL_PARENT = -1;
   7814 
   7815         /**
   7816          * Special value for the height or width requested by a View.
   7817          * MATCH_PARENT means that the view wants to be as big as its parent,
   7818          * minus the parent's padding, if any. Introduced in API Level 8.
   7819          */
   7820         public static final int MATCH_PARENT = -1;
   7821 
   7822         /**
   7823          * Special value for the height or width requested by a View.
   7824          * WRAP_CONTENT means that the view wants to be just large enough to fit
   7825          * its own internal content, taking its own padding into account.
   7826          */
   7827         public static final int WRAP_CONTENT = -2;
   7828 
   7829         /**
   7830          * Information about how wide the view wants to be. Can be one of the
   7831          * constants FILL_PARENT (replaced by MATCH_PARENT
   7832          * in API Level 8) or WRAP_CONTENT, or an exact size.
   7833          */
   7834         @ViewDebug.ExportedProperty(category = "layout", mapping = {
   7835             @ViewDebug.IntToString(from = MATCH_PARENT, to = "MATCH_PARENT"),
   7836             @ViewDebug.IntToString(from = WRAP_CONTENT, to = "WRAP_CONTENT")
   7837         })
   7838         @InspectableProperty(name = "layout_width", enumMapping = {
   7839                 @EnumEntry(name = "match_parent", value = MATCH_PARENT),
   7840                 @EnumEntry(name = "wrap_content", value = WRAP_CONTENT)
   7841         })
   7842         public int width;
   7843 
   7844         /**
   7845          * Information about how tall the view wants to be. Can be one of the
   7846          * constants FILL_PARENT (replaced by MATCH_PARENT
   7847          * in API Level 8) or WRAP_CONTENT, or an exact size.
   7848          */
   7849         @ViewDebug.ExportedProperty(category = "layout", mapping = {
   7850             @ViewDebug.IntToString(from = MATCH_PARENT, to = "MATCH_PARENT"),
   7851             @ViewDebug.IntToString(from = WRAP_CONTENT, to = "WRAP_CONTENT")
   7852         })
   7853         @InspectableProperty(name = "layout_height", enumMapping = {
   7854                 @EnumEntry(name = "match_parent", value = MATCH_PARENT),
   7855                 @EnumEntry(name = "wrap_content", value = WRAP_CONTENT)
   7856         })
   7857         public int height;
   7858 
   7859         /**
   7860          * Used to animate layouts.
   7861          */
   7862         public LayoutAnimationController.AnimationParameters layoutAnimationParameters;
   7863 
   7864         /**
   7865          * Creates a new set of layout parameters. The values are extracted from
   7866          * the supplied attributes set and context. The XML attributes mapped
   7867          * to this set of layout parameters are:
   7868          *
   7869          * <ul>
   7870          *   <li><code>layout_width</code>: the width, either an exact value,
   7871          *   {@link #WRAP_CONTENT}, or {@link #FILL_PARENT} (replaced by
   7872          *   {@link #MATCH_PARENT} in API Level 8)</li>
   7873          *   <li><code>layout_height</code>: the height, either an exact value,
   7874          *   {@link #WRAP_CONTENT}, or {@link #FILL_PARENT} (replaced by
   7875          *   {@link #MATCH_PARENT} in API Level 8)</li>
   7876          * </ul>
   7877          *
   7878          * @param c the application environment
   7879          * @param attrs the set of attributes from which to extract the layout
   7880          *              parameters' values
   7881          */
   7882         public LayoutParams(Context c, AttributeSet attrs) {
   7883             TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.ViewGroup_Layout);
   7884             setBaseAttributes(a,
   7885                     R.styleable.ViewGroup_Layout_layout_width,
   7886                     R.styleable.ViewGroup_Layout_layout_height);
   7887             a.recycle();
   7888         }
   7889 
   7890         /**
   7891          * Creates a new set of layout parameters with the specified width
   7892          * and height.
   7893          *
   7894          * @param width the width, either {@link #WRAP_CONTENT},
   7895          *        {@link #FILL_PARENT} (replaced by {@link #MATCH_PARENT} in
   7896          *        API Level 8), or a fixed size in pixels
   7897          * @param height the height, either {@link #WRAP_CONTENT},
   7898          *        {@link #FILL_PARENT} (replaced by {@link #MATCH_PARENT} in
   7899          *        API Level 8), or a fixed size in pixels
   7900          */
   7901         public LayoutParams(int width, int height) {
   7902             this.width = width;
   7903             this.height = height;
   7904         }
   7905 
   7906         /**
   7907          * Copy constructor. Clones the width and height values of the source.
   7908          *
   7909          * @param source The layout params to copy from.
   7910          */
   7911         public LayoutParams(LayoutParams source) {
   7912             this.width = source.width;
   7913             this.height = source.height;
   7914         }
   7915 
   7916         /**
   7917          * Used internally by MarginLayoutParams.
   7918          * @hide
   7919          */
   7920         @UnsupportedAppUsage
   7921         LayoutParams() {
   7922         }
   7923 
   7924         /**
   7925          * Extracts the layout parameters from the supplied attributes.
   7926          *
   7927          * @param a the style attributes to extract the parameters from
   7928          * @param widthAttr the identifier of the width attribute
   7929          * @param heightAttr the identifier of the height attribute
   7930          */
   7931         protected void setBaseAttributes(TypedArray a, int widthAttr, int heightAttr) {
   7932             width = a.getLayoutDimension(widthAttr, "layout_width");
   7933             height = a.getLayoutDimension(heightAttr, "layout_height");
   7934         }
   7935 
   7936         /**
   7937          * Resolve layout parameters depending on the layout direction. Subclasses that care about
   7938          * layoutDirection changes should override this method. The default implementation does
   7939          * nothing.
   7940          *
   7941          * @param layoutDirection the direction of the layout
   7942          *
   7943          * {@link View#LAYOUT_DIRECTION_LTR}
   7944          * {@link View#LAYOUT_DIRECTION_RTL}
   7945          */
   7946         public void resolveLayoutDirection(int layoutDirection) {
   7947         }
   7948 
   7949         /**
   7950          * Returns a String representation of this set of layout parameters.
   7951          *
   7952          * @param output the String to prepend to the internal representation
   7953          * @return a String with the following format: output +
   7954          *         "ViewGroup.LayoutParams={ width=WIDTH, height=HEIGHT }"
   7955          *
   7956          * @hide
   7957          */
   7958         public String debug(String output) {
   7959             return output + "ViewGroup.LayoutParams={ width="
   7960                     + sizeToString(width) + ", height=" + sizeToString(height) + " }";
   7961         }
   7962 
   7963         /**
   7964          * Use {@code canvas} to draw suitable debugging annotations for these LayoutParameters.
   7965          *
   7966          * @param view the view that contains these layout parameters
   7967          * @param canvas the canvas on which to draw
   7968          *
   7969          * @hide
   7970          */
   7971         public void onDebugDraw(View view, Canvas canvas, Paint paint) {
   7972         }
   7973 
   7974         /**
   7975          * Converts the specified size to a readable String.
   7976          *
   7977          * @param size the size to convert
   7978          * @return a String instance representing the supplied size
   7979          *
   7980          * @hide
   7981          */
   7982         protected static String sizeToString(int size) {
   7983             if (size == WRAP_CONTENT) {
   7984                 return "wrap-content";
   7985             }
   7986             if (size == MATCH_PARENT) {
   7987                 return "match-parent";
   7988             }
   7989             return String.valueOf(size);
   7990         }
   7991 
   7992         /** @hide */
   7993         void encode(@NonNull ViewHierarchyEncoder encoder) {
   7994             encoder.beginObject(this);
   7995             encodeProperties(encoder);
   7996             encoder.endObject();
   7997         }
   7998 
   7999         /** @hide */
   8000         protected void encodeProperties(@NonNull ViewHierarchyEncoder encoder) {
   8001             encoder.addProperty("width", width);
   8002             encoder.addProperty("height", height);
   8003         }
   8004     }
   8005 
   8006     /**
   8007      * Per-child layout information for layouts that support margins.
   8008      * See
   8009      * {@link android.R.styleable#ViewGroup_MarginLayout ViewGroup Margin Layout Attributes}
   8010      * for a list of all child view attributes that this class supports.
   8011      *
   8012      * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_margin
   8013      * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginHorizontal
   8014      * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginVertical
   8015      * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginLeft
   8016      * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginTop
   8017      * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginRight
   8018      * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginBottom
   8019      * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart
   8020      * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd
   8021      */
   8022     public static class MarginLayoutParams extends ViewGroup.LayoutParams {
   8023         /**
   8024          * The left margin in pixels of the child. Margin values should be positive.
   8025          * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
   8026          * to this field.
   8027          */
   8028         @ViewDebug.ExportedProperty(category = "layout")
   8029         @InspectableProperty(name = "layout_marginLeft")
   8030         public int leftMargin;
   8031 
   8032         /**
   8033          * The top margin in pixels of the child. Margin values should be positive.
   8034          * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
   8035          * to this field.
   8036          */
   8037         @ViewDebug.ExportedProperty(category = "layout")
   8038         @InspectableProperty(name = "layout_marginTop")
   8039         public int topMargin;
   8040 
   8041         /**
   8042          * The right margin in pixels of the child. Margin values should be positive.
   8043          * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
   8044          * to this field.
   8045          */
   8046         @ViewDebug.ExportedProperty(category = "layout")
   8047         @InspectableProperty(name = "layout_marginRight")
   8048         public int rightMargin;
   8049 
   8050         /**
   8051          * The bottom margin in pixels of the child. Margin values should be positive.
   8052          * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
   8053          * to this field.
   8054          */
   8055         @ViewDebug.ExportedProperty(category = "layout")
   8056         @InspectableProperty(name = "layout_marginBottom")
   8057         public int bottomMargin;
   8058 
   8059         /**
   8060          * The start margin in pixels of the child. Margin values should be positive.
   8061          * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
   8062          * to this field.
   8063          */
   8064         @ViewDebug.ExportedProperty(category = "layout")
   8065         @UnsupportedAppUsage
   8066         private int startMargin = DEFAULT_MARGIN_RELATIVE;
   8067 
   8068         /**
   8069          * The end margin in pixels of the child. Margin values should be positive.
   8070          * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
   8071          * to this field.
   8072          */
   8073         @ViewDebug.ExportedProperty(category = "layout")
   8074         @UnsupportedAppUsage
   8075         private int endMargin = DEFAULT_MARGIN_RELATIVE;
   8076 
   8077         /**
   8078          * The default start and end margin.
   8079          * @hide
   8080          */
   8081         public static final int DEFAULT_MARGIN_RELATIVE = Integer.MIN_VALUE;
   8082 
   8083         /**
   8084          * Bit  0: layout direction
   8085          * Bit  1: layout direction
   8086          * Bit  2: left margin undefined
   8087          * Bit  3: right margin undefined
   8088          * Bit  4: is RTL compatibility mode
   8089          * Bit  5: need resolution
   8090          *
   8091          * Bit 6 to 7 not used
   8092          *
   8093          * @hide
   8094          */
   8095         @ViewDebug.ExportedProperty(category = "layout", flagMapping = {
   8096                 @ViewDebug.FlagToString(mask = LAYOUT_DIRECTION_MASK,
   8097                         equals = LAYOUT_DIRECTION_MASK, name = "LAYOUT_DIRECTION"),
   8098                 @ViewDebug.FlagToString(mask = LEFT_MARGIN_UNDEFINED_MASK,
   8099                         equals = LEFT_MARGIN_UNDEFINED_MASK, name = "LEFT_MARGIN_UNDEFINED_MASK"),
   8100                 @ViewDebug.FlagToString(mask = RIGHT_MARGIN_UNDEFINED_MASK,
   8101                         equals = RIGHT_MARGIN_UNDEFINED_MASK, name = "RIGHT_MARGIN_UNDEFINED_MASK"),
   8102                 @ViewDebug.FlagToString(mask = RTL_COMPATIBILITY_MODE_MASK,
   8103                         equals = RTL_COMPATIBILITY_MODE_MASK, name = "RTL_COMPATIBILITY_MODE_MASK"),
   8104                 @ViewDebug.FlagToString(mask = NEED_RESOLUTION_MASK,
   8105                         equals = NEED_RESOLUTION_MASK, name = "NEED_RESOLUTION_MASK")
   8106         }, formatToHexString = true)
   8107         byte mMarginFlags;
   8108 
   8109         private static final int LAYOUT_DIRECTION_MASK = 0x00000003;
   8110         private static final int LEFT_MARGIN_UNDEFINED_MASK = 0x00000004;
   8111         private static final int RIGHT_MARGIN_UNDEFINED_MASK = 0x00000008;
   8112         private static final int RTL_COMPATIBILITY_MODE_MASK = 0x00000010;
   8113         private static final int NEED_RESOLUTION_MASK = 0x00000020;
   8114 
   8115         private static final int DEFAULT_MARGIN_RESOLVED = 0;
   8116         private static final int UNDEFINED_MARGIN = DEFAULT_MARGIN_RELATIVE;
   8117 
   8118         /**
   8119          * Creates a new set of layout parameters. The values are extracted from
   8120          * the supplied attributes set and context.
   8121          *
   8122          * @param c the application environment
   8123          * @param attrs the set of attributes from which to extract the layout
   8124          *              parameters' values
   8125          */
   8126         public MarginLayoutParams(Context c, AttributeSet attrs) {
   8127             super();
   8128 
   8129             TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.ViewGroup_MarginLayout);
   8130             setBaseAttributes(a,
   8131                     R.styleable.ViewGroup_MarginLayout_layout_width,
   8132                     R.styleable.ViewGroup_MarginLayout_layout_height);
   8133 
   8134             int margin = a.getDimensionPixelSize(
   8135                     com.android.internal.R.styleable.ViewGroup_MarginLayout_layout_margin, -1);
   8136             if (margin >= 0) {
   8137                 leftMargin = margin;
   8138                 topMargin = margin;
   8139                 rightMargin= margin;
   8140                 bottomMargin = margin;
   8141             } else {
   8142                 int horizontalMargin = a.getDimensionPixelSize(
   8143                         R.styleable.ViewGroup_MarginLayout_layout_marginHorizontal, -1);
   8144                 int verticalMargin = a.getDimensionPixelSize(
   8145                         R.styleable.ViewGroup_MarginLayout_layout_marginVertical, -1);
   8146 
   8147                 if (horizontalMargin >= 0) {
   8148                     leftMargin = horizontalMargin;
   8149                     rightMargin = horizontalMargin;
   8150                 } else {
   8151                     leftMargin = a.getDimensionPixelSize(
   8152                             R.styleable.ViewGroup_MarginLayout_layout_marginLeft,
   8153                             UNDEFINED_MARGIN);
   8154                     if (leftMargin == UNDEFINED_MARGIN) {
   8155                         mMarginFlags |= LEFT_MARGIN_UNDEFINED_MASK;
   8156                         leftMargin = DEFAULT_MARGIN_RESOLVED;
   8157                     }
   8158                     rightMargin = a.getDimensionPixelSize(
   8159                             R.styleable.ViewGroup_MarginLayout_layout_marginRight,
   8160                             UNDEFINED_MARGIN);
   8161                     if (rightMargin == UNDEFINED_MARGIN) {
   8162                         mMarginFlags |= RIGHT_MARGIN_UNDEFINED_MASK;
   8163                         rightMargin = DEFAULT_MARGIN_RESOLVED;
   8164                     }
   8165                 }
   8166 
   8167                 startMargin = a.getDimensionPixelSize(
   8168                         R.styleable.ViewGroup_MarginLayout_layout_marginStart,
   8169                         DEFAULT_MARGIN_RELATIVE);
   8170                 endMargin = a.getDimensionPixelSize(
   8171                         R.styleable.ViewGroup_MarginLayout_layout_marginEnd,
   8172                         DEFAULT_MARGIN_RELATIVE);
   8173 
   8174                 if (verticalMargin >= 0) {
   8175                     topMargin = verticalMargin;
   8176                     bottomMargin = verticalMargin;
   8177                 } else {
   8178                     topMargin = a.getDimensionPixelSize(
   8179                             R.styleable.ViewGroup_MarginLayout_layout_marginTop,
   8180                             DEFAULT_MARGIN_RESOLVED);
   8181                     bottomMargin = a.getDimensionPixelSize(
   8182                             R.styleable.ViewGroup_MarginLayout_layout_marginBottom,
   8183                             DEFAULT_MARGIN_RESOLVED);
   8184                 }
   8185 
   8186                 if (isMarginRelative()) {
   8187                    mMarginFlags |= NEED_RESOLUTION_MASK;
   8188                 }
   8189             }
   8190 
   8191             final boolean hasRtlSupport = c.getApplicationInfo().hasRtlSupport();
   8192             final int targetSdkVersion = c.getApplicationInfo().targetSdkVersion;
   8193             if (targetSdkVersion < JELLY_BEAN_MR1 || !hasRtlSupport) {
   8194                 mMarginFlags |= RTL_COMPATIBILITY_MODE_MASK;
   8195             }
   8196 
   8197             // Layout direction is LTR by default
   8198             mMarginFlags |= LAYOUT_DIRECTION_LTR;
   8199 
   8200             a.recycle();
   8201         }
   8202 
   8203         public MarginLayoutParams(int width, int height) {
   8204             super(width, height);
   8205 
   8206             mMarginFlags |= LEFT_MARGIN_UNDEFINED_MASK;
   8207             mMarginFlags |= RIGHT_MARGIN_UNDEFINED_MASK;
   8208 
   8209             mMarginFlags &= ~NEED_RESOLUTION_MASK;
   8210             mMarginFlags &= ~RTL_COMPATIBILITY_MODE_MASK;
   8211         }
   8212 
   8213         /**
   8214          * Copy constructor. Clones the width, height and margin values of the source.
   8215          *
   8216          * @param source The layout params to copy from.
   8217          */
   8218         public MarginLayoutParams(MarginLayoutParams source) {
   8219             this.width = source.width;
   8220             this.height = source.height;
   8221 
   8222             this.leftMargin = source.leftMargin;
   8223             this.topMargin = source.topMargin;
   8224             this.rightMargin = source.rightMargin;
   8225             this.bottomMargin = source.bottomMargin;
   8226             this.startMargin = source.startMargin;
   8227             this.endMargin = source.endMargin;
   8228 
   8229             this.mMarginFlags = source.mMarginFlags;
   8230         }
   8231 
   8232         public MarginLayoutParams(LayoutParams source) {
   8233             super(source);
   8234 
   8235             mMarginFlags |= LEFT_MARGIN_UNDEFINED_MASK;
   8236             mMarginFlags |= RIGHT_MARGIN_UNDEFINED_MASK;
   8237 
   8238             mMarginFlags &= ~NEED_RESOLUTION_MASK;
   8239             mMarginFlags &= ~RTL_COMPATIBILITY_MODE_MASK;
   8240         }
   8241 
   8242         /**
   8243          * @hide Used internally.
   8244          */
   8245         public final void copyMarginsFrom(MarginLayoutParams source) {
   8246             this.leftMargin = source.leftMargin;
   8247             this.topMargin = source.topMargin;
   8248             this.rightMargin = source.rightMargin;
   8249             this.bottomMargin = source.bottomMargin;
   8250             this.startMargin = source.startMargin;
   8251             this.endMargin = source.endMargin;
   8252 
   8253             this.mMarginFlags = source.mMarginFlags;
   8254         }
   8255 
   8256         /**
   8257          * Sets the margins, in pixels. A call to {@link android.view.View#requestLayout()} needs
   8258          * to be done so that the new margins are taken into account. Left and right margins may be
   8259          * overridden by {@link android.view.View#requestLayout()} depending on layout direction.
   8260          * Margin values should be positive.
   8261          *
   8262          * @param left the left margin size
   8263          * @param top the top margin size
   8264          * @param right the right margin size
   8265          * @param bottom the bottom margin size
   8266          *
   8267          * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginLeft
   8268          * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginTop
   8269          * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginRight
   8270          * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginBottom
   8271          */
   8272         public void setMargins(int left, int top, int right, int bottom) {
   8273             leftMargin = left;
   8274             topMargin = top;
   8275             rightMargin = right;
   8276             bottomMargin = bottom;
   8277             mMarginFlags &= ~LEFT_MARGIN_UNDEFINED_MASK;
   8278             mMarginFlags &= ~RIGHT_MARGIN_UNDEFINED_MASK;
   8279             if (isMarginRelative()) {
   8280                 mMarginFlags |= NEED_RESOLUTION_MASK;
   8281             } else {
   8282                 mMarginFlags &= ~NEED_RESOLUTION_MASK;
   8283             }
   8284         }
   8285 
   8286         /**
   8287          * Sets the relative margins, in pixels. A call to {@link android.view.View#requestLayout()}
   8288          * needs to be done so that the new relative margins are taken into account. Left and right
   8289          * margins may be overridden by {@link android.view.View#requestLayout()} depending on
   8290          * layout direction. Margin values should be positive.
   8291          *
   8292          * @param start the start margin size
   8293          * @param top the top margin size
   8294          * @param end the right margin size
   8295          * @param bottom the bottom margin size
   8296          *
   8297          * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart
   8298          * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginTop
   8299          * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd
   8300          * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginBottom
   8301          *
   8302          * @hide
   8303          */
   8304         @UnsupportedAppUsage
   8305         public void setMarginsRelative(int start, int top, int end, int bottom) {
   8306             startMargin = start;
   8307             topMargin = top;
   8308             endMargin = end;
   8309             bottomMargin = bottom;
   8310             mMarginFlags |= NEED_RESOLUTION_MASK;
   8311         }
   8312 
   8313         /**
   8314          * Sets the relative start margin. Margin values should be positive.
   8315          *
   8316          * @param start the start margin size
   8317          *
   8318          * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart
   8319          */
   8320         public void setMarginStart(int start) {
   8321             startMargin = start;
   8322             mMarginFlags |= NEED_RESOLUTION_MASK;
   8323         }
   8324 
   8325         /**
   8326          * Returns the start margin in pixels.
   8327          *
   8328          * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart
   8329          *
   8330          * @return the start margin in pixels.
   8331          */
   8332         public int getMarginStart() {
   8333             if (startMargin != DEFAULT_MARGIN_RELATIVE) return startMargin;
   8334             if ((mMarginFlags & NEED_RESOLUTION_MASK) == NEED_RESOLUTION_MASK) {
   8335                 doResolveMargins();
   8336             }
   8337             switch(mMarginFlags & LAYOUT_DIRECTION_MASK) {
   8338                 case View.LAYOUT_DIRECTION_RTL:
   8339                     return rightMargin;
   8340                 case View.LAYOUT_DIRECTION_LTR:
   8341                 default:
   8342                     return leftMargin;
   8343             }
   8344         }
   8345 
   8346         /**
   8347          * Sets the relative end margin. Margin values should be positive.
   8348          *
   8349          * @param end the end margin size
   8350          *
   8351          * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd
   8352          */
   8353         public void setMarginEnd(int end) {
   8354             endMargin = end;
   8355             mMarginFlags |= NEED_RESOLUTION_MASK;
   8356         }
   8357 
   8358         /**
   8359          * Returns the end margin in pixels.
   8360          *
   8361          * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd
   8362          *
   8363          * @return the end margin in pixels.
   8364          */
   8365         public int getMarginEnd() {
   8366             if (endMargin != DEFAULT_MARGIN_RELATIVE) return endMargin;
   8367             if ((mMarginFlags & NEED_RESOLUTION_MASK) == NEED_RESOLUTION_MASK) {
   8368                 doResolveMargins();
   8369             }
   8370             switch(mMarginFlags & LAYOUT_DIRECTION_MASK) {
   8371                 case View.LAYOUT_DIRECTION_RTL:
   8372                     return leftMargin;
   8373                 case View.LAYOUT_DIRECTION_LTR:
   8374                 default:
   8375                     return rightMargin;
   8376             }
   8377         }
   8378 
   8379         /**
   8380          * Check if margins are relative.
   8381          *
   8382          * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart
   8383          * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd
   8384          *
   8385          * @return true if either marginStart or marginEnd has been set.
   8386          */
   8387         public boolean isMarginRelative() {
   8388             return (startMargin != DEFAULT_MARGIN_RELATIVE || endMargin != DEFAULT_MARGIN_RELATIVE);
   8389         }
   8390 
   8391         /**
   8392          * Set the layout direction
   8393          * @param layoutDirection the layout direction.
   8394          *        Should be either {@link View#LAYOUT_DIRECTION_LTR}
   8395          *                     or {@link View#LAYOUT_DIRECTION_RTL}.
   8396          */
   8397         public void setLayoutDirection(int layoutDirection) {
   8398             if (layoutDirection != View.LAYOUT_DIRECTION_LTR &&
   8399                     layoutDirection != View.LAYOUT_DIRECTION_RTL) return;
   8400             if (layoutDirection != (mMarginFlags & LAYOUT_DIRECTION_MASK)) {
   8401                 mMarginFlags &= ~LAYOUT_DIRECTION_MASK;
   8402                 mMarginFlags |= (layoutDirection & LAYOUT_DIRECTION_MASK);
   8403                 if (isMarginRelative()) {
   8404                     mMarginFlags |= NEED_RESOLUTION_MASK;
   8405                 } else {
   8406                     mMarginFlags &= ~NEED_RESOLUTION_MASK;
   8407                 }
   8408             }
   8409         }
   8410 
   8411         /**
   8412          * Retuns the layout direction. Can be either {@link View#LAYOUT_DIRECTION_LTR} or
   8413          * {@link View#LAYOUT_DIRECTION_RTL}.
   8414          *
   8415          * @return the layout direction.
   8416          */
   8417         public int getLayoutDirection() {
   8418             return (mMarginFlags & LAYOUT_DIRECTION_MASK);
   8419         }
   8420 
   8421         /**
   8422          * This will be called by {@link android.view.View#requestLayout()}. Left and Right margins
   8423          * may be overridden depending on layout direction.
   8424          */
   8425         @Override
   8426         public void resolveLayoutDirection(int layoutDirection) {
   8427             setLayoutDirection(layoutDirection);
   8428 
   8429             // No relative margin or pre JB-MR1 case or no need to resolve, just dont do anything
   8430             // Will use the left and right margins if no relative margin is defined.
   8431             if (!isMarginRelative() ||
   8432                     (mMarginFlags & NEED_RESOLUTION_MASK) != NEED_RESOLUTION_MASK) return;
   8433 
   8434             // Proceed with resolution
   8435             doResolveMargins();
   8436         }
   8437 
   8438         private void doResolveMargins() {
   8439             if ((mMarginFlags & RTL_COMPATIBILITY_MODE_MASK) == RTL_COMPATIBILITY_MODE_MASK) {
   8440                 // if left or right margins are not defined and if we have some start or end margin
   8441                 // defined then use those start and end margins.
   8442                 if ((mMarginFlags & LEFT_MARGIN_UNDEFINED_MASK) == LEFT_MARGIN_UNDEFINED_MASK
   8443                         && startMargin > DEFAULT_MARGIN_RELATIVE) {
   8444                     leftMargin = startMargin;
   8445                 }
   8446                 if ((mMarginFlags & RIGHT_MARGIN_UNDEFINED_MASK) == RIGHT_MARGIN_UNDEFINED_MASK
   8447                         && endMargin > DEFAULT_MARGIN_RELATIVE) {
   8448                     rightMargin = endMargin;
   8449                 }
   8450             } else {
   8451                 // We have some relative margins (either the start one or the end one or both). So use
   8452                 // them and override what has been defined for left and right margins. If either start
   8453                 // or end margin is not defined, just set it to default "0".
   8454                 switch(mMarginFlags & LAYOUT_DIRECTION_MASK) {
   8455                     case View.LAYOUT_DIRECTION_RTL:
   8456                         leftMargin = (endMargin > DEFAULT_MARGIN_RELATIVE) ?
   8457                                 endMargin : DEFAULT_MARGIN_RESOLVED;
   8458                         rightMargin = (startMargin > DEFAULT_MARGIN_RELATIVE) ?
   8459                                 startMargin : DEFAULT_MARGIN_RESOLVED;
   8460                         break;
   8461                     case View.LAYOUT_DIRECTION_LTR:
   8462                     default:
   8463                         leftMargin = (startMargin > DEFAULT_MARGIN_RELATIVE) ?
   8464                                 startMargin : DEFAULT_MARGIN_RESOLVED;
   8465                         rightMargin = (endMargin > DEFAULT_MARGIN_RELATIVE) ?
   8466                                 endMargin : DEFAULT_MARGIN_RESOLVED;
   8467                         break;
   8468                 }
   8469             }
   8470             mMarginFlags &= ~NEED_RESOLUTION_MASK;
   8471         }
   8472 
   8473         /**
   8474          * @hide
   8475          */
   8476         public boolean isLayoutRtl() {
   8477             return ((mMarginFlags & LAYOUT_DIRECTION_MASK) == View.LAYOUT_DIRECTION_RTL);
   8478         }
   8479 
   8480         /**
   8481          * @hide
   8482          */
   8483         @Override
   8484         public void onDebugDraw(View view, Canvas canvas, Paint paint) {
   8485             Insets oi = isLayoutModeOptical(view.mParent) ? view.getOpticalInsets() : Insets.NONE;
   8486 
   8487             fillDifference(canvas,
   8488                     view.getLeft()   + oi.left,
   8489                     view.getTop()    + oi.top,
   8490                     view.getRight()  - oi.right,
   8491                     view.getBottom() - oi.bottom,
   8492                     leftMargin,
   8493                     topMargin,
   8494                     rightMargin,
   8495                     bottomMargin,
   8496                     paint);
   8497         }
   8498 
   8499         /** @hide */
   8500         @Override
   8501         protected void encodeProperties(@NonNull ViewHierarchyEncoder encoder) {
   8502             super.encodeProperties(encoder);
   8503             encoder.addProperty("leftMargin", leftMargin);
   8504             encoder.addProperty("topMargin", topMargin);
   8505             encoder.addProperty("rightMargin", rightMargin);
   8506             encoder.addProperty("bottomMargin", bottomMargin);
   8507             encoder.addProperty("startMargin", startMargin);
   8508             encoder.addProperty("endMargin", endMargin);
   8509         }
   8510     }
   8511 
   8512     /* Describes a touched view and the ids of the pointers that it has captured.
   8513      *
   8514      * This code assumes that pointer ids are always in the range 0..31 such that
   8515      * it can use a bitfield to track which pointer ids are present.
   8516      * As it happens, the lower layers of the input dispatch pipeline also use the
   8517      * same trick so the assumption should be safe here...
   8518      */
   8519     private static final class TouchTarget {
   8520         private static final int MAX_RECYCLED = 32;
   8521         private static final Object sRecycleLock = new Object[0];
   8522         private static TouchTarget sRecycleBin;
   8523         private static int sRecycledCount;
   8524 
   8525         public static final int ALL_POINTER_IDS = -1; // all ones
   8526 
   8527         // The touched child view.
   8528         @UnsupportedAppUsage
   8529         public View child;
   8530 
   8531         // The combined bit mask of pointer ids for all pointers captured by the target.
   8532         public int pointerIdBits;
   8533 
   8534         // The next target in the target list.
   8535         public TouchTarget next;
   8536 
   8537         @UnsupportedAppUsage
   8538         private TouchTarget() {
   8539         }
   8540 
   8541         public static TouchTarget obtain(@NonNull View child, int pointerIdBits) {
   8542             if (child == null) {
   8543                 throw new IllegalArgumentException("child must be non-null");
   8544             }
   8545 
   8546             final TouchTarget target;
   8547             synchronized (sRecycleLock) {
   8548                 if (sRecycleBin == null) {
   8549                     target = new TouchTarget();
   8550                 } else {
   8551                     target = sRecycleBin;
   8552                     sRecycleBin = target.next;
   8553                      sRecycledCount--;
   8554                     target.next = null;
   8555                 }
   8556             }
   8557             target.child = child;
   8558             target.pointerIdBits = pointerIdBits;
   8559             return target;
   8560         }
   8561 
   8562         public void recycle() {
   8563             if (child == null) {
   8564                 throw new IllegalStateException("already recycled once");
   8565             }
   8566 
   8567             synchronized (sRecycleLock) {
   8568                 if (sRecycledCount < MAX_RECYCLED) {
   8569                     next = sRecycleBin;
   8570                     sRecycleBin = this;
   8571                     sRecycledCount += 1;
   8572                 } else {
   8573                     next = null;
   8574                 }
   8575                 child = null;
   8576             }
   8577         }
   8578     }
   8579 
   8580     /* Describes a hovered view. */
   8581     private static final class HoverTarget {
   8582         private static final int MAX_RECYCLED = 32;
   8583         private static final Object sRecycleLock = new Object[0];
   8584         private static HoverTarget sRecycleBin;
   8585         private static int sRecycledCount;
   8586 
   8587         // The hovered child view.
   8588         public View child;
   8589 
   8590         // The next target in the target list.
   8591         public HoverTarget next;
   8592 
   8593         private HoverTarget() {
   8594         }
   8595 
   8596         public static HoverTarget obtain(@NonNull View child) {
   8597             if (child == null) {
   8598                 throw new IllegalArgumentException("child must be non-null");
   8599             }
   8600 
   8601             final HoverTarget target;
   8602             synchronized (sRecycleLock) {
   8603                 if (sRecycleBin == null) {
   8604                     target = new HoverTarget();
   8605                 } else {
   8606                     target = sRecycleBin;
   8607                     sRecycleBin = target.next;
   8608                     sRecycledCount--;
   8609                     target.next = null;
   8610                 }
   8611             }
   8612             target.child = child;
   8613             return target;
   8614         }
   8615 
   8616         public void recycle() {
   8617             if (child == null) {
   8618                 throw new IllegalStateException("already recycled once");
   8619             }
   8620 
   8621             synchronized (sRecycleLock) {
   8622                 if (sRecycledCount < MAX_RECYCLED) {
   8623                     next = sRecycleBin;
   8624                     sRecycleBin = this;
   8625                     sRecycledCount += 1;
   8626                 } else {
   8627                     next = null;
   8628                 }
   8629                 child = null;
   8630             }
   8631         }
   8632     }
   8633 
   8634     /**
   8635      * Pooled class that to hold the children for autifill.
   8636      */
   8637     private static class ChildListForAutofill extends ArrayList<View> {
   8638         private static final int MAX_POOL_SIZE = 32;
   8639 
   8640         private static final Pools.SimplePool<ChildListForAutofill> sPool =
   8641                 new Pools.SimplePool<>(MAX_POOL_SIZE);
   8642 
   8643         public static ChildListForAutofill obtain() {
   8644             ChildListForAutofill list = sPool.acquire();
   8645             if (list == null) {
   8646                 list = new ChildListForAutofill();
   8647             }
   8648             return list;
   8649         }
   8650 
   8651         public void recycle() {
   8652             clear();
   8653             sPool.release(this);
   8654         }
   8655     }
   8656 
   8657     /**
   8658      * Pooled class that orderes the children of a ViewGroup from start
   8659      * to end based on how they are laid out and the layout direction.
   8660      */
   8661     static class ChildListForAccessibility {
   8662 
   8663         private static final int MAX_POOL_SIZE = 32;
   8664 
   8665         private static final SynchronizedPool<ChildListForAccessibility> sPool =
   8666                 new SynchronizedPool<ChildListForAccessibility>(MAX_POOL_SIZE);
   8667 
   8668         private final ArrayList<View> mChildren = new ArrayList<View>();
   8669 
   8670         private final ArrayList<ViewLocationHolder> mHolders = new ArrayList<ViewLocationHolder>();
   8671 
   8672         public static ChildListForAccessibility obtain(ViewGroup parent, boolean sort) {
   8673             ChildListForAccessibility list = sPool.acquire();
   8674             if (list == null) {
   8675                 list = new ChildListForAccessibility();
   8676             }
   8677             list.init(parent, sort);
   8678             return list;
   8679         }
   8680 
   8681         public void recycle() {
   8682             clear();
   8683             sPool.release(this);
   8684         }
   8685 
   8686         public int getChildCount() {
   8687             return mChildren.size();
   8688         }
   8689 
   8690         public View getChildAt(int index) {
   8691             return mChildren.get(index);
   8692         }
   8693 
   8694         private void init(ViewGroup parent, boolean sort) {
   8695             ArrayList<View> children = mChildren;
   8696             final int childCount = parent.getChildCount();
   8697             for (int i = 0; i < childCount; i++) {
   8698                 View child = parent.getChildAt(i);
   8699                 children.add(child);
   8700             }
   8701             if (sort) {
   8702                 ArrayList<ViewLocationHolder> holders = mHolders;
   8703                 for (int i = 0; i < childCount; i++) {
   8704                     View child = children.get(i);
   8705                     ViewLocationHolder holder = ViewLocationHolder.obtain(parent, child);
   8706                     holders.add(holder);
   8707                 }
   8708                 sort(holders);
   8709                 for (int i = 0; i < childCount; i++) {
   8710                     ViewLocationHolder holder = holders.get(i);
   8711                     children.set(i, holder.mView);
   8712                     holder.recycle();
   8713                 }
   8714                 holders.clear();
   8715             }
   8716         }
   8717 
   8718         private void sort(ArrayList<ViewLocationHolder> holders) {
   8719             // This is gross but the least risky solution. The current comparison
   8720             // strategy breaks transitivity but produces very good results. Coming
   8721             // up with a new strategy requires time which we do not have, so ...
   8722             try {
   8723                 ViewLocationHolder.setComparisonStrategy(
   8724                         ViewLocationHolder.COMPARISON_STRATEGY_STRIPE);
   8725                 Collections.sort(holders);
   8726             } catch (IllegalArgumentException iae) {
   8727                 // Note that in practice this occurs extremely rarely in a couple
   8728                 // of pathological cases.
   8729                 ViewLocationHolder.setComparisonStrategy(
   8730                         ViewLocationHolder.COMPARISON_STRATEGY_LOCATION);
   8731                 Collections.sort(holders);
   8732             }
   8733         }
   8734 
   8735         private void clear() {
   8736             mChildren.clear();
   8737         }
   8738     }
   8739 
   8740     /**
   8741      * Pooled class that holds a View and its location with respect to
   8742      * a specified root. This enables sorting of views based on their
   8743      * coordinates without recomputing the position relative to the root
   8744      * on every comparison.
   8745      */
   8746     static class ViewLocationHolder implements Comparable<ViewLocationHolder> {
   8747 
   8748         private static final int MAX_POOL_SIZE = 32;
   8749 
   8750         private static final SynchronizedPool<ViewLocationHolder> sPool =
   8751                 new SynchronizedPool<ViewLocationHolder>(MAX_POOL_SIZE);
   8752 
   8753         public static final int COMPARISON_STRATEGY_STRIPE = 1;
   8754 
   8755         public static final int COMPARISON_STRATEGY_LOCATION = 2;
   8756 
   8757         private static int sComparisonStrategy = COMPARISON_STRATEGY_STRIPE;
   8758 
   8759         private final Rect mLocation = new Rect();
   8760 
   8761         private ViewGroup mRoot;
   8762 
   8763         public View mView;
   8764 
   8765         private int mLayoutDirection;
   8766 
   8767         public static ViewLocationHolder obtain(ViewGroup root, View view) {
   8768             ViewLocationHolder holder = sPool.acquire();
   8769             if (holder == null) {
   8770                 holder = new ViewLocationHolder();
   8771             }
   8772             holder.init(root, view);
   8773             return holder;
   8774         }
   8775 
   8776         public static void setComparisonStrategy(int strategy) {
   8777             sComparisonStrategy = strategy;
   8778         }
   8779 
   8780         public void recycle() {
   8781             clear();
   8782             sPool.release(this);
   8783         }
   8784 
   8785         @Override
   8786         public int compareTo(ViewLocationHolder another) {
   8787             // This instance is greater than an invalid argument.
   8788             if (another == null) {
   8789                 return 1;
   8790             }
   8791 
   8792             int boundsResult = compareBoundsOfTree(this, another);
   8793             if (boundsResult != 0) {
   8794                 return boundsResult;
   8795             }
   8796 
   8797             // Just break the tie somehow. The accessibility ids are unique
   8798             // and stable, hence this is deterministic tie breaking.
   8799             return mView.getAccessibilityViewId() - another.mView.getAccessibilityViewId();
   8800         }
   8801 
   8802         /**
   8803          * Compare two views based on their bounds. Use the bounds of their children to break ties.
   8804          *
   8805          * @param holder1 Holder of first view to compare
   8806          * @param holder2 Holder of second view to compare. Must have the same root as holder1.
   8807          * @return The compare result, with equality if no good comparison was found.
   8808          */
   8809         private static int compareBoundsOfTree(
   8810                 ViewLocationHolder holder1, ViewLocationHolder holder2) {
   8811             if (sComparisonStrategy == COMPARISON_STRATEGY_STRIPE) {
   8812                 // First is above second.
   8813                 if (holder1.mLocation.bottom - holder2.mLocation.top <= 0) {
   8814                     return -1;
   8815                 }
   8816                 // First is below second.
   8817                 if (holder1.mLocation.top - holder2.mLocation.bottom >= 0) {
   8818                     return 1;
   8819                 }
   8820             }
   8821 
   8822             // We are ordering left-to-right, top-to-bottom.
   8823             if (holder1.mLayoutDirection == LAYOUT_DIRECTION_LTR) {
   8824                 final int leftDifference = holder1.mLocation.left - holder2.mLocation.left;
   8825                 if (leftDifference != 0) {
   8826                     return leftDifference;
   8827                 }
   8828             } else { // RTL
   8829                 final int rightDifference = holder1.mLocation.right - holder2.mLocation.right;
   8830                 if (rightDifference != 0) {
   8831                     return -rightDifference;
   8832                 }
   8833             }
   8834             // We are ordering left-to-right, top-to-bottom.
   8835             final int topDifference = holder1.mLocation.top - holder2.mLocation.top;
   8836             if (topDifference != 0) {
   8837                 return topDifference;
   8838             }
   8839             // Break tie by height.
   8840             final int heightDiference = holder1.mLocation.height() - holder2.mLocation.height();
   8841             if (heightDiference != 0) {
   8842                 return -heightDiference;
   8843             }
   8844             // Break tie by width.
   8845             final int widthDifference = holder1.mLocation.width() - holder2.mLocation.width();
   8846             if (widthDifference != 0) {
   8847                 return -widthDifference;
   8848             }
   8849 
   8850             // Find a child of each view with different screen bounds.
   8851             final Rect view1Bounds = new Rect();
   8852             final Rect view2Bounds = new Rect();
   8853             final Rect tempRect = new Rect();
   8854             holder1.mView.getBoundsOnScreen(view1Bounds, true);
   8855             holder2.mView.getBoundsOnScreen(view2Bounds, true);
   8856             final View child1 = holder1.mView.findViewByPredicateTraversal((view) -> {
   8857                 view.getBoundsOnScreen(tempRect, true);
   8858                 return !tempRect.equals(view1Bounds);
   8859             }, null);
   8860             final View child2 = holder2.mView.findViewByPredicateTraversal((view) -> {
   8861                 view.getBoundsOnScreen(tempRect, true);
   8862                 return !tempRect.equals(view2Bounds);
   8863             }, null);
   8864 
   8865 
   8866             // Compare the children recursively
   8867             if ((child1 != null) && (child2 != null)) {
   8868                 final ViewLocationHolder childHolder1 =
   8869                         ViewLocationHolder.obtain(holder1.mRoot, child1);
   8870                 final ViewLocationHolder childHolder2 =
   8871                         ViewLocationHolder.obtain(holder1.mRoot, child2);
   8872                 return compareBoundsOfTree(childHolder1, childHolder2);
   8873             }
   8874 
   8875             // If only one has a child, use that one
   8876             if (child1 != null) {
   8877                 return 1;
   8878             }
   8879 
   8880             if (child2 != null) {
   8881                 return -1;
   8882             }
   8883 
   8884             // Give up
   8885             return 0;
   8886         }
   8887 
   8888         private void init(ViewGroup root, View view) {
   8889             Rect viewLocation = mLocation;
   8890             view.getDrawingRect(viewLocation);
   8891             root.offsetDescendantRectToMyCoords(view, viewLocation);
   8892             mView = view;
   8893             mRoot = root;
   8894             mLayoutDirection = root.getLayoutDirection();
   8895         }
   8896 
   8897         private void clear() {
   8898             mView = null;
   8899             mRoot = null;
   8900             mLocation.set(0, 0, 0, 0);
   8901         }
   8902     }
   8903 
   8904     private static void drawRect(Canvas canvas, Paint paint, int x1, int y1, int x2, int y2) {
   8905         if (sDebugLines== null) {
   8906             // TODO: This won't work with multiple UI threads in a single process
   8907             sDebugLines = new float[16];
   8908         }
   8909 
   8910         sDebugLines[0] = x1;
   8911         sDebugLines[1] = y1;
   8912         sDebugLines[2] = x2;
   8913         sDebugLines[3] = y1;
   8914 
   8915         sDebugLines[4] = x2;
   8916         sDebugLines[5] = y1;
   8917         sDebugLines[6] = x2;
   8918         sDebugLines[7] = y2;
   8919 
   8920         sDebugLines[8] = x2;
   8921         sDebugLines[9] = y2;
   8922         sDebugLines[10] = x1;
   8923         sDebugLines[11] = y2;
   8924 
   8925         sDebugLines[12] = x1;
   8926         sDebugLines[13] = y2;
   8927         sDebugLines[14] = x1;
   8928         sDebugLines[15] = y1;
   8929 
   8930         canvas.drawLines(sDebugLines, paint);
   8931     }
   8932 
   8933     /** @hide */
   8934     @Override
   8935     @UnsupportedAppUsage
   8936     protected void encodeProperties(@NonNull ViewHierarchyEncoder encoder) {
   8937         super.encodeProperties(encoder);
   8938 
   8939         encoder.addProperty("focus:descendantFocusability", getDescendantFocusability());
   8940         encoder.addProperty("drawing:clipChildren", getClipChildren());
   8941         encoder.addProperty("drawing:clipToPadding", getClipToPadding());
   8942         encoder.addProperty("drawing:childrenDrawingOrderEnabled", isChildrenDrawingOrderEnabled());
   8943         encoder.addProperty("drawing:persistentDrawingCache", getPersistentDrawingCache());
   8944 
   8945         int n = getChildCount();
   8946         encoder.addProperty("meta:__childCount__", (short)n);
   8947         for (int i = 0; i < n; i++) {
   8948             encoder.addPropertyKey("meta:__child__" + i);
   8949             getChildAt(i).encode(encoder);
   8950         }
   8951     }
   8952 }
   8953