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 com.android.internal.R;
     20 
     21 import android.content.Context;
     22 import android.content.res.Configuration;
     23 import android.content.res.TypedArray;
     24 import android.graphics.Bitmap;
     25 import android.graphics.Canvas;
     26 import android.graphics.Paint;
     27 import android.graphics.Rect;
     28 import android.graphics.RectF;
     29 import android.graphics.Region;
     30 import android.os.Parcelable;
     31 import android.os.SystemClock;
     32 import android.util.AttributeSet;
     33 import android.util.Config;
     34 import android.util.EventLog;
     35 import android.util.Log;
     36 import android.util.SparseArray;
     37 import android.view.accessibility.AccessibilityEvent;
     38 import android.view.animation.Animation;
     39 import android.view.animation.AnimationUtils;
     40 import android.view.animation.LayoutAnimationController;
     41 import android.view.animation.Transformation;
     42 
     43 import java.util.ArrayList;
     44 
     45 /**
     46  * <p>
     47  * A <code>ViewGroup</code> is a special view that can contain other views
     48  * (called children.) The view group is the base class for layouts and views
     49  * containers. This class also defines the
     50  * {@link android.view.ViewGroup.LayoutParams} class which serves as the base
     51  * class for layouts parameters.
     52  * </p>
     53  *
     54  * <p>
     55  * Also see {@link LayoutParams} for layout attributes.
     56  * </p>
     57  *
     58  * @attr ref android.R.styleable#ViewGroup_clipChildren
     59  * @attr ref android.R.styleable#ViewGroup_clipToPadding
     60  * @attr ref android.R.styleable#ViewGroup_layoutAnimation
     61  * @attr ref android.R.styleable#ViewGroup_animationCache
     62  * @attr ref android.R.styleable#ViewGroup_persistentDrawingCache
     63  * @attr ref android.R.styleable#ViewGroup_alwaysDrawnWithCache
     64  * @attr ref android.R.styleable#ViewGroup_addStatesFromChildren
     65  * @attr ref android.R.styleable#ViewGroup_descendantFocusability
     66  */
     67 public abstract class ViewGroup extends View implements ViewParent, ViewManager {
     68     private static final boolean DBG = false;
     69 
     70     /**
     71      * Views which have been hidden or removed which need to be animated on
     72      * their way out.
     73      * This field should be made private, so it is hidden from the SDK.
     74      * {@hide}
     75      */
     76     protected ArrayList<View> mDisappearingChildren;
     77 
     78     /**
     79      * Listener used to propagate events indicating when children are added
     80      * and/or removed from a view group.
     81      * This field should be made private, so it is hidden from the SDK.
     82      * {@hide}
     83      */
     84     protected OnHierarchyChangeListener mOnHierarchyChangeListener;
     85 
     86     // The view contained within this ViewGroup that has or contains focus.
     87     private View mFocused;
     88 
     89     // The current transformation to apply on the child being drawn
     90     private Transformation mChildTransformation;
     91     private RectF mInvalidateRegion;
     92 
     93     // Target of Motion events
     94     private View mMotionTarget;
     95     private final Rect mTempRect = new Rect();
     96 
     97     // Layout animation
     98     private LayoutAnimationController mLayoutAnimationController;
     99     private Animation.AnimationListener mAnimationListener;
    100 
    101     /**
    102      * Internal flags.
    103      *
    104      * This field should be made private, so it is hidden from the SDK.
    105      * {@hide}
    106      */
    107     protected int mGroupFlags;
    108 
    109     // When set, ViewGroup invalidates only the child's rectangle
    110     // Set by default
    111     private static final int FLAG_CLIP_CHILDREN = 0x1;
    112 
    113     // When set, ViewGroup excludes the padding area from the invalidate rectangle
    114     // Set by default
    115     private static final int FLAG_CLIP_TO_PADDING = 0x2;
    116 
    117     // When set, dispatchDraw() will invoke invalidate(); this is set by drawChild() when
    118     // a child needs to be invalidated and FLAG_OPTIMIZE_INVALIDATE is set
    119     private static final int FLAG_INVALIDATE_REQUIRED  = 0x4;
    120 
    121     // When set, dispatchDraw() will run the layout animation and unset the flag
    122     private static final int FLAG_RUN_ANIMATION = 0x8;
    123 
    124     // When set, there is either no layout animation on the ViewGroup or the layout
    125     // animation is over
    126     // Set by default
    127     private static final int FLAG_ANIMATION_DONE = 0x10;
    128 
    129     // If set, this ViewGroup has padding; if unset there is no padding and we don't need
    130     // to clip it, even if FLAG_CLIP_TO_PADDING is set
    131     private static final int FLAG_PADDING_NOT_NULL = 0x20;
    132 
    133     // When set, this ViewGroup caches its children in a Bitmap before starting a layout animation
    134     // Set by default
    135     private static final int FLAG_ANIMATION_CACHE = 0x40;
    136 
    137     // When set, this ViewGroup converts calls to invalidate(Rect) to invalidate() during a
    138     // layout animation; this avoid clobbering the hierarchy
    139     // Automatically set when the layout animation starts, depending on the animation's
    140     // characteristics
    141     private static final int FLAG_OPTIMIZE_INVALIDATE = 0x80;
    142 
    143     // When set, the next call to drawChild() will clear mChildTransformation's matrix
    144     private static final int FLAG_CLEAR_TRANSFORMATION = 0x100;
    145 
    146     // When set, this ViewGroup invokes mAnimationListener.onAnimationEnd() and removes
    147     // the children's Bitmap caches if necessary
    148     // This flag is set when the layout animation is over (after FLAG_ANIMATION_DONE is set)
    149     private static final int FLAG_NOTIFY_ANIMATION_LISTENER = 0x200;
    150 
    151     /**
    152      * When set, the drawing method will call {@link #getChildDrawingOrder(int, int)}
    153      * to get the index of the child to draw for that iteration.
    154      *
    155      * @hide
    156      */
    157     protected static final int FLAG_USE_CHILD_DRAWING_ORDER = 0x400;
    158 
    159     /**
    160      * When set, this ViewGroup supports static transformations on children; this causes
    161      * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} to be
    162      * invoked when a child is drawn.
    163      *
    164      * Any subclass overriding
    165      * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} should
    166      * set this flags in {@link #mGroupFlags}.
    167      *
    168      * {@hide}
    169      */
    170     protected static final int FLAG_SUPPORT_STATIC_TRANSFORMATIONS = 0x800;
    171 
    172     // When the previous drawChild() invocation used an alpha value that was lower than
    173     // 1.0 and set it in mCachePaint
    174     private static final int FLAG_ALPHA_LOWER_THAN_ONE = 0x1000;
    175 
    176     /**
    177      * When set, this ViewGroup's drawable states also include those
    178      * of its children.
    179      */
    180     private static final int FLAG_ADD_STATES_FROM_CHILDREN = 0x2000;
    181 
    182     /**
    183      * When set, this ViewGroup tries to always draw its children using their drawing cache.
    184      */
    185     private static final int FLAG_ALWAYS_DRAWN_WITH_CACHE = 0x4000;
    186 
    187     /**
    188      * When set, and if FLAG_ALWAYS_DRAWN_WITH_CACHE is not set, this ViewGroup will try to
    189      * draw its children with their drawing cache.
    190      */
    191     private static final int FLAG_CHILDREN_DRAWN_WITH_CACHE = 0x8000;
    192 
    193     /**
    194      * When set, this group will go through its list of children to notify them of
    195      * any drawable state change.
    196      */
    197     private static final int FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE = 0x10000;
    198 
    199     private static final int FLAG_MASK_FOCUSABILITY = 0x60000;
    200 
    201     /**
    202      * This view will get focus before any of its descendants.
    203      */
    204     public static final int FOCUS_BEFORE_DESCENDANTS = 0x20000;
    205 
    206     /**
    207      * This view will get focus only if none of its descendants want it.
    208      */
    209     public static final int FOCUS_AFTER_DESCENDANTS = 0x40000;
    210 
    211     /**
    212      * This view will block any of its descendants from getting focus, even
    213      * if they are focusable.
    214      */
    215     public static final int FOCUS_BLOCK_DESCENDANTS = 0x60000;
    216 
    217     /**
    218      * Used to map between enum in attrubutes and flag values.
    219      */
    220     private static final int[] DESCENDANT_FOCUSABILITY_FLAGS =
    221             {FOCUS_BEFORE_DESCENDANTS, FOCUS_AFTER_DESCENDANTS,
    222                     FOCUS_BLOCK_DESCENDANTS};
    223 
    224     /**
    225      * When set, this ViewGroup should not intercept touch events.
    226      */
    227     private static final int FLAG_DISALLOW_INTERCEPT = 0x80000;
    228 
    229     /**
    230      * Indicates which types of drawing caches are to be kept in memory.
    231      * This field should be made private, so it is hidden from the SDK.
    232      * {@hide}
    233      */
    234     protected int mPersistentDrawingCache;
    235 
    236     /**
    237      * Used to indicate that no drawing cache should be kept in memory.
    238      */
    239     public static final int PERSISTENT_NO_CACHE = 0x0;
    240 
    241     /**
    242      * Used to indicate that the animation drawing cache should be kept in memory.
    243      */
    244     public static final int PERSISTENT_ANIMATION_CACHE = 0x1;
    245 
    246     /**
    247      * Used to indicate that the scrolling drawing cache should be kept in memory.
    248      */
    249     public static final int PERSISTENT_SCROLLING_CACHE = 0x2;
    250 
    251     /**
    252      * Used to indicate that all drawing caches should be kept in memory.
    253      */
    254     public static final int PERSISTENT_ALL_CACHES = 0x3;
    255 
    256     /**
    257      * We clip to padding when FLAG_CLIP_TO_PADDING and FLAG_PADDING_NOT_NULL
    258      * are set at the same time.
    259      */
    260     protected static final int CLIP_TO_PADDING_MASK = FLAG_CLIP_TO_PADDING | FLAG_PADDING_NOT_NULL;
    261 
    262     // Index of the child's left position in the mLocation array
    263     private static final int CHILD_LEFT_INDEX = 0;
    264     // Index of the child's top position in the mLocation array
    265     private static final int CHILD_TOP_INDEX = 1;
    266 
    267     // Child views of this ViewGroup
    268     private View[] mChildren;
    269     // Number of valid children in the mChildren array, the rest should be null or not
    270     // considered as children
    271     private int mChildrenCount;
    272 
    273     private static final int ARRAY_INITIAL_CAPACITY = 12;
    274     private static final int ARRAY_CAPACITY_INCREMENT = 12;
    275 
    276     // Used to draw cached views
    277     private final Paint mCachePaint = new Paint();
    278 
    279     public ViewGroup(Context context) {
    280         super(context);
    281         initViewGroup();
    282     }
    283 
    284     public ViewGroup(Context context, AttributeSet attrs) {
    285         super(context, attrs);
    286         initViewGroup();
    287         initFromAttributes(context, attrs);
    288     }
    289 
    290     public ViewGroup(Context context, AttributeSet attrs, int defStyle) {
    291         super(context, attrs, defStyle);
    292         initViewGroup();
    293         initFromAttributes(context, attrs);
    294     }
    295 
    296     private void initViewGroup() {
    297         // ViewGroup doesn't draw by default
    298         setFlags(WILL_NOT_DRAW, DRAW_MASK);
    299         mGroupFlags |= FLAG_CLIP_CHILDREN;
    300         mGroupFlags |= FLAG_CLIP_TO_PADDING;
    301         mGroupFlags |= FLAG_ANIMATION_DONE;
    302         mGroupFlags |= FLAG_ANIMATION_CACHE;
    303         mGroupFlags |= FLAG_ALWAYS_DRAWN_WITH_CACHE;
    304 
    305         setDescendantFocusability(FOCUS_BEFORE_DESCENDANTS);
    306 
    307         mChildren = new View[ARRAY_INITIAL_CAPACITY];
    308         mChildrenCount = 0;
    309 
    310         mCachePaint.setDither(false);
    311 
    312         mPersistentDrawingCache = PERSISTENT_SCROLLING_CACHE;
    313     }
    314 
    315     private void initFromAttributes(Context context, AttributeSet attrs) {
    316         TypedArray a = context.obtainStyledAttributes(attrs,
    317                 R.styleable.ViewGroup);
    318 
    319         final int N = a.getIndexCount();
    320         for (int i = 0; i < N; i++) {
    321             int attr = a.getIndex(i);
    322             switch (attr) {
    323                 case R.styleable.ViewGroup_clipChildren:
    324                     setClipChildren(a.getBoolean(attr, true));
    325                     break;
    326                 case R.styleable.ViewGroup_clipToPadding:
    327                     setClipToPadding(a.getBoolean(attr, true));
    328                     break;
    329                 case R.styleable.ViewGroup_animationCache:
    330                     setAnimationCacheEnabled(a.getBoolean(attr, true));
    331                     break;
    332                 case R.styleable.ViewGroup_persistentDrawingCache:
    333                     setPersistentDrawingCache(a.getInt(attr, PERSISTENT_SCROLLING_CACHE));
    334                     break;
    335                 case R.styleable.ViewGroup_addStatesFromChildren:
    336                     setAddStatesFromChildren(a.getBoolean(attr, false));
    337                     break;
    338                 case R.styleable.ViewGroup_alwaysDrawnWithCache:
    339                     setAlwaysDrawnWithCacheEnabled(a.getBoolean(attr, true));
    340                     break;
    341                 case R.styleable.ViewGroup_layoutAnimation:
    342                     int id = a.getResourceId(attr, -1);
    343                     if (id > 0) {
    344                         setLayoutAnimation(AnimationUtils.loadLayoutAnimation(mContext, id));
    345                     }
    346                     break;
    347                 case R.styleable.ViewGroup_descendantFocusability:
    348                     setDescendantFocusability(DESCENDANT_FOCUSABILITY_FLAGS[a.getInt(attr, 0)]);
    349                     break;
    350             }
    351         }
    352 
    353         a.recycle();
    354     }
    355 
    356     /**
    357      * Gets the descendant focusability of this view group.  The descendant
    358      * focusability defines the relationship between this view group and its
    359      * descendants when looking for a view to take focus in
    360      * {@link #requestFocus(int, android.graphics.Rect)}.
    361      *
    362      * @return one of {@link #FOCUS_BEFORE_DESCENDANTS}, {@link #FOCUS_AFTER_DESCENDANTS},
    363      *   {@link #FOCUS_BLOCK_DESCENDANTS}.
    364      */
    365     @ViewDebug.ExportedProperty(mapping = {
    366         @ViewDebug.IntToString(from = FOCUS_BEFORE_DESCENDANTS, to = "FOCUS_BEFORE_DESCENDANTS"),
    367         @ViewDebug.IntToString(from = FOCUS_AFTER_DESCENDANTS, to = "FOCUS_AFTER_DESCENDANTS"),
    368         @ViewDebug.IntToString(from = FOCUS_BLOCK_DESCENDANTS, to = "FOCUS_BLOCK_DESCENDANTS")
    369     })
    370     public int getDescendantFocusability() {
    371         return mGroupFlags & FLAG_MASK_FOCUSABILITY;
    372     }
    373 
    374     /**
    375      * Set the descendant focusability of this view group. This defines the relationship
    376      * between this view group and its descendants when looking for a view to
    377      * take focus in {@link #requestFocus(int, android.graphics.Rect)}.
    378      *
    379      * @param focusability one of {@link #FOCUS_BEFORE_DESCENDANTS}, {@link #FOCUS_AFTER_DESCENDANTS},
    380      *   {@link #FOCUS_BLOCK_DESCENDANTS}.
    381      */
    382     public void setDescendantFocusability(int focusability) {
    383         switch (focusability) {
    384             case FOCUS_BEFORE_DESCENDANTS:
    385             case FOCUS_AFTER_DESCENDANTS:
    386             case FOCUS_BLOCK_DESCENDANTS:
    387                 break;
    388             default:
    389                 throw new IllegalArgumentException("must be one of FOCUS_BEFORE_DESCENDANTS, "
    390                         + "FOCUS_AFTER_DESCENDANTS, FOCUS_BLOCK_DESCENDANTS");
    391         }
    392         mGroupFlags &= ~FLAG_MASK_FOCUSABILITY;
    393         mGroupFlags |= (focusability & FLAG_MASK_FOCUSABILITY);
    394     }
    395 
    396     /**
    397      * {@inheritDoc}
    398      */
    399     @Override
    400     void handleFocusGainInternal(int direction, Rect previouslyFocusedRect) {
    401         if (mFocused != null) {
    402             mFocused.unFocus();
    403             mFocused = null;
    404         }
    405         super.handleFocusGainInternal(direction, previouslyFocusedRect);
    406     }
    407 
    408     /**
    409      * {@inheritDoc}
    410      */
    411     public void requestChildFocus(View child, View focused) {
    412         if (DBG) {
    413             System.out.println(this + " requestChildFocus()");
    414         }
    415         if (getDescendantFocusability() == FOCUS_BLOCK_DESCENDANTS) {
    416             return;
    417         }
    418 
    419         // Unfocus us, if necessary
    420         super.unFocus();
    421 
    422         // We had a previous notion of who had focus. Clear it.
    423         if (mFocused != child) {
    424             if (mFocused != null) {
    425                 mFocused.unFocus();
    426             }
    427 
    428             mFocused = child;
    429         }
    430         if (mParent != null) {
    431             mParent.requestChildFocus(this, focused);
    432         }
    433     }
    434 
    435     /**
    436      * {@inheritDoc}
    437      */
    438     public void focusableViewAvailable(View v) {
    439         if (mParent != null
    440                 // shortcut: don't report a new focusable view if we block our descendants from
    441                 // getting focus
    442                 && (getDescendantFocusability() != FOCUS_BLOCK_DESCENDANTS)
    443                 // shortcut: don't report a new focusable view if we already are focused
    444                 // (and we don't prefer our descendants)
    445                 //
    446                 // note: knowing that mFocused is non-null is not a good enough reason
    447                 // to break the traversal since in that case we'd actually have to find
    448                 // the focused view and make sure it wasn't FOCUS_AFTER_DESCENDANTS and
    449                 // an ancestor of v; this will get checked for at ViewRoot
    450                 && !(isFocused() && getDescendantFocusability() != FOCUS_AFTER_DESCENDANTS)) {
    451             mParent.focusableViewAvailable(v);
    452         }
    453     }
    454 
    455     /**
    456      * {@inheritDoc}
    457      */
    458     public boolean showContextMenuForChild(View originalView) {
    459         return mParent != null && mParent.showContextMenuForChild(originalView);
    460     }
    461 
    462     /**
    463      * Find the nearest view in the specified direction that wants to take
    464      * focus.
    465      *
    466      * @param focused The view that currently has focus
    467      * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and
    468      *        FOCUS_RIGHT, or 0 for not applicable.
    469      */
    470     public View focusSearch(View focused, int direction) {
    471         if (isRootNamespace()) {
    472             // root namespace means we should consider ourselves the top of the
    473             // tree for focus searching; otherwise we could be focus searching
    474             // into other tabs.  see LocalActivityManager and TabHost for more info
    475             return FocusFinder.getInstance().findNextFocus(this, focused, direction);
    476         } else if (mParent != null) {
    477             return mParent.focusSearch(focused, direction);
    478         }
    479         return null;
    480     }
    481 
    482     /**
    483      * {@inheritDoc}
    484      */
    485     public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
    486         return false;
    487     }
    488 
    489     /**
    490      * {@inheritDoc}
    491      */
    492     @Override
    493     public boolean dispatchUnhandledMove(View focused, int direction) {
    494         return mFocused != null &&
    495                 mFocused.dispatchUnhandledMove(focused, direction);
    496     }
    497 
    498     /**
    499      * {@inheritDoc}
    500      */
    501     public void clearChildFocus(View child) {
    502         if (DBG) {
    503             System.out.println(this + " clearChildFocus()");
    504         }
    505 
    506         mFocused = null;
    507         if (mParent != null) {
    508             mParent.clearChildFocus(this);
    509         }
    510     }
    511 
    512     /**
    513      * {@inheritDoc}
    514      */
    515     @Override
    516     public void clearFocus() {
    517         super.clearFocus();
    518 
    519         // clear any child focus if it exists
    520         if (mFocused != null) {
    521             mFocused.clearFocus();
    522         }
    523     }
    524 
    525     /**
    526      * {@inheritDoc}
    527      */
    528     @Override
    529     void unFocus() {
    530         if (DBG) {
    531             System.out.println(this + " unFocus()");
    532         }
    533 
    534         super.unFocus();
    535         if (mFocused != null) {
    536             mFocused.unFocus();
    537         }
    538         mFocused = null;
    539     }
    540 
    541     /**
    542      * Returns the focused child of this view, if any. The child may have focus
    543      * or contain focus.
    544      *
    545      * @return the focused child or null.
    546      */
    547     public View getFocusedChild() {
    548         return mFocused;
    549     }
    550 
    551     /**
    552      * Returns true if this view has or contains focus
    553      *
    554      * @return true if this view has or contains focus
    555      */
    556     @Override
    557     public boolean hasFocus() {
    558         return (mPrivateFlags & FOCUSED) != 0 || mFocused != null;
    559     }
    560 
    561     /*
    562      * (non-Javadoc)
    563      *
    564      * @see android.view.View#findFocus()
    565      */
    566     @Override
    567     public View findFocus() {
    568         if (DBG) {
    569             System.out.println("Find focus in " + this + ": flags="
    570                     + isFocused() + ", child=" + mFocused);
    571         }
    572 
    573         if (isFocused()) {
    574             return this;
    575         }
    576 
    577         if (mFocused != null) {
    578             return mFocused.findFocus();
    579         }
    580         return null;
    581     }
    582 
    583     /**
    584      * {@inheritDoc}
    585      */
    586     @Override
    587     public boolean hasFocusable() {
    588         if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) {
    589             return false;
    590         }
    591 
    592         if (isFocusable()) {
    593             return true;
    594         }
    595 
    596         final int descendantFocusability = getDescendantFocusability();
    597         if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS) {
    598             final int count = mChildrenCount;
    599             final View[] children = mChildren;
    600 
    601             for (int i = 0; i < count; i++) {
    602                 final View child = children[i];
    603                 if (child.hasFocusable()) {
    604                     return true;
    605                 }
    606             }
    607         }
    608 
    609         return false;
    610     }
    611 
    612     /**
    613      * {@inheritDoc}
    614      */
    615     @Override
    616     public void addFocusables(ArrayList<View> views, int direction) {
    617         addFocusables(views, direction, FOCUSABLES_TOUCH_MODE);
    618     }
    619 
    620     /**
    621      * {@inheritDoc}
    622      */
    623     @Override
    624     public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
    625         final int focusableCount = views.size();
    626 
    627         final int descendantFocusability = getDescendantFocusability();
    628 
    629         if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS) {
    630             final int count = mChildrenCount;
    631             final View[] children = mChildren;
    632 
    633             for (int i = 0; i < count; i++) {
    634                 final View child = children[i];
    635                 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
    636                     child.addFocusables(views, direction, focusableMode);
    637                 }
    638             }
    639         }
    640 
    641         // we add ourselves (if focusable) in all cases except for when we are
    642         // FOCUS_AFTER_DESCENDANTS and there are some descendants focusable.  this is
    643         // to avoid the focus search finding layouts when a more precise search
    644         // among the focusable children would be more interesting.
    645         if (
    646             descendantFocusability != FOCUS_AFTER_DESCENDANTS ||
    647                 // No focusable descendants
    648                 (focusableCount == views.size())) {
    649             super.addFocusables(views, direction, focusableMode);
    650         }
    651     }
    652 
    653     /**
    654      * {@inheritDoc}
    655      */
    656     @Override
    657     public void dispatchWindowFocusChanged(boolean hasFocus) {
    658         super.dispatchWindowFocusChanged(hasFocus);
    659         final int count = mChildrenCount;
    660         final View[] children = mChildren;
    661         for (int i = 0; i < count; i++) {
    662             children[i].dispatchWindowFocusChanged(hasFocus);
    663         }
    664     }
    665 
    666     /**
    667      * {@inheritDoc}
    668      */
    669     @Override
    670     public void addTouchables(ArrayList<View> views) {
    671         super.addTouchables(views);
    672 
    673         final int count = mChildrenCount;
    674         final View[] children = mChildren;
    675 
    676         for (int i = 0; i < count; i++) {
    677             final View child = children[i];
    678             if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
    679                 child.addTouchables(views);
    680             }
    681         }
    682     }
    683 
    684     /**
    685      * {@inheritDoc}
    686      */
    687     @Override
    688     public void dispatchDisplayHint(int hint) {
    689         super.dispatchDisplayHint(hint);
    690         final int count = mChildrenCount;
    691         final View[] children = mChildren;
    692         for (int i = 0; i < count; i++) {
    693             children[i].dispatchDisplayHint(hint);
    694         }
    695     }
    696 
    697     /**
    698      * {@inheritDoc}
    699      */
    700     @Override
    701     protected void dispatchVisibilityChanged(View changedView, int visibility) {
    702         super.dispatchVisibilityChanged(changedView, visibility);
    703         final int count = mChildrenCount;
    704         final View[] children = mChildren;
    705         for (int i = 0; i < count; i++) {
    706             children[i].dispatchVisibilityChanged(changedView, visibility);
    707         }
    708     }
    709 
    710     /**
    711      * {@inheritDoc}
    712      */
    713     @Override
    714     public void dispatchWindowVisibilityChanged(int visibility) {
    715         super.dispatchWindowVisibilityChanged(visibility);
    716         final int count = mChildrenCount;
    717         final View[] children = mChildren;
    718         for (int i = 0; i < count; i++) {
    719             children[i].dispatchWindowVisibilityChanged(visibility);
    720         }
    721     }
    722 
    723     /**
    724      * {@inheritDoc}
    725      */
    726     @Override
    727     public void dispatchConfigurationChanged(Configuration newConfig) {
    728         super.dispatchConfigurationChanged(newConfig);
    729         final int count = mChildrenCount;
    730         final View[] children = mChildren;
    731         for (int i = 0; i < count; i++) {
    732             children[i].dispatchConfigurationChanged(newConfig);
    733         }
    734     }
    735 
    736     /**
    737      * {@inheritDoc}
    738      */
    739     public void recomputeViewAttributes(View child) {
    740         ViewParent parent = mParent;
    741         if (parent != null) parent.recomputeViewAttributes(this);
    742     }
    743 
    744     @Override
    745     void dispatchCollectViewAttributes(int visibility) {
    746         visibility |= mViewFlags&VISIBILITY_MASK;
    747         super.dispatchCollectViewAttributes(visibility);
    748         final int count = mChildrenCount;
    749         final View[] children = mChildren;
    750         for (int i = 0; i < count; i++) {
    751             children[i].dispatchCollectViewAttributes(visibility);
    752         }
    753     }
    754 
    755     /**
    756      * {@inheritDoc}
    757      */
    758     public void bringChildToFront(View child) {
    759         int index = indexOfChild(child);
    760         if (index >= 0) {
    761             removeFromArray(index);
    762             addInArray(child, mChildrenCount);
    763             child.mParent = this;
    764         }
    765     }
    766 
    767     /**
    768      * {@inheritDoc}
    769      */
    770     @Override
    771     public boolean dispatchKeyEventPreIme(KeyEvent event) {
    772         if ((mPrivateFlags & (FOCUSED | HAS_BOUNDS)) == (FOCUSED | HAS_BOUNDS)) {
    773             return super.dispatchKeyEventPreIme(event);
    774         } else if (mFocused != null && (mFocused.mPrivateFlags & HAS_BOUNDS) == HAS_BOUNDS) {
    775             return mFocused.dispatchKeyEventPreIme(event);
    776         }
    777         return false;
    778     }
    779 
    780     /**
    781      * {@inheritDoc}
    782      */
    783     @Override
    784     public boolean dispatchKeyEvent(KeyEvent event) {
    785         if ((mPrivateFlags & (FOCUSED | HAS_BOUNDS)) == (FOCUSED | HAS_BOUNDS)) {
    786             return super.dispatchKeyEvent(event);
    787         } else if (mFocused != null && (mFocused.mPrivateFlags & HAS_BOUNDS) == HAS_BOUNDS) {
    788             return mFocused.dispatchKeyEvent(event);
    789         }
    790         return false;
    791     }
    792 
    793     /**
    794      * {@inheritDoc}
    795      */
    796     @Override
    797     public boolean dispatchKeyShortcutEvent(KeyEvent event) {
    798         if ((mPrivateFlags & (FOCUSED | HAS_BOUNDS)) == (FOCUSED | HAS_BOUNDS)) {
    799             return super.dispatchKeyShortcutEvent(event);
    800         } else if (mFocused != null && (mFocused.mPrivateFlags & HAS_BOUNDS) == HAS_BOUNDS) {
    801             return mFocused.dispatchKeyShortcutEvent(event);
    802         }
    803         return false;
    804     }
    805 
    806     /**
    807      * {@inheritDoc}
    808      */
    809     @Override
    810     public boolean dispatchTrackballEvent(MotionEvent event) {
    811         if ((mPrivateFlags & (FOCUSED | HAS_BOUNDS)) == (FOCUSED | HAS_BOUNDS)) {
    812             return super.dispatchTrackballEvent(event);
    813         } else if (mFocused != null && (mFocused.mPrivateFlags & HAS_BOUNDS) == HAS_BOUNDS) {
    814             return mFocused.dispatchTrackballEvent(event);
    815         }
    816         return false;
    817     }
    818 
    819     /**
    820      * {@inheritDoc}
    821      */
    822     @Override
    823     public boolean dispatchTouchEvent(MotionEvent ev) {
    824         final int action = ev.getAction();
    825         final float xf = ev.getX();
    826         final float yf = ev.getY();
    827         final float scrolledXFloat = xf + mScrollX;
    828         final float scrolledYFloat = yf + mScrollY;
    829         final Rect frame = mTempRect;
    830 
    831         boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
    832 
    833         if (action == MotionEvent.ACTION_DOWN) {
    834             if (mMotionTarget != null) {
    835                 // this is weird, we got a pen down, but we thought it was
    836                 // already down!
    837                 // XXX: We should probably send an ACTION_UP to the current
    838                 // target.
    839                 mMotionTarget = null;
    840             }
    841             // If we're disallowing intercept or if we're allowing and we didn't
    842             // intercept
    843             if (disallowIntercept || !onInterceptTouchEvent(ev)) {
    844                 // reset this event's action (just to protect ourselves)
    845                 ev.setAction(MotionEvent.ACTION_DOWN);
    846                 // We know we want to dispatch the event down, find a child
    847                 // who can handle it, start with the front-most child.
    848                 final int scrolledXInt = (int) scrolledXFloat;
    849                 final int scrolledYInt = (int) scrolledYFloat;
    850                 final View[] children = mChildren;
    851                 final int count = mChildrenCount;
    852                 for (int i = count - 1; i >= 0; i--) {
    853                     final View child = children[i];
    854                     if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE
    855                             || child.getAnimation() != null) {
    856                         child.getHitRect(frame);
    857                         if (frame.contains(scrolledXInt, scrolledYInt)) {
    858                             // offset the event to the view's coordinate system
    859                             final float xc = scrolledXFloat - child.mLeft;
    860                             final float yc = scrolledYFloat - child.mTop;
    861                             ev.setLocation(xc, yc);
    862                             child.mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT;
    863                             if (child.dispatchTouchEvent(ev))  {
    864                                 // Event handled, we have a target now.
    865                                 mMotionTarget = child;
    866                                 return true;
    867                             }
    868                             // The event didn't get handled, try the next view.
    869                             // Don't reset the event's location, it's not
    870                             // necessary here.
    871                         }
    872                     }
    873                 }
    874             }
    875         }
    876 
    877         boolean isUpOrCancel = (action == MotionEvent.ACTION_UP) ||
    878                 (action == MotionEvent.ACTION_CANCEL);
    879 
    880         if (isUpOrCancel) {
    881             // Note, we've already copied the previous state to our local
    882             // variable, so this takes effect on the next event
    883             mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
    884         }
    885 
    886         // The event wasn't an ACTION_DOWN, dispatch it to our target if
    887         // we have one.
    888         final View target = mMotionTarget;
    889         if (target == null) {
    890             // We don't have a target, this means we're handling the
    891             // event as a regular view.
    892             ev.setLocation(xf, yf);
    893             if ((mPrivateFlags & CANCEL_NEXT_UP_EVENT) != 0) {
    894                 ev.setAction(MotionEvent.ACTION_CANCEL);
    895                 mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT;
    896             }
    897             return super.dispatchTouchEvent(ev);
    898         }
    899 
    900         // if have a target, see if we're allowed to and want to intercept its
    901         // events
    902         if (!disallowIntercept && onInterceptTouchEvent(ev)) {
    903             final float xc = scrolledXFloat - (float) target.mLeft;
    904             final float yc = scrolledYFloat - (float) target.mTop;
    905             mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT;
    906             ev.setAction(MotionEvent.ACTION_CANCEL);
    907             ev.setLocation(xc, yc);
    908             if (!target.dispatchTouchEvent(ev)) {
    909                 // target didn't handle ACTION_CANCEL. not much we can do
    910                 // but they should have.
    911             }
    912             // clear the target
    913             mMotionTarget = null;
    914             // Don't dispatch this event to our own view, because we already
    915             // saw it when intercepting; we just want to give the following
    916             // event to the normal onTouchEvent().
    917             return true;
    918         }
    919 
    920         if (isUpOrCancel) {
    921             mMotionTarget = null;
    922         }
    923 
    924         // finally offset the event to the target's coordinate system and
    925         // dispatch the event.
    926         final float xc = scrolledXFloat - (float) target.mLeft;
    927         final float yc = scrolledYFloat - (float) target.mTop;
    928         ev.setLocation(xc, yc);
    929 
    930         if ((target.mPrivateFlags & CANCEL_NEXT_UP_EVENT) != 0) {
    931             ev.setAction(MotionEvent.ACTION_CANCEL);
    932             target.mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT;
    933             mMotionTarget = null;
    934         }
    935 
    936         return target.dispatchTouchEvent(ev);
    937     }
    938 
    939     /**
    940      * {@inheritDoc}
    941      */
    942     public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
    943 
    944         if (disallowIntercept == ((mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0)) {
    945             // We're already in this state, assume our ancestors are too
    946             return;
    947         }
    948 
    949         if (disallowIntercept) {
    950             mGroupFlags |= FLAG_DISALLOW_INTERCEPT;
    951         } else {
    952             mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
    953         }
    954 
    955         // Pass it up to our parent
    956         if (mParent != null) {
    957             mParent.requestDisallowInterceptTouchEvent(disallowIntercept);
    958         }
    959     }
    960 
    961     /**
    962      * Implement this method to intercept all touch screen motion events.  This
    963      * allows you to watch events as they are dispatched to your children, and
    964      * take ownership of the current gesture at any point.
    965      *
    966      * <p>Using this function takes some care, as it has a fairly complicated
    967      * interaction with {@link View#onTouchEvent(MotionEvent)
    968      * View.onTouchEvent(MotionEvent)}, and using it requires implementing
    969      * that method as well as this one in the correct way.  Events will be
    970      * received in the following order:
    971      *
    972      * <ol>
    973      * <li> You will receive the down event here.
    974      * <li> The down event will be handled either by a child of this view
    975      * group, or given to your own onTouchEvent() method to handle; this means
    976      * you should implement onTouchEvent() to return true, so you will
    977      * continue to see the rest of the gesture (instead of looking for
    978      * a parent view to handle it).  Also, by returning true from
    979      * onTouchEvent(), you will not receive any following
    980      * events in onInterceptTouchEvent() and all touch processing must
    981      * happen in onTouchEvent() like normal.
    982      * <li> For as long as you return false from this function, each following
    983      * event (up to and including the final up) will be delivered first here
    984      * and then to the target's onTouchEvent().
    985      * <li> If you return true from here, you will not receive any
    986      * following events: the target view will receive the same event but
    987      * with the action {@link MotionEvent#ACTION_CANCEL}, and all further
    988      * events will be delivered to your onTouchEvent() method and no longer
    989      * appear here.
    990      * </ol>
    991      *
    992      * @param ev The motion event being dispatched down the hierarchy.
    993      * @return Return true to steal motion events from the children and have
    994      * them dispatched to this ViewGroup through onTouchEvent().
    995      * The current target will receive an ACTION_CANCEL event, and no further
    996      * messages will be delivered here.
    997      */
    998     public boolean onInterceptTouchEvent(MotionEvent ev) {
    999         return false;
   1000     }
   1001 
   1002     /**
   1003      * {@inheritDoc}
   1004      *
   1005      * Looks for a view to give focus to respecting the setting specified by
   1006      * {@link #getDescendantFocusability()}.
   1007      *
   1008      * Uses {@link #onRequestFocusInDescendants(int, android.graphics.Rect)} to
   1009      * find focus within the children of this group when appropriate.
   1010      *
   1011      * @see #FOCUS_BEFORE_DESCENDANTS
   1012      * @see #FOCUS_AFTER_DESCENDANTS
   1013      * @see #FOCUS_BLOCK_DESCENDANTS
   1014      * @see #onRequestFocusInDescendants
   1015      */
   1016     @Override
   1017     public boolean requestFocus(int direction, Rect previouslyFocusedRect) {
   1018         if (DBG) {
   1019             System.out.println(this + " ViewGroup.requestFocus direction="
   1020                     + direction);
   1021         }
   1022         int descendantFocusability = getDescendantFocusability();
   1023 
   1024         switch (descendantFocusability) {
   1025             case FOCUS_BLOCK_DESCENDANTS:
   1026                 return super.requestFocus(direction, previouslyFocusedRect);
   1027             case FOCUS_BEFORE_DESCENDANTS: {
   1028                 final boolean took = super.requestFocus(direction, previouslyFocusedRect);
   1029                 return took ? took : onRequestFocusInDescendants(direction, previouslyFocusedRect);
   1030             }
   1031             case FOCUS_AFTER_DESCENDANTS: {
   1032                 final boolean took = onRequestFocusInDescendants(direction, previouslyFocusedRect);
   1033                 return took ? took : super.requestFocus(direction, previouslyFocusedRect);
   1034             }
   1035             default:
   1036                 throw new IllegalStateException("descendant focusability must be "
   1037                         + "one of FOCUS_BEFORE_DESCENDANTS, FOCUS_AFTER_DESCENDANTS, FOCUS_BLOCK_DESCENDANTS "
   1038                         + "but is " + descendantFocusability);
   1039         }
   1040     }
   1041 
   1042     /**
   1043      * Look for a descendant to call {@link View#requestFocus} on.
   1044      * Called by {@link ViewGroup#requestFocus(int, android.graphics.Rect)}
   1045      * when it wants to request focus within its children.  Override this to
   1046      * customize how your {@link ViewGroup} requests focus within its children.
   1047      * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT
   1048      * @param previouslyFocusedRect The rectangle (in this View's coordinate system)
   1049      *        to give a finer grained hint about where focus is coming from.  May be null
   1050      *        if there is no hint.
   1051      * @return Whether focus was taken.
   1052      */
   1053     @SuppressWarnings({"ConstantConditions"})
   1054     protected boolean onRequestFocusInDescendants(int direction,
   1055             Rect previouslyFocusedRect) {
   1056         int index;
   1057         int increment;
   1058         int end;
   1059         int count = mChildrenCount;
   1060         if ((direction & FOCUS_FORWARD) != 0) {
   1061             index = 0;
   1062             increment = 1;
   1063             end = count;
   1064         } else {
   1065             index = count - 1;
   1066             increment = -1;
   1067             end = -1;
   1068         }
   1069         final View[] children = mChildren;
   1070         for (int i = index; i != end; i += increment) {
   1071             View child = children[i];
   1072             if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
   1073                 if (child.requestFocus(direction, previouslyFocusedRect)) {
   1074                     return true;
   1075                 }
   1076             }
   1077         }
   1078         return false;
   1079     }
   1080 
   1081     /**
   1082      * {@inheritDoc}
   1083      *
   1084      * @hide
   1085      */
   1086     @Override
   1087     public void dispatchStartTemporaryDetach() {
   1088         super.dispatchStartTemporaryDetach();
   1089         final int count = mChildrenCount;
   1090         final View[] children = mChildren;
   1091         for (int i = 0; i < count; i++) {
   1092             children[i].dispatchStartTemporaryDetach();
   1093         }
   1094     }
   1095 
   1096     /**
   1097      * {@inheritDoc}
   1098      *
   1099      * @hide
   1100      */
   1101     @Override
   1102     public void dispatchFinishTemporaryDetach() {
   1103         super.dispatchFinishTemporaryDetach();
   1104         final int count = mChildrenCount;
   1105         final View[] children = mChildren;
   1106         for (int i = 0; i < count; i++) {
   1107             children[i].dispatchFinishTemporaryDetach();
   1108         }
   1109     }
   1110 
   1111     /**
   1112      * {@inheritDoc}
   1113      */
   1114     @Override
   1115     void dispatchAttachedToWindow(AttachInfo info, int visibility) {
   1116         super.dispatchAttachedToWindow(info, visibility);
   1117         visibility |= mViewFlags & VISIBILITY_MASK;
   1118         final int count = mChildrenCount;
   1119         final View[] children = mChildren;
   1120         for (int i = 0; i < count; i++) {
   1121             children[i].dispatchAttachedToWindow(info, visibility);
   1122         }
   1123     }
   1124 
   1125     @Override
   1126     public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
   1127         boolean populated = false;
   1128         for (int i = 0, count = getChildCount(); i < count; i++) {
   1129             populated |= getChildAt(i).dispatchPopulateAccessibilityEvent(event);
   1130         }
   1131         return populated;
   1132     }
   1133 
   1134     /**
   1135      * {@inheritDoc}
   1136      */
   1137     @Override
   1138     void dispatchDetachedFromWindow() {
   1139         // If we still have a motion target, we are still in the process of
   1140         // dispatching motion events to a child; we need to get rid of that
   1141         // child to avoid dispatching events to it after the window is torn
   1142         // down. To make sure we keep the child in a consistent state, we
   1143         // first send it an ACTION_CANCEL motion event.
   1144         if (mMotionTarget != null) {
   1145             final long now = SystemClock.uptimeMillis();
   1146             final MotionEvent event = MotionEvent.obtain(now, now,
   1147                     MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
   1148             mMotionTarget.dispatchTouchEvent(event);
   1149             event.recycle();
   1150             mMotionTarget = null;
   1151         }
   1152 
   1153         final int count = mChildrenCount;
   1154         final View[] children = mChildren;
   1155         for (int i = 0; i < count; i++) {
   1156             children[i].dispatchDetachedFromWindow();
   1157         }
   1158         super.dispatchDetachedFromWindow();
   1159     }
   1160 
   1161     /**
   1162      * {@inheritDoc}
   1163      */
   1164     @Override
   1165     public void setPadding(int left, int top, int right, int bottom) {
   1166         super.setPadding(left, top, right, bottom);
   1167 
   1168         if ((mPaddingLeft | mPaddingTop | mPaddingRight | mPaddingRight) != 0) {
   1169             mGroupFlags |= FLAG_PADDING_NOT_NULL;
   1170         } else {
   1171             mGroupFlags &= ~FLAG_PADDING_NOT_NULL;
   1172         }
   1173     }
   1174 
   1175     /**
   1176      * {@inheritDoc}
   1177      */
   1178     @Override
   1179     protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {
   1180         super.dispatchSaveInstanceState(container);
   1181         final int count = mChildrenCount;
   1182         final View[] children = mChildren;
   1183         for (int i = 0; i < count; i++) {
   1184             children[i].dispatchSaveInstanceState(container);
   1185         }
   1186     }
   1187 
   1188     /**
   1189      * Perform dispatching of a {@link #saveHierarchyState freeze()} to only this view,
   1190      * not to its children.  For use when overriding
   1191      * {@link #dispatchSaveInstanceState dispatchFreeze()} to allow subclasses to freeze
   1192      * their own state but not the state of their children.
   1193      *
   1194      * @param container the container
   1195      */
   1196     protected void dispatchFreezeSelfOnly(SparseArray<Parcelable> container) {
   1197         super.dispatchSaveInstanceState(container);
   1198     }
   1199 
   1200     /**
   1201      * {@inheritDoc}
   1202      */
   1203     @Override
   1204     protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {
   1205         super.dispatchRestoreInstanceState(container);
   1206         final int count = mChildrenCount;
   1207         final View[] children = mChildren;
   1208         for (int i = 0; i < count; i++) {
   1209             children[i].dispatchRestoreInstanceState(container);
   1210         }
   1211     }
   1212 
   1213     /**
   1214      * Perform dispatching of a {@link #restoreHierarchyState thaw()} to only this view,
   1215      * not to its children.  For use when overriding
   1216      * {@link #dispatchRestoreInstanceState dispatchThaw()} to allow subclasses to thaw
   1217      * their own state but not the state of their children.
   1218      *
   1219      * @param container the container
   1220      */
   1221     protected void dispatchThawSelfOnly(SparseArray<Parcelable> container) {
   1222         super.dispatchRestoreInstanceState(container);
   1223     }
   1224 
   1225     /**
   1226      * Enables or disables the drawing cache for each child of this view group.
   1227      *
   1228      * @param enabled true to enable the cache, false to dispose of it
   1229      */
   1230     protected void setChildrenDrawingCacheEnabled(boolean enabled) {
   1231         if (enabled || (mPersistentDrawingCache & PERSISTENT_ALL_CACHES) != PERSISTENT_ALL_CACHES) {
   1232             final View[] children = mChildren;
   1233             final int count = mChildrenCount;
   1234             for (int i = 0; i < count; i++) {
   1235                 children[i].setDrawingCacheEnabled(enabled);
   1236             }
   1237         }
   1238     }
   1239 
   1240     @Override
   1241     protected void onAnimationStart() {
   1242         super.onAnimationStart();
   1243 
   1244         // When this ViewGroup's animation starts, build the cache for the children
   1245         if ((mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE) {
   1246             final int count = mChildrenCount;
   1247             final View[] children = mChildren;
   1248 
   1249             for (int i = 0; i < count; i++) {
   1250                 final View child = children[i];
   1251                 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
   1252                     child.setDrawingCacheEnabled(true);
   1253                     child.buildDrawingCache(true);
   1254                 }
   1255             }
   1256 
   1257             mGroupFlags |= FLAG_CHILDREN_DRAWN_WITH_CACHE;
   1258         }
   1259     }
   1260 
   1261     @Override
   1262     protected void onAnimationEnd() {
   1263         super.onAnimationEnd();
   1264 
   1265         // When this ViewGroup's animation ends, destroy the cache of the children
   1266         if ((mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE) {
   1267             mGroupFlags &= ~FLAG_CHILDREN_DRAWN_WITH_CACHE;
   1268 
   1269             if ((mPersistentDrawingCache & PERSISTENT_ANIMATION_CACHE) == 0) {
   1270                 setChildrenDrawingCacheEnabled(false);
   1271             }
   1272         }
   1273     }
   1274 
   1275     @Override
   1276     Bitmap createSnapshot(Bitmap.Config quality, int backgroundColor, boolean skipChildren) {
   1277         int count = mChildrenCount;
   1278         int[] visibilities = null;
   1279 
   1280         if (skipChildren) {
   1281             visibilities = new int[count];
   1282             for (int i = 0; i < count; i++) {
   1283                 View child = getChildAt(i);
   1284                 visibilities[i] = child.getVisibility();
   1285                 if (visibilities[i] == View.VISIBLE) {
   1286                     child.setVisibility(INVISIBLE);
   1287                 }
   1288             }
   1289         }
   1290 
   1291         Bitmap b = super.createSnapshot(quality, backgroundColor, skipChildren);
   1292 
   1293         if (skipChildren) {
   1294             for (int i = 0; i < count; i++) {
   1295                 getChildAt(i).setVisibility(visibilities[i]);
   1296             }
   1297         }
   1298 
   1299         return b;
   1300     }
   1301 
   1302     /**
   1303      * {@inheritDoc}
   1304      */
   1305     @Override
   1306     protected void dispatchDraw(Canvas canvas) {
   1307         final int count = mChildrenCount;
   1308         final View[] children = mChildren;
   1309         int flags = mGroupFlags;
   1310 
   1311         if ((flags & FLAG_RUN_ANIMATION) != 0 && canAnimate()) {
   1312             final boolean cache = (mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE;
   1313 
   1314             for (int i = 0; i < count; i++) {
   1315                 final View child = children[i];
   1316                 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
   1317                     final LayoutParams params = child.getLayoutParams();
   1318                     attachLayoutAnimationParameters(child, params, i, count);
   1319                     bindLayoutAnimation(child);
   1320                     if (cache) {
   1321                         child.setDrawingCacheEnabled(true);
   1322                         child.buildDrawingCache(true);
   1323                     }
   1324                 }
   1325             }
   1326 
   1327             final LayoutAnimationController controller = mLayoutAnimationController;
   1328             if (controller.willOverlap()) {
   1329                 mGroupFlags |= FLAG_OPTIMIZE_INVALIDATE;
   1330             }
   1331 
   1332             controller.start();
   1333 
   1334             mGroupFlags &= ~FLAG_RUN_ANIMATION;
   1335             mGroupFlags &= ~FLAG_ANIMATION_DONE;
   1336 
   1337             if (cache) {
   1338                 mGroupFlags |= FLAG_CHILDREN_DRAWN_WITH_CACHE;
   1339             }
   1340 
   1341             if (mAnimationListener != null) {
   1342                 mAnimationListener.onAnimationStart(controller.getAnimation());
   1343             }
   1344         }
   1345 
   1346         int saveCount = 0;
   1347         final boolean clipToPadding = (flags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK;
   1348         if (clipToPadding) {
   1349             saveCount = canvas.save();
   1350             canvas.clipRect(mScrollX + mPaddingLeft, mScrollY + mPaddingTop,
   1351                     mScrollX + mRight - mLeft - mPaddingRight,
   1352                     mScrollY + mBottom - mTop - mPaddingBottom);
   1353 
   1354         }
   1355 
   1356         // We will draw our child's animation, let's reset the flag
   1357         mPrivateFlags &= ~DRAW_ANIMATION;
   1358         mGroupFlags &= ~FLAG_INVALIDATE_REQUIRED;
   1359 
   1360         boolean more = false;
   1361         final long drawingTime = getDrawingTime();
   1362 
   1363         if ((flags & FLAG_USE_CHILD_DRAWING_ORDER) == 0) {
   1364             for (int i = 0; i < count; i++) {
   1365                 final View child = children[i];
   1366                 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
   1367                     more |= drawChild(canvas, child, drawingTime);
   1368                 }
   1369             }
   1370         } else {
   1371             for (int i = 0; i < count; i++) {
   1372                 final View child = children[getChildDrawingOrder(count, i)];
   1373                 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
   1374                     more |= drawChild(canvas, child, drawingTime);
   1375                 }
   1376             }
   1377         }
   1378 
   1379         // Draw any disappearing views that have animations
   1380         if (mDisappearingChildren != null) {
   1381             final ArrayList<View> disappearingChildren = mDisappearingChildren;
   1382             final int disappearingCount = disappearingChildren.size() - 1;
   1383             // Go backwards -- we may delete as animations finish
   1384             for (int i = disappearingCount; i >= 0; i--) {
   1385                 final View child = disappearingChildren.get(i);
   1386                 more |= drawChild(canvas, child, drawingTime);
   1387             }
   1388         }
   1389 
   1390         if (clipToPadding) {
   1391             canvas.restoreToCount(saveCount);
   1392         }
   1393 
   1394         // mGroupFlags might have been updated by drawChild()
   1395         flags = mGroupFlags;
   1396 
   1397         if ((flags & FLAG_INVALIDATE_REQUIRED) == FLAG_INVALIDATE_REQUIRED) {
   1398             invalidate();
   1399         }
   1400 
   1401         if ((flags & FLAG_ANIMATION_DONE) == 0 && (flags & FLAG_NOTIFY_ANIMATION_LISTENER) == 0 &&
   1402                 mLayoutAnimationController.isDone() && !more) {
   1403             // We want to erase the drawing cache and notify the listener after the
   1404             // next frame is drawn because one extra invalidate() is caused by
   1405             // drawChild() after the animation is over
   1406             mGroupFlags |= FLAG_NOTIFY_ANIMATION_LISTENER;
   1407             final Runnable end = new Runnable() {
   1408                public void run() {
   1409                    notifyAnimationListener();
   1410                }
   1411             };
   1412             post(end);
   1413         }
   1414     }
   1415 
   1416     /**
   1417      * Returns the index of the child to draw for this iteration. Override this
   1418      * if you want to change the drawing order of children. By default, it
   1419      * returns i.
   1420      * <p>
   1421      * NOTE: In order for this method to be called, you must enable child ordering
   1422      * first by calling {@link #setChildrenDrawingOrderEnabled(boolean)}.
   1423      *
   1424      * @param i The current iteration.
   1425      * @return The index of the child to draw this iteration.
   1426      *
   1427      * @see #setChildrenDrawingOrderEnabled(boolean)
   1428      * @see #isChildrenDrawingOrderEnabled()
   1429      */
   1430     protected int getChildDrawingOrder(int childCount, int i) {
   1431         return i;
   1432     }
   1433 
   1434     private void notifyAnimationListener() {
   1435         mGroupFlags &= ~FLAG_NOTIFY_ANIMATION_LISTENER;
   1436         mGroupFlags |= FLAG_ANIMATION_DONE;
   1437 
   1438         if (mAnimationListener != null) {
   1439            final Runnable end = new Runnable() {
   1440                public void run() {
   1441                    mAnimationListener.onAnimationEnd(mLayoutAnimationController.getAnimation());
   1442                }
   1443            };
   1444            post(end);
   1445         }
   1446 
   1447         if ((mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE) {
   1448             mGroupFlags &= ~FLAG_CHILDREN_DRAWN_WITH_CACHE;
   1449             if ((mPersistentDrawingCache & PERSISTENT_ANIMATION_CACHE) == 0) {
   1450                 setChildrenDrawingCacheEnabled(false);
   1451             }
   1452         }
   1453 
   1454         invalidate();
   1455     }
   1456 
   1457     /**
   1458      * Draw one child of this View Group. This method is responsible for getting
   1459      * the canvas in the right state. This includes clipping, translating so
   1460      * that the child's scrolled origin is at 0, 0, and applying any animation
   1461      * transformations.
   1462      *
   1463      * @param canvas The canvas on which to draw the child
   1464      * @param child Who to draw
   1465      * @param drawingTime The time at which draw is occuring
   1466      * @return True if an invalidate() was issued
   1467      */
   1468     protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
   1469         boolean more = false;
   1470 
   1471         final int cl = child.mLeft;
   1472         final int ct = child.mTop;
   1473         final int cr = child.mRight;
   1474         final int cb = child.mBottom;
   1475 
   1476         final int flags = mGroupFlags;
   1477 
   1478         if ((flags & FLAG_CLEAR_TRANSFORMATION) == FLAG_CLEAR_TRANSFORMATION) {
   1479             if (mChildTransformation != null) {
   1480                 mChildTransformation.clear();
   1481             }
   1482             mGroupFlags &= ~FLAG_CLEAR_TRANSFORMATION;
   1483         }
   1484 
   1485         Transformation transformToApply = null;
   1486         final Animation a = child.getAnimation();
   1487         boolean concatMatrix = false;
   1488 
   1489         if (a != null) {
   1490             if (mInvalidateRegion == null) {
   1491                 mInvalidateRegion = new RectF();
   1492             }
   1493             final RectF region = mInvalidateRegion;
   1494 
   1495             final boolean initialized = a.isInitialized();
   1496             if (!initialized) {
   1497                 a.initialize(cr - cl, cb - ct, getWidth(), getHeight());
   1498                 a.initializeInvalidateRegion(0, 0, cr - cl, cb - ct);
   1499                 child.onAnimationStart();
   1500             }
   1501 
   1502             if (mChildTransformation == null) {
   1503                 mChildTransformation = new Transformation();
   1504             }
   1505             more = a.getTransformation(drawingTime, mChildTransformation);
   1506             transformToApply = mChildTransformation;
   1507 
   1508             concatMatrix = a.willChangeTransformationMatrix();
   1509 
   1510             if (more) {
   1511                 if (!a.willChangeBounds()) {
   1512                     if ((flags & (FLAG_OPTIMIZE_INVALIDATE | FLAG_ANIMATION_DONE)) ==
   1513                             FLAG_OPTIMIZE_INVALIDATE) {
   1514                         mGroupFlags |= FLAG_INVALIDATE_REQUIRED;
   1515                     } else if ((flags & FLAG_INVALIDATE_REQUIRED) == 0) {
   1516                         // The child need to draw an animation, potentially offscreen, so
   1517                         // make sure we do not cancel invalidate requests
   1518                         mPrivateFlags |= DRAW_ANIMATION;
   1519                         invalidate(cl, ct, cr, cb);
   1520                     }
   1521                 } else {
   1522                     a.getInvalidateRegion(0, 0, cr - cl, cb - ct, region, transformToApply);
   1523 
   1524                     // The child need to draw an animation, potentially offscreen, so
   1525                     // make sure we do not cancel invalidate requests
   1526                     mPrivateFlags |= DRAW_ANIMATION;
   1527 
   1528                     final int left = cl + (int) region.left;
   1529                     final int top = ct + (int) region.top;
   1530                     invalidate(left, top, left + (int) region.width(), top + (int) region.height());
   1531                 }
   1532             }
   1533         } else if ((flags & FLAG_SUPPORT_STATIC_TRANSFORMATIONS) ==
   1534                 FLAG_SUPPORT_STATIC_TRANSFORMATIONS) {
   1535             if (mChildTransformation == null) {
   1536                 mChildTransformation = new Transformation();
   1537             }
   1538             final boolean hasTransform = getChildStaticTransformation(child, mChildTransformation);
   1539             if (hasTransform) {
   1540                 final int transformType = mChildTransformation.getTransformationType();
   1541                 transformToApply = transformType != Transformation.TYPE_IDENTITY ?
   1542                         mChildTransformation : null;
   1543                 concatMatrix = (transformType & Transformation.TYPE_MATRIX) != 0;
   1544             }
   1545         }
   1546 
   1547         // Sets the flag as early as possible to allow draw() implementations
   1548         // to call invalidate() successfully when doing animations
   1549         child.mPrivateFlags |= DRAWN;
   1550 
   1551         if (!concatMatrix && canvas.quickReject(cl, ct, cr, cb, Canvas.EdgeType.BW) &&
   1552                 (child.mPrivateFlags & DRAW_ANIMATION) == 0) {
   1553             return more;
   1554         }
   1555 
   1556         child.computeScroll();
   1557 
   1558         final int sx = child.mScrollX;
   1559         final int sy = child.mScrollY;
   1560 
   1561         boolean scalingRequired = false;
   1562         Bitmap cache = null;
   1563         if ((flags & FLAG_CHILDREN_DRAWN_WITH_CACHE) == FLAG_CHILDREN_DRAWN_WITH_CACHE ||
   1564                 (flags & FLAG_ALWAYS_DRAWN_WITH_CACHE) == FLAG_ALWAYS_DRAWN_WITH_CACHE) {
   1565             cache = child.getDrawingCache(true);
   1566             if (mAttachInfo != null) scalingRequired = mAttachInfo.mScalingRequired;
   1567         }
   1568 
   1569         final boolean hasNoCache = cache == null;
   1570 
   1571         final int restoreTo = canvas.save();
   1572         if (hasNoCache) {
   1573             canvas.translate(cl - sx, ct - sy);
   1574         } else {
   1575             canvas.translate(cl, ct);
   1576             if (scalingRequired) {
   1577                 // mAttachInfo cannot be null, otherwise scalingRequired == false
   1578                 final float scale = 1.0f / mAttachInfo.mApplicationScale;
   1579                 canvas.scale(scale, scale);
   1580             }
   1581         }
   1582 
   1583         float alpha = 1.0f;
   1584 
   1585         if (transformToApply != null) {
   1586             if (concatMatrix) {
   1587                 int transX = 0;
   1588                 int transY = 0;
   1589                 if (hasNoCache) {
   1590                     transX = -sx;
   1591                     transY = -sy;
   1592                 }
   1593                 // Undo the scroll translation, apply the transformation matrix,
   1594                 // then redo the scroll translate to get the correct result.
   1595                 canvas.translate(-transX, -transY);
   1596                 canvas.concat(transformToApply.getMatrix());
   1597                 canvas.translate(transX, transY);
   1598                 mGroupFlags |= FLAG_CLEAR_TRANSFORMATION;
   1599             }
   1600 
   1601             alpha = transformToApply.getAlpha();
   1602             if (alpha < 1.0f) {
   1603                 mGroupFlags |= FLAG_CLEAR_TRANSFORMATION;
   1604             }
   1605 
   1606             if (alpha < 1.0f && hasNoCache) {
   1607                 final int multipliedAlpha = (int) (255 * alpha);
   1608                 if (!child.onSetAlpha(multipliedAlpha)) {
   1609                     canvas.saveLayerAlpha(sx, sy, sx + cr - cl, sy + cb - ct, multipliedAlpha,
   1610                             Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG);
   1611                 } else {
   1612                     child.mPrivateFlags |= ALPHA_SET;
   1613                 }
   1614             }
   1615         } else if ((child.mPrivateFlags & ALPHA_SET) == ALPHA_SET) {
   1616             child.onSetAlpha(255);
   1617         }
   1618 
   1619         if ((flags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN) {
   1620             if (hasNoCache) {
   1621                 canvas.clipRect(sx, sy, sx + (cr - cl), sy + (cb - ct));
   1622             } else {
   1623                 if (!scalingRequired) {
   1624                     canvas.clipRect(0, 0, cr - cl, cb - ct);
   1625                 } else {
   1626                     canvas.clipRect(0, 0, cache.getWidth(), cache.getHeight());
   1627                 }
   1628             }
   1629         }
   1630 
   1631         if (hasNoCache) {
   1632             // Fast path for layouts with no backgrounds
   1633             if ((child.mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
   1634                 if (ViewDebug.TRACE_HIERARCHY) {
   1635                     ViewDebug.trace(this, ViewDebug.HierarchyTraceType.DRAW);
   1636                 }
   1637                 child.mPrivateFlags &= ~DIRTY_MASK;
   1638                 child.dispatchDraw(canvas);
   1639             } else {
   1640                 child.draw(canvas);
   1641             }
   1642         } else {
   1643             final Paint cachePaint = mCachePaint;
   1644             if (alpha < 1.0f) {
   1645                 cachePaint.setAlpha((int) (alpha * 255));
   1646                 mGroupFlags |= FLAG_ALPHA_LOWER_THAN_ONE;
   1647             } else if  ((flags & FLAG_ALPHA_LOWER_THAN_ONE) == FLAG_ALPHA_LOWER_THAN_ONE) {
   1648                 cachePaint.setAlpha(255);
   1649                 mGroupFlags &= ~FLAG_ALPHA_LOWER_THAN_ONE;
   1650             }
   1651             if (Config.DEBUG && ViewDebug.profileDrawing) {
   1652                 EventLog.writeEvent(60003, hashCode());
   1653             }
   1654             canvas.drawBitmap(cache, 0.0f, 0.0f, cachePaint);
   1655         }
   1656 
   1657         canvas.restoreToCount(restoreTo);
   1658 
   1659         if (a != null && !more) {
   1660             child.onSetAlpha(255);
   1661             finishAnimatingView(child, a);
   1662         }
   1663 
   1664         return more;
   1665     }
   1666 
   1667     /**
   1668      * By default, children are clipped to their bounds before drawing. This
   1669      * allows view groups to override this behavior for animations, etc.
   1670      *
   1671      * @param clipChildren true to clip children to their bounds,
   1672      *        false otherwise
   1673      * @attr ref android.R.styleable#ViewGroup_clipChildren
   1674      */
   1675     public void setClipChildren(boolean clipChildren) {
   1676         setBooleanFlag(FLAG_CLIP_CHILDREN, clipChildren);
   1677     }
   1678 
   1679     /**
   1680      * By default, children are clipped to the padding of the ViewGroup. This
   1681      * allows view groups to override this behavior
   1682      *
   1683      * @param clipToPadding true to clip children to the padding of the
   1684      *        group, false otherwise
   1685      * @attr ref android.R.styleable#ViewGroup_clipToPadding
   1686      */
   1687     public void setClipToPadding(boolean clipToPadding) {
   1688         setBooleanFlag(FLAG_CLIP_TO_PADDING, clipToPadding);
   1689     }
   1690 
   1691     /**
   1692      * {@inheritDoc}
   1693      */
   1694     @Override
   1695     public void dispatchSetSelected(boolean selected) {
   1696         final View[] children = mChildren;
   1697         final int count = mChildrenCount;
   1698         for (int i = 0; i < count; i++) {
   1699             children[i].setSelected(selected);
   1700         }
   1701     }
   1702 
   1703     @Override
   1704     protected void dispatchSetPressed(boolean pressed) {
   1705         final View[] children = mChildren;
   1706         final int count = mChildrenCount;
   1707         for (int i = 0; i < count; i++) {
   1708             children[i].setPressed(pressed);
   1709         }
   1710     }
   1711 
   1712     /**
   1713      * When this property is set to true, this ViewGroup supports static transformations on
   1714      * children; this causes
   1715      * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} to be
   1716      * invoked when a child is drawn.
   1717      *
   1718      * Any subclass overriding
   1719      * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} should
   1720      * set this property to true.
   1721      *
   1722      * @param enabled True to enable static transformations on children, false otherwise.
   1723      *
   1724      * @see #FLAG_SUPPORT_STATIC_TRANSFORMATIONS
   1725      */
   1726     protected void setStaticTransformationsEnabled(boolean enabled) {
   1727         setBooleanFlag(FLAG_SUPPORT_STATIC_TRANSFORMATIONS, enabled);
   1728     }
   1729 
   1730     /**
   1731      * {@inheritDoc}
   1732      *
   1733      * @see #setStaticTransformationsEnabled(boolean)
   1734      */
   1735     protected boolean getChildStaticTransformation(View child, Transformation t) {
   1736         return false;
   1737     }
   1738 
   1739     /**
   1740      * {@hide}
   1741      */
   1742     @Override
   1743     protected View findViewTraversal(int id) {
   1744         if (id == mID) {
   1745             return this;
   1746         }
   1747 
   1748         final View[] where = mChildren;
   1749         final int len = mChildrenCount;
   1750 
   1751         for (int i = 0; i < len; i++) {
   1752             View v = where[i];
   1753 
   1754             if ((v.mPrivateFlags & IS_ROOT_NAMESPACE) == 0) {
   1755                 v = v.findViewById(id);
   1756 
   1757                 if (v != null) {
   1758                     return v;
   1759                 }
   1760             }
   1761         }
   1762 
   1763         return null;
   1764     }
   1765 
   1766     /**
   1767      * {@hide}
   1768      */
   1769     @Override
   1770     protected View findViewWithTagTraversal(Object tag) {
   1771         if (tag != null && tag.equals(mTag)) {
   1772             return this;
   1773         }
   1774 
   1775         final View[] where = mChildren;
   1776         final int len = mChildrenCount;
   1777 
   1778         for (int i = 0; i < len; i++) {
   1779             View v = where[i];
   1780 
   1781             if ((v.mPrivateFlags & IS_ROOT_NAMESPACE) == 0) {
   1782                 v = v.findViewWithTag(tag);
   1783 
   1784                 if (v != null) {
   1785                     return v;
   1786                 }
   1787             }
   1788         }
   1789 
   1790         return null;
   1791     }
   1792 
   1793     /**
   1794      * Adds a child view. If no layout parameters are already set on the child, the
   1795      * default parameters for this ViewGroup are set on the child.
   1796      *
   1797      * @param child the child view to add
   1798      *
   1799      * @see #generateDefaultLayoutParams()
   1800      */
   1801     public void addView(View child) {
   1802         addView(child, -1);
   1803     }
   1804 
   1805     /**
   1806      * Adds a child view. If no layout parameters are already set on the child, the
   1807      * default parameters for this ViewGroup are set on the child.
   1808      *
   1809      * @param child the child view to add
   1810      * @param index the position at which to add the child
   1811      *
   1812      * @see #generateDefaultLayoutParams()
   1813      */
   1814     public void addView(View child, int index) {
   1815         LayoutParams params = child.getLayoutParams();
   1816         if (params == null) {
   1817             params = generateDefaultLayoutParams();
   1818             if (params == null) {
   1819                 throw new IllegalArgumentException("generateDefaultLayoutParams() cannot return null");
   1820             }
   1821         }
   1822         addView(child, index, params);
   1823     }
   1824 
   1825     /**
   1826      * Adds a child view with this ViewGroup's default layout parameters and the
   1827      * specified width and height.
   1828      *
   1829      * @param child the child view to add
   1830      */
   1831     public void addView(View child, int width, int height) {
   1832         final LayoutParams params = generateDefaultLayoutParams();
   1833         params.width = width;
   1834         params.height = height;
   1835         addView(child, -1, params);
   1836     }
   1837 
   1838     /**
   1839      * Adds a child view with the specified layout parameters.
   1840      *
   1841      * @param child the child view to add
   1842      * @param params the layout parameters to set on the child
   1843      */
   1844     public void addView(View child, LayoutParams params) {
   1845         addView(child, -1, params);
   1846     }
   1847 
   1848     /**
   1849      * Adds a child view with the specified layout parameters.
   1850      *
   1851      * @param child the child view to add
   1852      * @param index the position at which to add the child
   1853      * @param params the layout parameters to set on the child
   1854      */
   1855     public void addView(View child, int index, LayoutParams params) {
   1856         if (DBG) {
   1857             System.out.println(this + " addView");
   1858         }
   1859 
   1860         // addViewInner() will call child.requestLayout() when setting the new LayoutParams
   1861         // therefore, we call requestLayout() on ourselves before, so that the child's request
   1862         // will be blocked at our level
   1863         requestLayout();
   1864         invalidate();
   1865         addViewInner(child, index, params, false);
   1866     }
   1867 
   1868     /**
   1869      * {@inheritDoc}
   1870      */
   1871     public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
   1872         if (!checkLayoutParams(params)) {
   1873             throw new IllegalArgumentException("Invalid LayoutParams supplied to " + this);
   1874         }
   1875         if (view.mParent != this) {
   1876             throw new IllegalArgumentException("Given view not a child of " + this);
   1877         }
   1878         view.setLayoutParams(params);
   1879     }
   1880 
   1881     /**
   1882      * {@inheritDoc}
   1883      */
   1884     protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
   1885         return  p != null;
   1886     }
   1887 
   1888     /**
   1889      * Interface definition for a callback to be invoked when the hierarchy
   1890      * within this view changed. The hierarchy changes whenever a child is added
   1891      * to or removed from this view.
   1892      */
   1893     public interface OnHierarchyChangeListener {
   1894         /**
   1895          * Called when a new child is added to a parent view.
   1896          *
   1897          * @param parent the view in which a child was added
   1898          * @param child the new child view added in the hierarchy
   1899          */
   1900         void onChildViewAdded(View parent, View child);
   1901 
   1902         /**
   1903          * Called when a child is removed from a parent view.
   1904          *
   1905          * @param parent the view from which the child was removed
   1906          * @param child the child removed from the hierarchy
   1907          */
   1908         void onChildViewRemoved(View parent, View child);
   1909     }
   1910 
   1911     /**
   1912      * Register a callback to be invoked when a child is added to or removed
   1913      * from this view.
   1914      *
   1915      * @param listener the callback to invoke on hierarchy change
   1916      */
   1917     public void setOnHierarchyChangeListener(OnHierarchyChangeListener listener) {
   1918         mOnHierarchyChangeListener = listener;
   1919     }
   1920 
   1921     /**
   1922      * Adds a view during layout. This is useful if in your onLayout() method,
   1923      * you need to add more views (as does the list view for example).
   1924      *
   1925      * If index is negative, it means put it at the end of the list.
   1926      *
   1927      * @param child the view to add to the group
   1928      * @param index the index at which the child must be added
   1929      * @param params the layout parameters to associate with the child
   1930      * @return true if the child was added, false otherwise
   1931      */
   1932     protected boolean addViewInLayout(View child, int index, LayoutParams params) {
   1933         return addViewInLayout(child, index, params, false);
   1934     }
   1935 
   1936     /**
   1937      * Adds a view during layout. This is useful if in your onLayout() method,
   1938      * you need to add more views (as does the list view for example).
   1939      *
   1940      * If index is negative, it means put it at the end of the list.
   1941      *
   1942      * @param child the view to add to the group
   1943      * @param index the index at which the child must be added
   1944      * @param params the layout parameters to associate with the child
   1945      * @param preventRequestLayout if true, calling this method will not trigger a
   1946      *        layout request on child
   1947      * @return true if the child was added, false otherwise
   1948      */
   1949     protected boolean addViewInLayout(View child, int index, LayoutParams params,
   1950             boolean preventRequestLayout) {
   1951         child.mParent = null;
   1952         addViewInner(child, index, params, preventRequestLayout);
   1953         child.mPrivateFlags = (child.mPrivateFlags & ~DIRTY_MASK) | DRAWN;
   1954         return true;
   1955     }
   1956 
   1957     /**
   1958      * Prevents the specified child to be laid out during the next layout pass.
   1959      *
   1960      * @param child the child on which to perform the cleanup
   1961      */
   1962     protected void cleanupLayoutState(View child) {
   1963         child.mPrivateFlags &= ~View.FORCE_LAYOUT;
   1964     }
   1965 
   1966     private void addViewInner(View child, int index, LayoutParams params,
   1967             boolean preventRequestLayout) {
   1968 
   1969         if (child.getParent() != null) {
   1970             throw new IllegalStateException("The specified child already has a parent. " +
   1971                     "You must call removeView() on the child's parent first.");
   1972         }
   1973 
   1974         if (!checkLayoutParams(params)) {
   1975             params = generateLayoutParams(params);
   1976         }
   1977 
   1978         if (preventRequestLayout) {
   1979             child.mLayoutParams = params;
   1980         } else {
   1981             child.setLayoutParams(params);
   1982         }
   1983 
   1984         if (index < 0) {
   1985             index = mChildrenCount;
   1986         }
   1987 
   1988         addInArray(child, index);
   1989 
   1990         // tell our children
   1991         if (preventRequestLayout) {
   1992             child.assignParent(this);
   1993         } else {
   1994             child.mParent = this;
   1995         }
   1996 
   1997         if (child.hasFocus()) {
   1998             requestChildFocus(child, child.findFocus());
   1999         }
   2000 
   2001         AttachInfo ai = mAttachInfo;
   2002         if (ai != null) {
   2003             boolean lastKeepOn = ai.mKeepScreenOn;
   2004             ai.mKeepScreenOn = false;
   2005             child.dispatchAttachedToWindow(mAttachInfo, (mViewFlags&VISIBILITY_MASK));
   2006             if (ai.mKeepScreenOn) {
   2007                 needGlobalAttributesUpdate(true);
   2008             }
   2009             ai.mKeepScreenOn = lastKeepOn;
   2010         }
   2011 
   2012         if (mOnHierarchyChangeListener != null) {
   2013             mOnHierarchyChangeListener.onChildViewAdded(this, child);
   2014         }
   2015 
   2016         if ((child.mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE) {
   2017             mGroupFlags |= FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE;
   2018         }
   2019     }
   2020 
   2021     private void addInArray(View child, int index) {
   2022         View[] children = mChildren;
   2023         final int count = mChildrenCount;
   2024         final int size = children.length;
   2025         if (index == count) {
   2026             if (size == count) {
   2027                 mChildren = new View[size + ARRAY_CAPACITY_INCREMENT];
   2028                 System.arraycopy(children, 0, mChildren, 0, size);
   2029                 children = mChildren;
   2030             }
   2031             children[mChildrenCount++] = child;
   2032         } else if (index < count) {
   2033             if (size == count) {
   2034                 mChildren = new View[size + ARRAY_CAPACITY_INCREMENT];
   2035                 System.arraycopy(children, 0, mChildren, 0, index);
   2036                 System.arraycopy(children, index, mChildren, index + 1, count - index);
   2037                 children = mChildren;
   2038             } else {
   2039                 System.arraycopy(children, index, children, index + 1, count - index);
   2040             }
   2041             children[index] = child;
   2042             mChildrenCount++;
   2043         } else {
   2044             throw new IndexOutOfBoundsException("index=" + index + " count=" + count);
   2045         }
   2046     }
   2047 
   2048     // This method also sets the child's mParent to null
   2049     private void removeFromArray(int index) {
   2050         final View[] children = mChildren;
   2051         children[index].mParent = null;
   2052         final int count = mChildrenCount;
   2053         if (index == count - 1) {
   2054             children[--mChildrenCount] = null;
   2055         } else if (index >= 0 && index < count) {
   2056             System.arraycopy(children, index + 1, children, index, count - index - 1);
   2057             children[--mChildrenCount] = null;
   2058         } else {
   2059             throw new IndexOutOfBoundsException();
   2060         }
   2061     }
   2062 
   2063     // This method also sets the children's mParent to null
   2064     private void removeFromArray(int start, int count) {
   2065         final View[] children = mChildren;
   2066         final int childrenCount = mChildrenCount;
   2067 
   2068         start = Math.max(0, start);
   2069         final int end = Math.min(childrenCount, start + count);
   2070 
   2071         if (start == end) {
   2072             return;
   2073         }
   2074 
   2075         if (end == childrenCount) {
   2076             for (int i = start; i < end; i++) {
   2077                 children[i].mParent = null;
   2078                 children[i] = null;
   2079             }
   2080         } else {
   2081             for (int i = start; i < end; i++) {
   2082                 children[i].mParent = null;
   2083             }
   2084 
   2085             // Since we're looping above, we might as well do the copy, but is arraycopy()
   2086             // faster than the extra 2 bounds checks we would do in the loop?
   2087             System.arraycopy(children, end, children, start, childrenCount - end);
   2088 
   2089             for (int i = childrenCount - (end - start); i < childrenCount; i++) {
   2090                 children[i] = null;
   2091             }
   2092         }
   2093 
   2094         mChildrenCount -= (end - start);
   2095     }
   2096 
   2097     private void bindLayoutAnimation(View child) {
   2098         Animation a = mLayoutAnimationController.getAnimationForView(child);
   2099         child.setAnimation(a);
   2100     }
   2101 
   2102     /**
   2103      * Subclasses should override this method to set layout animation
   2104      * parameters on the supplied child.
   2105      *
   2106      * @param child the child to associate with animation parameters
   2107      * @param params the child's layout parameters which hold the animation
   2108      *        parameters
   2109      * @param index the index of the child in the view group
   2110      * @param count the number of children in the view group
   2111      */
   2112     protected void attachLayoutAnimationParameters(View child,
   2113             LayoutParams params, int index, int count) {
   2114         LayoutAnimationController.AnimationParameters animationParams =
   2115                     params.layoutAnimationParameters;
   2116         if (animationParams == null) {
   2117             animationParams = new LayoutAnimationController.AnimationParameters();
   2118             params.layoutAnimationParameters = animationParams;
   2119         }
   2120 
   2121         animationParams.count = count;
   2122         animationParams.index = index;
   2123     }
   2124 
   2125     /**
   2126      * {@inheritDoc}
   2127      */
   2128     public void removeView(View view) {
   2129         removeViewInternal(view);
   2130         requestLayout();
   2131         invalidate();
   2132     }
   2133 
   2134     /**
   2135      * Removes a view during layout. This is useful if in your onLayout() method,
   2136      * you need to remove more views.
   2137      *
   2138      * @param view the view to remove from the group
   2139      */
   2140     public void removeViewInLayout(View view) {
   2141         removeViewInternal(view);
   2142     }
   2143 
   2144     /**
   2145      * Removes a range of views during layout. This is useful if in your onLayout() method,
   2146      * you need to remove more views.
   2147      *
   2148      * @param start the index of the first view to remove from the group
   2149      * @param count the number of views to remove from the group
   2150      */
   2151     public void removeViewsInLayout(int start, int count) {
   2152         removeViewsInternal(start, count);
   2153     }
   2154 
   2155     /**
   2156      * Removes the view at the specified position in the group.
   2157      *
   2158      * @param index the position in the group of the view to remove
   2159      */
   2160     public void removeViewAt(int index) {
   2161         removeViewInternal(index, getChildAt(index));
   2162         requestLayout();
   2163         invalidate();
   2164     }
   2165 
   2166     /**
   2167      * Removes the specified range of views from the group.
   2168      *
   2169      * @param start the first position in the group of the range of views to remove
   2170      * @param count the number of views to remove
   2171      */
   2172     public void removeViews(int start, int count) {
   2173         removeViewsInternal(start, count);
   2174         requestLayout();
   2175         invalidate();
   2176     }
   2177 
   2178     private void removeViewInternal(View view) {
   2179         final int index = indexOfChild(view);
   2180         if (index >= 0) {
   2181             removeViewInternal(index, view);
   2182         }
   2183     }
   2184 
   2185     private void removeViewInternal(int index, View view) {
   2186         boolean clearChildFocus = false;
   2187         if (view == mFocused) {
   2188             view.clearFocusForRemoval();
   2189             clearChildFocus = true;
   2190         }
   2191 
   2192         if (view.getAnimation() != null) {
   2193             addDisappearingView(view);
   2194         } else if (view.mAttachInfo != null) {
   2195            view.dispatchDetachedFromWindow();
   2196         }
   2197 
   2198         if (mOnHierarchyChangeListener != null) {
   2199             mOnHierarchyChangeListener.onChildViewRemoved(this, view);
   2200         }
   2201 
   2202         needGlobalAttributesUpdate(false);
   2203 
   2204         removeFromArray(index);
   2205 
   2206         if (clearChildFocus) {
   2207             clearChildFocus(view);
   2208         }
   2209     }
   2210 
   2211     private void removeViewsInternal(int start, int count) {
   2212         final OnHierarchyChangeListener onHierarchyChangeListener = mOnHierarchyChangeListener;
   2213         final boolean notifyListener = onHierarchyChangeListener != null;
   2214         final View focused = mFocused;
   2215         final boolean detach = mAttachInfo != null;
   2216         View clearChildFocus = null;
   2217 
   2218         final View[] children = mChildren;
   2219         final int end = start + count;
   2220 
   2221         for (int i = start; i < end; i++) {
   2222             final View view = children[i];
   2223 
   2224             if (view == focused) {
   2225                 view.clearFocusForRemoval();
   2226                 clearChildFocus = view;
   2227             }
   2228 
   2229             if (view.getAnimation() != null) {
   2230                 addDisappearingView(view);
   2231             } else if (detach) {
   2232                view.dispatchDetachedFromWindow();
   2233             }
   2234 
   2235             needGlobalAttributesUpdate(false);
   2236 
   2237             if (notifyListener) {
   2238                 onHierarchyChangeListener.onChildViewRemoved(this, view);
   2239             }
   2240         }
   2241 
   2242         removeFromArray(start, count);
   2243 
   2244         if (clearChildFocus != null) {
   2245             clearChildFocus(clearChildFocus);
   2246         }
   2247     }
   2248 
   2249     /**
   2250      * Call this method to remove all child views from the
   2251      * ViewGroup.
   2252      */
   2253     public void removeAllViews() {
   2254         removeAllViewsInLayout();
   2255         requestLayout();
   2256         invalidate();
   2257     }
   2258 
   2259     /**
   2260      * Called by a ViewGroup subclass to remove child views from itself,
   2261      * when it must first know its size on screen before it can calculate how many
   2262      * child views it will render. An example is a Gallery or a ListView, which
   2263      * may "have" 50 children, but actually only render the number of children
   2264      * that can currently fit inside the object on screen. Do not call
   2265      * this method unless you are extending ViewGroup and understand the
   2266      * view measuring and layout pipeline.
   2267      */
   2268     public void removeAllViewsInLayout() {
   2269         final int count = mChildrenCount;
   2270         if (count <= 0) {
   2271             return;
   2272         }
   2273 
   2274         final View[] children = mChildren;
   2275         mChildrenCount = 0;
   2276 
   2277         final OnHierarchyChangeListener listener = mOnHierarchyChangeListener;
   2278         final boolean notify = listener != null;
   2279         final View focused = mFocused;
   2280         final boolean detach = mAttachInfo != null;
   2281         View clearChildFocus = null;
   2282 
   2283         needGlobalAttributesUpdate(false);
   2284 
   2285         for (int i = count - 1; i >= 0; i--) {
   2286             final View view = children[i];
   2287 
   2288             if (view == focused) {
   2289                 view.clearFocusForRemoval();
   2290                 clearChildFocus = view;
   2291             }
   2292 
   2293             if (view.getAnimation() != null) {
   2294                 addDisappearingView(view);
   2295             } else if (detach) {
   2296                view.dispatchDetachedFromWindow();
   2297             }
   2298 
   2299             if (notify) {
   2300                 listener.onChildViewRemoved(this, view);
   2301             }
   2302 
   2303             view.mParent = null;
   2304             children[i] = null;
   2305         }
   2306 
   2307         if (clearChildFocus != null) {
   2308             clearChildFocus(clearChildFocus);
   2309         }
   2310     }
   2311 
   2312     /**
   2313      * Finishes the removal of a detached view. This method will dispatch the detached from
   2314      * window event and notify the hierarchy change listener.
   2315      *
   2316      * @param child the child to be definitely removed from the view hierarchy
   2317      * @param animate if true and the view has an animation, the view is placed in the
   2318      *                disappearing views list, otherwise, it is detached from the window
   2319      *
   2320      * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
   2321      * @see #detachAllViewsFromParent()
   2322      * @see #detachViewFromParent(View)
   2323      * @see #detachViewFromParent(int)
   2324      */
   2325     protected void removeDetachedView(View child, boolean animate) {
   2326         if (child == mFocused) {
   2327             child.clearFocus();
   2328         }
   2329 
   2330         if (animate && child.getAnimation() != null) {
   2331             addDisappearingView(child);
   2332         } else if (child.mAttachInfo != null) {
   2333             child.dispatchDetachedFromWindow();
   2334         }
   2335 
   2336         if (mOnHierarchyChangeListener != null) {
   2337             mOnHierarchyChangeListener.onChildViewRemoved(this, child);
   2338         }
   2339     }
   2340 
   2341     /**
   2342      * Attaches a view to this view group. Attaching a view assigns this group as the parent,
   2343      * sets the layout parameters and puts the view in the list of children so it can be retrieved
   2344      * by calling {@link #getChildAt(int)}.
   2345      *
   2346      * This method should be called only for view which were detached from their parent.
   2347      *
   2348      * @param child the child to attach
   2349      * @param index the index at which the child should be attached
   2350      * @param params the layout parameters of the child
   2351      *
   2352      * @see #removeDetachedView(View, boolean)
   2353      * @see #detachAllViewsFromParent()
   2354      * @see #detachViewFromParent(View)
   2355      * @see #detachViewFromParent(int)
   2356      */
   2357     protected void attachViewToParent(View child, int index, LayoutParams params) {
   2358         child.mLayoutParams = params;
   2359 
   2360         if (index < 0) {
   2361             index = mChildrenCount;
   2362         }
   2363 
   2364         addInArray(child, index);
   2365 
   2366         child.mParent = this;
   2367         child.mPrivateFlags = (child.mPrivateFlags & ~DIRTY_MASK & ~DRAWING_CACHE_VALID) | DRAWN;
   2368 
   2369         if (child.hasFocus()) {
   2370             requestChildFocus(child, child.findFocus());
   2371         }
   2372     }
   2373 
   2374     /**
   2375      * Detaches a view from its parent. Detaching a view should be temporary and followed
   2376      * either by a call to {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
   2377      * or a call to {@link #removeDetachedView(View, boolean)}. When a view is detached,
   2378      * its parent is null and cannot be retrieved by a call to {@link #getChildAt(int)}.
   2379      *
   2380      * @param child the child to detach
   2381      *
   2382      * @see #detachViewFromParent(int)
   2383      * @see #detachViewsFromParent(int, int)
   2384      * @see #detachAllViewsFromParent()
   2385      * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
   2386      * @see #removeDetachedView(View, boolean)
   2387      */
   2388     protected void detachViewFromParent(View child) {
   2389         removeFromArray(indexOfChild(child));
   2390     }
   2391 
   2392     /**
   2393      * Detaches a view from its parent. Detaching a view should be temporary and followed
   2394      * either by a call to {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
   2395      * or a call to {@link #removeDetachedView(View, boolean)}. When a view is detached,
   2396      * its parent is null and cannot be retrieved by a call to {@link #getChildAt(int)}.
   2397      *
   2398      * @param index the index of the child to detach
   2399      *
   2400      * @see #detachViewFromParent(View)
   2401      * @see #detachAllViewsFromParent()
   2402      * @see #detachViewsFromParent(int, int)
   2403      * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
   2404      * @see #removeDetachedView(View, boolean)
   2405      */
   2406     protected void detachViewFromParent(int index) {
   2407         removeFromArray(index);
   2408     }
   2409 
   2410     /**
   2411      * Detaches a range of view from their parent. Detaching a view should be temporary and followed
   2412      * either by a call to {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
   2413      * or a call to {@link #removeDetachedView(View, boolean)}. When a view is detached, its
   2414      * parent is null and cannot be retrieved by a call to {@link #getChildAt(int)}.
   2415      *
   2416      * @param start the first index of the childrend range to detach
   2417      * @param count the number of children to detach
   2418      *
   2419      * @see #detachViewFromParent(View)
   2420      * @see #detachViewFromParent(int)
   2421      * @see #detachAllViewsFromParent()
   2422      * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
   2423      * @see #removeDetachedView(View, boolean)
   2424      */
   2425     protected void detachViewsFromParent(int start, int count) {
   2426         removeFromArray(start, count);
   2427     }
   2428 
   2429     /**
   2430      * Detaches all views from the parent. Detaching a view should be temporary and followed
   2431      * either by a call to {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
   2432      * or a call to {@link #removeDetachedView(View, boolean)}. When a view is detached,
   2433      * its parent is null and cannot be retrieved by a call to {@link #getChildAt(int)}.
   2434      *
   2435      * @see #detachViewFromParent(View)
   2436      * @see #detachViewFromParent(int)
   2437      * @see #detachViewsFromParent(int, int)
   2438      * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
   2439      * @see #removeDetachedView(View, boolean)
   2440      */
   2441     protected void detachAllViewsFromParent() {
   2442         final int count = mChildrenCount;
   2443         if (count <= 0) {
   2444             return;
   2445         }
   2446 
   2447         final View[] children = mChildren;
   2448         mChildrenCount = 0;
   2449 
   2450         for (int i = count - 1; i >= 0; i--) {
   2451             children[i].mParent = null;
   2452             children[i] = null;
   2453         }
   2454     }
   2455 
   2456     /**
   2457      * Don't call or override this method. It is used for the implementation of
   2458      * the view hierarchy.
   2459      */
   2460     public final void invalidateChild(View child, final Rect dirty) {
   2461         if (ViewDebug.TRACE_HIERARCHY) {
   2462             ViewDebug.trace(this, ViewDebug.HierarchyTraceType.INVALIDATE_CHILD);
   2463         }
   2464 
   2465         ViewParent parent = this;
   2466 
   2467         final AttachInfo attachInfo = mAttachInfo;
   2468         if (attachInfo != null) {
   2469             final int[] location = attachInfo.mInvalidateChildLocation;
   2470             location[CHILD_LEFT_INDEX] = child.mLeft;
   2471             location[CHILD_TOP_INDEX] = child.mTop;
   2472 
   2473             // If the child is drawing an animation, we want to copy this flag onto
   2474             // ourselves and the parent to make sure the invalidate request goes
   2475             // through
   2476             final boolean drawAnimation = (child.mPrivateFlags & DRAW_ANIMATION) == DRAW_ANIMATION;
   2477 
   2478             // Check whether the child that requests the invalidate is fully opaque
   2479             final boolean isOpaque = child.isOpaque() && !drawAnimation &&
   2480                     child.getAnimation() != null;
   2481             // Mark the child as dirty, using the appropriate flag
   2482             // Make sure we do not set both flags at the same time
   2483             final int opaqueFlag = isOpaque ? DIRTY_OPAQUE : DIRTY;
   2484 
   2485             do {
   2486                 View view = null;
   2487                 if (parent instanceof View) {
   2488                     view = (View) parent;
   2489                 }
   2490 
   2491                 if (drawAnimation) {
   2492                     if (view != null) {
   2493                         view.mPrivateFlags |= DRAW_ANIMATION;
   2494                     } else if (parent instanceof ViewRoot) {
   2495                         ((ViewRoot) parent).mIsAnimating = true;
   2496                     }
   2497                 }
   2498 
   2499                 // If the parent is dirty opaque or not dirty, mark it dirty with the opaque
   2500                 // flag coming from the child that initiated the invalidate
   2501                 if (view != null && (view.mPrivateFlags & DIRTY_MASK) != DIRTY) {
   2502                     view.mPrivateFlags = (view.mPrivateFlags & ~DIRTY_MASK) | opaqueFlag;
   2503                 }
   2504 
   2505                 parent = parent.invalidateChildInParent(location, dirty);
   2506             } while (parent != null);
   2507         }
   2508     }
   2509 
   2510     /**
   2511      * Don't call or override this method. It is used for the implementation of
   2512      * the view hierarchy.
   2513      *
   2514      * This implementation returns null if this ViewGroup does not have a parent,
   2515      * if this ViewGroup is already fully invalidated or if the dirty rectangle
   2516      * does not intersect with this ViewGroup's bounds.
   2517      */
   2518     public ViewParent invalidateChildInParent(final int[] location, final Rect dirty) {
   2519         if (ViewDebug.TRACE_HIERARCHY) {
   2520             ViewDebug.trace(this, ViewDebug.HierarchyTraceType.INVALIDATE_CHILD_IN_PARENT);
   2521         }
   2522 
   2523         if ((mPrivateFlags & DRAWN) == DRAWN) {
   2524             if ((mGroupFlags & (FLAG_OPTIMIZE_INVALIDATE | FLAG_ANIMATION_DONE)) !=
   2525                         FLAG_OPTIMIZE_INVALIDATE) {
   2526                 dirty.offset(location[CHILD_LEFT_INDEX] - mScrollX,
   2527                         location[CHILD_TOP_INDEX] - mScrollY);
   2528 
   2529                 final int left = mLeft;
   2530                 final int top = mTop;
   2531 
   2532                 if (dirty.intersect(0, 0, mRight - left, mBottom - top) ||
   2533                         (mPrivateFlags & DRAW_ANIMATION) == DRAW_ANIMATION) {
   2534                     mPrivateFlags &= ~DRAWING_CACHE_VALID;
   2535 
   2536                     location[CHILD_LEFT_INDEX] = left;
   2537                     location[CHILD_TOP_INDEX] = top;
   2538 
   2539                     return mParent;
   2540                 }
   2541             } else {
   2542                 mPrivateFlags &= ~DRAWN & ~DRAWING_CACHE_VALID;
   2543 
   2544                 location[CHILD_LEFT_INDEX] = mLeft;
   2545                 location[CHILD_TOP_INDEX] = mTop;
   2546 
   2547                 dirty.set(0, 0, mRight - location[CHILD_LEFT_INDEX],
   2548                         mBottom - location[CHILD_TOP_INDEX]);
   2549 
   2550                 return mParent;
   2551             }
   2552         }
   2553 
   2554         return null;
   2555     }
   2556 
   2557     /**
   2558      * Offset a rectangle that is in a descendant's coordinate
   2559      * space into our coordinate space.
   2560      * @param descendant A descendant of this view
   2561      * @param rect A rectangle defined in descendant's coordinate space.
   2562      */
   2563     public final void offsetDescendantRectToMyCoords(View descendant, Rect rect) {
   2564         offsetRectBetweenParentAndChild(descendant, rect, true, false);
   2565     }
   2566 
   2567     /**
   2568      * Offset a rectangle that is in our coordinate space into an ancestor's
   2569      * coordinate space.
   2570      * @param descendant A descendant of this view
   2571      * @param rect A rectangle defined in descendant's coordinate space.
   2572      */
   2573     public final void offsetRectIntoDescendantCoords(View descendant, Rect rect) {
   2574         offsetRectBetweenParentAndChild(descendant, rect, false, false);
   2575     }
   2576 
   2577     /**
   2578      * Helper method that offsets a rect either from parent to descendant or
   2579      * descendant to parent.
   2580      */
   2581     void offsetRectBetweenParentAndChild(View descendant, Rect rect,
   2582             boolean offsetFromChildToParent, boolean clipToBounds) {
   2583 
   2584         // already in the same coord system :)
   2585         if (descendant == this) {
   2586             return;
   2587         }
   2588 
   2589         ViewParent theParent = descendant.mParent;
   2590 
   2591         // search and offset up to the parent
   2592         while ((theParent != null)
   2593                 && (theParent instanceof View)
   2594                 && (theParent != this)) {
   2595 
   2596             if (offsetFromChildToParent) {
   2597                 rect.offset(descendant.mLeft - descendant.mScrollX,
   2598                         descendant.mTop - descendant.mScrollY);
   2599                 if (clipToBounds) {
   2600                     View p = (View) theParent;
   2601                     rect.intersect(0, 0, p.mRight - p.mLeft, p.mBottom - p.mTop);
   2602                 }
   2603             } else {
   2604                 if (clipToBounds) {
   2605                     View p = (View) theParent;
   2606                     rect.intersect(0, 0, p.mRight - p.mLeft, p.mBottom - p.mTop);
   2607                 }
   2608                 rect.offset(descendant.mScrollX - descendant.mLeft,
   2609                         descendant.mScrollY - descendant.mTop);
   2610             }
   2611 
   2612             descendant = (View) theParent;
   2613             theParent = descendant.mParent;
   2614         }
   2615 
   2616         // now that we are up to this view, need to offset one more time
   2617         // to get into our coordinate space
   2618         if (theParent == this) {
   2619             if (offsetFromChildToParent) {
   2620                 rect.offset(descendant.mLeft - descendant.mScrollX,
   2621                         descendant.mTop - descendant.mScrollY);
   2622             } else {
   2623                 rect.offset(descendant.mScrollX - descendant.mLeft,
   2624                         descendant.mScrollY - descendant.mTop);
   2625             }
   2626         } else {
   2627             throw new IllegalArgumentException("parameter must be a descendant of this view");
   2628         }
   2629     }
   2630 
   2631     /**
   2632      * Offset the vertical location of all children of this view by the specified number of pixels.
   2633      *
   2634      * @param offset the number of pixels to offset
   2635      *
   2636      * @hide
   2637      */
   2638     public void offsetChildrenTopAndBottom(int offset) {
   2639         final int count = mChildrenCount;
   2640         final View[] children = mChildren;
   2641 
   2642         for (int i = 0; i < count; i++) {
   2643             final View v = children[i];
   2644             v.mTop += offset;
   2645             v.mBottom += offset;
   2646         }
   2647     }
   2648 
   2649     /**
   2650      * {@inheritDoc}
   2651      */
   2652     public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) {
   2653         int dx = child.mLeft - mScrollX;
   2654         int dy = child.mTop - mScrollY;
   2655         if (offset != null) {
   2656             offset.x += dx;
   2657             offset.y += dy;
   2658         }
   2659         r.offset(dx, dy);
   2660         return r.intersect(0, 0, mRight - mLeft, mBottom - mTop) &&
   2661                (mParent == null || mParent.getChildVisibleRect(this, r, offset));
   2662     }
   2663 
   2664     /**
   2665      * {@inheritDoc}
   2666      */
   2667     @Override
   2668     protected abstract void onLayout(boolean changed,
   2669             int l, int t, int r, int b);
   2670 
   2671     /**
   2672      * Indicates whether the view group has the ability to animate its children
   2673      * after the first layout.
   2674      *
   2675      * @return true if the children can be animated, false otherwise
   2676      */
   2677     protected boolean canAnimate() {
   2678         return mLayoutAnimationController != null;
   2679     }
   2680 
   2681     /**
   2682      * Runs the layout animation. Calling this method triggers a relayout of
   2683      * this view group.
   2684      */
   2685     public void startLayoutAnimation() {
   2686         if (mLayoutAnimationController != null) {
   2687             mGroupFlags |= FLAG_RUN_ANIMATION;
   2688             requestLayout();
   2689         }
   2690     }
   2691 
   2692     /**
   2693      * Schedules the layout animation to be played after the next layout pass
   2694      * of this view group. This can be used to restart the layout animation
   2695      * when the content of the view group changes or when the activity is
   2696      * paused and resumed.
   2697      */
   2698     public void scheduleLayoutAnimation() {
   2699         mGroupFlags |= FLAG_RUN_ANIMATION;
   2700     }
   2701 
   2702     /**
   2703      * Sets the layout animation controller used to animate the group's
   2704      * children after the first layout.
   2705      *
   2706      * @param controller the animation controller
   2707      */
   2708     public void setLayoutAnimation(LayoutAnimationController controller) {
   2709         mLayoutAnimationController = controller;
   2710         if (mLayoutAnimationController != null) {
   2711             mGroupFlags |= FLAG_RUN_ANIMATION;
   2712         }
   2713     }
   2714 
   2715     /**
   2716      * Returns the layout animation controller used to animate the group's
   2717      * children.
   2718      *
   2719      * @return the current animation controller
   2720      */
   2721     public LayoutAnimationController getLayoutAnimation() {
   2722         return mLayoutAnimationController;
   2723     }
   2724 
   2725     /**
   2726      * Indicates whether the children's drawing cache is used during a layout
   2727      * animation. By default, the drawing cache is enabled but this will prevent
   2728      * nested layout animations from working. To nest animations, you must disable
   2729      * the cache.
   2730      *
   2731      * @return true if the animation cache is enabled, false otherwise
   2732      *
   2733      * @see #setAnimationCacheEnabled(boolean)
   2734      * @see View#setDrawingCacheEnabled(boolean)
   2735      */
   2736     @ViewDebug.ExportedProperty
   2737     public boolean isAnimationCacheEnabled() {
   2738         return (mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE;
   2739     }
   2740 
   2741     /**
   2742      * Enables or disables the children's drawing cache during a layout animation.
   2743      * By default, the drawing cache is enabled but this will prevent nested
   2744      * layout animations from working. To nest animations, you must disable the
   2745      * cache.
   2746      *
   2747      * @param enabled true to enable the animation cache, false otherwise
   2748      *
   2749      * @see #isAnimationCacheEnabled()
   2750      * @see View#setDrawingCacheEnabled(boolean)
   2751      */
   2752     public void setAnimationCacheEnabled(boolean enabled) {
   2753         setBooleanFlag(FLAG_ANIMATION_CACHE, enabled);
   2754     }
   2755 
   2756     /**
   2757      * Indicates whether this ViewGroup will always try to draw its children using their
   2758      * drawing cache. By default this property is enabled.
   2759      *
   2760      * @return true if the animation cache is enabled, false otherwise
   2761      *
   2762      * @see #setAlwaysDrawnWithCacheEnabled(boolean)
   2763      * @see #setChildrenDrawnWithCacheEnabled(boolean)
   2764      * @see View#setDrawingCacheEnabled(boolean)
   2765      */
   2766     @ViewDebug.ExportedProperty
   2767     public boolean isAlwaysDrawnWithCacheEnabled() {
   2768         return (mGroupFlags & FLAG_ALWAYS_DRAWN_WITH_CACHE) == FLAG_ALWAYS_DRAWN_WITH_CACHE;
   2769     }
   2770 
   2771     /**
   2772      * Indicates whether this ViewGroup will always try to draw its children using their
   2773      * drawing cache. This property can be set to true when the cache rendering is
   2774      * slightly different from the children's normal rendering. Renderings can be different,
   2775      * for instance, when the cache's quality is set to low.
   2776      *
   2777      * When this property is disabled, the ViewGroup will use the drawing cache of its
   2778      * children only when asked to. It's usually the task of subclasses to tell ViewGroup
   2779      * when to start using the drawing cache and when to stop using it.
   2780      *
   2781      * @param always true to always draw with the drawing cache, false otherwise
   2782      *
   2783      * @see #isAlwaysDrawnWithCacheEnabled()
   2784      * @see #setChildrenDrawnWithCacheEnabled(boolean)
   2785      * @see View#setDrawingCacheEnabled(boolean)
   2786      * @see View#setDrawingCacheQuality(int)
   2787      */
   2788     public void setAlwaysDrawnWithCacheEnabled(boolean always) {
   2789         setBooleanFlag(FLAG_ALWAYS_DRAWN_WITH_CACHE, always);
   2790     }
   2791 
   2792     /**
   2793      * Indicates whether the ViewGroup is currently drawing its children using
   2794      * their drawing cache.
   2795      *
   2796      * @return true if children should be drawn with their cache, false otherwise
   2797      *
   2798      * @see #setAlwaysDrawnWithCacheEnabled(boolean)
   2799      * @see #setChildrenDrawnWithCacheEnabled(boolean)
   2800      */
   2801     @ViewDebug.ExportedProperty
   2802     protected boolean isChildrenDrawnWithCacheEnabled() {
   2803         return (mGroupFlags & FLAG_CHILDREN_DRAWN_WITH_CACHE) == FLAG_CHILDREN_DRAWN_WITH_CACHE;
   2804     }
   2805 
   2806     /**
   2807      * Tells the ViewGroup to draw its children using their drawing cache. This property
   2808      * is ignored when {@link #isAlwaysDrawnWithCacheEnabled()} is true. A child's drawing cache
   2809      * will be used only if it has been enabled.
   2810      *
   2811      * Subclasses should call this method to start and stop using the drawing cache when
   2812      * they perform performance sensitive operations, like scrolling or animating.
   2813      *
   2814      * @param enabled true if children should be drawn with their cache, false otherwise
   2815      *
   2816      * @see #setAlwaysDrawnWithCacheEnabled(boolean)
   2817      * @see #isChildrenDrawnWithCacheEnabled()
   2818      */
   2819     protected void setChildrenDrawnWithCacheEnabled(boolean enabled) {
   2820         setBooleanFlag(FLAG_CHILDREN_DRAWN_WITH_CACHE, enabled);
   2821     }
   2822 
   2823     /**
   2824      * Indicates whether the ViewGroup is drawing its children in the order defined by
   2825      * {@link #getChildDrawingOrder(int, int)}.
   2826      *
   2827      * @return true if children drawing order is defined by {@link #getChildDrawingOrder(int, int)},
   2828      *         false otherwise
   2829      *
   2830      * @see #setChildrenDrawingOrderEnabled(boolean)
   2831      * @see #getChildDrawingOrder(int, int)
   2832      */
   2833     @ViewDebug.ExportedProperty
   2834     protected boolean isChildrenDrawingOrderEnabled() {
   2835         return (mGroupFlags & FLAG_USE_CHILD_DRAWING_ORDER) == FLAG_USE_CHILD_DRAWING_ORDER;
   2836     }
   2837 
   2838     /**
   2839      * Tells the ViewGroup whether to draw its children in the order defined by the method
   2840      * {@link #getChildDrawingOrder(int, int)}.
   2841      *
   2842      * @param enabled true if the order of the children when drawing is determined by
   2843      *        {@link #getChildDrawingOrder(int, int)}, false otherwise
   2844      *
   2845      * @see #isChildrenDrawingOrderEnabled()
   2846      * @see #getChildDrawingOrder(int, int)
   2847      */
   2848     protected void setChildrenDrawingOrderEnabled(boolean enabled) {
   2849         setBooleanFlag(FLAG_USE_CHILD_DRAWING_ORDER, enabled);
   2850     }
   2851 
   2852     private void setBooleanFlag(int flag, boolean value) {
   2853         if (value) {
   2854             mGroupFlags |= flag;
   2855         } else {
   2856             mGroupFlags &= ~flag;
   2857         }
   2858     }
   2859 
   2860     /**
   2861      * Returns an integer indicating what types of drawing caches are kept in memory.
   2862      *
   2863      * @see #setPersistentDrawingCache(int)
   2864      * @see #setAnimationCacheEnabled(boolean)
   2865      *
   2866      * @return one or a combination of {@link #PERSISTENT_NO_CACHE},
   2867      *         {@link #PERSISTENT_ANIMATION_CACHE}, {@link #PERSISTENT_SCROLLING_CACHE}
   2868      *         and {@link #PERSISTENT_ALL_CACHES}
   2869      */
   2870     @ViewDebug.ExportedProperty(mapping = {
   2871         @ViewDebug.IntToString(from = PERSISTENT_NO_CACHE,        to = "NONE"),
   2872         @ViewDebug.IntToString(from = PERSISTENT_ALL_CACHES,      to = "ANIMATION"),
   2873         @ViewDebug.IntToString(from = PERSISTENT_SCROLLING_CACHE, to = "SCROLLING"),
   2874         @ViewDebug.IntToString(from = PERSISTENT_ALL_CACHES,      to = "ALL")
   2875     })
   2876     public int getPersistentDrawingCache() {
   2877         return mPersistentDrawingCache;
   2878     }
   2879 
   2880     /**
   2881      * Indicates what types of drawing caches should be kept in memory after
   2882      * they have been created.
   2883      *
   2884      * @see #getPersistentDrawingCache()
   2885      * @see #setAnimationCacheEnabled(boolean)
   2886      *
   2887      * @param drawingCacheToKeep one or a combination of {@link #PERSISTENT_NO_CACHE},
   2888      *        {@link #PERSISTENT_ANIMATION_CACHE}, {@link #PERSISTENT_SCROLLING_CACHE}
   2889      *        and {@link #PERSISTENT_ALL_CACHES}
   2890      */
   2891     public void setPersistentDrawingCache(int drawingCacheToKeep) {
   2892         mPersistentDrawingCache = drawingCacheToKeep & PERSISTENT_ALL_CACHES;
   2893     }
   2894 
   2895     /**
   2896      * Returns a new set of layout parameters based on the supplied attributes set.
   2897      *
   2898      * @param attrs the attributes to build the layout parameters from
   2899      *
   2900      * @return an instance of {@link android.view.ViewGroup.LayoutParams} or one
   2901      *         of its descendants
   2902      */
   2903     public LayoutParams generateLayoutParams(AttributeSet attrs) {
   2904         return new LayoutParams(getContext(), attrs);
   2905     }
   2906 
   2907     /**
   2908      * Returns a safe set of layout parameters based on the supplied layout params.
   2909      * When a ViewGroup is passed a View whose layout params do not pass the test of
   2910      * {@link #checkLayoutParams(android.view.ViewGroup.LayoutParams)}, this method
   2911      * is invoked. This method should return a new set of layout params suitable for
   2912      * this ViewGroup, possibly by copying the appropriate attributes from the
   2913      * specified set of layout params.
   2914      *
   2915      * @param p The layout parameters to convert into a suitable set of layout parameters
   2916      *          for this ViewGroup.
   2917      *
   2918      * @return an instance of {@link android.view.ViewGroup.LayoutParams} or one
   2919      *         of its descendants
   2920      */
   2921     protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
   2922         return p;
   2923     }
   2924 
   2925     /**
   2926      * Returns a set of default layout parameters. These parameters are requested
   2927      * when the View passed to {@link #addView(View)} has no layout parameters
   2928      * already set. If null is returned, an exception is thrown from addView.
   2929      *
   2930      * @return a set of default layout parameters or null
   2931      */
   2932     protected LayoutParams generateDefaultLayoutParams() {
   2933         return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
   2934     }
   2935 
   2936     /**
   2937      * @hide
   2938      */
   2939     @Override
   2940     protected boolean dispatchConsistencyCheck(int consistency) {
   2941         boolean result = super.dispatchConsistencyCheck(consistency);
   2942 
   2943         final int count = mChildrenCount;
   2944         final View[] children = mChildren;
   2945         for (int i = 0; i < count; i++) {
   2946             if (!children[i].dispatchConsistencyCheck(consistency)) result = false;
   2947         }
   2948 
   2949         return result;
   2950     }
   2951 
   2952     /**
   2953      * @hide
   2954      */
   2955     @Override
   2956     protected boolean onConsistencyCheck(int consistency) {
   2957         boolean result = super.onConsistencyCheck(consistency);
   2958 
   2959         final boolean checkLayout = (consistency & ViewDebug.CONSISTENCY_LAYOUT) != 0;
   2960         final boolean checkDrawing = (consistency & ViewDebug.CONSISTENCY_DRAWING) != 0;
   2961 
   2962         if (checkLayout) {
   2963             final int count = mChildrenCount;
   2964             final View[] children = mChildren;
   2965             for (int i = 0; i < count; i++) {
   2966                 if (children[i].getParent() != this) {
   2967                     result = false;
   2968                     android.util.Log.d(ViewDebug.CONSISTENCY_LOG_TAG,
   2969                             "View " + children[i] + " has no parent/a parent that is not " + this);
   2970                 }
   2971             }
   2972         }
   2973 
   2974         if (checkDrawing) {
   2975             // If this group is dirty, check that the parent is dirty as well
   2976             if ((mPrivateFlags & DIRTY_MASK) != 0) {
   2977                 final ViewParent parent = getParent();
   2978                 if (parent != null && !(parent instanceof ViewRoot)) {
   2979                     if ((((View) parent).mPrivateFlags & DIRTY_MASK) == 0) {
   2980                         result = false;
   2981                         android.util.Log.d(ViewDebug.CONSISTENCY_LOG_TAG,
   2982                                 "ViewGroup " + this + " is dirty but its parent is not: " + this);
   2983                     }
   2984                 }
   2985             }
   2986         }
   2987 
   2988         return result;
   2989     }
   2990 
   2991     /**
   2992      * {@inheritDoc}
   2993      */
   2994     @Override
   2995     protected void debug(int depth) {
   2996         super.debug(depth);
   2997         String output;
   2998 
   2999         if (mFocused != null) {
   3000             output = debugIndent(depth);
   3001             output += "mFocused";
   3002             Log.d(VIEW_LOG_TAG, output);
   3003         }
   3004         if (mChildrenCount != 0) {
   3005             output = debugIndent(depth);
   3006             output += "{";
   3007             Log.d(VIEW_LOG_TAG, output);
   3008         }
   3009         int count = mChildrenCount;
   3010         for (int i = 0; i < count; i++) {
   3011             View child = mChildren[i];
   3012             child.debug(depth + 1);
   3013         }
   3014 
   3015         if (mChildrenCount != 0) {
   3016             output = debugIndent(depth);
   3017             output += "}";
   3018             Log.d(VIEW_LOG_TAG, output);
   3019         }
   3020     }
   3021 
   3022     /**
   3023      * Returns the position in the group of the specified child view.
   3024      *
   3025      * @param child the view for which to get the position
   3026      * @return a positive integer representing the position of the view in the
   3027      *         group, or -1 if the view does not exist in the group
   3028      */
   3029     public int indexOfChild(View child) {
   3030         final int count = mChildrenCount;
   3031         final View[] children = mChildren;
   3032         for (int i = 0; i < count; i++) {
   3033             if (children[i] == child) {
   3034                 return i;
   3035             }
   3036         }
   3037         return -1;
   3038     }
   3039 
   3040     /**
   3041      * Returns the number of children in the group.
   3042      *
   3043      * @return a positive integer representing the number of children in
   3044      *         the group
   3045      */
   3046     public int getChildCount() {
   3047         return mChildrenCount;
   3048     }
   3049 
   3050     /**
   3051      * Returns the view at the specified position in the group.
   3052      *
   3053      * @param index the position at which to get the view from
   3054      * @return the view at the specified position or null if the position
   3055      *         does not exist within the group
   3056      */
   3057     public View getChildAt(int index) {
   3058         try {
   3059             return mChildren[index];
   3060         } catch (IndexOutOfBoundsException ex) {
   3061             return null;
   3062         }
   3063     }
   3064 
   3065     /**
   3066      * Ask all of the children of this view to measure themselves, taking into
   3067      * account both the MeasureSpec requirements for this view and its padding.
   3068      * We skip children that are in the GONE state The heavy lifting is done in
   3069      * getChildMeasureSpec.
   3070      *
   3071      * @param widthMeasureSpec The width requirements for this view
   3072      * @param heightMeasureSpec The height requirements for this view
   3073      */
   3074     protected void measureChildren(int widthMeasureSpec, int heightMeasureSpec) {
   3075         final int size = mChildrenCount;
   3076         final View[] children = mChildren;
   3077         for (int i = 0; i < size; ++i) {
   3078             final View child = children[i];
   3079             if ((child.mViewFlags & VISIBILITY_MASK) != GONE) {
   3080                 measureChild(child, widthMeasureSpec, heightMeasureSpec);
   3081             }
   3082         }
   3083     }
   3084 
   3085     /**
   3086      * Ask one of the children of this view to measure itself, taking into
   3087      * account both the MeasureSpec requirements for this view and its padding.
   3088      * The heavy lifting is done in getChildMeasureSpec.
   3089      *
   3090      * @param child The child to measure
   3091      * @param parentWidthMeasureSpec The width requirements for this view
   3092      * @param parentHeightMeasureSpec The height requirements for this view
   3093      */
   3094     protected void measureChild(View child, int parentWidthMeasureSpec,
   3095             int parentHeightMeasureSpec) {
   3096         final LayoutParams lp = child.getLayoutParams();
   3097 
   3098         final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
   3099                 mPaddingLeft + mPaddingRight, lp.width);
   3100         final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
   3101                 mPaddingTop + mPaddingBottom, lp.height);
   3102 
   3103         child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
   3104     }
   3105 
   3106     /**
   3107      * Ask one of the children of this view to measure itself, taking into
   3108      * account both the MeasureSpec requirements for this view and its padding
   3109      * and margins. The child must have MarginLayoutParams The heavy lifting is
   3110      * done in getChildMeasureSpec.
   3111      *
   3112      * @param child The child to measure
   3113      * @param parentWidthMeasureSpec The width requirements for this view
   3114      * @param widthUsed Extra space that has been used up by the parent
   3115      *        horizontally (possibly by other children of the parent)
   3116      * @param parentHeightMeasureSpec The height requirements for this view
   3117      * @param heightUsed Extra space that has been used up by the parent
   3118      *        vertically (possibly by other children of the parent)
   3119      */
   3120     protected void measureChildWithMargins(View child,
   3121             int parentWidthMeasureSpec, int widthUsed,
   3122             int parentHeightMeasureSpec, int heightUsed) {
   3123         final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
   3124 
   3125         final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
   3126                 mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin
   3127                         + widthUsed, lp.width);
   3128         final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
   3129                 mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin
   3130                         + heightUsed, lp.height);
   3131 
   3132         child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
   3133     }
   3134 
   3135     /**
   3136      * Does the hard part of measureChildren: figuring out the MeasureSpec to
   3137      * pass to a particular child. This method figures out the right MeasureSpec
   3138      * for one dimension (height or width) of one child view.
   3139      *
   3140      * The goal is to combine information from our MeasureSpec with the
   3141      * LayoutParams of the child to get the best possible results. For example,
   3142      * if the this view knows its size (because its MeasureSpec has a mode of
   3143      * EXACTLY), and the child has indicated in its LayoutParams that it wants
   3144      * to be the same size as the parent, the parent should ask the child to
   3145      * layout given an exact size.
   3146      *
   3147      * @param spec The requirements for this view
   3148      * @param padding The padding of this view for the current dimension and
   3149      *        margins, if applicable
   3150      * @param childDimension How big the child wants to be in the current
   3151      *        dimension
   3152      * @return a MeasureSpec integer for the child
   3153      */
   3154     public static int getChildMeasureSpec(int spec, int padding, int childDimension) {
   3155         int specMode = MeasureSpec.getMode(spec);
   3156         int specSize = MeasureSpec.getSize(spec);
   3157 
   3158         int size = Math.max(0, specSize - padding);
   3159 
   3160         int resultSize = 0;
   3161         int resultMode = 0;
   3162 
   3163         switch (specMode) {
   3164         // Parent has imposed an exact size on us
   3165         case MeasureSpec.EXACTLY:
   3166             if (childDimension >= 0) {
   3167                 resultSize = childDimension;
   3168                 resultMode = MeasureSpec.EXACTLY;
   3169             } else if (childDimension == LayoutParams.MATCH_PARENT) {
   3170                 // Child wants to be our size. So be it.
   3171                 resultSize = size;
   3172                 resultMode = MeasureSpec.EXACTLY;
   3173             } else if (childDimension == LayoutParams.WRAP_CONTENT) {
   3174                 // Child wants to determine its own size. It can't be
   3175                 // bigger than us.
   3176                 resultSize = size;
   3177                 resultMode = MeasureSpec.AT_MOST;
   3178             }
   3179             break;
   3180 
   3181         // Parent has imposed a maximum size on us
   3182         case MeasureSpec.AT_MOST:
   3183             if (childDimension >= 0) {
   3184                 // Child wants a specific size... so be it
   3185                 resultSize = childDimension;
   3186                 resultMode = MeasureSpec.EXACTLY;
   3187             } else if (childDimension == LayoutParams.MATCH_PARENT) {
   3188                 // Child wants to be our size, but our size is not fixed.
   3189                 // Constrain child to not be bigger than us.
   3190                 resultSize = size;
   3191                 resultMode = MeasureSpec.AT_MOST;
   3192             } else if (childDimension == LayoutParams.WRAP_CONTENT) {
   3193                 // Child wants to determine its own size. It can't be
   3194                 // bigger than us.
   3195                 resultSize = size;
   3196                 resultMode = MeasureSpec.AT_MOST;
   3197             }
   3198             break;
   3199 
   3200         // Parent asked to see how big we want to be
   3201         case MeasureSpec.UNSPECIFIED:
   3202             if (childDimension >= 0) {
   3203                 // Child wants a specific size... let him have it
   3204                 resultSize = childDimension;
   3205                 resultMode = MeasureSpec.EXACTLY;
   3206             } else if (childDimension == LayoutParams.MATCH_PARENT) {
   3207                 // Child wants to be our size... find out how big it should
   3208                 // be
   3209                 resultSize = 0;
   3210                 resultMode = MeasureSpec.UNSPECIFIED;
   3211             } else if (childDimension == LayoutParams.WRAP_CONTENT) {
   3212                 // Child wants to determine its own size.... find out how
   3213                 // big it should be
   3214                 resultSize = 0;
   3215                 resultMode = MeasureSpec.UNSPECIFIED;
   3216             }
   3217             break;
   3218         }
   3219         return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
   3220     }
   3221 
   3222 
   3223     /**
   3224      * Removes any pending animations for views that have been removed. Call
   3225      * this if you don't want animations for exiting views to stack up.
   3226      */
   3227     public void clearDisappearingChildren() {
   3228         if (mDisappearingChildren != null) {
   3229             mDisappearingChildren.clear();
   3230         }
   3231     }
   3232 
   3233     /**
   3234      * Add a view which is removed from mChildren but still needs animation
   3235      *
   3236      * @param v View to add
   3237      */
   3238     private void addDisappearingView(View v) {
   3239         ArrayList<View> disappearingChildren = mDisappearingChildren;
   3240 
   3241         if (disappearingChildren == null) {
   3242             disappearingChildren = mDisappearingChildren = new ArrayList<View>();
   3243         }
   3244 
   3245         disappearingChildren.add(v);
   3246     }
   3247 
   3248     /**
   3249      * Cleanup a view when its animation is done. This may mean removing it from
   3250      * the list of disappearing views.
   3251      *
   3252      * @param view The view whose animation has finished
   3253      * @param animation The animation, cannot be null
   3254      */
   3255     private void finishAnimatingView(final View view, Animation animation) {
   3256         final ArrayList<View> disappearingChildren = mDisappearingChildren;
   3257         if (disappearingChildren != null) {
   3258             if (disappearingChildren.contains(view)) {
   3259                 disappearingChildren.remove(view);
   3260 
   3261                 if (view.mAttachInfo != null) {
   3262                     view.dispatchDetachedFromWindow();
   3263                 }
   3264 
   3265                 view.clearAnimation();
   3266                 mGroupFlags |= FLAG_INVALIDATE_REQUIRED;
   3267             }
   3268         }
   3269 
   3270         if (animation != null && !animation.getFillAfter()) {
   3271             view.clearAnimation();
   3272         }
   3273 
   3274         if ((view.mPrivateFlags & ANIMATION_STARTED) == ANIMATION_STARTED) {
   3275             view.onAnimationEnd();
   3276             // Should be performed by onAnimationEnd() but this avoid an infinite loop,
   3277             // so we'd rather be safe than sorry
   3278             view.mPrivateFlags &= ~ANIMATION_STARTED;
   3279             // Draw one more frame after the animation is done
   3280             mGroupFlags |= FLAG_INVALIDATE_REQUIRED;
   3281         }
   3282     }
   3283 
   3284     /**
   3285      * {@inheritDoc}
   3286      */
   3287     @Override
   3288     public boolean gatherTransparentRegion(Region region) {
   3289         // If no transparent regions requested, we are always opaque.
   3290         final boolean meOpaque = (mPrivateFlags & View.REQUEST_TRANSPARENT_REGIONS) == 0;
   3291         if (meOpaque && region == null) {
   3292             // The caller doesn't care about the region, so stop now.
   3293             return true;
   3294         }
   3295         super.gatherTransparentRegion(region);
   3296         final View[] children = mChildren;
   3297         final int count = mChildrenCount;
   3298         boolean noneOfTheChildrenAreTransparent = true;
   3299         for (int i = 0; i < count; i++) {
   3300             final View child = children[i];
   3301             if ((child.mViewFlags & VISIBILITY_MASK) != GONE || child.getAnimation() != null) {
   3302                 if (!child.gatherTransparentRegion(region)) {
   3303                     noneOfTheChildrenAreTransparent = false;
   3304                 }
   3305             }
   3306         }
   3307         return meOpaque || noneOfTheChildrenAreTransparent;
   3308     }
   3309 
   3310     /**
   3311      * {@inheritDoc}
   3312      */
   3313     public void requestTransparentRegion(View child) {
   3314         if (child != null) {
   3315             child.mPrivateFlags |= View.REQUEST_TRANSPARENT_REGIONS;
   3316             if (mParent != null) {
   3317                 mParent.requestTransparentRegion(this);
   3318             }
   3319         }
   3320     }
   3321 
   3322 
   3323     @Override
   3324     protected boolean fitSystemWindows(Rect insets) {
   3325         boolean done = super.fitSystemWindows(insets);
   3326         if (!done) {
   3327             final int count = mChildrenCount;
   3328             final View[] children = mChildren;
   3329             for (int i = 0; i < count; i++) {
   3330                 done = children[i].fitSystemWindows(insets);
   3331                 if (done) {
   3332                     break;
   3333                 }
   3334             }
   3335         }
   3336         return done;
   3337     }
   3338 
   3339     /**
   3340      * Returns the animation listener to which layout animation events are
   3341      * sent.
   3342      *
   3343      * @return an {@link android.view.animation.Animation.AnimationListener}
   3344      */
   3345     public Animation.AnimationListener getLayoutAnimationListener() {
   3346         return mAnimationListener;
   3347     }
   3348 
   3349     @Override
   3350     protected void drawableStateChanged() {
   3351         super.drawableStateChanged();
   3352 
   3353         if ((mGroupFlags & FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE) != 0) {
   3354             if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0) {
   3355                 throw new IllegalStateException("addStateFromChildren cannot be enabled if a"
   3356                         + " child has duplicateParentState set to true");
   3357             }
   3358 
   3359             final View[] children = mChildren;
   3360             final int count = mChildrenCount;
   3361 
   3362             for (int i = 0; i < count; i++) {
   3363                 final View child = children[i];
   3364                 if ((child.mViewFlags & DUPLICATE_PARENT_STATE) != 0) {
   3365                     child.refreshDrawableState();
   3366                 }
   3367             }
   3368         }
   3369     }
   3370 
   3371     @Override
   3372     protected int[] onCreateDrawableState(int extraSpace) {
   3373         if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) == 0) {
   3374             return super.onCreateDrawableState(extraSpace);
   3375         }
   3376 
   3377         int need = 0;
   3378         int n = getChildCount();
   3379         for (int i = 0; i < n; i++) {
   3380             int[] childState = getChildAt(i).getDrawableState();
   3381 
   3382             if (childState != null) {
   3383                 need += childState.length;
   3384             }
   3385         }
   3386 
   3387         int[] state = super.onCreateDrawableState(extraSpace + need);
   3388 
   3389         for (int i = 0; i < n; i++) {
   3390             int[] childState = getChildAt(i).getDrawableState();
   3391 
   3392             if (childState != null) {
   3393                 state = mergeDrawableStates(state, childState);
   3394             }
   3395         }
   3396 
   3397         return state;
   3398     }
   3399 
   3400     /**
   3401      * Sets whether this ViewGroup's drawable states also include
   3402      * its children's drawable states.  This is used, for example, to
   3403      * make a group appear to be focused when its child EditText or button
   3404      * is focused.
   3405      */
   3406     public void setAddStatesFromChildren(boolean addsStates) {
   3407         if (addsStates) {
   3408             mGroupFlags |= FLAG_ADD_STATES_FROM_CHILDREN;
   3409         } else {
   3410             mGroupFlags &= ~FLAG_ADD_STATES_FROM_CHILDREN;
   3411         }
   3412 
   3413         refreshDrawableState();
   3414     }
   3415 
   3416     /**
   3417      * Returns whether this ViewGroup's drawable states also include
   3418      * its children's drawable states.  This is used, for example, to
   3419      * make a group appear to be focused when its child EditText or button
   3420      * is focused.
   3421      */
   3422     public boolean addStatesFromChildren() {
   3423         return (mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0;
   3424     }
   3425 
   3426     /**
   3427      * If {link #addStatesFromChildren} is true, refreshes this group's
   3428      * drawable state (to include the states from its children).
   3429      */
   3430     public void childDrawableStateChanged(View child) {
   3431         if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0) {
   3432             refreshDrawableState();
   3433         }
   3434     }
   3435 
   3436     /**
   3437      * Specifies the animation listener to which layout animation events must
   3438      * be sent. Only
   3439      * {@link android.view.animation.Animation.AnimationListener#onAnimationStart(Animation)}
   3440      * and
   3441      * {@link android.view.animation.Animation.AnimationListener#onAnimationEnd(Animation)}
   3442      * are invoked.
   3443      *
   3444      * @param animationListener the layout animation listener
   3445      */
   3446     public void setLayoutAnimationListener(Animation.AnimationListener animationListener) {
   3447         mAnimationListener = animationListener;
   3448     }
   3449 
   3450     /**
   3451      * LayoutParams are used by views to tell their parents how they want to be
   3452      * laid out. See
   3453      * {@link android.R.styleable#ViewGroup_Layout ViewGroup Layout Attributes}
   3454      * for a list of all child view attributes that this class supports.
   3455      *
   3456      * <p>
   3457      * The base LayoutParams class just describes how big the view wants to be
   3458      * for both width and height. For each dimension, it can specify one of:
   3459      * <ul>
   3460      * <li>FILL_PARENT (renamed MATCH_PARENT in API Level 8 and higher), which
   3461      * means that the view wants to be as big as its parent (minus padding)
   3462      * <li> WRAP_CONTENT, which means that the view wants to be just big enough
   3463      * to enclose its content (plus padding)
   3464      * <li> an exact number
   3465      * </ul>
   3466      * There are subclasses of LayoutParams for different subclasses of
   3467      * ViewGroup. For example, AbsoluteLayout has its own subclass of
   3468      * LayoutParams which adds an X and Y value.
   3469      *
   3470      * @attr ref android.R.styleable#ViewGroup_Layout_layout_height
   3471      * @attr ref android.R.styleable#ViewGroup_Layout_layout_width
   3472      */
   3473     public static class LayoutParams {
   3474         /**
   3475          * Special value for the height or width requested by a View.
   3476          * FILL_PARENT means that the view wants to be as big as its parent,
   3477          * minus the parent's padding, if any. This value is deprecated
   3478          * starting in API Level 8 and replaced by {@link #MATCH_PARENT}.
   3479          */
   3480         @SuppressWarnings({"UnusedDeclaration"})
   3481         @Deprecated
   3482         public static final int FILL_PARENT = -1;
   3483 
   3484         /**
   3485          * Special value for the height or width requested by a View.
   3486          * MATCH_PARENT means that the view wants to be as big as its parent,
   3487          * minus the parent's padding, if any. Introduced in API Level 8.
   3488          */
   3489         public static final int MATCH_PARENT = -1;
   3490 
   3491         /**
   3492          * Special value for the height or width requested by a View.
   3493          * WRAP_CONTENT means that the view wants to be just large enough to fit
   3494          * its own internal content, taking its own padding into account.
   3495          */
   3496         public static final int WRAP_CONTENT = -2;
   3497 
   3498         /**
   3499          * Information about how wide the view wants to be. Can be one of the
   3500          * constants FILL_PARENT (replaced by MATCH_PARENT ,
   3501          * in API Level 8) or WRAP_CONTENT. or an exact size.
   3502          */
   3503         @ViewDebug.ExportedProperty(mapping = {
   3504             @ViewDebug.IntToString(from = MATCH_PARENT, to = "MATCH_PARENT"),
   3505             @ViewDebug.IntToString(from = WRAP_CONTENT, to = "WRAP_CONTENT")
   3506         })
   3507         public int width;
   3508 
   3509         /**
   3510          * Information about how tall the view wants to be. Can be one of the
   3511          * constants FILL_PARENT (replaced by MATCH_PARENT ,
   3512          * in API Level 8) or WRAP_CONTENT. or an exact size.
   3513          */
   3514         @ViewDebug.ExportedProperty(mapping = {
   3515             @ViewDebug.IntToString(from = MATCH_PARENT, to = "MATCH_PARENT"),
   3516             @ViewDebug.IntToString(from = WRAP_CONTENT, to = "WRAP_CONTENT")
   3517         })
   3518         public int height;
   3519 
   3520         /**
   3521          * Used to animate layouts.
   3522          */
   3523         public LayoutAnimationController.AnimationParameters layoutAnimationParameters;
   3524 
   3525         /**
   3526          * Creates a new set of layout parameters. The values are extracted from
   3527          * the supplied attributes set and context. The XML attributes mapped
   3528          * to this set of layout parameters are:
   3529          *
   3530          * <ul>
   3531          *   <li><code>layout_width</code>: the width, either an exact value,
   3532          *   {@link #WRAP_CONTENT}, or {@link #FILL_PARENT} (replaced by
   3533          *   {@link #MATCH_PARENT} in API Level 8)</li>
   3534          *   <li><code>layout_height</code>: the height, either an exact value,
   3535          *   {@link #WRAP_CONTENT}, or {@link #FILL_PARENT} (replaced by
   3536          *   {@link #MATCH_PARENT} in API Level 8)</li>
   3537          * </ul>
   3538          *
   3539          * @param c the application environment
   3540          * @param attrs the set of attributes from which to extract the layout
   3541          *              parameters' values
   3542          */
   3543         public LayoutParams(Context c, AttributeSet attrs) {
   3544             TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.ViewGroup_Layout);
   3545             setBaseAttributes(a,
   3546                     R.styleable.ViewGroup_Layout_layout_width,
   3547                     R.styleable.ViewGroup_Layout_layout_height);
   3548             a.recycle();
   3549         }
   3550 
   3551         /**
   3552          * Creates a new set of layout parameters with the specified width
   3553          * and height.
   3554          *
   3555          * @param width the width, either {@link #WRAP_CONTENT},
   3556          *        {@link #FILL_PARENT} (replaced by {@link #MATCH_PARENT} in
   3557          *        API Level 8), or a fixed size in pixels
   3558          * @param height the height, either {@link #WRAP_CONTENT},
   3559          *        {@link #FILL_PARENT} (replaced by {@link #MATCH_PARENT} in
   3560          *        API Level 8), or a fixed size in pixels
   3561          */
   3562         public LayoutParams(int width, int height) {
   3563             this.width = width;
   3564             this.height = height;
   3565         }
   3566 
   3567         /**
   3568          * Copy constructor. Clones the width and height values of the source.
   3569          *
   3570          * @param source The layout params to copy from.
   3571          */
   3572         public LayoutParams(LayoutParams source) {
   3573             this.width = source.width;
   3574             this.height = source.height;
   3575         }
   3576 
   3577         /**
   3578          * Used internally by MarginLayoutParams.
   3579          * @hide
   3580          */
   3581         LayoutParams() {
   3582         }
   3583 
   3584         /**
   3585          * Extracts the layout parameters from the supplied attributes.
   3586          *
   3587          * @param a the style attributes to extract the parameters from
   3588          * @param widthAttr the identifier of the width attribute
   3589          * @param heightAttr the identifier of the height attribute
   3590          */
   3591         protected void setBaseAttributes(TypedArray a, int widthAttr, int heightAttr) {
   3592             width = a.getLayoutDimension(widthAttr, "layout_width");
   3593             height = a.getLayoutDimension(heightAttr, "layout_height");
   3594         }
   3595 
   3596         /**
   3597          * Returns a String representation of this set of layout parameters.
   3598          *
   3599          * @param output the String to prepend to the internal representation
   3600          * @return a String with the following format: output +
   3601          *         "ViewGroup.LayoutParams={ width=WIDTH, height=HEIGHT }"
   3602          *
   3603          * @hide
   3604          */
   3605         public String debug(String output) {
   3606             return output + "ViewGroup.LayoutParams={ width="
   3607                     + sizeToString(width) + ", height=" + sizeToString(height) + " }";
   3608         }
   3609 
   3610         /**
   3611          * Converts the specified size to a readable String.
   3612          *
   3613          * @param size the size to convert
   3614          * @return a String instance representing the supplied size
   3615          *
   3616          * @hide
   3617          */
   3618         protected static String sizeToString(int size) {
   3619             if (size == WRAP_CONTENT) {
   3620                 return "wrap-content";
   3621             }
   3622             if (size == MATCH_PARENT) {
   3623                 return "match-parent";
   3624             }
   3625             return String.valueOf(size);
   3626         }
   3627     }
   3628 
   3629     /**
   3630      * Per-child layout information for layouts that support margins.
   3631      * See
   3632      * {@link android.R.styleable#ViewGroup_MarginLayout ViewGroup Margin Layout Attributes}
   3633      * for a list of all child view attributes that this class supports.
   3634      */
   3635     public static class MarginLayoutParams extends ViewGroup.LayoutParams {
   3636         /**
   3637          * The left margin in pixels of the child.
   3638          */
   3639         @ViewDebug.ExportedProperty
   3640         public int leftMargin;
   3641 
   3642         /**
   3643          * The top margin in pixels of the child.
   3644          */
   3645         @ViewDebug.ExportedProperty
   3646         public int topMargin;
   3647 
   3648         /**
   3649          * The right margin in pixels of the child.
   3650          */
   3651         @ViewDebug.ExportedProperty
   3652         public int rightMargin;
   3653 
   3654         /**
   3655          * The bottom margin in pixels of the child.
   3656          */
   3657         @ViewDebug.ExportedProperty
   3658         public int bottomMargin;
   3659 
   3660         /**
   3661          * Creates a new set of layout parameters. The values are extracted from
   3662          * the supplied attributes set and context.
   3663          *
   3664          * @param c the application environment
   3665          * @param attrs the set of attributes from which to extract the layout
   3666          *              parameters' values
   3667          */
   3668         public MarginLayoutParams(Context c, AttributeSet attrs) {
   3669             super();
   3670 
   3671             TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.ViewGroup_MarginLayout);
   3672             setBaseAttributes(a,
   3673                     R.styleable.ViewGroup_MarginLayout_layout_width,
   3674                     R.styleable.ViewGroup_MarginLayout_layout_height);
   3675 
   3676             int margin = a.getDimensionPixelSize(
   3677                     com.android.internal.R.styleable.ViewGroup_MarginLayout_layout_margin, -1);
   3678             if (margin >= 0) {
   3679                 leftMargin = margin;
   3680                 topMargin = margin;
   3681                 rightMargin= margin;
   3682                 bottomMargin = margin;
   3683             } else {
   3684                 leftMargin = a.getDimensionPixelSize(
   3685                         R.styleable.ViewGroup_MarginLayout_layout_marginLeft, 0);
   3686                 topMargin = a.getDimensionPixelSize(
   3687                         R.styleable.ViewGroup_MarginLayout_layout_marginTop, 0);
   3688                 rightMargin = a.getDimensionPixelSize(
   3689                         R.styleable.ViewGroup_MarginLayout_layout_marginRight, 0);
   3690                 bottomMargin = a.getDimensionPixelSize(
   3691                         R.styleable.ViewGroup_MarginLayout_layout_marginBottom, 0);
   3692             }
   3693 
   3694             a.recycle();
   3695         }
   3696 
   3697         /**
   3698          * {@inheritDoc}
   3699          */
   3700         public MarginLayoutParams(int width, int height) {
   3701             super(width, height);
   3702         }
   3703 
   3704         /**
   3705          * Copy constructor. Clones the width, height and margin values of the source.
   3706          *
   3707          * @param source The layout params to copy from.
   3708          */
   3709         public MarginLayoutParams(MarginLayoutParams source) {
   3710             this.width = source.width;
   3711             this.height = source.height;
   3712 
   3713             this.leftMargin = source.leftMargin;
   3714             this.topMargin = source.topMargin;
   3715             this.rightMargin = source.rightMargin;
   3716             this.bottomMargin = source.bottomMargin;
   3717         }
   3718 
   3719         /**
   3720          * {@inheritDoc}
   3721          */
   3722         public MarginLayoutParams(LayoutParams source) {
   3723             super(source);
   3724         }
   3725 
   3726         /**
   3727          * Sets the margins, in pixels.
   3728          *
   3729          * @param left the left margin size
   3730          * @param top the top margin size
   3731          * @param right the right margin size
   3732          * @param bottom the bottom margin size
   3733          *
   3734          * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginLeft
   3735          * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginTop
   3736          * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginRight
   3737          * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginBottom
   3738          */
   3739         public void setMargins(int left, int top, int right, int bottom) {
   3740             leftMargin = left;
   3741             topMargin = top;
   3742             rightMargin = right;
   3743             bottomMargin = bottom;
   3744         }
   3745     }
   3746 }
   3747