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