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