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