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