ViewGroup.java revision 9bc829cc15757edd149a61868426b214430a1c24
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                RectF boundingRect = attachInfo.mTmpTransformRect;
2518                boundingRect.set(dirty);
2519                childMatrix.mapRect(boundingRect);
2520                dirty.set((int) boundingRect.left, (int) boundingRect.top,
2521                        (int) (boundingRect.right + 0.5f),
2522                        (int) (boundingRect.bottom + 0.5f));
2523            }
2524
2525            // If the child is drawing an animation, we want to copy this flag onto
2526            // ourselves and the parent to make sure the invalidate request goes
2527            // through
2528            final boolean drawAnimation = (child.mPrivateFlags & DRAW_ANIMATION) == DRAW_ANIMATION;
2529
2530            // Check whether the child that requests the invalidate is fully opaque
2531            final boolean isOpaque = child.isOpaque() && !drawAnimation &&
2532                    child.getAnimation() != null;
2533            // Mark the child as dirty, using the appropriate flag
2534            // Make sure we do not set both flags at the same time
2535            final int opaqueFlag = isOpaque ? DIRTY_OPAQUE : DIRTY;
2536
2537            do {
2538                View view = null;
2539                if (parent instanceof View) {
2540                    view = (View) parent;
2541                }
2542
2543                if (drawAnimation) {
2544                    if (view != null) {
2545                        view.mPrivateFlags |= DRAW_ANIMATION;
2546                    } else if (parent instanceof ViewRoot) {
2547                        ((ViewRoot) parent).mIsAnimating = true;
2548                    }
2549                }
2550
2551                // If the parent is dirty opaque or not dirty, mark it dirty with the opaque
2552                // flag coming from the child that initiated the invalidate
2553                if (view != null && (view.mPrivateFlags & DIRTY_MASK) != DIRTY) {
2554                    view.mPrivateFlags = (view.mPrivateFlags & ~DIRTY_MASK) | opaqueFlag;
2555                }
2556
2557                parent = parent.invalidateChildInParent(location, dirty);
2558                if (view != null) {
2559                    // Account for transform on current parent
2560                    Matrix m = view.getMatrix();
2561                    if (!m.isIdentity()) {
2562                        RectF boundingRect = attachInfo.mTmpTransformRect;
2563                        boundingRect.set(dirty);
2564                        m.mapRect(boundingRect);
2565                        dirty.set((int) boundingRect.left, (int) boundingRect.top,
2566                                (int) (boundingRect.right + 0.5f),
2567                                (int) (boundingRect.bottom + 0.5f));
2568                    }
2569                }
2570            } while (parent != null);
2571        }
2572    }
2573
2574    /**
2575     * Don't call or override this method. It is used for the implementation of
2576     * the view hierarchy.
2577     *
2578     * This implementation returns null if this ViewGroup does not have a parent,
2579     * if this ViewGroup is already fully invalidated or if the dirty rectangle
2580     * does not intersect with this ViewGroup's bounds.
2581     */
2582    public ViewParent invalidateChildInParent(final int[] location, final Rect dirty) {
2583        if (ViewDebug.TRACE_HIERARCHY) {
2584            ViewDebug.trace(this, ViewDebug.HierarchyTraceType.INVALIDATE_CHILD_IN_PARENT);
2585        }
2586
2587        if ((mPrivateFlags & DRAWN) == DRAWN) {
2588            if ((mGroupFlags & (FLAG_OPTIMIZE_INVALIDATE | FLAG_ANIMATION_DONE)) !=
2589                        FLAG_OPTIMIZE_INVALIDATE) {
2590                dirty.offset(location[CHILD_LEFT_INDEX] - mScrollX,
2591                        location[CHILD_TOP_INDEX] - mScrollY);
2592
2593                final int left = mLeft;
2594                final int top = mTop;
2595
2596                if (dirty.intersect(0, 0, mRight - left, mBottom - top) ||
2597                        (mPrivateFlags & DRAW_ANIMATION) == DRAW_ANIMATION) {
2598                    mPrivateFlags &= ~DRAWING_CACHE_VALID;
2599
2600                    location[CHILD_LEFT_INDEX] = left;
2601                    location[CHILD_TOP_INDEX] = top;
2602
2603                    return mParent;
2604                }
2605            } else {
2606                mPrivateFlags &= ~DRAWN & ~DRAWING_CACHE_VALID;
2607
2608                location[CHILD_LEFT_INDEX] = mLeft;
2609                location[CHILD_TOP_INDEX] = mTop;
2610
2611                dirty.set(0, 0, mRight - location[CHILD_LEFT_INDEX],
2612                        mBottom - location[CHILD_TOP_INDEX]);
2613
2614                return mParent;
2615            }
2616        }
2617
2618        return null;
2619    }
2620
2621    /**
2622     * Offset a rectangle that is in a descendant's coordinate
2623     * space into our coordinate space.
2624     * @param descendant A descendant of this view
2625     * @param rect A rectangle defined in descendant's coordinate space.
2626     */
2627    public final void offsetDescendantRectToMyCoords(View descendant, Rect rect) {
2628        offsetRectBetweenParentAndChild(descendant, rect, true, false);
2629    }
2630
2631    /**
2632     * Offset a rectangle that is in our coordinate space into an ancestor's
2633     * coordinate space.
2634     * @param descendant A descendant of this view
2635     * @param rect A rectangle defined in descendant's coordinate space.
2636     */
2637    public final void offsetRectIntoDescendantCoords(View descendant, Rect rect) {
2638        offsetRectBetweenParentAndChild(descendant, rect, false, false);
2639    }
2640
2641    /**
2642     * Helper method that offsets a rect either from parent to descendant or
2643     * descendant to parent.
2644     */
2645    void offsetRectBetweenParentAndChild(View descendant, Rect rect,
2646            boolean offsetFromChildToParent, boolean clipToBounds) {
2647
2648        // already in the same coord system :)
2649        if (descendant == this) {
2650            return;
2651        }
2652
2653        ViewParent theParent = descendant.mParent;
2654
2655        // search and offset up to the parent
2656        while ((theParent != null)
2657                && (theParent instanceof View)
2658                && (theParent != this)) {
2659
2660            if (offsetFromChildToParent) {
2661                rect.offset(descendant.mLeft - descendant.mScrollX,
2662                        descendant.mTop - descendant.mScrollY);
2663                if (clipToBounds) {
2664                    View p = (View) theParent;
2665                    rect.intersect(0, 0, p.mRight - p.mLeft, p.mBottom - p.mTop);
2666                }
2667            } else {
2668                if (clipToBounds) {
2669                    View p = (View) theParent;
2670                    rect.intersect(0, 0, p.mRight - p.mLeft, p.mBottom - p.mTop);
2671                }
2672                rect.offset(descendant.mScrollX - descendant.mLeft,
2673                        descendant.mScrollY - descendant.mTop);
2674            }
2675
2676            descendant = (View) theParent;
2677            theParent = descendant.mParent;
2678        }
2679
2680        // now that we are up to this view, need to offset one more time
2681        // to get into our coordinate space
2682        if (theParent == this) {
2683            if (offsetFromChildToParent) {
2684                rect.offset(descendant.mLeft - descendant.mScrollX,
2685                        descendant.mTop - descendant.mScrollY);
2686            } else {
2687                rect.offset(descendant.mScrollX - descendant.mLeft,
2688                        descendant.mScrollY - descendant.mTop);
2689            }
2690        } else {
2691            throw new IllegalArgumentException("parameter must be a descendant of this view");
2692        }
2693    }
2694
2695    /**
2696     * Offset the vertical location of all children of this view by the specified number of pixels.
2697     *
2698     * @param offset the number of pixels to offset
2699     *
2700     * @hide
2701     */
2702    public void offsetChildrenTopAndBottom(int offset) {
2703        final int count = mChildrenCount;
2704        final View[] children = mChildren;
2705
2706        for (int i = 0; i < count; i++) {
2707            final View v = children[i];
2708            v.mTop += offset;
2709            v.mBottom += offset;
2710        }
2711    }
2712
2713    /**
2714     * {@inheritDoc}
2715     */
2716    public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) {
2717        int dx = child.mLeft - mScrollX;
2718        int dy = child.mTop - mScrollY;
2719        if (offset != null) {
2720            offset.x += dx;
2721            offset.y += dy;
2722        }
2723        r.offset(dx, dy);
2724        return r.intersect(0, 0, mRight - mLeft, mBottom - mTop) &&
2725               (mParent == null || mParent.getChildVisibleRect(this, r, offset));
2726    }
2727
2728    /**
2729     * {@inheritDoc}
2730     */
2731    @Override
2732    protected abstract void onLayout(boolean changed,
2733            int l, int t, int r, int b);
2734
2735    /**
2736     * Indicates whether the view group has the ability to animate its children
2737     * after the first layout.
2738     *
2739     * @return true if the children can be animated, false otherwise
2740     */
2741    protected boolean canAnimate() {
2742        return mLayoutAnimationController != null;
2743    }
2744
2745    /**
2746     * Runs the layout animation. Calling this method triggers a relayout of
2747     * this view group.
2748     */
2749    public void startLayoutAnimation() {
2750        if (mLayoutAnimationController != null) {
2751            mGroupFlags |= FLAG_RUN_ANIMATION;
2752            requestLayout();
2753        }
2754    }
2755
2756    /**
2757     * Schedules the layout animation to be played after the next layout pass
2758     * of this view group. This can be used to restart the layout animation
2759     * when the content of the view group changes or when the activity is
2760     * paused and resumed.
2761     */
2762    public void scheduleLayoutAnimation() {
2763        mGroupFlags |= FLAG_RUN_ANIMATION;
2764    }
2765
2766    /**
2767     * Sets the layout animation controller used to animate the group's
2768     * children after the first layout.
2769     *
2770     * @param controller the animation controller
2771     */
2772    public void setLayoutAnimation(LayoutAnimationController controller) {
2773        mLayoutAnimationController = controller;
2774        if (mLayoutAnimationController != null) {
2775            mGroupFlags |= FLAG_RUN_ANIMATION;
2776        }
2777    }
2778
2779    /**
2780     * Returns the layout animation controller used to animate the group's
2781     * children.
2782     *
2783     * @return the current animation controller
2784     */
2785    public LayoutAnimationController getLayoutAnimation() {
2786        return mLayoutAnimationController;
2787    }
2788
2789    /**
2790     * Indicates whether the children's drawing cache is used during a layout
2791     * animation. By default, the drawing cache is enabled but this will prevent
2792     * nested layout animations from working. To nest animations, you must disable
2793     * the cache.
2794     *
2795     * @return true if the animation cache is enabled, false otherwise
2796     *
2797     * @see #setAnimationCacheEnabled(boolean)
2798     * @see View#setDrawingCacheEnabled(boolean)
2799     */
2800    @ViewDebug.ExportedProperty
2801    public boolean isAnimationCacheEnabled() {
2802        return (mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE;
2803    }
2804
2805    /**
2806     * Enables or disables the children's drawing cache during a layout animation.
2807     * By default, the drawing cache is enabled but this will prevent nested
2808     * layout animations from working. To nest animations, you must disable the
2809     * cache.
2810     *
2811     * @param enabled true to enable the animation cache, false otherwise
2812     *
2813     * @see #isAnimationCacheEnabled()
2814     * @see View#setDrawingCacheEnabled(boolean)
2815     */
2816    public void setAnimationCacheEnabled(boolean enabled) {
2817        setBooleanFlag(FLAG_ANIMATION_CACHE, enabled);
2818    }
2819
2820    /**
2821     * Indicates whether this ViewGroup will always try to draw its children using their
2822     * drawing cache. By default this property is enabled.
2823     *
2824     * @return true if the animation cache is enabled, false otherwise
2825     *
2826     * @see #setAlwaysDrawnWithCacheEnabled(boolean)
2827     * @see #setChildrenDrawnWithCacheEnabled(boolean)
2828     * @see View#setDrawingCacheEnabled(boolean)
2829     */
2830    @ViewDebug.ExportedProperty
2831    public boolean isAlwaysDrawnWithCacheEnabled() {
2832        return (mGroupFlags & FLAG_ALWAYS_DRAWN_WITH_CACHE) == FLAG_ALWAYS_DRAWN_WITH_CACHE;
2833    }
2834
2835    /**
2836     * Indicates whether this ViewGroup will always try to draw its children using their
2837     * drawing cache. This property can be set to true when the cache rendering is
2838     * slightly different from the children's normal rendering. Renderings can be different,
2839     * for instance, when the cache's quality is set to low.
2840     *
2841     * When this property is disabled, the ViewGroup will use the drawing cache of its
2842     * children only when asked to. It's usually the task of subclasses to tell ViewGroup
2843     * when to start using the drawing cache and when to stop using it.
2844     *
2845     * @param always true to always draw with the drawing cache, false otherwise
2846     *
2847     * @see #isAlwaysDrawnWithCacheEnabled()
2848     * @see #setChildrenDrawnWithCacheEnabled(boolean)
2849     * @see View#setDrawingCacheEnabled(boolean)
2850     * @see View#setDrawingCacheQuality(int)
2851     */
2852    public void setAlwaysDrawnWithCacheEnabled(boolean always) {
2853        setBooleanFlag(FLAG_ALWAYS_DRAWN_WITH_CACHE, always);
2854    }
2855
2856    /**
2857     * Indicates whether the ViewGroup is currently drawing its children using
2858     * their drawing cache.
2859     *
2860     * @return true if children should be drawn with their cache, false otherwise
2861     *
2862     * @see #setAlwaysDrawnWithCacheEnabled(boolean)
2863     * @see #setChildrenDrawnWithCacheEnabled(boolean)
2864     */
2865    @ViewDebug.ExportedProperty
2866    protected boolean isChildrenDrawnWithCacheEnabled() {
2867        return (mGroupFlags & FLAG_CHILDREN_DRAWN_WITH_CACHE) == FLAG_CHILDREN_DRAWN_WITH_CACHE;
2868    }
2869
2870    /**
2871     * Tells the ViewGroup to draw its children using their drawing cache. This property
2872     * is ignored when {@link #isAlwaysDrawnWithCacheEnabled()} is true. A child's drawing cache
2873     * will be used only if it has been enabled.
2874     *
2875     * Subclasses should call this method to start and stop using the drawing cache when
2876     * they perform performance sensitive operations, like scrolling or animating.
2877     *
2878     * @param enabled true if children should be drawn with their cache, false otherwise
2879     *
2880     * @see #setAlwaysDrawnWithCacheEnabled(boolean)
2881     * @see #isChildrenDrawnWithCacheEnabled()
2882     */
2883    protected void setChildrenDrawnWithCacheEnabled(boolean enabled) {
2884        setBooleanFlag(FLAG_CHILDREN_DRAWN_WITH_CACHE, enabled);
2885    }
2886
2887    /**
2888     * Indicates whether the ViewGroup is drawing its children in the order defined by
2889     * {@link #getChildDrawingOrder(int, int)}.
2890     *
2891     * @return true if children drawing order is defined by {@link #getChildDrawingOrder(int, int)},
2892     *         false otherwise
2893     *
2894     * @see #setChildrenDrawingOrderEnabled(boolean)
2895     * @see #getChildDrawingOrder(int, int)
2896     */
2897    @ViewDebug.ExportedProperty
2898    protected boolean isChildrenDrawingOrderEnabled() {
2899        return (mGroupFlags & FLAG_USE_CHILD_DRAWING_ORDER) == FLAG_USE_CHILD_DRAWING_ORDER;
2900    }
2901
2902    /**
2903     * Tells the ViewGroup whether to draw its children in the order defined by the method
2904     * {@link #getChildDrawingOrder(int, int)}.
2905     *
2906     * @param enabled true if the order of the children when drawing is determined by
2907     *        {@link #getChildDrawingOrder(int, int)}, false otherwise
2908     *
2909     * @see #isChildrenDrawingOrderEnabled()
2910     * @see #getChildDrawingOrder(int, int)
2911     */
2912    protected void setChildrenDrawingOrderEnabled(boolean enabled) {
2913        setBooleanFlag(FLAG_USE_CHILD_DRAWING_ORDER, enabled);
2914    }
2915
2916    private void setBooleanFlag(int flag, boolean value) {
2917        if (value) {
2918            mGroupFlags |= flag;
2919        } else {
2920            mGroupFlags &= ~flag;
2921        }
2922    }
2923
2924    /**
2925     * Returns an integer indicating what types of drawing caches are kept in memory.
2926     *
2927     * @see #setPersistentDrawingCache(int)
2928     * @see #setAnimationCacheEnabled(boolean)
2929     *
2930     * @return one or a combination of {@link #PERSISTENT_NO_CACHE},
2931     *         {@link #PERSISTENT_ANIMATION_CACHE}, {@link #PERSISTENT_SCROLLING_CACHE}
2932     *         and {@link #PERSISTENT_ALL_CACHES}
2933     */
2934    @ViewDebug.ExportedProperty(mapping = {
2935        @ViewDebug.IntToString(from = PERSISTENT_NO_CACHE,        to = "NONE"),
2936        @ViewDebug.IntToString(from = PERSISTENT_ANIMATION_CACHE, to = "ANIMATION"),
2937        @ViewDebug.IntToString(from = PERSISTENT_SCROLLING_CACHE, to = "SCROLLING"),
2938        @ViewDebug.IntToString(from = PERSISTENT_ALL_CACHES,      to = "ALL")
2939    })
2940    public int getPersistentDrawingCache() {
2941        return mPersistentDrawingCache;
2942    }
2943
2944    /**
2945     * Indicates what types of drawing caches should be kept in memory after
2946     * they have been created.
2947     *
2948     * @see #getPersistentDrawingCache()
2949     * @see #setAnimationCacheEnabled(boolean)
2950     *
2951     * @param drawingCacheToKeep one or a combination of {@link #PERSISTENT_NO_CACHE},
2952     *        {@link #PERSISTENT_ANIMATION_CACHE}, {@link #PERSISTENT_SCROLLING_CACHE}
2953     *        and {@link #PERSISTENT_ALL_CACHES}
2954     */
2955    public void setPersistentDrawingCache(int drawingCacheToKeep) {
2956        mPersistentDrawingCache = drawingCacheToKeep & PERSISTENT_ALL_CACHES;
2957    }
2958
2959    /**
2960     * Returns a new set of layout parameters based on the supplied attributes set.
2961     *
2962     * @param attrs the attributes to build the layout parameters from
2963     *
2964     * @return an instance of {@link android.view.ViewGroup.LayoutParams} or one
2965     *         of its descendants
2966     */
2967    public LayoutParams generateLayoutParams(AttributeSet attrs) {
2968        return new LayoutParams(getContext(), attrs);
2969    }
2970
2971    /**
2972     * Returns a safe set of layout parameters based on the supplied layout params.
2973     * When a ViewGroup is passed a View whose layout params do not pass the test of
2974     * {@link #checkLayoutParams(android.view.ViewGroup.LayoutParams)}, this method
2975     * is invoked. This method should return a new set of layout params suitable for
2976     * this ViewGroup, possibly by copying the appropriate attributes from the
2977     * specified set of layout params.
2978     *
2979     * @param p The layout parameters to convert into a suitable set of layout parameters
2980     *          for this ViewGroup.
2981     *
2982     * @return an instance of {@link android.view.ViewGroup.LayoutParams} or one
2983     *         of its descendants
2984     */
2985    protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
2986        return p;
2987    }
2988
2989    /**
2990     * Returns a set of default layout parameters. These parameters are requested
2991     * when the View passed to {@link #addView(View)} has no layout parameters
2992     * already set. If null is returned, an exception is thrown from addView.
2993     *
2994     * @return a set of default layout parameters or null
2995     */
2996    protected LayoutParams generateDefaultLayoutParams() {
2997        return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
2998    }
2999
3000    /**
3001     * @hide
3002     */
3003    @Override
3004    protected boolean dispatchConsistencyCheck(int consistency) {
3005        boolean result = super.dispatchConsistencyCheck(consistency);
3006
3007        final int count = mChildrenCount;
3008        final View[] children = mChildren;
3009        for (int i = 0; i < count; i++) {
3010            if (!children[i].dispatchConsistencyCheck(consistency)) result = false;
3011        }
3012
3013        return result;
3014    }
3015
3016    /**
3017     * @hide
3018     */
3019    @Override
3020    protected boolean onConsistencyCheck(int consistency) {
3021        boolean result = super.onConsistencyCheck(consistency);
3022
3023        final boolean checkLayout = (consistency & ViewDebug.CONSISTENCY_LAYOUT) != 0;
3024        final boolean checkDrawing = (consistency & ViewDebug.CONSISTENCY_DRAWING) != 0;
3025
3026        if (checkLayout) {
3027            final int count = mChildrenCount;
3028            final View[] children = mChildren;
3029            for (int i = 0; i < count; i++) {
3030                if (children[i].getParent() != this) {
3031                    result = false;
3032                    android.util.Log.d(ViewDebug.CONSISTENCY_LOG_TAG,
3033                            "View " + children[i] + " has no parent/a parent that is not " + this);
3034                }
3035            }
3036        }
3037
3038        if (checkDrawing) {
3039            // If this group is dirty, check that the parent is dirty as well
3040            if ((mPrivateFlags & DIRTY_MASK) != 0) {
3041                final ViewParent parent = getParent();
3042                if (parent != null && !(parent instanceof ViewRoot)) {
3043                    if ((((View) parent).mPrivateFlags & DIRTY_MASK) == 0) {
3044                        result = false;
3045                        android.util.Log.d(ViewDebug.CONSISTENCY_LOG_TAG,
3046                                "ViewGroup " + this + " is dirty but its parent is not: " + this);
3047                    }
3048                }
3049            }
3050        }
3051
3052        return result;
3053    }
3054
3055    /**
3056     * {@inheritDoc}
3057     */
3058    @Override
3059    protected void debug(int depth) {
3060        super.debug(depth);
3061        String output;
3062
3063        if (mFocused != null) {
3064            output = debugIndent(depth);
3065            output += "mFocused";
3066            Log.d(VIEW_LOG_TAG, output);
3067        }
3068        if (mChildrenCount != 0) {
3069            output = debugIndent(depth);
3070            output += "{";
3071            Log.d(VIEW_LOG_TAG, output);
3072        }
3073        int count = mChildrenCount;
3074        for (int i = 0; i < count; i++) {
3075            View child = mChildren[i];
3076            child.debug(depth + 1);
3077        }
3078
3079        if (mChildrenCount != 0) {
3080            output = debugIndent(depth);
3081            output += "}";
3082            Log.d(VIEW_LOG_TAG, output);
3083        }
3084    }
3085
3086    /**
3087     * Returns the position in the group of the specified child view.
3088     *
3089     * @param child the view for which to get the position
3090     * @return a positive integer representing the position of the view in the
3091     *         group, or -1 if the view does not exist in the group
3092     */
3093    public int indexOfChild(View child) {
3094        final int count = mChildrenCount;
3095        final View[] children = mChildren;
3096        for (int i = 0; i < count; i++) {
3097            if (children[i] == child) {
3098                return i;
3099            }
3100        }
3101        return -1;
3102    }
3103
3104    /**
3105     * Returns the number of children in the group.
3106     *
3107     * @return a positive integer representing the number of children in
3108     *         the group
3109     */
3110    public int getChildCount() {
3111        return mChildrenCount;
3112    }
3113
3114    /**
3115     * Returns the view at the specified position in the group.
3116     *
3117     * @param index the position at which to get the view from
3118     * @return the view at the specified position or null if the position
3119     *         does not exist within the group
3120     */
3121    public View getChildAt(int index) {
3122        try {
3123            return mChildren[index];
3124        } catch (IndexOutOfBoundsException ex) {
3125            return null;
3126        }
3127    }
3128
3129    /**
3130     * Ask all of the children of this view to measure themselves, taking into
3131     * account both the MeasureSpec requirements for this view and its padding.
3132     * We skip children that are in the GONE state The heavy lifting is done in
3133     * getChildMeasureSpec.
3134     *
3135     * @param widthMeasureSpec The width requirements for this view
3136     * @param heightMeasureSpec The height requirements for this view
3137     */
3138    protected void measureChildren(int widthMeasureSpec, int heightMeasureSpec) {
3139        final int size = mChildrenCount;
3140        final View[] children = mChildren;
3141        for (int i = 0; i < size; ++i) {
3142            final View child = children[i];
3143            if ((child.mViewFlags & VISIBILITY_MASK) != GONE) {
3144                measureChild(child, widthMeasureSpec, heightMeasureSpec);
3145            }
3146        }
3147    }
3148
3149    /**
3150     * Ask one of the children of this view to measure itself, taking into
3151     * account both the MeasureSpec requirements for this view and its padding.
3152     * The heavy lifting is done in getChildMeasureSpec.
3153     *
3154     * @param child The child to measure
3155     * @param parentWidthMeasureSpec The width requirements for this view
3156     * @param parentHeightMeasureSpec The height requirements for this view
3157     */
3158    protected void measureChild(View child, int parentWidthMeasureSpec,
3159            int parentHeightMeasureSpec) {
3160        final LayoutParams lp = child.getLayoutParams();
3161
3162        final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
3163                mPaddingLeft + mPaddingRight, lp.width);
3164        final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
3165                mPaddingTop + mPaddingBottom, lp.height);
3166
3167        child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
3168    }
3169
3170    /**
3171     * Ask one of the children of this view to measure itself, taking into
3172     * account both the MeasureSpec requirements for this view and its padding
3173     * and margins. The child must have MarginLayoutParams The heavy lifting is
3174     * done in getChildMeasureSpec.
3175     *
3176     * @param child The child to measure
3177     * @param parentWidthMeasureSpec The width requirements for this view
3178     * @param widthUsed Extra space that has been used up by the parent
3179     *        horizontally (possibly by other children of the parent)
3180     * @param parentHeightMeasureSpec The height requirements for this view
3181     * @param heightUsed Extra space that has been used up by the parent
3182     *        vertically (possibly by other children of the parent)
3183     */
3184    protected void measureChildWithMargins(View child,
3185            int parentWidthMeasureSpec, int widthUsed,
3186            int parentHeightMeasureSpec, int heightUsed) {
3187        final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
3188
3189        final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
3190                mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin
3191                        + widthUsed, lp.width);
3192        final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
3193                mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin
3194                        + heightUsed, lp.height);
3195
3196        child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
3197    }
3198
3199    /**
3200     * Does the hard part of measureChildren: figuring out the MeasureSpec to
3201     * pass to a particular child. This method figures out the right MeasureSpec
3202     * for one dimension (height or width) of one child view.
3203     *
3204     * The goal is to combine information from our MeasureSpec with the
3205     * LayoutParams of the child to get the best possible results. For example,
3206     * if the this view knows its size (because its MeasureSpec has a mode of
3207     * EXACTLY), and the child has indicated in its LayoutParams that it wants
3208     * to be the same size as the parent, the parent should ask the child to
3209     * layout given an exact size.
3210     *
3211     * @param spec The requirements for this view
3212     * @param padding The padding of this view for the current dimension and
3213     *        margins, if applicable
3214     * @param childDimension How big the child wants to be in the current
3215     *        dimension
3216     * @return a MeasureSpec integer for the child
3217     */
3218    public static int getChildMeasureSpec(int spec, int padding, int childDimension) {
3219        int specMode = MeasureSpec.getMode(spec);
3220        int specSize = MeasureSpec.getSize(spec);
3221
3222        int size = Math.max(0, specSize - padding);
3223
3224        int resultSize = 0;
3225        int resultMode = 0;
3226
3227        switch (specMode) {
3228        // Parent has imposed an exact size on us
3229        case MeasureSpec.EXACTLY:
3230            if (childDimension >= 0) {
3231                resultSize = childDimension;
3232                resultMode = MeasureSpec.EXACTLY;
3233            } else if (childDimension == LayoutParams.MATCH_PARENT) {
3234                // Child wants to be our size. So be it.
3235                resultSize = size;
3236                resultMode = MeasureSpec.EXACTLY;
3237            } else if (childDimension == LayoutParams.WRAP_CONTENT) {
3238                // Child wants to determine its own size. It can't be
3239                // bigger than us.
3240                resultSize = size;
3241                resultMode = MeasureSpec.AT_MOST;
3242            }
3243            break;
3244
3245        // Parent has imposed a maximum size on us
3246        case MeasureSpec.AT_MOST:
3247            if (childDimension >= 0) {
3248                // Child wants a specific size... so be it
3249                resultSize = childDimension;
3250                resultMode = MeasureSpec.EXACTLY;
3251            } else if (childDimension == LayoutParams.MATCH_PARENT) {
3252                // Child wants to be our size, but our size is not fixed.
3253                // Constrain child to not be bigger than us.
3254                resultSize = size;
3255                resultMode = MeasureSpec.AT_MOST;
3256            } else if (childDimension == LayoutParams.WRAP_CONTENT) {
3257                // Child wants to determine its own size. It can't be
3258                // bigger than us.
3259                resultSize = size;
3260                resultMode = MeasureSpec.AT_MOST;
3261            }
3262            break;
3263
3264        // Parent asked to see how big we want to be
3265        case MeasureSpec.UNSPECIFIED:
3266            if (childDimension >= 0) {
3267                // Child wants a specific size... let him have it
3268                resultSize = childDimension;
3269                resultMode = MeasureSpec.EXACTLY;
3270            } else if (childDimension == LayoutParams.MATCH_PARENT) {
3271                // Child wants to be our size... find out how big it should
3272                // be
3273                resultSize = 0;
3274                resultMode = MeasureSpec.UNSPECIFIED;
3275            } else if (childDimension == LayoutParams.WRAP_CONTENT) {
3276                // Child wants to determine its own size.... find out how
3277                // big it should be
3278                resultSize = 0;
3279                resultMode = MeasureSpec.UNSPECIFIED;
3280            }
3281            break;
3282        }
3283        return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
3284    }
3285
3286
3287    /**
3288     * Removes any pending animations for views that have been removed. Call
3289     * this if you don't want animations for exiting views to stack up.
3290     */
3291    public void clearDisappearingChildren() {
3292        if (mDisappearingChildren != null) {
3293            mDisappearingChildren.clear();
3294        }
3295    }
3296
3297    /**
3298     * Add a view which is removed from mChildren but still needs animation
3299     *
3300     * @param v View to add
3301     */
3302    private void addDisappearingView(View v) {
3303        ArrayList<View> disappearingChildren = mDisappearingChildren;
3304
3305        if (disappearingChildren == null) {
3306            disappearingChildren = mDisappearingChildren = new ArrayList<View>();
3307        }
3308
3309        disappearingChildren.add(v);
3310    }
3311
3312    /**
3313     * Cleanup a view when its animation is done. This may mean removing it from
3314     * the list of disappearing views.
3315     *
3316     * @param view The view whose animation has finished
3317     * @param animation The animation, cannot be null
3318     */
3319    private void finishAnimatingView(final View view, Animation animation) {
3320        final ArrayList<View> disappearingChildren = mDisappearingChildren;
3321        if (disappearingChildren != null) {
3322            if (disappearingChildren.contains(view)) {
3323                disappearingChildren.remove(view);
3324
3325                if (view.mAttachInfo != null) {
3326                    view.dispatchDetachedFromWindow();
3327                }
3328
3329                view.clearAnimation();
3330                mGroupFlags |= FLAG_INVALIDATE_REQUIRED;
3331            }
3332        }
3333
3334        if (animation != null && !animation.getFillAfter()) {
3335            view.clearAnimation();
3336        }
3337
3338        if ((view.mPrivateFlags & ANIMATION_STARTED) == ANIMATION_STARTED) {
3339            view.onAnimationEnd();
3340            // Should be performed by onAnimationEnd() but this avoid an infinite loop,
3341            // so we'd rather be safe than sorry
3342            view.mPrivateFlags &= ~ANIMATION_STARTED;
3343            // Draw one more frame after the animation is done
3344            mGroupFlags |= FLAG_INVALIDATE_REQUIRED;
3345        }
3346    }
3347
3348    /**
3349     * {@inheritDoc}
3350     */
3351    @Override
3352    public boolean gatherTransparentRegion(Region region) {
3353        // If no transparent regions requested, we are always opaque.
3354        final boolean meOpaque = (mPrivateFlags & View.REQUEST_TRANSPARENT_REGIONS) == 0;
3355        if (meOpaque && region == null) {
3356            // The caller doesn't care about the region, so stop now.
3357            return true;
3358        }
3359        super.gatherTransparentRegion(region);
3360        final View[] children = mChildren;
3361        final int count = mChildrenCount;
3362        boolean noneOfTheChildrenAreTransparent = true;
3363        for (int i = 0; i < count; i++) {
3364            final View child = children[i];
3365            if ((child.mViewFlags & VISIBILITY_MASK) != GONE || child.getAnimation() != null) {
3366                if (!child.gatherTransparentRegion(region)) {
3367                    noneOfTheChildrenAreTransparent = false;
3368                }
3369            }
3370        }
3371        return meOpaque || noneOfTheChildrenAreTransparent;
3372    }
3373
3374    /**
3375     * {@inheritDoc}
3376     */
3377    public void requestTransparentRegion(View child) {
3378        if (child != null) {
3379            child.mPrivateFlags |= View.REQUEST_TRANSPARENT_REGIONS;
3380            if (mParent != null) {
3381                mParent.requestTransparentRegion(this);
3382            }
3383        }
3384    }
3385
3386
3387    @Override
3388    protected boolean fitSystemWindows(Rect insets) {
3389        boolean done = super.fitSystemWindows(insets);
3390        if (!done) {
3391            final int count = mChildrenCount;
3392            final View[] children = mChildren;
3393            for (int i = 0; i < count; i++) {
3394                done = children[i].fitSystemWindows(insets);
3395                if (done) {
3396                    break;
3397                }
3398            }
3399        }
3400        return done;
3401    }
3402
3403    /**
3404     * Returns the animation listener to which layout animation events are
3405     * sent.
3406     *
3407     * @return an {@link android.view.animation.Animation.AnimationListener}
3408     */
3409    public Animation.AnimationListener getLayoutAnimationListener() {
3410        return mAnimationListener;
3411    }
3412
3413    @Override
3414    protected void drawableStateChanged() {
3415        super.drawableStateChanged();
3416
3417        if ((mGroupFlags & FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE) != 0) {
3418            if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0) {
3419                throw new IllegalStateException("addStateFromChildren cannot be enabled if a"
3420                        + " child has duplicateParentState set to true");
3421            }
3422
3423            final View[] children = mChildren;
3424            final int count = mChildrenCount;
3425
3426            for (int i = 0; i < count; i++) {
3427                final View child = children[i];
3428                if ((child.mViewFlags & DUPLICATE_PARENT_STATE) != 0) {
3429                    child.refreshDrawableState();
3430                }
3431            }
3432        }
3433    }
3434
3435    @Override
3436    protected int[] onCreateDrawableState(int extraSpace) {
3437        if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) == 0) {
3438            return super.onCreateDrawableState(extraSpace);
3439        }
3440
3441        int need = 0;
3442        int n = getChildCount();
3443        for (int i = 0; i < n; i++) {
3444            int[] childState = getChildAt(i).getDrawableState();
3445
3446            if (childState != null) {
3447                need += childState.length;
3448            }
3449        }
3450
3451        int[] state = super.onCreateDrawableState(extraSpace + need);
3452
3453        for (int i = 0; i < n; i++) {
3454            int[] childState = getChildAt(i).getDrawableState();
3455
3456            if (childState != null) {
3457                state = mergeDrawableStates(state, childState);
3458            }
3459        }
3460
3461        return state;
3462    }
3463
3464    /**
3465     * Sets whether this ViewGroup's drawable states also include
3466     * its children's drawable states.  This is used, for example, to
3467     * make a group appear to be focused when its child EditText or button
3468     * is focused.
3469     */
3470    public void setAddStatesFromChildren(boolean addsStates) {
3471        if (addsStates) {
3472            mGroupFlags |= FLAG_ADD_STATES_FROM_CHILDREN;
3473        } else {
3474            mGroupFlags &= ~FLAG_ADD_STATES_FROM_CHILDREN;
3475        }
3476
3477        refreshDrawableState();
3478    }
3479
3480    /**
3481     * Returns whether this ViewGroup's drawable states also include
3482     * its children's drawable states.  This is used, for example, to
3483     * make a group appear to be focused when its child EditText or button
3484     * is focused.
3485     */
3486    public boolean addStatesFromChildren() {
3487        return (mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0;
3488    }
3489
3490    /**
3491     * If {link #addStatesFromChildren} is true, refreshes this group's
3492     * drawable state (to include the states from its children).
3493     */
3494    public void childDrawableStateChanged(View child) {
3495        if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0) {
3496            refreshDrawableState();
3497        }
3498    }
3499
3500    /**
3501     * Specifies the animation listener to which layout animation events must
3502     * be sent. Only
3503     * {@link android.view.animation.Animation.AnimationListener#onAnimationStart(Animation)}
3504     * and
3505     * {@link android.view.animation.Animation.AnimationListener#onAnimationEnd(Animation)}
3506     * are invoked.
3507     *
3508     * @param animationListener the layout animation listener
3509     */
3510    public void setLayoutAnimationListener(Animation.AnimationListener animationListener) {
3511        mAnimationListener = animationListener;
3512    }
3513
3514    /**
3515     * LayoutParams are used by views to tell their parents how they want to be
3516     * laid out. See
3517     * {@link android.R.styleable#ViewGroup_Layout ViewGroup Layout Attributes}
3518     * for a list of all child view attributes that this class supports.
3519     *
3520     * <p>
3521     * The base LayoutParams class just describes how big the view wants to be
3522     * for both width and height. For each dimension, it can specify one of:
3523     * <ul>
3524     * <li>FILL_PARENT (renamed MATCH_PARENT in API Level 8 and higher), which
3525     * means that the view wants to be as big as its parent (minus padding)
3526     * <li> WRAP_CONTENT, which means that the view wants to be just big enough
3527     * to enclose its content (plus padding)
3528     * <li> an exact number
3529     * </ul>
3530     * There are subclasses of LayoutParams for different subclasses of
3531     * ViewGroup. For example, AbsoluteLayout has its own subclass of
3532     * LayoutParams which adds an X and Y value.
3533     *
3534     * @attr ref android.R.styleable#ViewGroup_Layout_layout_height
3535     * @attr ref android.R.styleable#ViewGroup_Layout_layout_width
3536     */
3537    public static class LayoutParams {
3538        /**
3539         * Special value for the height or width requested by a View.
3540         * FILL_PARENT means that the view wants to be as big as its parent,
3541         * minus the parent's padding, if any. This value is deprecated
3542         * starting in API Level 8 and replaced by {@link #MATCH_PARENT}.
3543         */
3544        @SuppressWarnings({"UnusedDeclaration"})
3545        @Deprecated
3546        public static final int FILL_PARENT = -1;
3547
3548        /**
3549         * Special value for the height or width requested by a View.
3550         * MATCH_PARENT means that the view wants to be as big as its parent,
3551         * minus the parent's padding, if any. Introduced in API Level 8.
3552         */
3553        public static final int MATCH_PARENT = -1;
3554
3555        /**
3556         * Special value for the height or width requested by a View.
3557         * WRAP_CONTENT means that the view wants to be just large enough to fit
3558         * its own internal content, taking its own padding into account.
3559         */
3560        public static final int WRAP_CONTENT = -2;
3561
3562        /**
3563         * Information about how wide the view wants to be. Can be one of the
3564         * constants FILL_PARENT (replaced by MATCH_PARENT ,
3565         * in API Level 8) or WRAP_CONTENT. or an exact size.
3566         */
3567        @ViewDebug.ExportedProperty(mapping = {
3568            @ViewDebug.IntToString(from = MATCH_PARENT, to = "MATCH_PARENT"),
3569            @ViewDebug.IntToString(from = WRAP_CONTENT, to = "WRAP_CONTENT")
3570        })
3571        public int width;
3572
3573        /**
3574         * Information about how tall the view wants to be. Can be one of the
3575         * constants FILL_PARENT (replaced by MATCH_PARENT ,
3576         * in API Level 8) or WRAP_CONTENT. or an exact size.
3577         */
3578        @ViewDebug.ExportedProperty(mapping = {
3579            @ViewDebug.IntToString(from = MATCH_PARENT, to = "MATCH_PARENT"),
3580            @ViewDebug.IntToString(from = WRAP_CONTENT, to = "WRAP_CONTENT")
3581        })
3582        public int height;
3583
3584        /**
3585         * Used to animate layouts.
3586         */
3587        public LayoutAnimationController.AnimationParameters layoutAnimationParameters;
3588
3589        /**
3590         * Creates a new set of layout parameters. The values are extracted from
3591         * the supplied attributes set and context. The XML attributes mapped
3592         * to this set of layout parameters are:
3593         *
3594         * <ul>
3595         *   <li><code>layout_width</code>: the width, either an exact value,
3596         *   {@link #WRAP_CONTENT}, or {@link #FILL_PARENT} (replaced by
3597         *   {@link #MATCH_PARENT} in API Level 8)</li>
3598         *   <li><code>layout_height</code>: the height, either an exact value,
3599         *   {@link #WRAP_CONTENT}, or {@link #FILL_PARENT} (replaced by
3600         *   {@link #MATCH_PARENT} in API Level 8)</li>
3601         * </ul>
3602         *
3603         * @param c the application environment
3604         * @param attrs the set of attributes from which to extract the layout
3605         *              parameters' values
3606         */
3607        public LayoutParams(Context c, AttributeSet attrs) {
3608            TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.ViewGroup_Layout);
3609            setBaseAttributes(a,
3610                    R.styleable.ViewGroup_Layout_layout_width,
3611                    R.styleable.ViewGroup_Layout_layout_height);
3612            a.recycle();
3613        }
3614
3615        /**
3616         * Creates a new set of layout parameters with the specified width
3617         * and height.
3618         *
3619         * @param width the width, either {@link #WRAP_CONTENT},
3620         *        {@link #FILL_PARENT} (replaced by {@link #MATCH_PARENT} in
3621         *        API Level 8), or a fixed size in pixels
3622         * @param height the height, either {@link #WRAP_CONTENT},
3623         *        {@link #FILL_PARENT} (replaced by {@link #MATCH_PARENT} in
3624         *        API Level 8), or a fixed size in pixels
3625         */
3626        public LayoutParams(int width, int height) {
3627            this.width = width;
3628            this.height = height;
3629        }
3630
3631        /**
3632         * Copy constructor. Clones the width and height values of the source.
3633         *
3634         * @param source The layout params to copy from.
3635         */
3636        public LayoutParams(LayoutParams source) {
3637            this.width = source.width;
3638            this.height = source.height;
3639        }
3640
3641        /**
3642         * Used internally by MarginLayoutParams.
3643         * @hide
3644         */
3645        LayoutParams() {
3646        }
3647
3648        /**
3649         * Extracts the layout parameters from the supplied attributes.
3650         *
3651         * @param a the style attributes to extract the parameters from
3652         * @param widthAttr the identifier of the width attribute
3653         * @param heightAttr the identifier of the height attribute
3654         */
3655        protected void setBaseAttributes(TypedArray a, int widthAttr, int heightAttr) {
3656            width = a.getLayoutDimension(widthAttr, "layout_width");
3657            height = a.getLayoutDimension(heightAttr, "layout_height");
3658        }
3659
3660        /**
3661         * Returns a String representation of this set of layout parameters.
3662         *
3663         * @param output the String to prepend to the internal representation
3664         * @return a String with the following format: output +
3665         *         "ViewGroup.LayoutParams={ width=WIDTH, height=HEIGHT }"
3666         *
3667         * @hide
3668         */
3669        public String debug(String output) {
3670            return output + "ViewGroup.LayoutParams={ width="
3671                    + sizeToString(width) + ", height=" + sizeToString(height) + " }";
3672        }
3673
3674        /**
3675         * Converts the specified size to a readable String.
3676         *
3677         * @param size the size to convert
3678         * @return a String instance representing the supplied size
3679         *
3680         * @hide
3681         */
3682        protected static String sizeToString(int size) {
3683            if (size == WRAP_CONTENT) {
3684                return "wrap-content";
3685            }
3686            if (size == MATCH_PARENT) {
3687                return "match-parent";
3688            }
3689            return String.valueOf(size);
3690        }
3691    }
3692
3693    /**
3694     * Per-child layout information for layouts that support margins.
3695     * See
3696     * {@link android.R.styleable#ViewGroup_MarginLayout ViewGroup Margin Layout Attributes}
3697     * for a list of all child view attributes that this class supports.
3698     */
3699    public static class MarginLayoutParams extends ViewGroup.LayoutParams {
3700        /**
3701         * The left margin in pixels of the child.
3702         */
3703        @ViewDebug.ExportedProperty
3704        public int leftMargin;
3705
3706        /**
3707         * The top margin in pixels of the child.
3708         */
3709        @ViewDebug.ExportedProperty
3710        public int topMargin;
3711
3712        /**
3713         * The right margin in pixels of the child.
3714         */
3715        @ViewDebug.ExportedProperty
3716        public int rightMargin;
3717
3718        /**
3719         * The bottom margin in pixels of the child.
3720         */
3721        @ViewDebug.ExportedProperty
3722        public int bottomMargin;
3723
3724        /**
3725         * Creates a new set of layout parameters. The values are extracted from
3726         * the supplied attributes set and context.
3727         *
3728         * @param c the application environment
3729         * @param attrs the set of attributes from which to extract the layout
3730         *              parameters' values
3731         */
3732        public MarginLayoutParams(Context c, AttributeSet attrs) {
3733            super();
3734
3735            TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.ViewGroup_MarginLayout);
3736            setBaseAttributes(a,
3737                    R.styleable.ViewGroup_MarginLayout_layout_width,
3738                    R.styleable.ViewGroup_MarginLayout_layout_height);
3739
3740            int margin = a.getDimensionPixelSize(
3741                    com.android.internal.R.styleable.ViewGroup_MarginLayout_layout_margin, -1);
3742            if (margin >= 0) {
3743                leftMargin = margin;
3744                topMargin = margin;
3745                rightMargin= margin;
3746                bottomMargin = margin;
3747            } else {
3748                leftMargin = a.getDimensionPixelSize(
3749                        R.styleable.ViewGroup_MarginLayout_layout_marginLeft, 0);
3750                topMargin = a.getDimensionPixelSize(
3751                        R.styleable.ViewGroup_MarginLayout_layout_marginTop, 0);
3752                rightMargin = a.getDimensionPixelSize(
3753                        R.styleable.ViewGroup_MarginLayout_layout_marginRight, 0);
3754                bottomMargin = a.getDimensionPixelSize(
3755                        R.styleable.ViewGroup_MarginLayout_layout_marginBottom, 0);
3756            }
3757
3758            a.recycle();
3759        }
3760
3761        /**
3762         * {@inheritDoc}
3763         */
3764        public MarginLayoutParams(int width, int height) {
3765            super(width, height);
3766        }
3767
3768        /**
3769         * Copy constructor. Clones the width, height and margin values of the source.
3770         *
3771         * @param source The layout params to copy from.
3772         */
3773        public MarginLayoutParams(MarginLayoutParams source) {
3774            this.width = source.width;
3775            this.height = source.height;
3776
3777            this.leftMargin = source.leftMargin;
3778            this.topMargin = source.topMargin;
3779            this.rightMargin = source.rightMargin;
3780            this.bottomMargin = source.bottomMargin;
3781        }
3782
3783        /**
3784         * {@inheritDoc}
3785         */
3786        public MarginLayoutParams(LayoutParams source) {
3787            super(source);
3788        }
3789
3790        /**
3791         * Sets the margins, in pixels.
3792         *
3793         * @param left the left margin size
3794         * @param top the top margin size
3795         * @param right the right margin size
3796         * @param bottom the bottom margin size
3797         *
3798         * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginLeft
3799         * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginTop
3800         * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginRight
3801         * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginBottom
3802         */
3803        public void setMargins(int left, int top, int right, int bottom) {
3804            leftMargin = left;
3805            topMargin = top;
3806            rightMargin = right;
3807            bottomMargin = bottom;
3808        }
3809    }
3810}
3811