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