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