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