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