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