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