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