ViewGroup.java revision e36d6e277e49475076b7872d36ea6a5c5b996e9d
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
17package android.view;
18
19import com.android.internal.R;
20
21import android.content.Context;
22import android.content.res.Configuration;
23import android.content.res.TypedArray;
24import android.graphics.Bitmap;
25import android.graphics.Canvas;
26import android.graphics.Paint;
27import android.graphics.Rect;
28import android.graphics.RectF;
29import android.graphics.Region;
30import android.os.Parcelable;
31import android.os.SystemClock;
32import android.util.AttributeSet;
33import android.util.Config;
34import android.util.EventLog;
35import android.util.Log;
36import android.util.SparseArray;
37import android.view.accessibility.AccessibilityEvent;
38import android.view.animation.Animation;
39import android.view.animation.AnimationUtils;
40import android.view.animation.LayoutAnimationController;
41import android.view.animation.Transformation;
42
43import 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 */
67public 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                            if (child.dispatchTouchEvent(ev))  {
863                                // Event handled, we have a target now.
864                                mMotionTarget = child;
865                                return true;
866                            }
867                            // The event didn't get handled, try the next view.
868                            // Don't reset the event's location, it's not
869                            // necessary here.
870                        }
871                    }
872                }
873            }
874        }
875
876        boolean isUpOrCancel = (action == MotionEvent.ACTION_UP) ||
877                (action == MotionEvent.ACTION_CANCEL);
878
879        if (isUpOrCancel) {
880            // Note, we've already copied the previous state to our local
881            // variable, so this takes effect on the next event
882            mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
883        }
884
885        // The event wasn't an ACTION_DOWN, dispatch it to our target if
886        // we have one.
887        final View target = mMotionTarget;
888        if (target == null) {
889            // We don't have a target, this means we're handling the
890            // event as a regular view.
891            ev.setLocation(xf, yf);
892            return super.dispatchTouchEvent(ev);
893        }
894
895        // if have a target, see if we're allowed to and want to intercept its
896        // events
897        if (!disallowIntercept && onInterceptTouchEvent(ev)) {
898            final float xc = scrolledXFloat - (float) target.mLeft;
899            final float yc = scrolledYFloat - (float) target.mTop;
900            ev.setAction(MotionEvent.ACTION_CANCEL);
901            ev.setLocation(xc, yc);
902            if (!target.dispatchTouchEvent(ev)) {
903                // target didn't handle ACTION_CANCEL. not much we can do
904                // but they should have.
905            }
906            // clear the target
907            mMotionTarget = null;
908            // Don't dispatch this event to our own view, because we already
909            // saw it when intercepting; we just want to give the following
910            // event to the normal onTouchEvent().
911            return true;
912        }
913
914        if (isUpOrCancel) {
915            mMotionTarget = null;
916        }
917
918        // finally offset the event to the target's coordinate system and
919        // dispatch the event.
920        final float xc = scrolledXFloat - (float) target.mLeft;
921        final float yc = scrolledYFloat - (float) target.mTop;
922        ev.setLocation(xc, yc);
923
924        return target.dispatchTouchEvent(ev);
925    }
926
927    /**
928     * {@inheritDoc}
929     */
930    public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
931
932        if (disallowIntercept == ((mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0)) {
933            // We're already in this state, assume our ancestors are too
934            return;
935        }
936
937        if (disallowIntercept) {
938            mGroupFlags |= FLAG_DISALLOW_INTERCEPT;
939        } else {
940            mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
941        }
942
943        // Pass it up to our parent
944        if (mParent != null) {
945            mParent.requestDisallowInterceptTouchEvent(disallowIntercept);
946        }
947    }
948
949    /**
950     * Implement this method to intercept all touch screen motion events.  This
951     * allows you to watch events as they are dispatched to your children, and
952     * take ownership of the current gesture at any point.
953     *
954     * <p>Using this function takes some care, as it has a fairly complicated
955     * interaction with {@link View#onTouchEvent(MotionEvent)
956     * View.onTouchEvent(MotionEvent)}, and using it requires implementing
957     * that method as well as this one in the correct way.  Events will be
958     * received in the following order:
959     *
960     * <ol>
961     * <li> You will receive the down event here.
962     * <li> The down event will be handled either by a child of this view
963     * group, or given to your own onTouchEvent() method to handle; this means
964     * you should implement onTouchEvent() to return true, so you will
965     * continue to see the rest of the gesture (instead of looking for
966     * a parent view to handle it).  Also, by returning true from
967     * onTouchEvent(), you will not receive any following
968     * events in onInterceptTouchEvent() and all touch processing must
969     * happen in onTouchEvent() like normal.
970     * <li> For as long as you return false from this function, each following
971     * event (up to and including the final up) will be delivered first here
972     * and then to the target's onTouchEvent().
973     * <li> If you return true from here, you will not receive any
974     * following events: the target view will receive the same event but
975     * with the action {@link MotionEvent#ACTION_CANCEL}, and all further
976     * events will be delivered to your onTouchEvent() method and no longer
977     * appear here.
978     * </ol>
979     *
980     * @param ev The motion event being dispatched down the hierarchy.
981     * @return Return true to steal motion events from the children and have
982     * them dispatched to this ViewGroup through onTouchEvent().
983     * The current target will receive an ACTION_CANCEL event, and no further
984     * messages will be delivered here.
985     */
986    public boolean onInterceptTouchEvent(MotionEvent ev) {
987        return false;
988    }
989
990    /**
991     * {@inheritDoc}
992     *
993     * Looks for a view to give focus to respecting the setting specified by
994     * {@link #getDescendantFocusability()}.
995     *
996     * Uses {@link #onRequestFocusInDescendants(int, android.graphics.Rect)} to
997     * find focus within the children of this group when appropriate.
998     *
999     * @see #FOCUS_BEFORE_DESCENDANTS
1000     * @see #FOCUS_AFTER_DESCENDANTS
1001     * @see #FOCUS_BLOCK_DESCENDANTS
1002     * @see #onRequestFocusInDescendants
1003     */
1004    @Override
1005    public boolean requestFocus(int direction, Rect previouslyFocusedRect) {
1006        if (DBG) {
1007            System.out.println(this + " ViewGroup.requestFocus direction="
1008                    + direction);
1009        }
1010        int descendantFocusability = getDescendantFocusability();
1011
1012        switch (descendantFocusability) {
1013            case FOCUS_BLOCK_DESCENDANTS:
1014                return super.requestFocus(direction, previouslyFocusedRect);
1015            case FOCUS_BEFORE_DESCENDANTS: {
1016                final boolean took = super.requestFocus(direction, previouslyFocusedRect);
1017                return took ? took : onRequestFocusInDescendants(direction, previouslyFocusedRect);
1018            }
1019            case FOCUS_AFTER_DESCENDANTS: {
1020                final boolean took = onRequestFocusInDescendants(direction, previouslyFocusedRect);
1021                return took ? took : super.requestFocus(direction, previouslyFocusedRect);
1022            }
1023            default:
1024                throw new IllegalStateException("descendant focusability must be "
1025                        + "one of FOCUS_BEFORE_DESCENDANTS, FOCUS_AFTER_DESCENDANTS, FOCUS_BLOCK_DESCENDANTS "
1026                        + "but is " + descendantFocusability);
1027        }
1028    }
1029
1030    /**
1031     * Look for a descendant to call {@link View#requestFocus} on.
1032     * Called by {@link ViewGroup#requestFocus(int, android.graphics.Rect)}
1033     * when it wants to request focus within its children.  Override this to
1034     * customize how your {@link ViewGroup} requests focus within its children.
1035     * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT
1036     * @param previouslyFocusedRect The rectangle (in this View's coordinate system)
1037     *        to give a finer grained hint about where focus is coming from.  May be null
1038     *        if there is no hint.
1039     * @return Whether focus was taken.
1040     */
1041    @SuppressWarnings({"ConstantConditions"})
1042    protected boolean onRequestFocusInDescendants(int direction,
1043            Rect previouslyFocusedRect) {
1044        int index;
1045        int increment;
1046        int end;
1047        int count = mChildrenCount;
1048        if ((direction & FOCUS_FORWARD) != 0) {
1049            index = 0;
1050            increment = 1;
1051            end = count;
1052        } else {
1053            index = count - 1;
1054            increment = -1;
1055            end = -1;
1056        }
1057        final View[] children = mChildren;
1058        for (int i = index; i != end; i += increment) {
1059            View child = children[i];
1060            if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
1061                if (child.requestFocus(direction, previouslyFocusedRect)) {
1062                    return true;
1063                }
1064            }
1065        }
1066        return false;
1067    }
1068
1069    /**
1070     * {@inheritDoc}
1071     */
1072    @Override
1073    void dispatchAttachedToWindow(AttachInfo info, int visibility) {
1074        super.dispatchAttachedToWindow(info, visibility);
1075        visibility |= mViewFlags & VISIBILITY_MASK;
1076        final int count = mChildrenCount;
1077        final View[] children = mChildren;
1078        for (int i = 0; i < count; i++) {
1079            children[i].dispatchAttachedToWindow(info, visibility);
1080        }
1081    }
1082
1083    @Override
1084    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
1085        boolean populated = false;
1086        for (int i = 0, count = getChildCount(); i < count; i++) {
1087            populated |= getChildAt(i).dispatchPopulateAccessibilityEvent(event);
1088        }
1089        return populated;
1090    }
1091
1092    /**
1093     * {@inheritDoc}
1094     */
1095    @Override
1096    void dispatchDetachedFromWindow() {
1097        // If we still have a motion target, we are still in the process of
1098        // dispatching motion events to a child; we need to get rid of that
1099        // child to avoid dispatching events to it after the window is torn
1100        // down. To make sure we keep the child in a consistent state, we
1101        // first send it an ACTION_CANCEL motion event.
1102        if (mMotionTarget != null) {
1103            final long now = SystemClock.uptimeMillis();
1104            final MotionEvent event = MotionEvent.obtain(now, now,
1105                    MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
1106            mMotionTarget.dispatchTouchEvent(event);
1107            event.recycle();
1108            mMotionTarget = null;
1109        }
1110
1111        final int count = mChildrenCount;
1112        final View[] children = mChildren;
1113        for (int i = 0; i < count; i++) {
1114            children[i].dispatchDetachedFromWindow();
1115        }
1116        super.dispatchDetachedFromWindow();
1117    }
1118
1119    /**
1120     * {@inheritDoc}
1121     */
1122    @Override
1123    public void setPadding(int left, int top, int right, int bottom) {
1124        super.setPadding(left, top, right, bottom);
1125
1126        if ((mPaddingLeft | mPaddingTop | mPaddingRight | mPaddingRight) != 0) {
1127            mGroupFlags |= FLAG_PADDING_NOT_NULL;
1128        } else {
1129            mGroupFlags &= ~FLAG_PADDING_NOT_NULL;
1130        }
1131    }
1132
1133    /**
1134     * {@inheritDoc}
1135     */
1136    @Override
1137    protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {
1138        super.dispatchSaveInstanceState(container);
1139        final int count = mChildrenCount;
1140        final View[] children = mChildren;
1141        for (int i = 0; i < count; i++) {
1142            children[i].dispatchSaveInstanceState(container);
1143        }
1144    }
1145
1146    /**
1147     * Perform dispatching of a {@link #saveHierarchyState freeze()} to only this view,
1148     * not to its children.  For use when overriding
1149     * {@link #dispatchSaveInstanceState dispatchFreeze()} to allow subclasses to freeze
1150     * their own state but not the state of their children.
1151     *
1152     * @param container the container
1153     */
1154    protected void dispatchFreezeSelfOnly(SparseArray<Parcelable> container) {
1155        super.dispatchSaveInstanceState(container);
1156    }
1157
1158    /**
1159     * {@inheritDoc}
1160     */
1161    @Override
1162    protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {
1163        super.dispatchRestoreInstanceState(container);
1164        final int count = mChildrenCount;
1165        final View[] children = mChildren;
1166        for (int i = 0; i < count; i++) {
1167            children[i].dispatchRestoreInstanceState(container);
1168        }
1169    }
1170
1171    /**
1172     * Perform dispatching of a {@link #restoreHierarchyState thaw()} to only this view,
1173     * not to its children.  For use when overriding
1174     * {@link #dispatchRestoreInstanceState dispatchThaw()} to allow subclasses to thaw
1175     * their own state but not the state of their children.
1176     *
1177     * @param container the container
1178     */
1179    protected void dispatchThawSelfOnly(SparseArray<Parcelable> container) {
1180        super.dispatchRestoreInstanceState(container);
1181    }
1182
1183    /**
1184     * Enables or disables the drawing cache for each child of this view group.
1185     *
1186     * @param enabled true to enable the cache, false to dispose of it
1187     */
1188    protected void setChildrenDrawingCacheEnabled(boolean enabled) {
1189        if (enabled || (mPersistentDrawingCache & PERSISTENT_ALL_CACHES) != PERSISTENT_ALL_CACHES) {
1190            final View[] children = mChildren;
1191            final int count = mChildrenCount;
1192            for (int i = 0; i < count; i++) {
1193                children[i].setDrawingCacheEnabled(enabled);
1194            }
1195        }
1196    }
1197
1198    @Override
1199    protected void onAnimationStart() {
1200        super.onAnimationStart();
1201
1202        // When this ViewGroup's animation starts, build the cache for the children
1203        if ((mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE) {
1204            final int count = mChildrenCount;
1205            final View[] children = mChildren;
1206
1207            for (int i = 0; i < count; i++) {
1208                final View child = children[i];
1209                if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
1210                    child.setDrawingCacheEnabled(true);
1211                    child.buildDrawingCache(true);
1212                }
1213            }
1214
1215            mGroupFlags |= FLAG_CHILDREN_DRAWN_WITH_CACHE;
1216        }
1217    }
1218
1219    @Override
1220    protected void onAnimationEnd() {
1221        super.onAnimationEnd();
1222
1223        // When this ViewGroup's animation ends, destroy the cache of the children
1224        if ((mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE) {
1225            mGroupFlags &= ~FLAG_CHILDREN_DRAWN_WITH_CACHE;
1226
1227            if ((mPersistentDrawingCache & PERSISTENT_ANIMATION_CACHE) == 0) {
1228                setChildrenDrawingCacheEnabled(false);
1229            }
1230        }
1231    }
1232
1233    /**
1234     * {@inheritDoc}
1235     */
1236    @Override
1237    protected void dispatchDraw(Canvas canvas) {
1238        final int count = mChildrenCount;
1239        final View[] children = mChildren;
1240        int flags = mGroupFlags;
1241
1242        if ((flags & FLAG_RUN_ANIMATION) != 0 && canAnimate()) {
1243            final boolean cache = (mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE;
1244
1245            for (int i = 0; i < count; i++) {
1246                final View child = children[i];
1247                if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
1248                    final LayoutParams params = child.getLayoutParams();
1249                    attachLayoutAnimationParameters(child, params, i, count);
1250                    bindLayoutAnimation(child);
1251                    if (cache) {
1252                        child.setDrawingCacheEnabled(true);
1253                        child.buildDrawingCache(true);
1254                    }
1255                }
1256            }
1257
1258            final LayoutAnimationController controller = mLayoutAnimationController;
1259            if (controller.willOverlap()) {
1260                mGroupFlags |= FLAG_OPTIMIZE_INVALIDATE;
1261            }
1262
1263            controller.start();
1264
1265            mGroupFlags &= ~FLAG_RUN_ANIMATION;
1266            mGroupFlags &= ~FLAG_ANIMATION_DONE;
1267
1268            if (cache) {
1269                mGroupFlags |= FLAG_CHILDREN_DRAWN_WITH_CACHE;
1270            }
1271
1272            if (mAnimationListener != null) {
1273                mAnimationListener.onAnimationStart(controller.getAnimation());
1274            }
1275        }
1276
1277        int saveCount = 0;
1278        final boolean clipToPadding = (flags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK;
1279        if (clipToPadding) {
1280            saveCount = canvas.save();
1281            canvas.clipRect(mScrollX + mPaddingLeft, mScrollY + mPaddingTop,
1282                    mScrollX + mRight - mLeft - mPaddingRight,
1283                    mScrollY + mBottom - mTop - mPaddingBottom);
1284
1285        }
1286
1287        // We will draw our child's animation, let's reset the flag
1288        mPrivateFlags &= ~DRAW_ANIMATION;
1289        mGroupFlags &= ~FLAG_INVALIDATE_REQUIRED;
1290
1291        boolean more = false;
1292        final long drawingTime = getDrawingTime();
1293
1294        if ((flags & FLAG_USE_CHILD_DRAWING_ORDER) == 0) {
1295            for (int i = 0; i < count; i++) {
1296                final View child = children[i];
1297                if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
1298                    more |= drawChild(canvas, child, drawingTime);
1299                }
1300            }
1301        } else {
1302            for (int i = 0; i < count; i++) {
1303                final View child = children[getChildDrawingOrder(count, i)];
1304                if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
1305                    more |= drawChild(canvas, child, drawingTime);
1306                }
1307            }
1308        }
1309
1310        // Draw any disappearing views that have animations
1311        if (mDisappearingChildren != null) {
1312            final ArrayList<View> disappearingChildren = mDisappearingChildren;
1313            final int disappearingCount = disappearingChildren.size() - 1;
1314            // Go backwards -- we may delete as animations finish
1315            for (int i = disappearingCount; i >= 0; i--) {
1316                final View child = disappearingChildren.get(i);
1317                more |= drawChild(canvas, child, drawingTime);
1318            }
1319        }
1320
1321        if (clipToPadding) {
1322            canvas.restoreToCount(saveCount);
1323        }
1324
1325        // mGroupFlags might have been updated by drawChild()
1326        flags = mGroupFlags;
1327
1328        if ((flags & FLAG_INVALIDATE_REQUIRED) == FLAG_INVALIDATE_REQUIRED) {
1329            invalidate();
1330        }
1331
1332        if ((flags & FLAG_ANIMATION_DONE) == 0 && (flags & FLAG_NOTIFY_ANIMATION_LISTENER) == 0 &&
1333                mLayoutAnimationController.isDone() && !more) {
1334            // We want to erase the drawing cache and notify the listener after the
1335            // next frame is drawn because one extra invalidate() is caused by
1336            // drawChild() after the animation is over
1337            mGroupFlags |= FLAG_NOTIFY_ANIMATION_LISTENER;
1338            final Runnable end = new Runnable() {
1339               public void run() {
1340                   notifyAnimationListener();
1341               }
1342            };
1343            post(end);
1344        }
1345    }
1346
1347    /**
1348     * Returns the index of the child to draw for this iteration. Override this
1349     * if you want to change the drawing order of children. By default, it
1350     * returns i.
1351     * <p>
1352     * NOTE: In order for this method to be called, you must enable child ordering
1353     * first by calling {@link #setChildrenDrawingOrderEnabled(boolean)}.
1354     *
1355     * @param i The current iteration.
1356     * @return The index of the child to draw this iteration.
1357     *
1358     * @see #setChildrenDrawingOrderEnabled(boolean)
1359     * @see #isChildrenDrawingOrderEnabled()
1360     */
1361    protected int getChildDrawingOrder(int childCount, int i) {
1362        return i;
1363    }
1364
1365    private void notifyAnimationListener() {
1366        mGroupFlags &= ~FLAG_NOTIFY_ANIMATION_LISTENER;
1367        mGroupFlags |= FLAG_ANIMATION_DONE;
1368
1369        if (mAnimationListener != null) {
1370           final Runnable end = new Runnable() {
1371               public void run() {
1372                   mAnimationListener.onAnimationEnd(mLayoutAnimationController.getAnimation());
1373               }
1374           };
1375           post(end);
1376        }
1377
1378        if ((mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE) {
1379            mGroupFlags &= ~FLAG_CHILDREN_DRAWN_WITH_CACHE;
1380            if ((mPersistentDrawingCache & PERSISTENT_ANIMATION_CACHE) == 0) {
1381                setChildrenDrawingCacheEnabled(false);
1382            }
1383        }
1384
1385        invalidate();
1386    }
1387
1388    /**
1389     * Draw one child of this View Group. This method is responsible for getting
1390     * the canvas in the right state. This includes clipping, translating so
1391     * that the child's scrolled origin is at 0, 0, and applying any animation
1392     * transformations.
1393     *
1394     * @param canvas The canvas on which to draw the child
1395     * @param child Who to draw
1396     * @param drawingTime The time at which draw is occuring
1397     * @return True if an invalidate() was issued
1398     */
1399    protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
1400        boolean more = false;
1401
1402        final int cl = child.mLeft;
1403        final int ct = child.mTop;
1404        final int cr = child.mRight;
1405        final int cb = child.mBottom;
1406
1407        final int flags = mGroupFlags;
1408
1409        if ((flags & FLAG_CLEAR_TRANSFORMATION) == FLAG_CLEAR_TRANSFORMATION) {
1410            if (mChildTransformation != null) {
1411                mChildTransformation.clear();
1412            }
1413            mGroupFlags &= ~FLAG_CLEAR_TRANSFORMATION;
1414        }
1415
1416        Transformation transformToApply = null;
1417        final Animation a = child.getAnimation();
1418        boolean concatMatrix = false;
1419
1420        if (a != null) {
1421            if (mInvalidateRegion == null) {
1422                mInvalidateRegion = new RectF();
1423            }
1424            final RectF region = mInvalidateRegion;
1425
1426            final boolean initialized = a.isInitialized();
1427            if (!initialized) {
1428                a.initialize(cr - cl, cb - ct, getWidth(), getHeight());
1429                a.initializeInvalidateRegion(0, 0, cr - cl, cb - ct);
1430                child.onAnimationStart();
1431            }
1432
1433            if (mChildTransformation == null) {
1434                mChildTransformation = new Transformation();
1435            }
1436            more = a.getTransformation(drawingTime, mChildTransformation);
1437            transformToApply = mChildTransformation;
1438
1439            concatMatrix = a.willChangeTransformationMatrix();
1440
1441            if (more) {
1442                if (!a.willChangeBounds()) {
1443                    if ((flags & (FLAG_OPTIMIZE_INVALIDATE | FLAG_ANIMATION_DONE)) ==
1444                            FLAG_OPTIMIZE_INVALIDATE) {
1445                        mGroupFlags |= FLAG_INVALIDATE_REQUIRED;
1446                    } else if ((flags & FLAG_INVALIDATE_REQUIRED) == 0) {
1447                        // The child need to draw an animation, potentially offscreen, so
1448                        // make sure we do not cancel invalidate requests
1449                        mPrivateFlags |= DRAW_ANIMATION;
1450                        invalidate(cl, ct, cr, cb);
1451                    }
1452                } else {
1453                    a.getInvalidateRegion(0, 0, cr - cl, cb - ct, region, transformToApply);
1454
1455                    // The child need to draw an animation, potentially offscreen, so
1456                    // make sure we do not cancel invalidate requests
1457                    mPrivateFlags |= DRAW_ANIMATION;
1458
1459                    final int left = cl + (int) region.left;
1460                    final int top = ct + (int) region.top;
1461                    invalidate(left, top, left + (int) region.width(), top + (int) region.height());
1462                }
1463            }
1464        } else if ((flags & FLAG_SUPPORT_STATIC_TRANSFORMATIONS) ==
1465                FLAG_SUPPORT_STATIC_TRANSFORMATIONS) {
1466            if (mChildTransformation == null) {
1467                mChildTransformation = new Transformation();
1468            }
1469            final boolean hasTransform = getChildStaticTransformation(child, mChildTransformation);
1470            if (hasTransform) {
1471                final int transformType = mChildTransformation.getTransformationType();
1472                transformToApply = transformType != Transformation.TYPE_IDENTITY ?
1473                        mChildTransformation : null;
1474                concatMatrix = (transformType & Transformation.TYPE_MATRIX) != 0;
1475            }
1476        }
1477
1478        // Sets the flag as early as possible to allow draw() implementations
1479        // to call invalidate() successfully when doing animations
1480        child.mPrivateFlags |= DRAWN;
1481
1482        if (!concatMatrix && canvas.quickReject(cl, ct, cr, cb, Canvas.EdgeType.BW) &&
1483                (child.mPrivateFlags & DRAW_ANIMATION) == 0) {
1484            return more;
1485        }
1486
1487        child.computeScroll();
1488
1489        final int sx = child.mScrollX;
1490        final int sy = child.mScrollY;
1491
1492        boolean scalingRequired = false;
1493        Bitmap cache = null;
1494        if ((flags & FLAG_CHILDREN_DRAWN_WITH_CACHE) == FLAG_CHILDREN_DRAWN_WITH_CACHE ||
1495                (flags & FLAG_ALWAYS_DRAWN_WITH_CACHE) == FLAG_ALWAYS_DRAWN_WITH_CACHE) {
1496            cache = child.getDrawingCache(true);
1497            if (mAttachInfo != null) scalingRequired = mAttachInfo.mScalingRequired;
1498        }
1499
1500        final boolean hasNoCache = cache == null;
1501
1502        final int restoreTo = canvas.save();
1503        if (hasNoCache) {
1504            canvas.translate(cl - sx, ct - sy);
1505        } else {
1506            canvas.translate(cl, ct);
1507            if (scalingRequired) {
1508                // mAttachInfo cannot be null, otherwise scalingRequired == false
1509                final float scale = 1.0f / mAttachInfo.mApplicationScale;
1510                canvas.scale(scale, scale);
1511            }
1512        }
1513
1514        float alpha = 1.0f;
1515
1516        if (transformToApply != null) {
1517            if (concatMatrix) {
1518                int transX = 0;
1519                int transY = 0;
1520                if (hasNoCache) {
1521                    transX = -sx;
1522                    transY = -sy;
1523                }
1524                // Undo the scroll translation, apply the transformation matrix,
1525                // then redo the scroll translate to get the correct result.
1526                canvas.translate(-transX, -transY);
1527                canvas.concat(transformToApply.getMatrix());
1528                canvas.translate(transX, transY);
1529                mGroupFlags |= FLAG_CLEAR_TRANSFORMATION;
1530            }
1531
1532            alpha = transformToApply.getAlpha();
1533            if (alpha < 1.0f) {
1534                mGroupFlags |= FLAG_CLEAR_TRANSFORMATION;
1535            }
1536
1537            if (alpha < 1.0f && hasNoCache) {
1538                final int multipliedAlpha = (int) (255 * alpha);
1539                if (!child.onSetAlpha(multipliedAlpha)) {
1540                    canvas.saveLayerAlpha(sx, sy, sx + cr - cl, sy + cb - ct, multipliedAlpha,
1541                            Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG);
1542                } else {
1543                    child.mPrivateFlags |= ALPHA_SET;
1544                }
1545            }
1546        } else if ((child.mPrivateFlags & ALPHA_SET) == ALPHA_SET) {
1547            child.onSetAlpha(255);
1548        }
1549
1550        if ((flags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN) {
1551            if (hasNoCache) {
1552                canvas.clipRect(sx, sy, sx + (cr - cl), sy + (cb - ct));
1553            } else {
1554                if (!scalingRequired) {
1555                    canvas.clipRect(0, 0, cr - cl, cb - ct);
1556                } else {
1557                    canvas.clipRect(0, 0, cache.getWidth(), cache.getHeight());
1558                }
1559            }
1560        }
1561
1562        if (hasNoCache) {
1563            // Fast path for layouts with no backgrounds
1564            if ((child.mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
1565                if (ViewDebug.TRACE_HIERARCHY) {
1566                    ViewDebug.trace(this, ViewDebug.HierarchyTraceType.DRAW);
1567                }
1568                child.mPrivateFlags &= ~DIRTY_MASK;
1569                child.dispatchDraw(canvas);
1570            } else {
1571                child.draw(canvas);
1572            }
1573        } else {
1574            final Paint cachePaint = mCachePaint;
1575            if (alpha < 1.0f) {
1576                cachePaint.setAlpha((int) (alpha * 255));
1577                mGroupFlags |= FLAG_ALPHA_LOWER_THAN_ONE;
1578            } else if  ((flags & FLAG_ALPHA_LOWER_THAN_ONE) == FLAG_ALPHA_LOWER_THAN_ONE) {
1579                cachePaint.setAlpha(255);
1580                mGroupFlags &= ~FLAG_ALPHA_LOWER_THAN_ONE;
1581            }
1582            if (Config.DEBUG && ViewDebug.profileDrawing) {
1583                EventLog.writeEvent(60003, hashCode());
1584            }
1585            canvas.drawBitmap(cache, 0.0f, 0.0f, cachePaint);
1586        }
1587
1588        canvas.restoreToCount(restoreTo);
1589
1590        if (a != null && !more) {
1591            child.onSetAlpha(255);
1592            finishAnimatingView(child, a);
1593        }
1594
1595        return more;
1596    }
1597
1598    /**
1599     * By default, children are clipped to their bounds before drawing. This
1600     * allows view groups to override this behavior for animations, etc.
1601     *
1602     * @param clipChildren true to clip children to their bounds,
1603     *        false otherwise
1604     * @attr ref android.R.styleable#ViewGroup_clipChildren
1605     */
1606    public void setClipChildren(boolean clipChildren) {
1607        setBooleanFlag(FLAG_CLIP_CHILDREN, clipChildren);
1608    }
1609
1610    /**
1611     * By default, children are clipped to the padding of the ViewGroup. This
1612     * allows view groups to override this behavior
1613     *
1614     * @param clipToPadding true to clip children to the padding of the
1615     *        group, false otherwise
1616     * @attr ref android.R.styleable#ViewGroup_clipToPadding
1617     */
1618    public void setClipToPadding(boolean clipToPadding) {
1619        setBooleanFlag(FLAG_CLIP_TO_PADDING, clipToPadding);
1620    }
1621
1622    /**
1623     * {@inheritDoc}
1624     */
1625    @Override
1626    public void dispatchSetSelected(boolean selected) {
1627        final View[] children = mChildren;
1628        final int count = mChildrenCount;
1629        for (int i = 0; i < count; i++) {
1630            children[i].setSelected(selected);
1631        }
1632    }
1633
1634    @Override
1635    protected void dispatchSetPressed(boolean pressed) {
1636        final View[] children = mChildren;
1637        final int count = mChildrenCount;
1638        for (int i = 0; i < count; i++) {
1639            children[i].setPressed(pressed);
1640        }
1641    }
1642
1643    /**
1644     * When this property is set to true, this ViewGroup supports static transformations on
1645     * children; this causes
1646     * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} to be
1647     * invoked when a child is drawn.
1648     *
1649     * Any subclass overriding
1650     * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} should
1651     * set this property to true.
1652     *
1653     * @param enabled True to enable static transformations on children, false otherwise.
1654     *
1655     * @see #FLAG_SUPPORT_STATIC_TRANSFORMATIONS
1656     */
1657    protected void setStaticTransformationsEnabled(boolean enabled) {
1658        setBooleanFlag(FLAG_SUPPORT_STATIC_TRANSFORMATIONS, enabled);
1659    }
1660
1661    /**
1662     * {@inheritDoc}
1663     *
1664     * @see #setStaticTransformationsEnabled(boolean)
1665     */
1666    protected boolean getChildStaticTransformation(View child, Transformation t) {
1667        return false;
1668    }
1669
1670    /**
1671     * {@hide}
1672     */
1673    @Override
1674    protected View findViewTraversal(int id) {
1675        if (id == mID) {
1676            return this;
1677        }
1678
1679        final View[] where = mChildren;
1680        final int len = mChildrenCount;
1681
1682        for (int i = 0; i < len; i++) {
1683            View v = where[i];
1684
1685            if ((v.mPrivateFlags & IS_ROOT_NAMESPACE) == 0) {
1686                v = v.findViewById(id);
1687
1688                if (v != null) {
1689                    return v;
1690                }
1691            }
1692        }
1693
1694        return null;
1695    }
1696
1697    /**
1698     * {@hide}
1699     */
1700    @Override
1701    protected View findViewWithTagTraversal(Object tag) {
1702        if (tag != null && tag.equals(mTag)) {
1703            return this;
1704        }
1705
1706        final View[] where = mChildren;
1707        final int len = mChildrenCount;
1708
1709        for (int i = 0; i < len; i++) {
1710            View v = where[i];
1711
1712            if ((v.mPrivateFlags & IS_ROOT_NAMESPACE) == 0) {
1713                v = v.findViewWithTag(tag);
1714
1715                if (v != null) {
1716                    return v;
1717                }
1718            }
1719        }
1720
1721        return null;
1722    }
1723
1724    /**
1725     * Adds a child view. If no layout parameters are already set on the child, the
1726     * default parameters for this ViewGroup are set on the child.
1727     *
1728     * @param child the child view to add
1729     *
1730     * @see #generateDefaultLayoutParams()
1731     */
1732    public void addView(View child) {
1733        addView(child, -1);
1734    }
1735
1736    /**
1737     * Adds a child view. If no layout parameters are already set on the child, the
1738     * default parameters for this ViewGroup are set on the child.
1739     *
1740     * @param child the child view to add
1741     * @param index the position at which to add the child
1742     *
1743     * @see #generateDefaultLayoutParams()
1744     */
1745    public void addView(View child, int index) {
1746        LayoutParams params = child.getLayoutParams();
1747        if (params == null) {
1748            params = generateDefaultLayoutParams();
1749            if (params == null) {
1750                throw new IllegalArgumentException("generateDefaultLayoutParams() cannot return null");
1751            }
1752        }
1753        addView(child, index, params);
1754    }
1755
1756    /**
1757     * Adds a child view with this ViewGroup's default layout parameters and the
1758     * specified width and height.
1759     *
1760     * @param child the child view to add
1761     */
1762    public void addView(View child, int width, int height) {
1763        final LayoutParams params = generateDefaultLayoutParams();
1764        params.width = width;
1765        params.height = height;
1766        addView(child, -1, params);
1767    }
1768
1769    /**
1770     * Adds a child view with the specified layout parameters.
1771     *
1772     * @param child the child view to add
1773     * @param params the layout parameters to set on the child
1774     */
1775    public void addView(View child, LayoutParams params) {
1776        addView(child, -1, params);
1777    }
1778
1779    /**
1780     * Adds a child view with the specified layout parameters.
1781     *
1782     * @param child the child view to add
1783     * @param index the position at which to add the child
1784     * @param params the layout parameters to set on the child
1785     */
1786    public void addView(View child, int index, LayoutParams params) {
1787        if (DBG) {
1788            System.out.println(this + " addView");
1789        }
1790
1791        // addViewInner() will call child.requestLayout() when setting the new LayoutParams
1792        // therefore, we call requestLayout() on ourselves before, so that the child's request
1793        // will be blocked at our level
1794        requestLayout();
1795        invalidate();
1796        addViewInner(child, index, params, false);
1797    }
1798
1799    /**
1800     * {@inheritDoc}
1801     */
1802    public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
1803        if (!checkLayoutParams(params)) {
1804            throw new IllegalArgumentException("Invalid LayoutParams supplied to " + this);
1805        }
1806        if (view.mParent != this) {
1807            throw new IllegalArgumentException("Given view not a child of " + this);
1808        }
1809        view.setLayoutParams(params);
1810    }
1811
1812    /**
1813     * {@inheritDoc}
1814     */
1815    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
1816        return  p != null;
1817    }
1818
1819    /**
1820     * Interface definition for a callback to be invoked when the hierarchy
1821     * within this view changed. The hierarchy changes whenever a child is added
1822     * to or removed from this view.
1823     */
1824    public interface OnHierarchyChangeListener {
1825        /**
1826         * Called when a new child is added to a parent view.
1827         *
1828         * @param parent the view in which a child was added
1829         * @param child the new child view added in the hierarchy
1830         */
1831        void onChildViewAdded(View parent, View child);
1832
1833        /**
1834         * Called when a child is removed from a parent view.
1835         *
1836         * @param parent the view from which the child was removed
1837         * @param child the child removed from the hierarchy
1838         */
1839        void onChildViewRemoved(View parent, View child);
1840    }
1841
1842    /**
1843     * Register a callback to be invoked when a child is added to or removed
1844     * from this view.
1845     *
1846     * @param listener the callback to invoke on hierarchy change
1847     */
1848    public void setOnHierarchyChangeListener(OnHierarchyChangeListener listener) {
1849        mOnHierarchyChangeListener = listener;
1850    }
1851
1852    /**
1853     * Adds a view during layout. This is useful if in your onLayout() method,
1854     * you need to add more views (as does the list view for example).
1855     *
1856     * If index is negative, it means put it at the end of the list.
1857     *
1858     * @param child the view to add to the group
1859     * @param index the index at which the child must be added
1860     * @param params the layout parameters to associate with the child
1861     * @return true if the child was added, false otherwise
1862     */
1863    protected boolean addViewInLayout(View child, int index, LayoutParams params) {
1864        return addViewInLayout(child, index, params, false);
1865    }
1866
1867    /**
1868     * Adds a view during layout. This is useful if in your onLayout() method,
1869     * you need to add more views (as does the list view for example).
1870     *
1871     * If index is negative, it means put it at the end of the list.
1872     *
1873     * @param child the view to add to the group
1874     * @param index the index at which the child must be added
1875     * @param params the layout parameters to associate with the child
1876     * @param preventRequestLayout if true, calling this method will not trigger a
1877     *        layout request on child
1878     * @return true if the child was added, false otherwise
1879     */
1880    protected boolean addViewInLayout(View child, int index, LayoutParams params,
1881            boolean preventRequestLayout) {
1882        child.mParent = null;
1883        addViewInner(child, index, params, preventRequestLayout);
1884        child.mPrivateFlags = (child.mPrivateFlags & ~DIRTY_MASK) | DRAWN;
1885        return true;
1886    }
1887
1888    /**
1889     * Prevents the specified child to be laid out during the next layout pass.
1890     *
1891     * @param child the child on which to perform the cleanup
1892     */
1893    protected void cleanupLayoutState(View child) {
1894        child.mPrivateFlags &= ~View.FORCE_LAYOUT;
1895    }
1896
1897    private void addViewInner(View child, int index, LayoutParams params,
1898            boolean preventRequestLayout) {
1899
1900        if (child.getParent() != null) {
1901            throw new IllegalStateException("The specified child already has a parent. " +
1902                    "You must call removeView() on the child's parent first.");
1903        }
1904
1905        if (!checkLayoutParams(params)) {
1906            params = generateLayoutParams(params);
1907        }
1908
1909        if (preventRequestLayout) {
1910            child.mLayoutParams = params;
1911        } else {
1912            child.setLayoutParams(params);
1913        }
1914
1915        if (index < 0) {
1916            index = mChildrenCount;
1917        }
1918
1919        addInArray(child, index);
1920
1921        // tell our children
1922        if (preventRequestLayout) {
1923            child.assignParent(this);
1924        } else {
1925            child.mParent = this;
1926        }
1927
1928        if (child.hasFocus()) {
1929            requestChildFocus(child, child.findFocus());
1930        }
1931
1932        AttachInfo ai = mAttachInfo;
1933        if (ai != null) {
1934            boolean lastKeepOn = ai.mKeepScreenOn;
1935            ai.mKeepScreenOn = false;
1936            child.dispatchAttachedToWindow(mAttachInfo, (mViewFlags&VISIBILITY_MASK));
1937            if (ai.mKeepScreenOn) {
1938                needGlobalAttributesUpdate(true);
1939            }
1940            ai.mKeepScreenOn = lastKeepOn;
1941        }
1942
1943        if (mOnHierarchyChangeListener != null) {
1944            mOnHierarchyChangeListener.onChildViewAdded(this, child);
1945        }
1946
1947        if ((child.mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE) {
1948            mGroupFlags |= FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE;
1949        }
1950    }
1951
1952    private void addInArray(View child, int index) {
1953        View[] children = mChildren;
1954        final int count = mChildrenCount;
1955        final int size = children.length;
1956        if (index == count) {
1957            if (size == count) {
1958                mChildren = new View[size + ARRAY_CAPACITY_INCREMENT];
1959                System.arraycopy(children, 0, mChildren, 0, size);
1960                children = mChildren;
1961            }
1962            children[mChildrenCount++] = child;
1963        } else if (index < count) {
1964            if (size == count) {
1965                mChildren = new View[size + ARRAY_CAPACITY_INCREMENT];
1966                System.arraycopy(children, 0, mChildren, 0, index);
1967                System.arraycopy(children, index, mChildren, index + 1, count - index);
1968                children = mChildren;
1969            } else {
1970                System.arraycopy(children, index, children, index + 1, count - index);
1971            }
1972            children[index] = child;
1973            mChildrenCount++;
1974        } else {
1975            throw new IndexOutOfBoundsException("index=" + index + " count=" + count);
1976        }
1977    }
1978
1979    // This method also sets the child's mParent to null
1980    private void removeFromArray(int index) {
1981        final View[] children = mChildren;
1982        children[index].mParent = null;
1983        final int count = mChildrenCount;
1984        if (index == count - 1) {
1985            children[--mChildrenCount] = null;
1986        } else if (index >= 0 && index < count) {
1987            System.arraycopy(children, index + 1, children, index, count - index - 1);
1988            children[--mChildrenCount] = null;
1989        } else {
1990            throw new IndexOutOfBoundsException();
1991        }
1992    }
1993
1994    // This method also sets the children's mParent to null
1995    private void removeFromArray(int start, int count) {
1996        final View[] children = mChildren;
1997        final int childrenCount = mChildrenCount;
1998
1999        start = Math.max(0, start);
2000        final int end = Math.min(childrenCount, start + count);
2001
2002        if (start == end) {
2003            return;
2004        }
2005
2006        if (end == childrenCount) {
2007            for (int i = start; i < end; i++) {
2008                children[i].mParent = null;
2009                children[i] = null;
2010            }
2011        } else {
2012            for (int i = start; i < end; i++) {
2013                children[i].mParent = null;
2014            }
2015
2016            // Since we're looping above, we might as well do the copy, but is arraycopy()
2017            // faster than the extra 2 bounds checks we would do in the loop?
2018            System.arraycopy(children, end, children, start, childrenCount - end);
2019
2020            for (int i = childrenCount - (end - start); i < childrenCount; i++) {
2021                children[i] = null;
2022            }
2023        }
2024
2025        mChildrenCount -= (end - start);
2026    }
2027
2028    private void bindLayoutAnimation(View child) {
2029        Animation a = mLayoutAnimationController.getAnimationForView(child);
2030        child.setAnimation(a);
2031    }
2032
2033    /**
2034     * Subclasses should override this method to set layout animation
2035     * parameters on the supplied child.
2036     *
2037     * @param child the child to associate with animation parameters
2038     * @param params the child's layout parameters which hold the animation
2039     *        parameters
2040     * @param index the index of the child in the view group
2041     * @param count the number of children in the view group
2042     */
2043    protected void attachLayoutAnimationParameters(View child,
2044            LayoutParams params, int index, int count) {
2045        LayoutAnimationController.AnimationParameters animationParams =
2046                    params.layoutAnimationParameters;
2047        if (animationParams == null) {
2048            animationParams = new LayoutAnimationController.AnimationParameters();
2049            params.layoutAnimationParameters = animationParams;
2050        }
2051
2052        animationParams.count = count;
2053        animationParams.index = index;
2054    }
2055
2056    /**
2057     * {@inheritDoc}
2058     */
2059    public void removeView(View view) {
2060        removeViewInternal(view);
2061        requestLayout();
2062        invalidate();
2063    }
2064
2065    /**
2066     * Removes a view during layout. This is useful if in your onLayout() method,
2067     * you need to remove more views.
2068     *
2069     * @param view the view to remove from the group
2070     */
2071    public void removeViewInLayout(View view) {
2072        removeViewInternal(view);
2073    }
2074
2075    /**
2076     * Removes a range of views during layout. This is useful if in your onLayout() method,
2077     * you need to remove more views.
2078     *
2079     * @param start the index of the first view to remove from the group
2080     * @param count the number of views to remove from the group
2081     */
2082    public void removeViewsInLayout(int start, int count) {
2083        removeViewsInternal(start, count);
2084    }
2085
2086    /**
2087     * Removes the view at the specified position in the group.
2088     *
2089     * @param index the position in the group of the view to remove
2090     */
2091    public void removeViewAt(int index) {
2092        removeViewInternal(index, getChildAt(index));
2093        requestLayout();
2094        invalidate();
2095    }
2096
2097    /**
2098     * Removes the specified range of views from the group.
2099     *
2100     * @param start the first position in the group of the range of views to remove
2101     * @param count the number of views to remove
2102     */
2103    public void removeViews(int start, int count) {
2104        removeViewsInternal(start, count);
2105        requestLayout();
2106        invalidate();
2107    }
2108
2109    private void removeViewInternal(View view) {
2110        final int index = indexOfChild(view);
2111        if (index >= 0) {
2112            removeViewInternal(index, view);
2113        }
2114    }
2115
2116    private void removeViewInternal(int index, View view) {
2117        boolean clearChildFocus = false;
2118        if (view == mFocused) {
2119            view.clearFocusForRemoval();
2120            clearChildFocus = true;
2121        }
2122
2123        if (view.getAnimation() != null) {
2124            addDisappearingView(view);
2125        } else if (view.mAttachInfo != null) {
2126           view.dispatchDetachedFromWindow();
2127        }
2128
2129        if (mOnHierarchyChangeListener != null) {
2130            mOnHierarchyChangeListener.onChildViewRemoved(this, view);
2131        }
2132
2133        needGlobalAttributesUpdate(false);
2134
2135        removeFromArray(index);
2136
2137        if (clearChildFocus) {
2138            clearChildFocus(view);
2139        }
2140    }
2141
2142    private void removeViewsInternal(int start, int count) {
2143        final OnHierarchyChangeListener onHierarchyChangeListener = mOnHierarchyChangeListener;
2144        final boolean notifyListener = onHierarchyChangeListener != null;
2145        final View focused = mFocused;
2146        final boolean detach = mAttachInfo != null;
2147        View clearChildFocus = null;
2148
2149        final View[] children = mChildren;
2150        final int end = start + count;
2151
2152        for (int i = start; i < end; i++) {
2153            final View view = children[i];
2154
2155            if (view == focused) {
2156                view.clearFocusForRemoval();
2157                clearChildFocus = view;
2158            }
2159
2160            if (view.getAnimation() != null) {
2161                addDisappearingView(view);
2162            } else if (detach) {
2163               view.dispatchDetachedFromWindow();
2164            }
2165
2166            needGlobalAttributesUpdate(false);
2167
2168            if (notifyListener) {
2169                onHierarchyChangeListener.onChildViewRemoved(this, view);
2170            }
2171        }
2172
2173        removeFromArray(start, count);
2174
2175        if (clearChildFocus != null) {
2176            clearChildFocus(clearChildFocus);
2177        }
2178    }
2179
2180    /**
2181     * Call this method to remove all child views from the
2182     * ViewGroup.
2183     */
2184    public void removeAllViews() {
2185        removeAllViewsInLayout();
2186        requestLayout();
2187        invalidate();
2188    }
2189
2190    /**
2191     * Called by a ViewGroup subclass to remove child views from itself,
2192     * when it must first know its size on screen before it can calculate how many
2193     * child views it will render. An example is a Gallery or a ListView, which
2194     * may "have" 50 children, but actually only render the number of children
2195     * that can currently fit inside the object on screen. Do not call
2196     * this method unless you are extending ViewGroup and understand the
2197     * view measuring and layout pipeline.
2198     */
2199    public void removeAllViewsInLayout() {
2200        final int count = mChildrenCount;
2201        if (count <= 0) {
2202            return;
2203        }
2204
2205        final View[] children = mChildren;
2206        mChildrenCount = 0;
2207
2208        final OnHierarchyChangeListener listener = mOnHierarchyChangeListener;
2209        final boolean notify = listener != null;
2210        final View focused = mFocused;
2211        final boolean detach = mAttachInfo != null;
2212        View clearChildFocus = null;
2213
2214        needGlobalAttributesUpdate(false);
2215
2216        for (int i = count - 1; i >= 0; i--) {
2217            final View view = children[i];
2218
2219            if (view == focused) {
2220                view.clearFocusForRemoval();
2221                clearChildFocus = view;
2222            }
2223
2224            if (view.getAnimation() != null) {
2225                addDisappearingView(view);
2226            } else if (detach) {
2227               view.dispatchDetachedFromWindow();
2228            }
2229
2230            if (notify) {
2231                listener.onChildViewRemoved(this, view);
2232            }
2233
2234            view.mParent = null;
2235            children[i] = null;
2236        }
2237
2238        if (clearChildFocus != null) {
2239            clearChildFocus(clearChildFocus);
2240        }
2241    }
2242
2243    /**
2244     * Finishes the removal of a detached view. This method will dispatch the detached from
2245     * window event and notify the hierarchy change listener.
2246     *
2247     * @param child the child to be definitely removed from the view hierarchy
2248     * @param animate if true and the view has an animation, the view is placed in the
2249     *                disappearing views list, otherwise, it is detached from the window
2250     *
2251     * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
2252     * @see #detachAllViewsFromParent()
2253     * @see #detachViewFromParent(View)
2254     * @see #detachViewFromParent(int)
2255     */
2256    protected void removeDetachedView(View child, boolean animate) {
2257        if (child == mFocused) {
2258            child.clearFocus();
2259        }
2260
2261        if (animate && child.getAnimation() != null) {
2262            addDisappearingView(child);
2263        } else if (child.mAttachInfo != null) {
2264            child.dispatchDetachedFromWindow();
2265        }
2266
2267        if (mOnHierarchyChangeListener != null) {
2268            mOnHierarchyChangeListener.onChildViewRemoved(this, child);
2269        }
2270    }
2271
2272    /**
2273     * Attaches a view to this view group. Attaching a view assigns this group as the parent,
2274     * sets the layout parameters and puts the view in the list of children so it can be retrieved
2275     * by calling {@link #getChildAt(int)}.
2276     *
2277     * This method should be called only for view which were detached from their parent.
2278     *
2279     * @param child the child to attach
2280     * @param index the index at which the child should be attached
2281     * @param params the layout parameters of the child
2282     *
2283     * @see #removeDetachedView(View, boolean)
2284     * @see #detachAllViewsFromParent()
2285     * @see #detachViewFromParent(View)
2286     * @see #detachViewFromParent(int)
2287     */
2288    protected void attachViewToParent(View child, int index, LayoutParams params) {
2289        child.mLayoutParams = params;
2290
2291        if (index < 0) {
2292            index = mChildrenCount;
2293        }
2294
2295        addInArray(child, index);
2296
2297        child.mParent = this;
2298        child.mPrivateFlags = (child.mPrivateFlags & ~DIRTY_MASK & ~DRAWING_CACHE_VALID) | DRAWN;
2299
2300        if (child.hasFocus()) {
2301            requestChildFocus(child, child.findFocus());
2302        }
2303    }
2304
2305    /**
2306     * Detaches a view from its parent. Detaching a view should be temporary and followed
2307     * either by a call to {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
2308     * or a call to {@link #removeDetachedView(View, boolean)}. When a view is detached,
2309     * its parent is null and cannot be retrieved by a call to {@link #getChildAt(int)}.
2310     *
2311     * @param child the child to detach
2312     *
2313     * @see #detachViewFromParent(int)
2314     * @see #detachViewsFromParent(int, int)
2315     * @see #detachAllViewsFromParent()
2316     * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
2317     * @see #removeDetachedView(View, boolean)
2318     */
2319    protected void detachViewFromParent(View child) {
2320        removeFromArray(indexOfChild(child));
2321    }
2322
2323    /**
2324     * Detaches a view from its parent. Detaching a view should be temporary and followed
2325     * either by a call to {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
2326     * or a call to {@link #removeDetachedView(View, boolean)}. When a view is detached,
2327     * its parent is null and cannot be retrieved by a call to {@link #getChildAt(int)}.
2328     *
2329     * @param index the index of the child to detach
2330     *
2331     * @see #detachViewFromParent(View)
2332     * @see #detachAllViewsFromParent()
2333     * @see #detachViewsFromParent(int, int)
2334     * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
2335     * @see #removeDetachedView(View, boolean)
2336     */
2337    protected void detachViewFromParent(int index) {
2338        removeFromArray(index);
2339    }
2340
2341    /**
2342     * Detaches a range of view from their parent. Detaching a view should be temporary and followed
2343     * either by a call to {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
2344     * or a call to {@link #removeDetachedView(View, boolean)}. When a view is detached, its
2345     * parent is null and cannot be retrieved by a call to {@link #getChildAt(int)}.
2346     *
2347     * @param start the first index of the childrend range to detach
2348     * @param count the number of children to detach
2349     *
2350     * @see #detachViewFromParent(View)
2351     * @see #detachViewFromParent(int)
2352     * @see #detachAllViewsFromParent()
2353     * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
2354     * @see #removeDetachedView(View, boolean)
2355     */
2356    protected void detachViewsFromParent(int start, int count) {
2357        removeFromArray(start, count);
2358    }
2359
2360    /**
2361     * Detaches all views from the parent. Detaching a view should be temporary and followed
2362     * either by a call to {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
2363     * or a call to {@link #removeDetachedView(View, boolean)}. When a view is detached,
2364     * its parent is null and cannot be retrieved by a call to {@link #getChildAt(int)}.
2365     *
2366     * @see #detachViewFromParent(View)
2367     * @see #detachViewFromParent(int)
2368     * @see #detachViewsFromParent(int, int)
2369     * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
2370     * @see #removeDetachedView(View, boolean)
2371     */
2372    protected void detachAllViewsFromParent() {
2373        final int count = mChildrenCount;
2374        if (count <= 0) {
2375            return;
2376        }
2377
2378        final View[] children = mChildren;
2379        mChildrenCount = 0;
2380
2381        for (int i = count - 1; i >= 0; i--) {
2382            children[i].mParent = null;
2383            children[i] = null;
2384        }
2385    }
2386
2387    /**
2388     * Don't call or override this method. It is used for the implementation of
2389     * the view hierarchy.
2390     */
2391    public final void invalidateChild(View child, final Rect dirty) {
2392        if (ViewDebug.TRACE_HIERARCHY) {
2393            ViewDebug.trace(this, ViewDebug.HierarchyTraceType.INVALIDATE_CHILD);
2394        }
2395
2396        ViewParent parent = this;
2397
2398        final AttachInfo attachInfo = mAttachInfo;
2399        if (attachInfo != null) {
2400            final int[] location = attachInfo.mInvalidateChildLocation;
2401            location[CHILD_LEFT_INDEX] = child.mLeft;
2402            location[CHILD_TOP_INDEX] = child.mTop;
2403
2404            // If the child is drawing an animation, we want to copy this flag onto
2405            // ourselves and the parent to make sure the invalidate request goes
2406            // through
2407            final boolean drawAnimation = (child.mPrivateFlags & DRAW_ANIMATION) == DRAW_ANIMATION;
2408
2409            // Check whether the child that requests the invalidate is fully opaque
2410            final boolean isOpaque = child.isOpaque() && !drawAnimation &&
2411                    child.getAnimation() != null;
2412            // Mark the child as dirty, using the appropriate flag
2413            // Make sure we do not set both flags at the same time
2414            final int opaqueFlag = isOpaque ? DIRTY_OPAQUE : DIRTY;
2415
2416            do {
2417                View view = null;
2418                if (parent instanceof View) {
2419                    view = (View) parent;
2420                }
2421
2422                if (drawAnimation) {
2423                    if (view != null) {
2424                        view.mPrivateFlags |= DRAW_ANIMATION;
2425                    } else if (parent instanceof ViewRoot) {
2426                        ((ViewRoot) parent).mIsAnimating = true;
2427                    }
2428                }
2429
2430                // If the parent is dirty opaque or not dirty, mark it dirty with the opaque
2431                // flag coming from the child that initiated the invalidate
2432                if (view != null && (view.mPrivateFlags & DIRTY_MASK) != DIRTY) {
2433                    view.mPrivateFlags = (view.mPrivateFlags & ~DIRTY_MASK) | opaqueFlag;
2434                }
2435
2436                parent = parent.invalidateChildInParent(location, dirty);
2437            } while (parent != null);
2438        }
2439    }
2440
2441    /**
2442     * Don't call or override this method. It is used for the implementation of
2443     * the view hierarchy.
2444     *
2445     * This implementation returns null if this ViewGroup does not have a parent,
2446     * if this ViewGroup is already fully invalidated or if the dirty rectangle
2447     * does not intersect with this ViewGroup's bounds.
2448     */
2449    public ViewParent invalidateChildInParent(final int[] location, final Rect dirty) {
2450        if (ViewDebug.TRACE_HIERARCHY) {
2451            ViewDebug.trace(this, ViewDebug.HierarchyTraceType.INVALIDATE_CHILD_IN_PARENT);
2452        }
2453
2454        if ((mPrivateFlags & DRAWN) == DRAWN) {
2455            if ((mGroupFlags & (FLAG_OPTIMIZE_INVALIDATE | FLAG_ANIMATION_DONE)) !=
2456                        FLAG_OPTIMIZE_INVALIDATE) {
2457                dirty.offset(location[CHILD_LEFT_INDEX] - mScrollX,
2458                        location[CHILD_TOP_INDEX] - mScrollY);
2459
2460                final int left = mLeft;
2461                final int top = mTop;
2462
2463                if (dirty.intersect(0, 0, mRight - left, mBottom - top) ||
2464                        (mPrivateFlags & DRAW_ANIMATION) == DRAW_ANIMATION) {
2465                    mPrivateFlags &= ~DRAWING_CACHE_VALID;
2466
2467                    location[CHILD_LEFT_INDEX] = left;
2468                    location[CHILD_TOP_INDEX] = top;
2469
2470                    return mParent;
2471                }
2472            } else {
2473                mPrivateFlags &= ~DRAWN & ~DRAWING_CACHE_VALID;
2474
2475                location[CHILD_LEFT_INDEX] = mLeft;
2476                location[CHILD_TOP_INDEX] = mTop;
2477
2478                dirty.set(0, 0, mRight - location[CHILD_LEFT_INDEX],
2479                        mBottom - location[CHILD_TOP_INDEX]);
2480
2481                return mParent;
2482            }
2483        }
2484
2485        return null;
2486    }
2487
2488    /**
2489     * Offset a rectangle that is in a descendant's coordinate
2490     * space into our coordinate space.
2491     * @param descendant A descendant of this view
2492     * @param rect A rectangle defined in descendant's coordinate space.
2493     */
2494    public final void offsetDescendantRectToMyCoords(View descendant, Rect rect) {
2495        offsetRectBetweenParentAndChild(descendant, rect, true, false);
2496    }
2497
2498    /**
2499     * Offset a rectangle that is in our coordinate space into an ancestor's
2500     * coordinate space.
2501     * @param descendant A descendant of this view
2502     * @param rect A rectangle defined in descendant's coordinate space.
2503     */
2504    public final void offsetRectIntoDescendantCoords(View descendant, Rect rect) {
2505        offsetRectBetweenParentAndChild(descendant, rect, false, false);
2506    }
2507
2508    /**
2509     * Helper method that offsets a rect either from parent to descendant or
2510     * descendant to parent.
2511     */
2512    void offsetRectBetweenParentAndChild(View descendant, Rect rect,
2513            boolean offsetFromChildToParent, boolean clipToBounds) {
2514
2515        // already in the same coord system :)
2516        if (descendant == this) {
2517            return;
2518        }
2519
2520        ViewParent theParent = descendant.mParent;
2521
2522        // search and offset up to the parent
2523        while ((theParent != null)
2524                && (theParent instanceof View)
2525                && (theParent != this)) {
2526
2527            if (offsetFromChildToParent) {
2528                rect.offset(descendant.mLeft - descendant.mScrollX,
2529                        descendant.mTop - descendant.mScrollY);
2530                if (clipToBounds) {
2531                    View p = (View) theParent;
2532                    rect.intersect(0, 0, p.mRight - p.mLeft, p.mBottom - p.mTop);
2533                }
2534            } else {
2535                if (clipToBounds) {
2536                    View p = (View) theParent;
2537                    rect.intersect(0, 0, p.mRight - p.mLeft, p.mBottom - p.mTop);
2538                }
2539                rect.offset(descendant.mScrollX - descendant.mLeft,
2540                        descendant.mScrollY - descendant.mTop);
2541            }
2542
2543            descendant = (View) theParent;
2544            theParent = descendant.mParent;
2545        }
2546
2547        // now that we are up to this view, need to offset one more time
2548        // to get into our coordinate space
2549        if (theParent == this) {
2550            if (offsetFromChildToParent) {
2551                rect.offset(descendant.mLeft - descendant.mScrollX,
2552                        descendant.mTop - descendant.mScrollY);
2553            } else {
2554                rect.offset(descendant.mScrollX - descendant.mLeft,
2555                        descendant.mScrollY - descendant.mTop);
2556            }
2557        } else {
2558            throw new IllegalArgumentException("parameter must be a descendant of this view");
2559        }
2560    }
2561
2562    /**
2563     * Offset the vertical location of all children of this view by the specified number of pixels.
2564     *
2565     * @param offset the number of pixels to offset
2566     *
2567     * @hide
2568     */
2569    public void offsetChildrenTopAndBottom(int offset) {
2570        final int count = mChildrenCount;
2571        final View[] children = mChildren;
2572
2573        for (int i = 0; i < count; i++) {
2574            final View v = children[i];
2575            v.mTop += offset;
2576            v.mBottom += offset;
2577        }
2578    }
2579
2580    /**
2581     * {@inheritDoc}
2582     */
2583    public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) {
2584        int dx = child.mLeft - mScrollX;
2585        int dy = child.mTop - mScrollY;
2586        if (offset != null) {
2587            offset.x += dx;
2588            offset.y += dy;
2589        }
2590        r.offset(dx, dy);
2591        return r.intersect(0, 0, mRight - mLeft, mBottom - mTop) &&
2592               (mParent == null || mParent.getChildVisibleRect(this, r, offset));
2593    }
2594
2595    /**
2596     * {@inheritDoc}
2597     */
2598    @Override
2599    protected abstract void onLayout(boolean changed,
2600            int l, int t, int r, int b);
2601
2602    /**
2603     * Indicates whether the view group has the ability to animate its children
2604     * after the first layout.
2605     *
2606     * @return true if the children can be animated, false otherwise
2607     */
2608    protected boolean canAnimate() {
2609        return mLayoutAnimationController != null;
2610    }
2611
2612    /**
2613     * Runs the layout animation. Calling this method triggers a relayout of
2614     * this view group.
2615     */
2616    public void startLayoutAnimation() {
2617        if (mLayoutAnimationController != null) {
2618            mGroupFlags |= FLAG_RUN_ANIMATION;
2619            requestLayout();
2620        }
2621    }
2622
2623    /**
2624     * Schedules the layout animation to be played after the next layout pass
2625     * of this view group. This can be used to restart the layout animation
2626     * when the content of the view group changes or when the activity is
2627     * paused and resumed.
2628     */
2629    public void scheduleLayoutAnimation() {
2630        mGroupFlags |= FLAG_RUN_ANIMATION;
2631    }
2632
2633    /**
2634     * Sets the layout animation controller used to animate the group's
2635     * children after the first layout.
2636     *
2637     * @param controller the animation controller
2638     */
2639    public void setLayoutAnimation(LayoutAnimationController controller) {
2640        mLayoutAnimationController = controller;
2641        if (mLayoutAnimationController != null) {
2642            mGroupFlags |= FLAG_RUN_ANIMATION;
2643        }
2644    }
2645
2646    /**
2647     * Returns the layout animation controller used to animate the group's
2648     * children.
2649     *
2650     * @return the current animation controller
2651     */
2652    public LayoutAnimationController getLayoutAnimation() {
2653        return mLayoutAnimationController;
2654    }
2655
2656    /**
2657     * Indicates whether the children's drawing cache is used during a layout
2658     * animation. By default, the drawing cache is enabled but this will prevent
2659     * nested layout animations from working. To nest animations, you must disable
2660     * the cache.
2661     *
2662     * @return true if the animation cache is enabled, false otherwise
2663     *
2664     * @see #setAnimationCacheEnabled(boolean)
2665     * @see View#setDrawingCacheEnabled(boolean)
2666     */
2667    @ViewDebug.ExportedProperty
2668    public boolean isAnimationCacheEnabled() {
2669        return (mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE;
2670    }
2671
2672    /**
2673     * Enables or disables the children's drawing cache during a layout animation.
2674     * By default, the drawing cache is enabled but this will prevent nested
2675     * layout animations from working. To nest animations, you must disable the
2676     * cache.
2677     *
2678     * @param enabled true to enable the animation cache, false otherwise
2679     *
2680     * @see #isAnimationCacheEnabled()
2681     * @see View#setDrawingCacheEnabled(boolean)
2682     */
2683    public void setAnimationCacheEnabled(boolean enabled) {
2684        setBooleanFlag(FLAG_ANIMATION_CACHE, enabled);
2685    }
2686
2687    /**
2688     * Indicates whether this ViewGroup will always try to draw its children using their
2689     * drawing cache. By default this property is enabled.
2690     *
2691     * @return true if the animation cache is enabled, false otherwise
2692     *
2693     * @see #setAlwaysDrawnWithCacheEnabled(boolean)
2694     * @see #setChildrenDrawnWithCacheEnabled(boolean)
2695     * @see View#setDrawingCacheEnabled(boolean)
2696     */
2697    @ViewDebug.ExportedProperty
2698    public boolean isAlwaysDrawnWithCacheEnabled() {
2699        return (mGroupFlags & FLAG_ALWAYS_DRAWN_WITH_CACHE) == FLAG_ALWAYS_DRAWN_WITH_CACHE;
2700    }
2701
2702    /**
2703     * Indicates whether this ViewGroup will always try to draw its children using their
2704     * drawing cache. This property can be set to true when the cache rendering is
2705     * slightly different from the children's normal rendering. Renderings can be different,
2706     * for instance, when the cache's quality is set to low.
2707     *
2708     * When this property is disabled, the ViewGroup will use the drawing cache of its
2709     * children only when asked to. It's usually the task of subclasses to tell ViewGroup
2710     * when to start using the drawing cache and when to stop using it.
2711     *
2712     * @param always true to always draw with the drawing cache, false otherwise
2713     *
2714     * @see #isAlwaysDrawnWithCacheEnabled()
2715     * @see #setChildrenDrawnWithCacheEnabled(boolean)
2716     * @see View#setDrawingCacheEnabled(boolean)
2717     * @see View#setDrawingCacheQuality(int)
2718     */
2719    public void setAlwaysDrawnWithCacheEnabled(boolean always) {
2720        setBooleanFlag(FLAG_ALWAYS_DRAWN_WITH_CACHE, always);
2721    }
2722
2723    /**
2724     * Indicates whether the ViewGroup is currently drawing its children using
2725     * their drawing cache.
2726     *
2727     * @return true if children should be drawn with their cache, false otherwise
2728     *
2729     * @see #setAlwaysDrawnWithCacheEnabled(boolean)
2730     * @see #setChildrenDrawnWithCacheEnabled(boolean)
2731     */
2732    @ViewDebug.ExportedProperty
2733    protected boolean isChildrenDrawnWithCacheEnabled() {
2734        return (mGroupFlags & FLAG_CHILDREN_DRAWN_WITH_CACHE) == FLAG_CHILDREN_DRAWN_WITH_CACHE;
2735    }
2736
2737    /**
2738     * Tells the ViewGroup to draw its children using their drawing cache. This property
2739     * is ignored when {@link #isAlwaysDrawnWithCacheEnabled()} is true. A child's drawing cache
2740     * will be used only if it has been enabled.
2741     *
2742     * Subclasses should call this method to start and stop using the drawing cache when
2743     * they perform performance sensitive operations, like scrolling or animating.
2744     *
2745     * @param enabled true if children should be drawn with their cache, false otherwise
2746     *
2747     * @see #setAlwaysDrawnWithCacheEnabled(boolean)
2748     * @see #isChildrenDrawnWithCacheEnabled()
2749     */
2750    protected void setChildrenDrawnWithCacheEnabled(boolean enabled) {
2751        setBooleanFlag(FLAG_CHILDREN_DRAWN_WITH_CACHE, enabled);
2752    }
2753
2754    /**
2755     * Indicates whether the ViewGroup is drawing its children in the order defined by
2756     * {@link #getChildDrawingOrder(int, int)}.
2757     *
2758     * @return true if children drawing order is defined by {@link #getChildDrawingOrder(int, int)},
2759     *         false otherwise
2760     *
2761     * @see #setChildrenDrawingOrderEnabled(boolean)
2762     * @see #getChildDrawingOrder(int, int)
2763     */
2764    @ViewDebug.ExportedProperty
2765    protected boolean isChildrenDrawingOrderEnabled() {
2766        return (mGroupFlags & FLAG_USE_CHILD_DRAWING_ORDER) == FLAG_USE_CHILD_DRAWING_ORDER;
2767    }
2768
2769    /**
2770     * Tells the ViewGroup whether to draw its children in the order defined by the method
2771     * {@link #getChildDrawingOrder(int, int)}.
2772     *
2773     * @param enabled true if the order of the children when drawing is determined by
2774     *        {@link #getChildDrawingOrder(int, int)}, false otherwise
2775     *
2776     * @see #isChildrenDrawingOrderEnabled()
2777     * @see #getChildDrawingOrder(int, int)
2778     */
2779    protected void setChildrenDrawingOrderEnabled(boolean enabled) {
2780        setBooleanFlag(FLAG_USE_CHILD_DRAWING_ORDER, enabled);
2781    }
2782
2783    private void setBooleanFlag(int flag, boolean value) {
2784        if (value) {
2785            mGroupFlags |= flag;
2786        } else {
2787            mGroupFlags &= ~flag;
2788        }
2789    }
2790
2791    /**
2792     * Returns an integer indicating what types of drawing caches are kept in memory.
2793     *
2794     * @see #setPersistentDrawingCache(int)
2795     * @see #setAnimationCacheEnabled(boolean)
2796     *
2797     * @return one or a combination of {@link #PERSISTENT_NO_CACHE},
2798     *         {@link #PERSISTENT_ANIMATION_CACHE}, {@link #PERSISTENT_SCROLLING_CACHE}
2799     *         and {@link #PERSISTENT_ALL_CACHES}
2800     */
2801    @ViewDebug.ExportedProperty(mapping = {
2802        @ViewDebug.IntToString(from = PERSISTENT_NO_CACHE,        to = "NONE"),
2803        @ViewDebug.IntToString(from = PERSISTENT_ALL_CACHES,      to = "ANIMATION"),
2804        @ViewDebug.IntToString(from = PERSISTENT_SCROLLING_CACHE, to = "SCROLLING"),
2805        @ViewDebug.IntToString(from = PERSISTENT_ALL_CACHES,      to = "ALL")
2806    })
2807    public int getPersistentDrawingCache() {
2808        return mPersistentDrawingCache;
2809    }
2810
2811    /**
2812     * Indicates what types of drawing caches should be kept in memory after
2813     * they have been created.
2814     *
2815     * @see #getPersistentDrawingCache()
2816     * @see #setAnimationCacheEnabled(boolean)
2817     *
2818     * @param drawingCacheToKeep one or a combination of {@link #PERSISTENT_NO_CACHE},
2819     *        {@link #PERSISTENT_ANIMATION_CACHE}, {@link #PERSISTENT_SCROLLING_CACHE}
2820     *        and {@link #PERSISTENT_ALL_CACHES}
2821     */
2822    public void setPersistentDrawingCache(int drawingCacheToKeep) {
2823        mPersistentDrawingCache = drawingCacheToKeep & PERSISTENT_ALL_CACHES;
2824    }
2825
2826    /**
2827     * Returns a new set of layout parameters based on the supplied attributes set.
2828     *
2829     * @param attrs the attributes to build the layout parameters from
2830     *
2831     * @return an instance of {@link android.view.ViewGroup.LayoutParams} or one
2832     *         of its descendants
2833     */
2834    public LayoutParams generateLayoutParams(AttributeSet attrs) {
2835        return new LayoutParams(getContext(), attrs);
2836    }
2837
2838    /**
2839     * Returns a safe set of layout parameters based on the supplied layout params.
2840     * When a ViewGroup is passed a View whose layout params do not pass the test of
2841     * {@link #checkLayoutParams(android.view.ViewGroup.LayoutParams)}, this method
2842     * is invoked. This method should return a new set of layout params suitable for
2843     * this ViewGroup, possibly by copying the appropriate attributes from the
2844     * specified set of layout params.
2845     *
2846     * @param p The layout parameters to convert into a suitable set of layout parameters
2847     *          for this ViewGroup.
2848     *
2849     * @return an instance of {@link android.view.ViewGroup.LayoutParams} or one
2850     *         of its descendants
2851     */
2852    protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
2853        return p;
2854    }
2855
2856    /**
2857     * Returns a set of default layout parameters. These parameters are requested
2858     * when the View passed to {@link #addView(View)} has no layout parameters
2859     * already set. If null is returned, an exception is thrown from addView.
2860     *
2861     * @return a set of default layout parameters or null
2862     */
2863    protected LayoutParams generateDefaultLayoutParams() {
2864        return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
2865    }
2866
2867    /**
2868     * @hide
2869     */
2870    @Override
2871    protected boolean dispatchConsistencyCheck(int consistency) {
2872        boolean result = super.dispatchConsistencyCheck(consistency);
2873
2874        final int count = mChildrenCount;
2875        final View[] children = mChildren;
2876        for (int i = 0; i < count; i++) {
2877            if (!children[i].dispatchConsistencyCheck(consistency)) result = false;
2878        }
2879
2880        return result;
2881    }
2882
2883    /**
2884     * @hide
2885     */
2886    @Override
2887    protected boolean onConsistencyCheck(int consistency) {
2888        boolean result = super.onConsistencyCheck(consistency);
2889
2890        final boolean checkLayout = (consistency & ViewDebug.CONSISTENCY_LAYOUT) != 0;
2891        final boolean checkDrawing = (consistency & ViewDebug.CONSISTENCY_DRAWING) != 0;
2892
2893        if (checkLayout) {
2894            final int count = mChildrenCount;
2895            final View[] children = mChildren;
2896            for (int i = 0; i < count; i++) {
2897                if (children[i].getParent() != this) {
2898                    result = false;
2899                    android.util.Log.d(ViewDebug.CONSISTENCY_LOG_TAG,
2900                            "View " + children[i] + " has no parent/a parent that is not " + this);
2901                }
2902            }
2903        }
2904
2905        if (checkDrawing) {
2906            // If this group is dirty, check that the parent is dirty as well
2907            if ((mPrivateFlags & DIRTY_MASK) != 0) {
2908                final ViewParent parent = getParent();
2909                if (parent != null && !(parent instanceof ViewRoot)) {
2910                    if ((((View) parent).mPrivateFlags & DIRTY_MASK) == 0) {
2911                        result = false;
2912                        android.util.Log.d(ViewDebug.CONSISTENCY_LOG_TAG,
2913                                "ViewGroup " + this + " is dirty but its parent is not: " + this);
2914                    }
2915                }
2916            }
2917        }
2918
2919        return result;
2920    }
2921
2922    /**
2923     * {@inheritDoc}
2924     */
2925    @Override
2926    protected void debug(int depth) {
2927        super.debug(depth);
2928        String output;
2929
2930        if (mFocused != null) {
2931            output = debugIndent(depth);
2932            output += "mFocused";
2933            Log.d(VIEW_LOG_TAG, output);
2934        }
2935        if (mChildrenCount != 0) {
2936            output = debugIndent(depth);
2937            output += "{";
2938            Log.d(VIEW_LOG_TAG, output);
2939        }
2940        int count = mChildrenCount;
2941        for (int i = 0; i < count; i++) {
2942            View child = mChildren[i];
2943            child.debug(depth + 1);
2944        }
2945
2946        if (mChildrenCount != 0) {
2947            output = debugIndent(depth);
2948            output += "}";
2949            Log.d(VIEW_LOG_TAG, output);
2950        }
2951    }
2952
2953    /**
2954     * Returns the position in the group of the specified child view.
2955     *
2956     * @param child the view for which to get the position
2957     * @return a positive integer representing the position of the view in the
2958     *         group, or -1 if the view does not exist in the group
2959     */
2960    public int indexOfChild(View child) {
2961        final int count = mChildrenCount;
2962        final View[] children = mChildren;
2963        for (int i = 0; i < count; i++) {
2964            if (children[i] == child) {
2965                return i;
2966            }
2967        }
2968        return -1;
2969    }
2970
2971    /**
2972     * Returns the number of children in the group.
2973     *
2974     * @return a positive integer representing the number of children in
2975     *         the group
2976     */
2977    public int getChildCount() {
2978        return mChildrenCount;
2979    }
2980
2981    /**
2982     * Returns the view at the specified position in the group.
2983     *
2984     * @param index the position at which to get the view from
2985     * @return the view at the specified position or null if the position
2986     *         does not exist within the group
2987     */
2988    public View getChildAt(int index) {
2989        try {
2990            return mChildren[index];
2991        } catch (IndexOutOfBoundsException ex) {
2992            return null;
2993        }
2994    }
2995
2996    /**
2997     * Ask all of the children of this view to measure themselves, taking into
2998     * account both the MeasureSpec requirements for this view and its padding.
2999     * We skip children that are in the GONE state The heavy lifting is done in
3000     * getChildMeasureSpec.
3001     *
3002     * @param widthMeasureSpec The width requirements for this view
3003     * @param heightMeasureSpec The height requirements for this view
3004     */
3005    protected void measureChildren(int widthMeasureSpec, int heightMeasureSpec) {
3006        final int size = mChildrenCount;
3007        final View[] children = mChildren;
3008        for (int i = 0; i < size; ++i) {
3009            final View child = children[i];
3010            if ((child.mViewFlags & VISIBILITY_MASK) != GONE) {
3011                measureChild(child, widthMeasureSpec, heightMeasureSpec);
3012            }
3013        }
3014    }
3015
3016    /**
3017     * Ask one of the children of this view to measure itself, taking into
3018     * account both the MeasureSpec requirements for this view and its padding.
3019     * The heavy lifting is done in getChildMeasureSpec.
3020     *
3021     * @param child The child to measure
3022     * @param parentWidthMeasureSpec The width requirements for this view
3023     * @param parentHeightMeasureSpec The height requirements for this view
3024     */
3025    protected void measureChild(View child, int parentWidthMeasureSpec,
3026            int parentHeightMeasureSpec) {
3027        final LayoutParams lp = child.getLayoutParams();
3028
3029        final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
3030                mPaddingLeft + mPaddingRight, lp.width);
3031        final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
3032                mPaddingTop + mPaddingBottom, lp.height);
3033
3034        child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
3035    }
3036
3037    /**
3038     * Ask one of the children of this view to measure itself, taking into
3039     * account both the MeasureSpec requirements for this view and its padding
3040     * and margins. The child must have MarginLayoutParams The heavy lifting is
3041     * done in getChildMeasureSpec.
3042     *
3043     * @param child The child to measure
3044     * @param parentWidthMeasureSpec The width requirements for this view
3045     * @param widthUsed Extra space that has been used up by the parent
3046     *        horizontally (possibly by other children of the parent)
3047     * @param parentHeightMeasureSpec The height requirements for this view
3048     * @param heightUsed Extra space that has been used up by the parent
3049     *        vertically (possibly by other children of the parent)
3050     */
3051    protected void measureChildWithMargins(View child,
3052            int parentWidthMeasureSpec, int widthUsed,
3053            int parentHeightMeasureSpec, int heightUsed) {
3054        final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
3055
3056        final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
3057                mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin
3058                        + widthUsed, lp.width);
3059        final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
3060                mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin
3061                        + heightUsed, lp.height);
3062
3063        child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
3064    }
3065
3066    /**
3067     * Does the hard part of measureChildren: figuring out the MeasureSpec to
3068     * pass to a particular child. This method figures out the right MeasureSpec
3069     * for one dimension (height or width) of one child view.
3070     *
3071     * The goal is to combine information from our MeasureSpec with the
3072     * LayoutParams of the child to get the best possible results. For example,
3073     * if the this view knows its size (because its MeasureSpec has a mode of
3074     * EXACTLY), and the child has indicated in its LayoutParams that it wants
3075     * to be the same size as the parent, the parent should ask the child to
3076     * layout given an exact size.
3077     *
3078     * @param spec The requirements for this view
3079     * @param padding The padding of this view for the current dimension and
3080     *        margins, if applicable
3081     * @param childDimension How big the child wants to be in the current
3082     *        dimension
3083     * @return a MeasureSpec integer for the child
3084     */
3085    public static int getChildMeasureSpec(int spec, int padding, int childDimension) {
3086        int specMode = MeasureSpec.getMode(spec);
3087        int specSize = MeasureSpec.getSize(spec);
3088
3089        int size = Math.max(0, specSize - padding);
3090
3091        int resultSize = 0;
3092        int resultMode = 0;
3093
3094        switch (specMode) {
3095        // Parent has imposed an exact size on us
3096        case MeasureSpec.EXACTLY:
3097            if (childDimension >= 0) {
3098                resultSize = childDimension;
3099                resultMode = MeasureSpec.EXACTLY;
3100            } else if (childDimension == LayoutParams.MATCH_PARENT) {
3101                // Child wants to be our size. So be it.
3102                resultSize = size;
3103                resultMode = MeasureSpec.EXACTLY;
3104            } else if (childDimension == LayoutParams.WRAP_CONTENT) {
3105                // Child wants to determine its own size. It can't be
3106                // bigger than us.
3107                resultSize = size;
3108                resultMode = MeasureSpec.AT_MOST;
3109            }
3110            break;
3111
3112        // Parent has imposed a maximum size on us
3113        case MeasureSpec.AT_MOST:
3114            if (childDimension >= 0) {
3115                // Child wants a specific size... so be it
3116                resultSize = childDimension;
3117                resultMode = MeasureSpec.EXACTLY;
3118            } else if (childDimension == LayoutParams.MATCH_PARENT) {
3119                // Child wants to be our size, but our size is not fixed.
3120                // Constrain child to not be bigger than us.
3121                resultSize = size;
3122                resultMode = MeasureSpec.AT_MOST;
3123            } else if (childDimension == LayoutParams.WRAP_CONTENT) {
3124                // Child wants to determine its own size. It can't be
3125                // bigger than us.
3126                resultSize = size;
3127                resultMode = MeasureSpec.AT_MOST;
3128            }
3129            break;
3130
3131        // Parent asked to see how big we want to be
3132        case MeasureSpec.UNSPECIFIED:
3133            if (childDimension >= 0) {
3134                // Child wants a specific size... let him have it
3135                resultSize = childDimension;
3136                resultMode = MeasureSpec.EXACTLY;
3137            } else if (childDimension == LayoutParams.MATCH_PARENT) {
3138                // Child wants to be our size... find out how big it should
3139                // be
3140                resultSize = 0;
3141                resultMode = MeasureSpec.UNSPECIFIED;
3142            } else if (childDimension == LayoutParams.WRAP_CONTENT) {
3143                // Child wants to determine its own size.... find out how
3144                // big it should be
3145                resultSize = 0;
3146                resultMode = MeasureSpec.UNSPECIFIED;
3147            }
3148            break;
3149        }
3150        return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
3151    }
3152
3153
3154    /**
3155     * Removes any pending animations for views that have been removed. Call
3156     * this if you don't want animations for exiting views to stack up.
3157     */
3158    public void clearDisappearingChildren() {
3159        if (mDisappearingChildren != null) {
3160            mDisappearingChildren.clear();
3161        }
3162    }
3163
3164    /**
3165     * Add a view which is removed from mChildren but still needs animation
3166     *
3167     * @param v View to add
3168     */
3169    private void addDisappearingView(View v) {
3170        ArrayList<View> disappearingChildren = mDisappearingChildren;
3171
3172        if (disappearingChildren == null) {
3173            disappearingChildren = mDisappearingChildren = new ArrayList<View>();
3174        }
3175
3176        disappearingChildren.add(v);
3177    }
3178
3179    /**
3180     * Cleanup a view when its animation is done. This may mean removing it from
3181     * the list of disappearing views.
3182     *
3183     * @param view The view whose animation has finished
3184     * @param animation The animation, cannot be null
3185     */
3186    private void finishAnimatingView(final View view, Animation animation) {
3187        final ArrayList<View> disappearingChildren = mDisappearingChildren;
3188        if (disappearingChildren != null) {
3189            if (disappearingChildren.contains(view)) {
3190                disappearingChildren.remove(view);
3191
3192                if (view.mAttachInfo != null) {
3193                    view.dispatchDetachedFromWindow();
3194                }
3195
3196                view.clearAnimation();
3197                mGroupFlags |= FLAG_INVALIDATE_REQUIRED;
3198            }
3199        }
3200
3201        if (animation != null && !animation.getFillAfter()) {
3202            view.clearAnimation();
3203        }
3204
3205        if ((view.mPrivateFlags & ANIMATION_STARTED) == ANIMATION_STARTED) {
3206            view.onAnimationEnd();
3207            // Should be performed by onAnimationEnd() but this avoid an infinite loop,
3208            // so we'd rather be safe than sorry
3209            view.mPrivateFlags &= ~ANIMATION_STARTED;
3210            // Draw one more frame after the animation is done
3211            mGroupFlags |= FLAG_INVALIDATE_REQUIRED;
3212        }
3213    }
3214
3215    /**
3216     * {@inheritDoc}
3217     */
3218    @Override
3219    public boolean gatherTransparentRegion(Region region) {
3220        // If no transparent regions requested, we are always opaque.
3221        final boolean meOpaque = (mPrivateFlags & View.REQUEST_TRANSPARENT_REGIONS) == 0;
3222        if (meOpaque && region == null) {
3223            // The caller doesn't care about the region, so stop now.
3224            return true;
3225        }
3226        super.gatherTransparentRegion(region);
3227        final View[] children = mChildren;
3228        final int count = mChildrenCount;
3229        boolean noneOfTheChildrenAreTransparent = true;
3230        for (int i = 0; i < count; i++) {
3231            final View child = children[i];
3232            if ((child.mViewFlags & VISIBILITY_MASK) != GONE || child.getAnimation() != null) {
3233                if (!child.gatherTransparentRegion(region)) {
3234                    noneOfTheChildrenAreTransparent = false;
3235                }
3236            }
3237        }
3238        return meOpaque || noneOfTheChildrenAreTransparent;
3239    }
3240
3241    /**
3242     * {@inheritDoc}
3243     */
3244    public void requestTransparentRegion(View child) {
3245        if (child != null) {
3246            child.mPrivateFlags |= View.REQUEST_TRANSPARENT_REGIONS;
3247            if (mParent != null) {
3248                mParent.requestTransparentRegion(this);
3249            }
3250        }
3251    }
3252
3253
3254    @Override
3255    protected boolean fitSystemWindows(Rect insets) {
3256        boolean done = super.fitSystemWindows(insets);
3257        if (!done) {
3258            final int count = mChildrenCount;
3259            final View[] children = mChildren;
3260            for (int i = 0; i < count; i++) {
3261                done = children[i].fitSystemWindows(insets);
3262                if (done) {
3263                    break;
3264                }
3265            }
3266        }
3267        return done;
3268    }
3269
3270    /**
3271     * Returns the animation listener to which layout animation events are
3272     * sent.
3273     *
3274     * @return an {@link android.view.animation.Animation.AnimationListener}
3275     */
3276    public Animation.AnimationListener getLayoutAnimationListener() {
3277        return mAnimationListener;
3278    }
3279
3280    @Override
3281    protected void drawableStateChanged() {
3282        super.drawableStateChanged();
3283
3284        if ((mGroupFlags & FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE) != 0) {
3285            if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0) {
3286                throw new IllegalStateException("addStateFromChildren cannot be enabled if a"
3287                        + " child has duplicateParentState set to true");
3288            }
3289
3290            final View[] children = mChildren;
3291            final int count = mChildrenCount;
3292
3293            for (int i = 0; i < count; i++) {
3294                final View child = children[i];
3295                if ((child.mViewFlags & DUPLICATE_PARENT_STATE) != 0) {
3296                    child.refreshDrawableState();
3297                }
3298            }
3299        }
3300    }
3301
3302    @Override
3303    protected int[] onCreateDrawableState(int extraSpace) {
3304        if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) == 0) {
3305            return super.onCreateDrawableState(extraSpace);
3306        }
3307
3308        int need = 0;
3309        int n = getChildCount();
3310        for (int i = 0; i < n; i++) {
3311            int[] childState = getChildAt(i).getDrawableState();
3312
3313            if (childState != null) {
3314                need += childState.length;
3315            }
3316        }
3317
3318        int[] state = super.onCreateDrawableState(extraSpace + need);
3319
3320        for (int i = 0; i < n; i++) {
3321            int[] childState = getChildAt(i).getDrawableState();
3322
3323            if (childState != null) {
3324                state = mergeDrawableStates(state, childState);
3325            }
3326        }
3327
3328        return state;
3329    }
3330
3331    /**
3332     * Sets whether this ViewGroup's drawable states also include
3333     * its children's drawable states.  This is used, for example, to
3334     * make a group appear to be focused when its child EditText or button
3335     * is focused.
3336     */
3337    public void setAddStatesFromChildren(boolean addsStates) {
3338        if (addsStates) {
3339            mGroupFlags |= FLAG_ADD_STATES_FROM_CHILDREN;
3340        } else {
3341            mGroupFlags &= ~FLAG_ADD_STATES_FROM_CHILDREN;
3342        }
3343
3344        refreshDrawableState();
3345    }
3346
3347    /**
3348     * Returns whether this ViewGroup's drawable states also include
3349     * its children's drawable states.  This is used, for example, to
3350     * make a group appear to be focused when its child EditText or button
3351     * is focused.
3352     */
3353    public boolean addStatesFromChildren() {
3354        return (mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0;
3355    }
3356
3357    /**
3358     * If {link #addStatesFromChildren} is true, refreshes this group's
3359     * drawable state (to include the states from its children).
3360     */
3361    public void childDrawableStateChanged(View child) {
3362        if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0) {
3363            refreshDrawableState();
3364        }
3365    }
3366
3367    /**
3368     * Specifies the animation listener to which layout animation events must
3369     * be sent. Only
3370     * {@link android.view.animation.Animation.AnimationListener#onAnimationStart(Animation)}
3371     * and
3372     * {@link android.view.animation.Animation.AnimationListener#onAnimationEnd(Animation)}
3373     * are invoked.
3374     *
3375     * @param animationListener the layout animation listener
3376     */
3377    public void setLayoutAnimationListener(Animation.AnimationListener animationListener) {
3378        mAnimationListener = animationListener;
3379    }
3380
3381    /**
3382     * LayoutParams are used by views to tell their parents how they want to be
3383     * laid out. See
3384     * {@link android.R.styleable#ViewGroup_Layout ViewGroup Layout Attributes}
3385     * for a list of all child view attributes that this class supports.
3386     *
3387     * <p>
3388     * The base LayoutParams class just describes how big the view wants to be
3389     * for both width and height. For each dimension, it can specify one of:
3390     * <ul>
3391     * <li> an exact number
3392     * <li>MATCH_PARENT, which means the view wants to be as big as its parent
3393     * (minus padding)
3394     * <li> WRAP_CONTENT, which means that the view wants to be just big enough
3395     * to enclose its content (plus padding)
3396     * </ul>
3397     * There are subclasses of LayoutParams for different subclasses of
3398     * ViewGroup. For example, AbsoluteLayout has its own subclass of
3399     * LayoutParams which adds an X and Y value.
3400     *
3401     * @attr ref android.R.styleable#ViewGroup_Layout_layout_height
3402     * @attr ref android.R.styleable#ViewGroup_Layout_layout_width
3403     */
3404    public static class LayoutParams {
3405        /**
3406         * This value has the same meaning as {@link #MATCH_PARENT} but has
3407         * been deprecated.
3408         */
3409        @SuppressWarnings({"UnusedDeclaration"})
3410        @Deprecated
3411        public static final int FILL_PARENT = -1;
3412
3413        /**
3414         * Special value for the height or width requested by a View.
3415         * MATCH_PARENT means that the view wants to be as big as its parent,
3416         * minus the parent's padding, if any.
3417         */
3418        public static final int MATCH_PARENT = -1;
3419
3420        /**
3421         * Special value for the height or width requested by a View.
3422         * WRAP_CONTENT means that the view wants to be just large enough to fit
3423         * its own internal content, taking its own padding into account.
3424         */
3425        public static final int WRAP_CONTENT = -2;
3426
3427        /**
3428         * Information about how wide the view wants to be. Can be an exact
3429         * size, or one of the constants MATCH_PARENT or WRAP_CONTENT.
3430         */
3431        @ViewDebug.ExportedProperty(mapping = {
3432            @ViewDebug.IntToString(from = MATCH_PARENT, to = "MATCH_PARENT"),
3433            @ViewDebug.IntToString(from = WRAP_CONTENT, to = "WRAP_CONTENT")
3434        })
3435        public int width;
3436
3437        /**
3438         * Information about how tall the view wants to be. Can be an exact
3439         * size, or one of the constants MATCH_PARENT or WRAP_CONTENT.
3440         */
3441        @ViewDebug.ExportedProperty(mapping = {
3442            @ViewDebug.IntToString(from = MATCH_PARENT, to = "MATCH_PARENT"),
3443            @ViewDebug.IntToString(from = WRAP_CONTENT, to = "WRAP_CONTENT")
3444        })
3445        public int height;
3446
3447        /**
3448         * Used to animate layouts.
3449         */
3450        public LayoutAnimationController.AnimationParameters layoutAnimationParameters;
3451
3452        /**
3453         * Creates a new set of layout parameters. The values are extracted from
3454         * the supplied attributes set and context. The XML attributes mapped
3455         * to this set of layout parameters are:
3456         *
3457         * <ul>
3458         *   <li><code>layout_width</code>: the width, either an exact value,
3459         *   {@link #WRAP_CONTENT} or {@link #MATCH_PARENT}</li>
3460         *   <li><code>layout_height</code>: the height, either an exact value,
3461         *   {@link #WRAP_CONTENT} or {@link #MATCH_PARENT}</li>
3462         * </ul>
3463         *
3464         * @param c the application environment
3465         * @param attrs the set of attributes from which to extract the layout
3466         *              parameters' values
3467         */
3468        public LayoutParams(Context c, AttributeSet attrs) {
3469            TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.ViewGroup_Layout);
3470            setBaseAttributes(a,
3471                    R.styleable.ViewGroup_Layout_layout_width,
3472                    R.styleable.ViewGroup_Layout_layout_height);
3473            a.recycle();
3474        }
3475
3476        /**
3477         * Creates a new set of layout parameters with the specified width
3478         * and height.
3479         *
3480         * @param width the width, either {@link #MATCH_PARENT},
3481         *        {@link #WRAP_CONTENT} or a fixed size in pixels
3482         * @param height the height, either {@link #MATCH_PARENT},
3483         *        {@link #WRAP_CONTENT} or a fixed size in pixels
3484         */
3485        public LayoutParams(int width, int height) {
3486            this.width = width;
3487            this.height = height;
3488        }
3489
3490        /**
3491         * Copy constructor. Clones the width and height values of the source.
3492         *
3493         * @param source The layout params to copy from.
3494         */
3495        public LayoutParams(LayoutParams source) {
3496            this.width = source.width;
3497            this.height = source.height;
3498        }
3499
3500        /**
3501         * Used internally by MarginLayoutParams.
3502         * @hide
3503         */
3504        LayoutParams() {
3505        }
3506
3507        /**
3508         * Extracts the layout parameters from the supplied attributes.
3509         *
3510         * @param a the style attributes to extract the parameters from
3511         * @param widthAttr the identifier of the width attribute
3512         * @param heightAttr the identifier of the height attribute
3513         */
3514        protected void setBaseAttributes(TypedArray a, int widthAttr, int heightAttr) {
3515            width = a.getLayoutDimension(widthAttr, "layout_width");
3516            height = a.getLayoutDimension(heightAttr, "layout_height");
3517        }
3518
3519        /**
3520         * Returns a String representation of this set of layout parameters.
3521         *
3522         * @param output the String to prepend to the internal representation
3523         * @return a String with the following format: output +
3524         *         "ViewGroup.LayoutParams={ width=WIDTH, height=HEIGHT }"
3525         *
3526         * @hide
3527         */
3528        public String debug(String output) {
3529            return output + "ViewGroup.LayoutParams={ width="
3530                    + sizeToString(width) + ", height=" + sizeToString(height) + " }";
3531        }
3532
3533        /**
3534         * Converts the specified size to a readable String.
3535         *
3536         * @param size the size to convert
3537         * @return a String instance representing the supplied size
3538         *
3539         * @hide
3540         */
3541        protected static String sizeToString(int size) {
3542            if (size == WRAP_CONTENT) {
3543                return "wrap-content";
3544            }
3545            if (size == MATCH_PARENT) {
3546                return "match-parent";
3547            }
3548            return String.valueOf(size);
3549        }
3550    }
3551
3552    /**
3553     * Per-child layout information for layouts that support margins.
3554     * See
3555     * {@link android.R.styleable#ViewGroup_MarginLayout ViewGroup Margin Layout Attributes}
3556     * for a list of all child view attributes that this class supports.
3557     */
3558    public static class MarginLayoutParams extends ViewGroup.LayoutParams {
3559        /**
3560         * The left margin in pixels of the child.
3561         */
3562        @ViewDebug.ExportedProperty
3563        public int leftMargin;
3564
3565        /**
3566         * The top margin in pixels of the child.
3567         */
3568        @ViewDebug.ExportedProperty
3569        public int topMargin;
3570
3571        /**
3572         * The right margin in pixels of the child.
3573         */
3574        @ViewDebug.ExportedProperty
3575        public int rightMargin;
3576
3577        /**
3578         * The bottom margin in pixels of the child.
3579         */
3580        @ViewDebug.ExportedProperty
3581        public int bottomMargin;
3582
3583        /**
3584         * Creates a new set of layout parameters. The values are extracted from
3585         * the supplied attributes set and context.
3586         *
3587         * @param c the application environment
3588         * @param attrs the set of attributes from which to extract the layout
3589         *              parameters' values
3590         */
3591        public MarginLayoutParams(Context c, AttributeSet attrs) {
3592            super();
3593
3594            TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.ViewGroup_MarginLayout);
3595            setBaseAttributes(a,
3596                    R.styleable.ViewGroup_MarginLayout_layout_width,
3597                    R.styleable.ViewGroup_MarginLayout_layout_height);
3598
3599            int margin = a.getDimensionPixelSize(
3600                    com.android.internal.R.styleable.ViewGroup_MarginLayout_layout_margin, -1);
3601            if (margin >= 0) {
3602                leftMargin = margin;
3603                topMargin = margin;
3604                rightMargin= margin;
3605                bottomMargin = margin;
3606            } else {
3607                leftMargin = a.getDimensionPixelSize(
3608                        R.styleable.ViewGroup_MarginLayout_layout_marginLeft, 0);
3609                topMargin = a.getDimensionPixelSize(
3610                        R.styleable.ViewGroup_MarginLayout_layout_marginTop, 0);
3611                rightMargin = a.getDimensionPixelSize(
3612                        R.styleable.ViewGroup_MarginLayout_layout_marginRight, 0);
3613                bottomMargin = a.getDimensionPixelSize(
3614                        R.styleable.ViewGroup_MarginLayout_layout_marginBottom, 0);
3615            }
3616
3617            a.recycle();
3618        }
3619
3620        /**
3621         * {@inheritDoc}
3622         */
3623        public MarginLayoutParams(int width, int height) {
3624            super(width, height);
3625        }
3626
3627        /**
3628         * Copy constructor. Clones the width, height and margin values of the source.
3629         *
3630         * @param source The layout params to copy from.
3631         */
3632        public MarginLayoutParams(MarginLayoutParams source) {
3633            this.width = source.width;
3634            this.height = source.height;
3635
3636            this.leftMargin = source.leftMargin;
3637            this.topMargin = source.topMargin;
3638            this.rightMargin = source.rightMargin;
3639            this.bottomMargin = source.bottomMargin;
3640        }
3641
3642        /**
3643         * {@inheritDoc}
3644         */
3645        public MarginLayoutParams(LayoutParams source) {
3646            super(source);
3647        }
3648
3649        /**
3650         * Sets the margins, in pixels.
3651         *
3652         * @param left the left margin size
3653         * @param top the top margin size
3654         * @param right the right margin size
3655         * @param bottom the bottom margin size
3656         *
3657         * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginLeft
3658         * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginTop
3659         * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginRight
3660         * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginBottom
3661         */
3662        public void setMargins(int left, int top, int right, int bottom) {
3663            leftMargin = left;
3664            topMargin = top;
3665            rightMargin = right;
3666            bottomMargin = bottom;
3667        }
3668    }
3669}
3670