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