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