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