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