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