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