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