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