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