ViewGroup.java revision 2c095f367779ef32130c72849936a2e3013c8492
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 android.animation.LayoutTransition;
20import com.android.internal.R;
21
22import android.content.ClipData;
23import android.content.ClipDescription;
24import android.content.Context;
25import android.content.res.Configuration;
26import android.content.res.TypedArray;
27import android.graphics.Bitmap;
28import android.graphics.Canvas;
29import android.graphics.Matrix;
30import android.graphics.Paint;
31import android.graphics.PointF;
32import android.graphics.Rect;
33import android.graphics.RectF;
34import android.graphics.Region;
35import android.os.Parcelable;
36import android.os.SystemClock;
37import android.util.AttributeSet;
38import android.util.Log;
39import android.util.SparseArray;
40import android.view.accessibility.AccessibilityEvent;
41import android.view.animation.Animation;
42import android.view.animation.AnimationUtils;
43import android.view.animation.LayoutAnimationController;
44import android.view.animation.Transformation;
45
46import java.util.ArrayList;
47
48/**
49 * <p>
50 * A <code>ViewGroup</code> is a special view that can contain other views
51 * (called children.) The view group is the base class for layouts and views
52 * containers. This class also defines the
53 * {@link android.view.ViewGroup.LayoutParams} class which serves as the base
54 * class for layouts parameters.
55 * </p>
56 *
57 * <p>
58 * Also see {@link LayoutParams} for layout attributes.
59 * </p>
60 *
61 * @attr ref android.R.styleable#ViewGroup_clipChildren
62 * @attr ref android.R.styleable#ViewGroup_clipToPadding
63 * @attr ref android.R.styleable#ViewGroup_layoutAnimation
64 * @attr ref android.R.styleable#ViewGroup_animationCache
65 * @attr ref android.R.styleable#ViewGroup_persistentDrawingCache
66 * @attr ref android.R.styleable#ViewGroup_alwaysDrawnWithCache
67 * @attr ref android.R.styleable#ViewGroup_addStatesFromChildren
68 * @attr ref android.R.styleable#ViewGroup_descendantFocusability
69 * @attr ref android.R.styleable#ViewGroup_animateLayoutChanges
70 */
71public abstract class ViewGroup extends View implements ViewParent, ViewManager {
72
73    private static final boolean DBG = false;
74
75    /**
76     * Views which have been hidden or removed which need to be animated on
77     * their way out.
78     * This field should be made private, so it is hidden from the SDK.
79     * {@hide}
80     */
81    protected ArrayList<View> mDisappearingChildren;
82
83    /**
84     * Listener used to propagate events indicating when children are added
85     * and/or removed from a view group.
86     * This field should be made private, so it is hidden from the SDK.
87     * {@hide}
88     */
89    protected OnHierarchyChangeListener mOnHierarchyChangeListener;
90
91    // The view contained within this ViewGroup that has or contains focus.
92    private View mFocused;
93
94    /**
95     * A Transformation used when drawing children, to
96     * apply on the child being drawn.
97     */
98    private final Transformation mChildTransformation = new Transformation();
99
100    /**
101     * Used to track the current invalidation region.
102     */
103    private RectF mInvalidateRegion;
104
105    /**
106     * A Transformation used to calculate a correct
107     * invalidation area when the application is autoscaled.
108     */
109    private Transformation mInvalidationTransformation;
110
111    // View currently under an ongoing drag
112    private View mCurrentDragView;
113
114    // Does this group have a child that can accept the current drag payload?
115    private boolean mChildAcceptsDrag;
116
117    // Used during drag dispatch
118    private final PointF mLocalPoint = new PointF();
119
120    // Layout animation
121    private LayoutAnimationController mLayoutAnimationController;
122    private Animation.AnimationListener mAnimationListener;
123
124    // First touch target in the linked list of touch targets.
125    private TouchTarget mFirstTouchTarget;
126
127    // Temporary arrays for splitting pointers.
128    private int[] mTmpPointerIndexMap;
129    private int[] mTmpPointerIds;
130    private MotionEvent.PointerCoords[] mTmpPointerCoords;
131
132    /**
133     * Internal flags.
134     *
135     * This field should be made private, so it is hidden from the SDK.
136     * {@hide}
137     */
138    protected int mGroupFlags;
139
140    // When set, ViewGroup invalidates only the child's rectangle
141    // Set by default
142    private static final int FLAG_CLIP_CHILDREN = 0x1;
143
144    // When set, ViewGroup excludes the padding area from the invalidate rectangle
145    // Set by default
146    private static final int FLAG_CLIP_TO_PADDING = 0x2;
147
148    // When set, dispatchDraw() will invoke invalidate(); this is set by drawChild() when
149    // a child needs to be invalidated and FLAG_OPTIMIZE_INVALIDATE is set
150    private static final int FLAG_INVALIDATE_REQUIRED  = 0x4;
151
152    // When set, dispatchDraw() will run the layout animation and unset the flag
153    private static final int FLAG_RUN_ANIMATION = 0x8;
154
155    // When set, there is either no layout animation on the ViewGroup or the layout
156    // animation is over
157    // Set by default
158    private static final int FLAG_ANIMATION_DONE = 0x10;
159
160    // If set, this ViewGroup has padding; if unset there is no padding and we don't need
161    // to clip it, even if FLAG_CLIP_TO_PADDING is set
162    private static final int FLAG_PADDING_NOT_NULL = 0x20;
163
164    // When set, this ViewGroup caches its children in a Bitmap before starting a layout animation
165    // Set by default
166    private static final int FLAG_ANIMATION_CACHE = 0x40;
167
168    // When set, this ViewGroup converts calls to invalidate(Rect) to invalidate() during a
169    // layout animation; this avoid clobbering the hierarchy
170    // Automatically set when the layout animation starts, depending on the animation's
171    // characteristics
172    private static final int FLAG_OPTIMIZE_INVALIDATE = 0x80;
173
174    // When set, the next call to drawChild() will clear mChildTransformation's matrix
175    private static final int FLAG_CLEAR_TRANSFORMATION = 0x100;
176
177    // When set, this ViewGroup invokes mAnimationListener.onAnimationEnd() and removes
178    // the children's Bitmap caches if necessary
179    // This flag is set when the layout animation is over (after FLAG_ANIMATION_DONE is set)
180    private static final int FLAG_NOTIFY_ANIMATION_LISTENER = 0x200;
181
182    /**
183     * When set, the drawing method will call {@link #getChildDrawingOrder(int, int)}
184     * to get the index of the child to draw for that iteration.
185     *
186     * @hide
187     */
188    protected static final int FLAG_USE_CHILD_DRAWING_ORDER = 0x400;
189
190    /**
191     * When set, this ViewGroup supports static transformations on children; this causes
192     * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} to be
193     * invoked when a child is drawn.
194     *
195     * Any subclass overriding
196     * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} should
197     * set this flags in {@link #mGroupFlags}.
198     *
199     * {@hide}
200     */
201    protected static final int FLAG_SUPPORT_STATIC_TRANSFORMATIONS = 0x800;
202
203    // When the previous drawChild() invocation used an alpha value that was lower than
204    // 1.0 and set it in mCachePaint
205    private static final int FLAG_ALPHA_LOWER_THAN_ONE = 0x1000;
206
207    /**
208     * When set, this ViewGroup's drawable states also include those
209     * of its children.
210     */
211    private static final int FLAG_ADD_STATES_FROM_CHILDREN = 0x2000;
212
213    /**
214     * When set, this ViewGroup tries to always draw its children using their drawing cache.
215     */
216    private static final int FLAG_ALWAYS_DRAWN_WITH_CACHE = 0x4000;
217
218    /**
219     * When set, and if FLAG_ALWAYS_DRAWN_WITH_CACHE is not set, this ViewGroup will try to
220     * draw its children with their drawing cache.
221     */
222    private static final int FLAG_CHILDREN_DRAWN_WITH_CACHE = 0x8000;
223
224    /**
225     * When set, this group will go through its list of children to notify them of
226     * any drawable state change.
227     */
228    private static final int FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE = 0x10000;
229
230    private static final int FLAG_MASK_FOCUSABILITY = 0x60000;
231
232    /**
233     * This view will get focus before any of its descendants.
234     */
235    public static final int FOCUS_BEFORE_DESCENDANTS = 0x20000;
236
237    /**
238     * This view will get focus only if none of its descendants want it.
239     */
240    public static final int FOCUS_AFTER_DESCENDANTS = 0x40000;
241
242    /**
243     * This view will block any of its descendants from getting focus, even
244     * if they are focusable.
245     */
246    public static final int FOCUS_BLOCK_DESCENDANTS = 0x60000;
247
248    /**
249     * Used to map between enum in attrubutes and flag values.
250     */
251    private static final int[] DESCENDANT_FOCUSABILITY_FLAGS =
252            {FOCUS_BEFORE_DESCENDANTS, FOCUS_AFTER_DESCENDANTS,
253                    FOCUS_BLOCK_DESCENDANTS};
254
255    /**
256     * When set, this ViewGroup should not intercept touch events.
257     * {@hide}
258     */
259    protected static final int FLAG_DISALLOW_INTERCEPT = 0x80000;
260
261    /**
262     * When set, this ViewGroup will split MotionEvents to multiple child Views when appropriate.
263     */
264    private static final int FLAG_SPLIT_MOTION_EVENTS = 0x200000;
265
266    /**
267     * Indicates which types of drawing caches are to be kept in memory.
268     * This field should be made private, so it is hidden from the SDK.
269     * {@hide}
270     */
271    protected int mPersistentDrawingCache;
272
273    /**
274     * Used to indicate that no drawing cache should be kept in memory.
275     */
276    public static final int PERSISTENT_NO_CACHE = 0x0;
277
278    /**
279     * Used to indicate that the animation drawing cache should be kept in memory.
280     */
281    public static final int PERSISTENT_ANIMATION_CACHE = 0x1;
282
283    /**
284     * Used to indicate that the scrolling drawing cache should be kept in memory.
285     */
286    public static final int PERSISTENT_SCROLLING_CACHE = 0x2;
287
288    /**
289     * Used to indicate that all drawing caches should be kept in memory.
290     */
291    public static final int PERSISTENT_ALL_CACHES = 0x3;
292
293    /**
294     * We clip to padding when FLAG_CLIP_TO_PADDING and FLAG_PADDING_NOT_NULL
295     * are set at the same time.
296     */
297    protected static final int CLIP_TO_PADDING_MASK = FLAG_CLIP_TO_PADDING | FLAG_PADDING_NOT_NULL;
298
299    // Index of the child's left position in the mLocation array
300    private static final int CHILD_LEFT_INDEX = 0;
301    // Index of the child's top position in the mLocation array
302    private static final int CHILD_TOP_INDEX = 1;
303
304    // Child views of this ViewGroup
305    private View[] mChildren;
306    // Number of valid children in the mChildren array, the rest should be null or not
307    // considered as children
308    private int mChildrenCount;
309
310    private static final int ARRAY_INITIAL_CAPACITY = 12;
311    private static final int ARRAY_CAPACITY_INCREMENT = 12;
312
313    // Used to draw cached views
314    private final Paint mCachePaint = new Paint();
315
316    // Used to animate add/remove changes in layout
317    private LayoutTransition mTransition;
318
319    // The set of views that are currently being transitioned. This list is used to track views
320    // being removed that should not actually be removed from the parent yet because they are
321    // being animated.
322    private ArrayList<View> mTransitioningViews;
323
324    // List of children changing visibility. This is used to potentially keep rendering
325    // views during a transition when they otherwise would have become gone/invisible
326    private ArrayList<View> mVisibilityChangingChildren;
327
328    public ViewGroup(Context context) {
329        super(context);
330        initViewGroup();
331    }
332
333    public ViewGroup(Context context, AttributeSet attrs) {
334        super(context, attrs);
335        initViewGroup();
336        initFromAttributes(context, attrs);
337    }
338
339    public ViewGroup(Context context, AttributeSet attrs, int defStyle) {
340        super(context, attrs, defStyle);
341        initViewGroup();
342        initFromAttributes(context, attrs);
343    }
344
345    private void initViewGroup() {
346        // ViewGroup doesn't draw by default
347        setFlags(WILL_NOT_DRAW, DRAW_MASK);
348        mGroupFlags |= FLAG_CLIP_CHILDREN;
349        mGroupFlags |= FLAG_CLIP_TO_PADDING;
350        mGroupFlags |= FLAG_ANIMATION_DONE;
351        mGroupFlags |= FLAG_ANIMATION_CACHE;
352        mGroupFlags |= FLAG_ALWAYS_DRAWN_WITH_CACHE;
353
354        setDescendantFocusability(FOCUS_BEFORE_DESCENDANTS);
355
356        mChildren = new View[ARRAY_INITIAL_CAPACITY];
357        mChildrenCount = 0;
358
359        mCachePaint.setDither(false);
360
361        mPersistentDrawingCache = PERSISTENT_SCROLLING_CACHE;
362    }
363
364    private void initFromAttributes(Context context, AttributeSet attrs) {
365        TypedArray a = context.obtainStyledAttributes(attrs,
366                R.styleable.ViewGroup);
367
368        final int N = a.getIndexCount();
369        for (int i = 0; i < N; i++) {
370            int attr = a.getIndex(i);
371            switch (attr) {
372                case R.styleable.ViewGroup_clipChildren:
373                    setClipChildren(a.getBoolean(attr, true));
374                    break;
375                case R.styleable.ViewGroup_clipToPadding:
376                    setClipToPadding(a.getBoolean(attr, true));
377                    break;
378                case R.styleable.ViewGroup_animationCache:
379                    setAnimationCacheEnabled(a.getBoolean(attr, true));
380                    break;
381                case R.styleable.ViewGroup_persistentDrawingCache:
382                    setPersistentDrawingCache(a.getInt(attr, PERSISTENT_SCROLLING_CACHE));
383                    break;
384                case R.styleable.ViewGroup_addStatesFromChildren:
385                    setAddStatesFromChildren(a.getBoolean(attr, false));
386                    break;
387                case R.styleable.ViewGroup_alwaysDrawnWithCache:
388                    setAlwaysDrawnWithCacheEnabled(a.getBoolean(attr, true));
389                    break;
390                case R.styleable.ViewGroup_layoutAnimation:
391                    int id = a.getResourceId(attr, -1);
392                    if (id > 0) {
393                        setLayoutAnimation(AnimationUtils.loadLayoutAnimation(mContext, id));
394                    }
395                    break;
396                case R.styleable.ViewGroup_descendantFocusability:
397                    setDescendantFocusability(DESCENDANT_FOCUSABILITY_FLAGS[a.getInt(attr, 0)]);
398                    break;
399                case R.styleable.ViewGroup_splitMotionEvents:
400                    setMotionEventSplittingEnabled(a.getBoolean(attr, false));
401                    break;
402                case R.styleable.ViewGroup_animateLayoutChanges:
403                    boolean animateLayoutChanges = a.getBoolean(attr, false);
404                    if (animateLayoutChanges) {
405                        setLayoutTransition(new LayoutTransition());
406                    }
407                    break;
408            }
409        }
410
411        a.recycle();
412    }
413
414    /**
415     * Gets the descendant focusability of this view group.  The descendant
416     * focusability defines the relationship between this view group and its
417     * descendants when looking for a view to take focus in
418     * {@link #requestFocus(int, android.graphics.Rect)}.
419     *
420     * @return one of {@link #FOCUS_BEFORE_DESCENDANTS}, {@link #FOCUS_AFTER_DESCENDANTS},
421     *   {@link #FOCUS_BLOCK_DESCENDANTS}.
422     */
423    @ViewDebug.ExportedProperty(category = "focus", mapping = {
424        @ViewDebug.IntToString(from = FOCUS_BEFORE_DESCENDANTS, to = "FOCUS_BEFORE_DESCENDANTS"),
425        @ViewDebug.IntToString(from = FOCUS_AFTER_DESCENDANTS, to = "FOCUS_AFTER_DESCENDANTS"),
426        @ViewDebug.IntToString(from = FOCUS_BLOCK_DESCENDANTS, to = "FOCUS_BLOCK_DESCENDANTS")
427    })
428    public int getDescendantFocusability() {
429        return mGroupFlags & FLAG_MASK_FOCUSABILITY;
430    }
431
432    /**
433     * Set the descendant focusability of this view group. This defines the relationship
434     * between this view group and its descendants when looking for a view to
435     * take focus in {@link #requestFocus(int, android.graphics.Rect)}.
436     *
437     * @param focusability one of {@link #FOCUS_BEFORE_DESCENDANTS}, {@link #FOCUS_AFTER_DESCENDANTS},
438     *   {@link #FOCUS_BLOCK_DESCENDANTS}.
439     */
440    public void setDescendantFocusability(int focusability) {
441        switch (focusability) {
442            case FOCUS_BEFORE_DESCENDANTS:
443            case FOCUS_AFTER_DESCENDANTS:
444            case FOCUS_BLOCK_DESCENDANTS:
445                break;
446            default:
447                throw new IllegalArgumentException("must be one of FOCUS_BEFORE_DESCENDANTS, "
448                        + "FOCUS_AFTER_DESCENDANTS, FOCUS_BLOCK_DESCENDANTS");
449        }
450        mGroupFlags &= ~FLAG_MASK_FOCUSABILITY;
451        mGroupFlags |= (focusability & FLAG_MASK_FOCUSABILITY);
452    }
453
454    /**
455     * {@inheritDoc}
456     */
457    @Override
458    void handleFocusGainInternal(int direction, Rect previouslyFocusedRect) {
459        if (mFocused != null) {
460            mFocused.unFocus();
461            mFocused = null;
462        }
463        super.handleFocusGainInternal(direction, previouslyFocusedRect);
464    }
465
466    /**
467     * {@inheritDoc}
468     */
469    public void requestChildFocus(View child, View focused) {
470        if (DBG) {
471            System.out.println(this + " requestChildFocus()");
472        }
473        if (getDescendantFocusability() == FOCUS_BLOCK_DESCENDANTS) {
474            return;
475        }
476
477        // Unfocus us, if necessary
478        super.unFocus();
479
480        // We had a previous notion of who had focus. Clear it.
481        if (mFocused != child) {
482            if (mFocused != null) {
483                mFocused.unFocus();
484            }
485
486            mFocused = child;
487        }
488        if (mParent != null) {
489            mParent.requestChildFocus(this, focused);
490        }
491    }
492
493    /**
494     * {@inheritDoc}
495     */
496    public void focusableViewAvailable(View v) {
497        if (mParent != null
498                // shortcut: don't report a new focusable view if we block our descendants from
499                // getting focus
500                && (getDescendantFocusability() != FOCUS_BLOCK_DESCENDANTS)
501                // shortcut: don't report a new focusable view if we already are focused
502                // (and we don't prefer our descendants)
503                //
504                // note: knowing that mFocused is non-null is not a good enough reason
505                // to break the traversal since in that case we'd actually have to find
506                // the focused view and make sure it wasn't FOCUS_AFTER_DESCENDANTS and
507                // an ancestor of v; this will get checked for at ViewRoot
508                && !(isFocused() && getDescendantFocusability() != FOCUS_AFTER_DESCENDANTS)) {
509            mParent.focusableViewAvailable(v);
510        }
511    }
512
513    /**
514     * {@inheritDoc}
515     */
516    public boolean showContextMenuForChild(View originalView) {
517        return mParent != null && mParent.showContextMenuForChild(originalView);
518    }
519
520    /**
521     * {@inheritDoc}
522     */
523    public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback) {
524        return mParent != null ? mParent.startActionModeForChild(originalView, callback) : null;
525    }
526
527    /**
528     * Find the nearest view in the specified direction that wants to take
529     * focus.
530     *
531     * @param focused The view that currently has focus
532     * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and
533     *        FOCUS_RIGHT, or 0 for not applicable.
534     */
535    public View focusSearch(View focused, int direction) {
536        if (isRootNamespace()) {
537            // root namespace means we should consider ourselves the top of the
538            // tree for focus searching; otherwise we could be focus searching
539            // into other tabs.  see LocalActivityManager and TabHost for more info
540            return FocusFinder.getInstance().findNextFocus(this, focused, direction);
541        } else if (mParent != null) {
542            return mParent.focusSearch(focused, direction);
543        }
544        return null;
545    }
546
547    /**
548     * {@inheritDoc}
549     */
550    public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
551        return false;
552    }
553
554    /**
555     * {@inheritDoc}
556     */
557    @Override
558    public boolean dispatchUnhandledMove(View focused, int direction) {
559        return mFocused != null &&
560                mFocused.dispatchUnhandledMove(focused, direction);
561    }
562
563    /**
564     * {@inheritDoc}
565     */
566    public void clearChildFocus(View child) {
567        if (DBG) {
568            System.out.println(this + " clearChildFocus()");
569        }
570
571        mFocused = null;
572        if (mParent != null) {
573            mParent.clearChildFocus(this);
574        }
575    }
576
577    /**
578     * {@inheritDoc}
579     */
580    @Override
581    public void clearFocus() {
582        super.clearFocus();
583
584        // clear any child focus if it exists
585        if (mFocused != null) {
586            mFocused.clearFocus();
587        }
588    }
589
590    /**
591     * {@inheritDoc}
592     */
593    @Override
594    void unFocus() {
595        if (DBG) {
596            System.out.println(this + " unFocus()");
597        }
598
599        super.unFocus();
600        if (mFocused != null) {
601            mFocused.unFocus();
602        }
603        mFocused = null;
604    }
605
606    /**
607     * Returns the focused child of this view, if any. The child may have focus
608     * or contain focus.
609     *
610     * @return the focused child or null.
611     */
612    public View getFocusedChild() {
613        return mFocused;
614    }
615
616    /**
617     * Returns true if this view has or contains focus
618     *
619     * @return true if this view has or contains focus
620     */
621    @Override
622    public boolean hasFocus() {
623        return (mPrivateFlags & FOCUSED) != 0 || mFocused != null;
624    }
625
626    /*
627     * (non-Javadoc)
628     *
629     * @see android.view.View#findFocus()
630     */
631    @Override
632    public View findFocus() {
633        if (DBG) {
634            System.out.println("Find focus in " + this + ": flags="
635                    + isFocused() + ", child=" + mFocused);
636        }
637
638        if (isFocused()) {
639            return this;
640        }
641
642        if (mFocused != null) {
643            return mFocused.findFocus();
644        }
645        return null;
646    }
647
648    /**
649     * {@inheritDoc}
650     */
651    @Override
652    public boolean hasFocusable() {
653        if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) {
654            return false;
655        }
656
657        if (isFocusable()) {
658            return true;
659        }
660
661        final int descendantFocusability = getDescendantFocusability();
662        if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS) {
663            final int count = mChildrenCount;
664            final View[] children = mChildren;
665
666            for (int i = 0; i < count; i++) {
667                final View child = children[i];
668                if (child.hasFocusable()) {
669                    return true;
670                }
671            }
672        }
673
674        return false;
675    }
676
677    /**
678     * {@inheritDoc}
679     */
680    @Override
681    public void addFocusables(ArrayList<View> views, int direction) {
682        addFocusables(views, direction, FOCUSABLES_TOUCH_MODE);
683    }
684
685    /**
686     * {@inheritDoc}
687     */
688    @Override
689    public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
690        final int focusableCount = views.size();
691
692        final int descendantFocusability = getDescendantFocusability();
693
694        if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS) {
695            final int count = mChildrenCount;
696            final View[] children = mChildren;
697
698            for (int i = 0; i < count; i++) {
699                final View child = children[i];
700                if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
701                    child.addFocusables(views, direction, focusableMode);
702                }
703            }
704        }
705
706        // we add ourselves (if focusable) in all cases except for when we are
707        // FOCUS_AFTER_DESCENDANTS and there are some descendants focusable.  this is
708        // to avoid the focus search finding layouts when a more precise search
709        // among the focusable children would be more interesting.
710        if (
711            descendantFocusability != FOCUS_AFTER_DESCENDANTS ||
712                // No focusable descendants
713                (focusableCount == views.size())) {
714            super.addFocusables(views, direction, focusableMode);
715        }
716    }
717
718    /**
719     * {@inheritDoc}
720     */
721    @Override
722    public void dispatchWindowFocusChanged(boolean hasFocus) {
723        super.dispatchWindowFocusChanged(hasFocus);
724        final int count = mChildrenCount;
725        final View[] children = mChildren;
726        for (int i = 0; i < count; i++) {
727            children[i].dispatchWindowFocusChanged(hasFocus);
728        }
729    }
730
731    /**
732     * {@inheritDoc}
733     */
734    @Override
735    public void addTouchables(ArrayList<View> views) {
736        super.addTouchables(views);
737
738        final int count = mChildrenCount;
739        final View[] children = mChildren;
740
741        for (int i = 0; i < count; i++) {
742            final View child = children[i];
743            if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
744                child.addTouchables(views);
745            }
746        }
747    }
748
749    /**
750     * {@inheritDoc}
751     */
752    @Override
753    public void dispatchDisplayHint(int hint) {
754        super.dispatchDisplayHint(hint);
755        final int count = mChildrenCount;
756        final View[] children = mChildren;
757        for (int i = 0; i < count; i++) {
758            children[i].dispatchDisplayHint(hint);
759        }
760    }
761
762    /**
763     * @hide
764     * @param child
765     * @param visibility
766     */
767    void onChildVisibilityChanged(View child, int visibility) {
768        if (mTransition != null) {
769            if (visibility == VISIBLE) {
770                mTransition.showChild(this, child);
771            } else {
772                mTransition.hideChild(this, child);
773            }
774            if (visibility != VISIBLE) {
775                // Only track this on disappearing views - appearing views are already visible
776                // and don't need special handling during drawChild()
777                if (mVisibilityChangingChildren == null) {
778                    mVisibilityChangingChildren = new ArrayList<View>();
779                }
780                mVisibilityChangingChildren.add(child);
781                if (mTransitioningViews != null && mTransitioningViews.contains(child)) {
782                    addDisappearingView(child);
783                }
784            }
785        }
786    }
787
788    /**
789     * {@inheritDoc}
790     */
791    @Override
792    protected void dispatchVisibilityChanged(View changedView, int visibility) {
793        super.dispatchVisibilityChanged(changedView, visibility);
794        final int count = mChildrenCount;
795        final View[] children = mChildren;
796        for (int i = 0; i < count; i++) {
797            children[i].dispatchVisibilityChanged(changedView, visibility);
798        }
799    }
800
801    /**
802     * {@inheritDoc}
803     */
804    @Override
805    public void dispatchWindowVisibilityChanged(int visibility) {
806        super.dispatchWindowVisibilityChanged(visibility);
807        final int count = mChildrenCount;
808        final View[] children = mChildren;
809        for (int i = 0; i < count; i++) {
810            children[i].dispatchWindowVisibilityChanged(visibility);
811        }
812    }
813
814    /**
815     * {@inheritDoc}
816     */
817    @Override
818    public void dispatchConfigurationChanged(Configuration newConfig) {
819        super.dispatchConfigurationChanged(newConfig);
820        final int count = mChildrenCount;
821        final View[] children = mChildren;
822        for (int i = 0; i < count; i++) {
823            children[i].dispatchConfigurationChanged(newConfig);
824        }
825    }
826
827    /**
828     * {@inheritDoc}
829     */
830    public void recomputeViewAttributes(View child) {
831        ViewParent parent = mParent;
832        if (parent != null) parent.recomputeViewAttributes(this);
833    }
834
835    @Override
836    void dispatchCollectViewAttributes(int visibility) {
837        visibility |= mViewFlags&VISIBILITY_MASK;
838        super.dispatchCollectViewAttributes(visibility);
839        final int count = mChildrenCount;
840        final View[] children = mChildren;
841        for (int i = 0; i < count; i++) {
842            children[i].dispatchCollectViewAttributes(visibility);
843        }
844    }
845
846    /**
847     * {@inheritDoc}
848     */
849    public void bringChildToFront(View child) {
850        int index = indexOfChild(child);
851        if (index >= 0) {
852            removeFromArray(index);
853            addInArray(child, mChildrenCount);
854            child.mParent = this;
855        }
856    }
857
858    /**
859     * {@inheritDoc}
860     *
861     * !!! TODO: write real docs
862     */
863    @Override
864    public boolean dispatchDragEvent(DragEvent event) {
865        boolean retval = false;
866        final float tx = event.mX;
867        final float ty = event.mY;
868
869        ViewRoot root = getViewRoot();
870
871        // Dispatch down the view hierarchy
872        switch (event.mAction) {
873        case DragEvent.ACTION_DRAG_STARTED: {
874            // clear state to recalculate which views we drag over
875            root.setDragFocus(event, null);
876
877            // Now dispatch down to our children, caching the responses
878            mChildAcceptsDrag = false;
879            final int count = mChildrenCount;
880            final View[] children = mChildren;
881            for (int i = 0; i < count; i++) {
882                final View child = children[i];
883                if (child.getVisibility() == VISIBLE) {
884                    final boolean handled = children[i].dispatchDragEvent(event);
885                    children[i].mCanAcceptDrop = handled;
886                    if (handled) {
887                        mChildAcceptsDrag = true;
888                    }
889                }
890            }
891
892            // Return HANDLED if one of our children can accept the drag
893            if (mChildAcceptsDrag) {
894                retval = true;
895            }
896        } break;
897
898        case DragEvent.ACTION_DRAG_ENDED: {
899            // Notify all of our children that the drag is over
900            final int count = mChildrenCount;
901            final View[] children = mChildren;
902            for (int i = 0; i < count; i++) {
903                final View child = children[i];
904                if (child.getVisibility() == VISIBLE) {
905                    child.dispatchDragEvent(event);
906                }
907            }
908            // We consider drag-ended to have been handled if one of our children
909            // had offered to handle the drag.
910            if (mChildAcceptsDrag) {
911                retval = true;
912            }
913        } break;
914
915        case DragEvent.ACTION_DRAG_LOCATION: {
916            // Find the [possibly new] drag target
917            final View target = findFrontmostDroppableChildAt(event.mX, event.mY, mLocalPoint);
918
919            // If we've changed apparent drag target, tell the view root which view
920            // we're over now.  This will in turn send out DRAG_ENTERED / DRAG_EXITED
921            // notifications as appropriate.
922            if (mCurrentDragView != target) {
923                root.setDragFocus(event, target);
924                mCurrentDragView = target;
925            }
926
927            // Dispatch the actual drag location notice, localized into its coordinates
928            if (target != null) {
929                event.mX = mLocalPoint.x;
930                event.mY = mLocalPoint.y;
931
932                retval = target.dispatchDragEvent(event);
933
934                event.mX = tx;
935                event.mY = ty;
936            }
937        } break;
938
939        case DragEvent.ACTION_DROP: {
940            if (ViewDebug.DEBUG_DRAG) Log.d(View.VIEW_LOG_TAG, "Drop event: " + event);
941            View target = findFrontmostDroppableChildAt(event.mX, event.mY, mLocalPoint);
942            if (target != null) {
943                event.mX = mLocalPoint.x;
944                event.mY = mLocalPoint.y;
945                retval = target.dispatchDragEvent(event);
946                event.mX = tx;
947                event.mY = ty;
948            }
949        } break;
950        }
951
952        // If none of our children could handle the event, try here
953        if (!retval) {
954            retval = onDragEvent(event);
955        }
956        return retval;
957    }
958
959    // Find the frontmost child view that lies under the given point, and calculate
960    // the position within its own local coordinate system.
961    View findFrontmostDroppableChildAt(float x, float y, PointF outLocalPoint) {
962        final int count = mChildrenCount;
963        final View[] children = mChildren;
964        for (int i = count - 1; i >= 0; i--) {
965            final View child = children[i];
966            if (child.mCanAcceptDrop == false) {
967                continue;
968            }
969
970            if (isTransformedTouchPointInView(x, y, child, outLocalPoint)) {
971                return child;
972            }
973        }
974        return null;
975    }
976
977    /**
978     * {@inheritDoc}
979     */
980    @Override
981    public boolean dispatchKeyEventPreIme(KeyEvent event) {
982        if ((mPrivateFlags & (FOCUSED | HAS_BOUNDS)) == (FOCUSED | HAS_BOUNDS)) {
983            return super.dispatchKeyEventPreIme(event);
984        } else if (mFocused != null && (mFocused.mPrivateFlags & HAS_BOUNDS) == HAS_BOUNDS) {
985            return mFocused.dispatchKeyEventPreIme(event);
986        }
987        return false;
988    }
989
990    /**
991     * {@inheritDoc}
992     */
993    @Override
994    public boolean dispatchKeyEvent(KeyEvent event) {
995        if ((mPrivateFlags & (FOCUSED | HAS_BOUNDS)) == (FOCUSED | HAS_BOUNDS)) {
996            return super.dispatchKeyEvent(event);
997        } else if (mFocused != null && (mFocused.mPrivateFlags & HAS_BOUNDS) == HAS_BOUNDS) {
998            return mFocused.dispatchKeyEvent(event);
999        }
1000        return false;
1001    }
1002
1003    /**
1004     * {@inheritDoc}
1005     */
1006    @Override
1007    public boolean dispatchKeyShortcutEvent(KeyEvent event) {
1008        if ((mPrivateFlags & (FOCUSED | HAS_BOUNDS)) == (FOCUSED | HAS_BOUNDS)) {
1009            return super.dispatchKeyShortcutEvent(event);
1010        } else if (mFocused != null && (mFocused.mPrivateFlags & HAS_BOUNDS) == HAS_BOUNDS) {
1011            return mFocused.dispatchKeyShortcutEvent(event);
1012        }
1013        return false;
1014    }
1015
1016    /**
1017     * {@inheritDoc}
1018     */
1019    @Override
1020    public boolean dispatchTrackballEvent(MotionEvent event) {
1021        if ((mPrivateFlags & (FOCUSED | HAS_BOUNDS)) == (FOCUSED | HAS_BOUNDS)) {
1022            return super.dispatchTrackballEvent(event);
1023        } else if (mFocused != null && (mFocused.mPrivateFlags & HAS_BOUNDS) == HAS_BOUNDS) {
1024            return mFocused.dispatchTrackballEvent(event);
1025        }
1026        return false;
1027    }
1028
1029    /**
1030     * {@inheritDoc}
1031     */
1032    @Override
1033    public boolean dispatchTouchEvent(MotionEvent ev) {
1034        if (!onFilterTouchEventForSecurity(ev)) {
1035            return false;
1036        }
1037
1038        final int action = ev.getAction();
1039        final int actionMasked = action & MotionEvent.ACTION_MASK;
1040
1041        // Handle an initial down.
1042        if (actionMasked == MotionEvent.ACTION_DOWN) {
1043            // Throw away all previous state when starting a new touch gesture.
1044            // The framework may have dropped the up or cancel event for the previous gesture
1045            // due to an app switch, ANR, or some other state change.
1046            cancelAndClearTouchTargets(ev);
1047            resetTouchState();
1048        }
1049
1050        // Check for interception.
1051        final boolean intercepted;
1052        if (actionMasked == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null) {
1053            final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
1054            if (!disallowIntercept) {
1055                intercepted = onInterceptTouchEvent(ev);
1056                ev.setAction(action); // restore action in case onInterceptTouchEvent() changed it
1057            } else {
1058                intercepted = false;
1059            }
1060        } else {
1061            intercepted = true;
1062        }
1063
1064        // Check for cancelation.
1065        final boolean canceled = resetCancelNextUpFlag(this)
1066                || actionMasked == MotionEvent.ACTION_CANCEL;
1067
1068        // Update list of touch targets for pointer down, if needed.
1069        final boolean split = (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) != 0;
1070        TouchTarget newTouchTarget = null;
1071        boolean alreadyDispatchedToNewTouchTarget = false;
1072        if (!canceled && !intercepted) {
1073            if (actionMasked == MotionEvent.ACTION_DOWN
1074                    || (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN)) {
1075                final int actionIndex = ev.getActionIndex(); // always 0 for down
1076                final int idBitsToAssign = split ? 1 << ev.getPointerId(actionIndex)
1077                        : TouchTarget.ALL_POINTER_IDS;
1078
1079                // Clean up earlier touch targets for this pointer id in case they
1080                // have become out of sync.
1081                removePointersFromTouchTargets(idBitsToAssign);
1082
1083                final int childrenCount = mChildrenCount;
1084                if (childrenCount != 0) {
1085                    // Find a child that can receive the event.  Scan children from front to back.
1086                    final View[] children = mChildren;
1087                    final float x = ev.getX(actionIndex);
1088                    final float y = ev.getY(actionIndex);
1089
1090                    for (int i = childrenCount - 1; i >= 0; i--) {
1091                        final View child = children[i];
1092                        if ((child.mViewFlags & VISIBILITY_MASK) != VISIBLE
1093                                && child.getAnimation() == null) {
1094                            // Skip invisible child unless it is animating.
1095                            continue;
1096                        }
1097
1098                        if (!isTransformedTouchPointInView(x, y, child, null)) {
1099                            // New pointer is out of child's bounds.
1100                            continue;
1101                        }
1102
1103                        newTouchTarget = getTouchTarget(child);
1104                        if (newTouchTarget != null) {
1105                            // Child is already receiving touch within its bounds.
1106                            // Give it the new pointer in addition to the ones it is handling.
1107                            newTouchTarget.pointerIdBits |= idBitsToAssign;
1108                            break;
1109                        }
1110
1111                        resetCancelNextUpFlag(child);
1112                        if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
1113                            // Child wants to receive touch within its bounds.
1114                            newTouchTarget = addTouchTarget(child, idBitsToAssign);
1115                            alreadyDispatchedToNewTouchTarget = true;
1116                            break;
1117                        }
1118                    }
1119                }
1120
1121                if (newTouchTarget == null && mFirstTouchTarget != null) {
1122                    // Did not find a child to receive the event.
1123                    // Assign the pointer to the least recently added target.
1124                    newTouchTarget = mFirstTouchTarget;
1125                    while (newTouchTarget.next != null) {
1126                        newTouchTarget = newTouchTarget.next;
1127                    }
1128                    newTouchTarget.pointerIdBits |= idBitsToAssign;
1129                }
1130            }
1131        }
1132
1133        // Dispatch to touch targets.
1134        boolean handled = false;
1135        if (mFirstTouchTarget == null) {
1136            // No touch targets so treat this as an ordinary view.
1137            handled = dispatchTransformedTouchEvent(ev, canceled, null,
1138                    TouchTarget.ALL_POINTER_IDS);
1139        } else {
1140            // Dispatch to touch targets, excluding the new touch target if we already
1141            // dispatched to it.  Cancel touch targets if necessary.
1142            TouchTarget predecessor = null;
1143            TouchTarget target = mFirstTouchTarget;
1144            while (target != null) {
1145                final TouchTarget next = target.next;
1146                if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) {
1147                    handled = true;
1148                } else {
1149                    final boolean cancelChild = resetCancelNextUpFlag(target.child) || intercepted;
1150                    if (dispatchTransformedTouchEvent(ev, cancelChild,
1151                            target.child, target.pointerIdBits)) {
1152                        handled = true;
1153                    }
1154                    if (cancelChild) {
1155                        if (predecessor == null) {
1156                            mFirstTouchTarget = next;
1157                        } else {
1158                            predecessor.next = next;
1159                        }
1160                        target.recycle();
1161                        target = next;
1162                        continue;
1163                    }
1164                }
1165                predecessor = target;
1166                target = next;
1167            }
1168        }
1169
1170        // Update list of touch targets for pointer up or cancel, if needed.
1171        if (canceled || actionMasked == MotionEvent.ACTION_UP) {
1172            resetTouchState();
1173        } else if (split && actionMasked == MotionEvent.ACTION_POINTER_UP) {
1174            final int actionIndex = ev.getActionIndex();
1175            final int idBitsToRemove = 1 << ev.getPointerId(actionIndex);
1176            removePointersFromTouchTargets(idBitsToRemove);
1177        }
1178
1179        return handled;
1180    }
1181
1182    /* Resets all touch state in preparation for a new cycle. */
1183    private final void resetTouchState() {
1184        clearTouchTargets();
1185        resetCancelNextUpFlag(this);
1186        mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
1187    }
1188
1189    /* Resets the cancel next up flag.
1190     * Returns true if the flag was previously set. */
1191    private final boolean resetCancelNextUpFlag(View view) {
1192        if ((view.mPrivateFlags & CANCEL_NEXT_UP_EVENT) != 0) {
1193            view.mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT;
1194            return true;
1195        }
1196        return false;
1197    }
1198
1199    /* Clears all touch targets. */
1200    private final void clearTouchTargets() {
1201        TouchTarget target = mFirstTouchTarget;
1202        if (target != null) {
1203            do {
1204                TouchTarget next = target.next;
1205                target.recycle();
1206                target = next;
1207            } while (target != null);
1208            mFirstTouchTarget = null;
1209        }
1210    }
1211
1212    /* Cancels and clears all touch targets. */
1213    private final void cancelAndClearTouchTargets(MotionEvent event) {
1214        if (mFirstTouchTarget != null) {
1215            boolean syntheticEvent = false;
1216            if (event == null) {
1217                final long now = SystemClock.uptimeMillis();
1218                event = MotionEvent.obtain(now, now,
1219                        MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
1220                syntheticEvent = true;
1221            }
1222
1223            for (TouchTarget target = mFirstTouchTarget; target != null; target = target.next) {
1224                resetCancelNextUpFlag(target.child);
1225                dispatchTransformedTouchEvent(event, true, target.child, target.pointerIdBits);
1226            }
1227            clearTouchTargets();
1228
1229            if (syntheticEvent) {
1230                event.recycle();
1231            }
1232        }
1233    }
1234
1235    /* Gets the touch target for specified child view.
1236     * Returns null if not found. */
1237    private final TouchTarget getTouchTarget(View child) {
1238        for (TouchTarget target = mFirstTouchTarget; target != null; target = target.next) {
1239            if (target.child == child) {
1240                return target;
1241            }
1242        }
1243        return null;
1244    }
1245
1246    /* Adds a touch target for specified child to the beginning of the list.
1247     * Assumes the target child is not already present. */
1248    private final TouchTarget addTouchTarget(View child, int pointerIdBits) {
1249        TouchTarget target = TouchTarget.obtain(child, pointerIdBits);
1250        target.next = mFirstTouchTarget;
1251        mFirstTouchTarget = target;
1252        return target;
1253    }
1254
1255    /* Removes the pointer ids from consideration. */
1256    private final void removePointersFromTouchTargets(int pointerIdBits) {
1257        TouchTarget predecessor = null;
1258        TouchTarget target = mFirstTouchTarget;
1259        while (target != null) {
1260            final TouchTarget next = target.next;
1261            if ((target.pointerIdBits & pointerIdBits) != 0) {
1262                target.pointerIdBits &= ~pointerIdBits;
1263                if (target.pointerIdBits == 0) {
1264                    if (predecessor == null) {
1265                        mFirstTouchTarget = next;
1266                    } else {
1267                        predecessor.next = next;
1268                    }
1269                    target.recycle();
1270                    target = next;
1271                    continue;
1272                }
1273            }
1274            predecessor = target;
1275            target = next;
1276        }
1277    }
1278
1279    /* Returns true if a child view contains the specified point when transformed
1280     * into its coordinate space.
1281     * Child must not be null. */
1282    private final boolean isTransformedTouchPointInView(float x, float y, View child,
1283            PointF outLocalPoint) {
1284        float localX = x + mScrollX - child.mLeft;
1285        float localY = y + mScrollY - child.mTop;
1286        if (! child.hasIdentityMatrix() && mAttachInfo != null) {
1287            final float[] localXY = mAttachInfo.mTmpTransformLocation;
1288            localXY[0] = localX;
1289            localXY[1] = localY;
1290            child.getInverseMatrix().mapPoints(localXY);
1291            localX = localXY[0];
1292            localY = localXY[1];
1293        }
1294        final boolean isInView = child.pointInView(localX, localY);
1295        if (isInView && outLocalPoint != null) {
1296            outLocalPoint.set(localX, localY);
1297        }
1298        return isInView;
1299    }
1300
1301    /* Transforms a motion event into the coordinate space of a particular child view,
1302     * filters out irrelevant pointer ids, and overrides its action if necessary.
1303     * If child is null, assumes the MotionEvent will be sent to this ViewGroup instead. */
1304    private final boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,
1305            View child, int desiredPointerIdBits) {
1306        final boolean handled;
1307
1308        // Canceling motions is a special case.  We don't need to perform any transformations
1309        // or filtering.  The important part is the action, not the contents.
1310        final int oldAction = event.getAction();
1311        if (cancel || oldAction == MotionEvent.ACTION_CANCEL) {
1312            event.setAction(MotionEvent.ACTION_CANCEL);
1313            if (child == null) {
1314                handled = super.dispatchTouchEvent(event);
1315            } else {
1316                handled = child.dispatchTouchEvent(event);
1317            }
1318            event.setAction(oldAction);
1319            return handled;
1320        }
1321
1322        // Calculate the number of pointers to deliver.
1323        final int oldPointerCount = event.getPointerCount();
1324        int newPointerCount = 0;
1325        if (desiredPointerIdBits == TouchTarget.ALL_POINTER_IDS) {
1326            newPointerCount = oldPointerCount;
1327        } else {
1328            for (int i = 0; i < oldPointerCount; i++) {
1329                final int pointerId = event.getPointerId(i);
1330                final int pointerIdBit = 1 << pointerId;
1331                if ((pointerIdBit & desiredPointerIdBits) != 0) {
1332                    newPointerCount += 1;
1333                }
1334            }
1335        }
1336
1337        // If for some reason we ended up in an inconsistent state where it looks like we
1338        // might produce a motion event with no pointers in it, then drop the event.
1339        if (newPointerCount == 0) {
1340            return false;
1341        }
1342
1343        // If the number of pointers is the same and we don't need to perform any fancy
1344        // irreversible transformations, then we can reuse the motion event for this
1345        // dispatch as long as we are careful to revert any changes we make.
1346        final boolean reuse = newPointerCount == oldPointerCount
1347                && (child == null || child.hasIdentityMatrix());
1348        if (reuse) {
1349            if (child == null) {
1350                handled = super.dispatchTouchEvent(event);
1351            } else {
1352                final float offsetX = mScrollX - child.mLeft;
1353                final float offsetY = mScrollY - child.mTop;
1354                event.offsetLocation(offsetX, offsetY);
1355
1356                handled = child.dispatchTouchEvent(event);
1357
1358                event.offsetLocation(-offsetX, -offsetY);
1359            }
1360            return handled;
1361        }
1362
1363        // Make a copy of the event.
1364        // If the number of pointers is different, then we need to filter out irrelevant pointers
1365        // as we make a copy of the motion event.
1366        MotionEvent transformedEvent;
1367        if (newPointerCount == oldPointerCount) {
1368            transformedEvent = MotionEvent.obtain(event);
1369        } else {
1370            growTmpPointerArrays(newPointerCount);
1371            final int[] newPointerIndexMap = mTmpPointerIndexMap;
1372            final int[] newPointerIds = mTmpPointerIds;
1373            final MotionEvent.PointerCoords[] newPointerCoords = mTmpPointerCoords;
1374
1375            int newPointerIndex = 0;
1376            int oldPointerIndex = 0;
1377            while (newPointerIndex < newPointerCount) {
1378                final int pointerId = event.getPointerId(oldPointerIndex);
1379                final int pointerIdBits = 1 << pointerId;
1380                if ((pointerIdBits & desiredPointerIdBits) != 0) {
1381                    newPointerIndexMap[newPointerIndex] = oldPointerIndex;
1382                    newPointerIds[newPointerIndex] = pointerId;
1383                    if (newPointerCoords[newPointerIndex] == null) {
1384                        newPointerCoords[newPointerIndex] = new MotionEvent.PointerCoords();
1385                    }
1386
1387                    newPointerIndex += 1;
1388                }
1389                oldPointerIndex += 1;
1390            }
1391
1392            final int newAction;
1393            if (cancel) {
1394                newAction = MotionEvent.ACTION_CANCEL;
1395            } else {
1396                final int oldMaskedAction = oldAction & MotionEvent.ACTION_MASK;
1397                if (oldMaskedAction == MotionEvent.ACTION_POINTER_DOWN
1398                        || oldMaskedAction == MotionEvent.ACTION_POINTER_UP) {
1399                    final int changedPointerId = event.getPointerId(
1400                            (oldAction & MotionEvent.ACTION_POINTER_INDEX_MASK)
1401                                    >> MotionEvent.ACTION_POINTER_INDEX_SHIFT);
1402                    final int changedPointerIdBits = 1 << changedPointerId;
1403                    if ((changedPointerIdBits & desiredPointerIdBits) != 0) {
1404                        if (newPointerCount == 1) {
1405                            // The first/last pointer went down/up.
1406                            newAction = oldMaskedAction == MotionEvent.ACTION_POINTER_DOWN
1407                                    ? MotionEvent.ACTION_DOWN : MotionEvent.ACTION_UP;
1408                        } else {
1409                            // A secondary pointer went down/up.
1410                            int newChangedPointerIndex = 0;
1411                            while (newPointerIds[newChangedPointerIndex] != changedPointerId) {
1412                                newChangedPointerIndex += 1;
1413                            }
1414                            newAction = oldMaskedAction | (newChangedPointerIndex
1415                                    << MotionEvent.ACTION_POINTER_INDEX_SHIFT);
1416                        }
1417                    } else {
1418                        // An unrelated pointer changed.
1419                        newAction = MotionEvent.ACTION_MOVE;
1420                    }
1421                } else {
1422                    // Simple up/down/cancel/move motion action.
1423                    newAction = oldMaskedAction;
1424                }
1425            }
1426
1427            transformedEvent = null;
1428            final int historySize = event.getHistorySize();
1429            for (int historyIndex = 0; historyIndex <= historySize; historyIndex++) {
1430                for (newPointerIndex = 0; newPointerIndex < newPointerCount; newPointerIndex++) {
1431                    final MotionEvent.PointerCoords c = newPointerCoords[newPointerIndex];
1432                    oldPointerIndex = newPointerIndexMap[newPointerIndex];
1433                    if (historyIndex != historySize) {
1434                        event.getHistoricalPointerCoords(oldPointerIndex, historyIndex, c);
1435                    } else {
1436                        event.getPointerCoords(oldPointerIndex, c);
1437                    }
1438                }
1439
1440                final long eventTime;
1441                if (historyIndex != historySize) {
1442                    eventTime = event.getHistoricalEventTime(historyIndex);
1443                } else {
1444                    eventTime = event.getEventTime();
1445                }
1446
1447                if (transformedEvent == null) {
1448                    transformedEvent = MotionEvent.obtain(
1449                            event.getDownTime(), eventTime, newAction,
1450                            newPointerCount, newPointerIds, newPointerCoords,
1451                            event.getMetaState(), event.getXPrecision(), event.getYPrecision(),
1452                            event.getDeviceId(), event.getEdgeFlags(), event.getSource(),
1453                            event.getFlags());
1454                } else {
1455                    transformedEvent.addBatch(eventTime, newPointerCoords, 0);
1456                }
1457            }
1458        }
1459
1460        // Perform any necessary transformations and dispatch.
1461        if (child == null) {
1462            handled = super.dispatchTouchEvent(transformedEvent);
1463        } else {
1464            final float offsetX = mScrollX - child.mLeft;
1465            final float offsetY = mScrollY - child.mTop;
1466            transformedEvent.offsetLocation(offsetX, offsetY);
1467            if (! child.hasIdentityMatrix()) {
1468                transformedEvent.transform(child.getInverseMatrix());
1469            }
1470
1471            handled = child.dispatchTouchEvent(transformedEvent);
1472        }
1473
1474        // Done.
1475        transformedEvent.recycle();
1476        return handled;
1477    }
1478
1479    /* Enlarge the temporary pointer arrays for splitting pointers.
1480     * May discard contents (but keeps PointerCoords objects to avoid reallocating them). */
1481    private final void growTmpPointerArrays(int desiredCapacity) {
1482        final MotionEvent.PointerCoords[] oldTmpPointerCoords = mTmpPointerCoords;
1483        int capacity;
1484        if (oldTmpPointerCoords != null) {
1485            capacity = oldTmpPointerCoords.length;
1486            if (desiredCapacity <= capacity) {
1487                return;
1488            }
1489        } else {
1490            capacity = 4;
1491        }
1492
1493        while (capacity < desiredCapacity) {
1494            capacity *= 2;
1495        }
1496
1497        mTmpPointerIndexMap = new int[capacity];
1498        mTmpPointerIds = new int[capacity];
1499        mTmpPointerCoords = new MotionEvent.PointerCoords[capacity];
1500
1501        if (oldTmpPointerCoords != null) {
1502            System.arraycopy(oldTmpPointerCoords, 0, mTmpPointerCoords, 0,
1503                    oldTmpPointerCoords.length);
1504        }
1505    }
1506
1507    /**
1508     * Enable or disable the splitting of MotionEvents to multiple children during touch event
1509     * dispatch. This behavior is disabled by default.
1510     *
1511     * <p>When this option is enabled MotionEvents may be split and dispatched to different child
1512     * views depending on where each pointer initially went down. This allows for user interactions
1513     * such as scrolling two panes of content independently, chording of buttons, and performing
1514     * independent gestures on different pieces of content.
1515     *
1516     * @param split <code>true</code> to allow MotionEvents to be split and dispatched to multiple
1517     *              child views. <code>false</code> to only allow one child view to be the target of
1518     *              any MotionEvent received by this ViewGroup.
1519     */
1520    public void setMotionEventSplittingEnabled(boolean split) {
1521        // TODO Applications really shouldn't change this setting mid-touch event,
1522        // but perhaps this should handle that case and send ACTION_CANCELs to any child views
1523        // with gestures in progress when this is changed.
1524        if (split) {
1525            mGroupFlags |= FLAG_SPLIT_MOTION_EVENTS;
1526        } else {
1527            mGroupFlags &= ~FLAG_SPLIT_MOTION_EVENTS;
1528        }
1529    }
1530
1531    /**
1532     * @return true if MotionEvents dispatched to this ViewGroup can be split to multiple children.
1533     */
1534    public boolean isMotionEventSplittingEnabled() {
1535        return (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) == FLAG_SPLIT_MOTION_EVENTS;
1536    }
1537
1538    /**
1539     * {@inheritDoc}
1540     */
1541    public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
1542
1543        if (disallowIntercept == ((mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0)) {
1544            // We're already in this state, assume our ancestors are too
1545            return;
1546        }
1547
1548        if (disallowIntercept) {
1549            mGroupFlags |= FLAG_DISALLOW_INTERCEPT;
1550        } else {
1551            mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
1552        }
1553
1554        // Pass it up to our parent
1555        if (mParent != null) {
1556            mParent.requestDisallowInterceptTouchEvent(disallowIntercept);
1557        }
1558    }
1559
1560    /**
1561     * Implement this method to intercept all touch screen motion events.  This
1562     * allows you to watch events as they are dispatched to your children, and
1563     * take ownership of the current gesture at any point.
1564     *
1565     * <p>Using this function takes some care, as it has a fairly complicated
1566     * interaction with {@link View#onTouchEvent(MotionEvent)
1567     * View.onTouchEvent(MotionEvent)}, and using it requires implementing
1568     * that method as well as this one in the correct way.  Events will be
1569     * received in the following order:
1570     *
1571     * <ol>
1572     * <li> You will receive the down event here.
1573     * <li> The down event will be handled either by a child of this view
1574     * group, or given to your own onTouchEvent() method to handle; this means
1575     * you should implement onTouchEvent() to return true, so you will
1576     * continue to see the rest of the gesture (instead of looking for
1577     * a parent view to handle it).  Also, by returning true from
1578     * onTouchEvent(), you will not receive any following
1579     * events in onInterceptTouchEvent() and all touch processing must
1580     * happen in onTouchEvent() like normal.
1581     * <li> For as long as you return false from this function, each following
1582     * event (up to and including the final up) will be delivered first here
1583     * and then to the target's onTouchEvent().
1584     * <li> If you return true from here, you will not receive any
1585     * following events: the target view will receive the same event but
1586     * with the action {@link MotionEvent#ACTION_CANCEL}, and all further
1587     * events will be delivered to your onTouchEvent() method and no longer
1588     * appear here.
1589     * </ol>
1590     *
1591     * @param ev The motion event being dispatched down the hierarchy.
1592     * @return Return true to steal motion events from the children and have
1593     * them dispatched to this ViewGroup through onTouchEvent().
1594     * The current target will receive an ACTION_CANCEL event, and no further
1595     * messages will be delivered here.
1596     */
1597    public boolean onInterceptTouchEvent(MotionEvent ev) {
1598        return false;
1599    }
1600
1601    /**
1602     * {@inheritDoc}
1603     *
1604     * Looks for a view to give focus to respecting the setting specified by
1605     * {@link #getDescendantFocusability()}.
1606     *
1607     * Uses {@link #onRequestFocusInDescendants(int, android.graphics.Rect)} to
1608     * find focus within the children of this group when appropriate.
1609     *
1610     * @see #FOCUS_BEFORE_DESCENDANTS
1611     * @see #FOCUS_AFTER_DESCENDANTS
1612     * @see #FOCUS_BLOCK_DESCENDANTS
1613     * @see #onRequestFocusInDescendants
1614     */
1615    @Override
1616    public boolean requestFocus(int direction, Rect previouslyFocusedRect) {
1617        if (DBG) {
1618            System.out.println(this + " ViewGroup.requestFocus direction="
1619                    + direction);
1620        }
1621        int descendantFocusability = getDescendantFocusability();
1622
1623        switch (descendantFocusability) {
1624            case FOCUS_BLOCK_DESCENDANTS:
1625                return super.requestFocus(direction, previouslyFocusedRect);
1626            case FOCUS_BEFORE_DESCENDANTS: {
1627                final boolean took = super.requestFocus(direction, previouslyFocusedRect);
1628                return took ? took : onRequestFocusInDescendants(direction, previouslyFocusedRect);
1629            }
1630            case FOCUS_AFTER_DESCENDANTS: {
1631                final boolean took = onRequestFocusInDescendants(direction, previouslyFocusedRect);
1632                return took ? took : super.requestFocus(direction, previouslyFocusedRect);
1633            }
1634            default:
1635                throw new IllegalStateException("descendant focusability must be "
1636                        + "one of FOCUS_BEFORE_DESCENDANTS, FOCUS_AFTER_DESCENDANTS, FOCUS_BLOCK_DESCENDANTS "
1637                        + "but is " + descendantFocusability);
1638        }
1639    }
1640
1641    /**
1642     * Look for a descendant to call {@link View#requestFocus} on.
1643     * Called by {@link ViewGroup#requestFocus(int, android.graphics.Rect)}
1644     * when it wants to request focus within its children.  Override this to
1645     * customize how your {@link ViewGroup} requests focus within its children.
1646     * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT
1647     * @param previouslyFocusedRect The rectangle (in this View's coordinate system)
1648     *        to give a finer grained hint about where focus is coming from.  May be null
1649     *        if there is no hint.
1650     * @return Whether focus was taken.
1651     */
1652    @SuppressWarnings({"ConstantConditions"})
1653    protected boolean onRequestFocusInDescendants(int direction,
1654            Rect previouslyFocusedRect) {
1655        int index;
1656        int increment;
1657        int end;
1658        int count = mChildrenCount;
1659        if ((direction & FOCUS_FORWARD) != 0) {
1660            index = 0;
1661            increment = 1;
1662            end = count;
1663        } else {
1664            index = count - 1;
1665            increment = -1;
1666            end = -1;
1667        }
1668        final View[] children = mChildren;
1669        for (int i = index; i != end; i += increment) {
1670            View child = children[i];
1671            if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
1672                if (child.requestFocus(direction, previouslyFocusedRect)) {
1673                    return true;
1674                }
1675            }
1676        }
1677        return false;
1678    }
1679
1680    /**
1681     * {@inheritDoc}
1682     *
1683     * @hide
1684     */
1685    @Override
1686    public void dispatchStartTemporaryDetach() {
1687        super.dispatchStartTemporaryDetach();
1688        final int count = mChildrenCount;
1689        final View[] children = mChildren;
1690        for (int i = 0; i < count; i++) {
1691            children[i].dispatchStartTemporaryDetach();
1692        }
1693    }
1694
1695    /**
1696     * {@inheritDoc}
1697     *
1698     * @hide
1699     */
1700    @Override
1701    public void dispatchFinishTemporaryDetach() {
1702        super.dispatchFinishTemporaryDetach();
1703        final int count = mChildrenCount;
1704        final View[] children = mChildren;
1705        for (int i = 0; i < count; i++) {
1706            children[i].dispatchFinishTemporaryDetach();
1707        }
1708    }
1709
1710    /**
1711     * {@inheritDoc}
1712     */
1713    @Override
1714    void dispatchAttachedToWindow(AttachInfo info, int visibility) {
1715        super.dispatchAttachedToWindow(info, visibility);
1716        visibility |= mViewFlags & VISIBILITY_MASK;
1717        final int count = mChildrenCount;
1718        final View[] children = mChildren;
1719        for (int i = 0; i < count; i++) {
1720            children[i].dispatchAttachedToWindow(info, visibility);
1721        }
1722    }
1723
1724    @Override
1725    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
1726        boolean populated = false;
1727        for (int i = 0, count = getChildCount(); i < count; i++) {
1728            populated |= getChildAt(i).dispatchPopulateAccessibilityEvent(event);
1729        }
1730        return populated;
1731    }
1732
1733    /**
1734     * {@inheritDoc}
1735     */
1736    @Override
1737    void dispatchDetachedFromWindow() {
1738        // If we still have a touch target, we are still in the process of
1739        // dispatching motion events to a child; we need to get rid of that
1740        // child to avoid dispatching events to it after the window is torn
1741        // down. To make sure we keep the child in a consistent state, we
1742        // first send it an ACTION_CANCEL motion event.
1743        cancelAndClearTouchTargets(null);
1744
1745        final int count = mChildrenCount;
1746        final View[] children = mChildren;
1747        for (int i = 0; i < count; i++) {
1748            children[i].dispatchDetachedFromWindow();
1749        }
1750        super.dispatchDetachedFromWindow();
1751    }
1752
1753    /**
1754     * {@inheritDoc}
1755     */
1756    @Override
1757    public void setPadding(int left, int top, int right, int bottom) {
1758        super.setPadding(left, top, right, bottom);
1759
1760        if ((mPaddingLeft | mPaddingTop | mPaddingRight | mPaddingRight) != 0) {
1761            mGroupFlags |= FLAG_PADDING_NOT_NULL;
1762        } else {
1763            mGroupFlags &= ~FLAG_PADDING_NOT_NULL;
1764        }
1765    }
1766
1767    /**
1768     * {@inheritDoc}
1769     */
1770    @Override
1771    protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {
1772        super.dispatchSaveInstanceState(container);
1773        final int count = mChildrenCount;
1774        final View[] children = mChildren;
1775        for (int i = 0; i < count; i++) {
1776            View c = children[i];
1777            if ((c.mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED) {
1778                c.dispatchSaveInstanceState(container);
1779            }
1780        }
1781    }
1782
1783    /**
1784     * Perform dispatching of a {@link #saveHierarchyState freeze()} to only this view,
1785     * not to its children.  For use when overriding
1786     * {@link #dispatchSaveInstanceState dispatchFreeze()} to allow subclasses to freeze
1787     * their own state but not the state of their children.
1788     *
1789     * @param container the container
1790     */
1791    protected void dispatchFreezeSelfOnly(SparseArray<Parcelable> container) {
1792        super.dispatchSaveInstanceState(container);
1793    }
1794
1795    /**
1796     * {@inheritDoc}
1797     */
1798    @Override
1799    protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {
1800        super.dispatchRestoreInstanceState(container);
1801        final int count = mChildrenCount;
1802        final View[] children = mChildren;
1803        for (int i = 0; i < count; i++) {
1804            View c = children[i];
1805            if ((c.mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED) {
1806                c.dispatchRestoreInstanceState(container);
1807            }
1808        }
1809    }
1810
1811    /**
1812     * Perform dispatching of a {@link #restoreHierarchyState thaw()} to only this view,
1813     * not to its children.  For use when overriding
1814     * {@link #dispatchRestoreInstanceState dispatchThaw()} to allow subclasses to thaw
1815     * their own state but not the state of their children.
1816     *
1817     * @param container the container
1818     */
1819    protected void dispatchThawSelfOnly(SparseArray<Parcelable> container) {
1820        super.dispatchRestoreInstanceState(container);
1821    }
1822
1823    /**
1824     * Enables or disables the drawing cache for each child of this view group.
1825     *
1826     * @param enabled true to enable the cache, false to dispose of it
1827     */
1828    protected void setChildrenDrawingCacheEnabled(boolean enabled) {
1829        if (enabled || (mPersistentDrawingCache & PERSISTENT_ALL_CACHES) != PERSISTENT_ALL_CACHES) {
1830            final View[] children = mChildren;
1831            final int count = mChildrenCount;
1832            for (int i = 0; i < count; i++) {
1833                children[i].setDrawingCacheEnabled(enabled);
1834            }
1835        }
1836    }
1837
1838    @Override
1839    protected void onAnimationStart() {
1840        super.onAnimationStart();
1841
1842        // When this ViewGroup's animation starts, build the cache for the children
1843        if ((mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE) {
1844            final int count = mChildrenCount;
1845            final View[] children = mChildren;
1846
1847            for (int i = 0; i < count; i++) {
1848                final View child = children[i];
1849                if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
1850                    child.setDrawingCacheEnabled(true);
1851                    child.buildDrawingCache(true);
1852                }
1853            }
1854
1855            mGroupFlags |= FLAG_CHILDREN_DRAWN_WITH_CACHE;
1856        }
1857    }
1858
1859    @Override
1860    protected void onAnimationEnd() {
1861        super.onAnimationEnd();
1862
1863        // When this ViewGroup's animation ends, destroy the cache of the children
1864        if ((mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE) {
1865            mGroupFlags &= ~FLAG_CHILDREN_DRAWN_WITH_CACHE;
1866
1867            if ((mPersistentDrawingCache & PERSISTENT_ANIMATION_CACHE) == 0) {
1868                setChildrenDrawingCacheEnabled(false);
1869            }
1870        }
1871    }
1872
1873    @Override
1874    Bitmap createSnapshot(Bitmap.Config quality, int backgroundColor, boolean skipChildren) {
1875        int count = mChildrenCount;
1876        int[] visibilities = null;
1877
1878        if (skipChildren) {
1879            visibilities = new int[count];
1880            for (int i = 0; i < count; i++) {
1881                View child = getChildAt(i);
1882                visibilities[i] = child.getVisibility();
1883                if (visibilities[i] == View.VISIBLE) {
1884                    child.setVisibility(INVISIBLE);
1885                }
1886            }
1887        }
1888
1889        Bitmap b = super.createSnapshot(quality, backgroundColor, skipChildren);
1890
1891        if (skipChildren) {
1892            for (int i = 0; i < count; i++) {
1893                getChildAt(i).setVisibility(visibilities[i]);
1894            }
1895        }
1896
1897        return b;
1898    }
1899
1900    /**
1901     * {@inheritDoc}
1902     */
1903    @Override
1904    protected void dispatchDraw(Canvas canvas) {
1905        final int count = mChildrenCount;
1906        final View[] children = mChildren;
1907        int flags = mGroupFlags;
1908
1909        if ((flags & FLAG_RUN_ANIMATION) != 0 && canAnimate()) {
1910            final boolean cache = (mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE;
1911
1912            for (int i = 0; i < count; i++) {
1913                final View child = children[i];
1914                if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
1915                    final LayoutParams params = child.getLayoutParams();
1916                    attachLayoutAnimationParameters(child, params, i, count);
1917                    bindLayoutAnimation(child);
1918                    if (cache) {
1919                        child.setDrawingCacheEnabled(true);
1920                        child.buildDrawingCache(true);
1921                    }
1922                }
1923            }
1924
1925            final LayoutAnimationController controller = mLayoutAnimationController;
1926            if (controller.willOverlap()) {
1927                mGroupFlags |= FLAG_OPTIMIZE_INVALIDATE;
1928            }
1929
1930            controller.start();
1931
1932            mGroupFlags &= ~FLAG_RUN_ANIMATION;
1933            mGroupFlags &= ~FLAG_ANIMATION_DONE;
1934
1935            if (cache) {
1936                mGroupFlags |= FLAG_CHILDREN_DRAWN_WITH_CACHE;
1937            }
1938
1939            if (mAnimationListener != null) {
1940                mAnimationListener.onAnimationStart(controller.getAnimation());
1941            }
1942        }
1943
1944        int saveCount = 0;
1945        final boolean clipToPadding = (flags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK;
1946        if (clipToPadding) {
1947            saveCount = canvas.save();
1948            canvas.clipRect(mScrollX + mPaddingLeft, mScrollY + mPaddingTop,
1949                    mScrollX + mRight - mLeft - mPaddingRight,
1950                    mScrollY + mBottom - mTop - mPaddingBottom);
1951
1952        }
1953
1954        // We will draw our child's animation, let's reset the flag
1955        mPrivateFlags &= ~DRAW_ANIMATION;
1956        mGroupFlags &= ~FLAG_INVALIDATE_REQUIRED;
1957
1958        boolean more = false;
1959        final long drawingTime = getDrawingTime();
1960
1961        if ((flags & FLAG_USE_CHILD_DRAWING_ORDER) == 0) {
1962            for (int i = 0; i < count; i++) {
1963                final View child = children[i];
1964                if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
1965                    more |= drawChild(canvas, child, drawingTime);
1966                }
1967            }
1968        } else {
1969            for (int i = 0; i < count; i++) {
1970                final View child = children[getChildDrawingOrder(count, i)];
1971                if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
1972                    more |= drawChild(canvas, child, drawingTime);
1973                }
1974            }
1975        }
1976
1977        // Draw any disappearing views that have animations
1978        if (mDisappearingChildren != null) {
1979            final ArrayList<View> disappearingChildren = mDisappearingChildren;
1980            final int disappearingCount = disappearingChildren.size() - 1;
1981            // Go backwards -- we may delete as animations finish
1982            for (int i = disappearingCount; i >= 0; i--) {
1983                final View child = disappearingChildren.get(i);
1984                more |= drawChild(canvas, child, drawingTime);
1985            }
1986        }
1987
1988        if (clipToPadding) {
1989            canvas.restoreToCount(saveCount);
1990        }
1991
1992        // mGroupFlags might have been updated by drawChild()
1993        flags = mGroupFlags;
1994
1995        if ((flags & FLAG_INVALIDATE_REQUIRED) == FLAG_INVALIDATE_REQUIRED) {
1996            invalidate();
1997        }
1998
1999        if ((flags & FLAG_ANIMATION_DONE) == 0 && (flags & FLAG_NOTIFY_ANIMATION_LISTENER) == 0 &&
2000                mLayoutAnimationController.isDone() && !more) {
2001            // We want to erase the drawing cache and notify the listener after the
2002            // next frame is drawn because one extra invalidate() is caused by
2003            // drawChild() after the animation is over
2004            mGroupFlags |= FLAG_NOTIFY_ANIMATION_LISTENER;
2005            final Runnable end = new Runnable() {
2006               public void run() {
2007                   notifyAnimationListener();
2008               }
2009            };
2010            post(end);
2011        }
2012    }
2013
2014    /**
2015     * Returns the index of the child to draw for this iteration. Override this
2016     * if you want to change the drawing order of children. By default, it
2017     * returns i.
2018     * <p>
2019     * NOTE: In order for this method to be called, you must enable child ordering
2020     * first by calling {@link #setChildrenDrawingOrderEnabled(boolean)}.
2021     *
2022     * @param i The current iteration.
2023     * @return The index of the child to draw this iteration.
2024     *
2025     * @see #setChildrenDrawingOrderEnabled(boolean)
2026     * @see #isChildrenDrawingOrderEnabled()
2027     */
2028    protected int getChildDrawingOrder(int childCount, int i) {
2029        return i;
2030    }
2031
2032    private void notifyAnimationListener() {
2033        mGroupFlags &= ~FLAG_NOTIFY_ANIMATION_LISTENER;
2034        mGroupFlags |= FLAG_ANIMATION_DONE;
2035
2036        if (mAnimationListener != null) {
2037           final Runnable end = new Runnable() {
2038               public void run() {
2039                   mAnimationListener.onAnimationEnd(mLayoutAnimationController.getAnimation());
2040               }
2041           };
2042           post(end);
2043        }
2044
2045        if ((mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE) {
2046            mGroupFlags &= ~FLAG_CHILDREN_DRAWN_WITH_CACHE;
2047            if ((mPersistentDrawingCache & PERSISTENT_ANIMATION_CACHE) == 0) {
2048                setChildrenDrawingCacheEnabled(false);
2049            }
2050        }
2051
2052        invalidate();
2053    }
2054
2055    /**
2056     * Draw one child of this View Group. This method is responsible for getting
2057     * the canvas in the right state. This includes clipping, translating so
2058     * that the child's scrolled origin is at 0, 0, and applying any animation
2059     * transformations.
2060     *
2061     * @param canvas The canvas on which to draw the child
2062     * @param child Who to draw
2063     * @param drawingTime The time at which draw is occuring
2064     * @return True if an invalidate() was issued
2065     */
2066    protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
2067        boolean more = false;
2068
2069        final int cl = child.mLeft;
2070        final int ct = child.mTop;
2071        final int cr = child.mRight;
2072        final int cb = child.mBottom;
2073
2074        final int flags = mGroupFlags;
2075
2076        if ((flags & FLAG_CLEAR_TRANSFORMATION) == FLAG_CLEAR_TRANSFORMATION) {
2077            mChildTransformation.clear();
2078            mGroupFlags &= ~FLAG_CLEAR_TRANSFORMATION;
2079        }
2080
2081        Transformation transformToApply = null;
2082        Transformation invalidationTransform;
2083        final Animation a = child.getAnimation();
2084        boolean concatMatrix = false;
2085
2086        boolean scalingRequired = false;
2087        boolean caching = false;
2088        if ((flags & FLAG_CHILDREN_DRAWN_WITH_CACHE) == FLAG_CHILDREN_DRAWN_WITH_CACHE ||
2089                (flags & FLAG_ALWAYS_DRAWN_WITH_CACHE) == FLAG_ALWAYS_DRAWN_WITH_CACHE) {
2090            caching = true;
2091            if (mAttachInfo != null) scalingRequired = mAttachInfo.mScalingRequired;
2092        }
2093
2094        if (a != null) {
2095            final boolean initialized = a.isInitialized();
2096            if (!initialized) {
2097                a.initialize(cr - cl, cb - ct, getWidth(), getHeight());
2098                a.initializeInvalidateRegion(0, 0, cr - cl, cb - ct);
2099                child.onAnimationStart();
2100            }
2101
2102            more = a.getTransformation(drawingTime, mChildTransformation,
2103                    scalingRequired ? mAttachInfo.mApplicationScale : 1f);
2104            if (scalingRequired && mAttachInfo.mApplicationScale != 1f) {
2105                if (mInvalidationTransformation == null) {
2106                    mInvalidationTransformation = new Transformation();
2107                }
2108                invalidationTransform = mInvalidationTransformation;
2109                a.getTransformation(drawingTime, invalidationTransform, 1f);
2110            } else {
2111                invalidationTransform = mChildTransformation;
2112            }
2113            transformToApply = mChildTransformation;
2114
2115            concatMatrix = a.willChangeTransformationMatrix();
2116
2117            if (more) {
2118                if (!a.willChangeBounds()) {
2119                    if ((flags & (FLAG_OPTIMIZE_INVALIDATE | FLAG_ANIMATION_DONE)) ==
2120                            FLAG_OPTIMIZE_INVALIDATE) {
2121                        mGroupFlags |= FLAG_INVALIDATE_REQUIRED;
2122                    } else if ((flags & FLAG_INVALIDATE_REQUIRED) == 0) {
2123                        // The child need to draw an animation, potentially offscreen, so
2124                        // make sure we do not cancel invalidate requests
2125                        mPrivateFlags |= DRAW_ANIMATION;
2126                        invalidate(cl, ct, cr, cb);
2127                    }
2128                } else {
2129                    if (mInvalidateRegion == null) {
2130                        mInvalidateRegion = new RectF();
2131                    }
2132                    final RectF region = mInvalidateRegion;
2133                    a.getInvalidateRegion(0, 0, cr - cl, cb - ct, region, invalidationTransform);
2134
2135                    // The child need to draw an animation, potentially offscreen, so
2136                    // make sure we do not cancel invalidate requests
2137                    mPrivateFlags |= DRAW_ANIMATION;
2138
2139                    final int left = cl + (int) region.left;
2140                    final int top = ct + (int) region.top;
2141                    invalidate(left, top, left + (int) region.width(), top + (int) region.height());
2142                }
2143            }
2144        } else if ((flags & FLAG_SUPPORT_STATIC_TRANSFORMATIONS) ==
2145                FLAG_SUPPORT_STATIC_TRANSFORMATIONS) {
2146            final boolean hasTransform = getChildStaticTransformation(child, mChildTransformation);
2147            if (hasTransform) {
2148                final int transformType = mChildTransformation.getTransformationType();
2149                transformToApply = transformType != Transformation.TYPE_IDENTITY ?
2150                        mChildTransformation : null;
2151                concatMatrix = (transformType & Transformation.TYPE_MATRIX) != 0;
2152            }
2153        }
2154
2155        concatMatrix |= !child.hasIdentityMatrix();
2156
2157        // Sets the flag as early as possible to allow draw() implementations
2158        // to call invalidate() successfully when doing animations
2159        child.mPrivateFlags |= DRAWN;
2160
2161        if (!concatMatrix && canvas.quickReject(cl, ct, cr, cb, Canvas.EdgeType.BW) &&
2162                (child.mPrivateFlags & DRAW_ANIMATION) == 0) {
2163            return more;
2164        }
2165
2166        child.computeScroll();
2167
2168        final int sx = child.mScrollX;
2169        final int sy = child.mScrollY;
2170
2171        DisplayList displayList = null;
2172        Bitmap cache = null;
2173        if (caching) {
2174            if (!canvas.isHardwareAccelerated()) {
2175                cache = child.getDrawingCache(true);
2176            } else {
2177                displayList = child.getDisplayList();
2178            }
2179        }
2180
2181        final boolean hasDisplayList = displayList != null && displayList.isReady();
2182        final boolean hasNoCache = cache == null || hasDisplayList;
2183
2184        final int restoreTo = canvas.save();
2185        if (hasNoCache) {
2186            canvas.translate(cl - sx, ct - sy);
2187        } else {
2188            canvas.translate(cl, ct);
2189            if (scalingRequired) {
2190                // mAttachInfo cannot be null, otherwise scalingRequired == false
2191                final float scale = 1.0f / mAttachInfo.mApplicationScale;
2192                canvas.scale(scale, scale);
2193            }
2194        }
2195
2196        float alpha = child.getAlpha();
2197
2198        if (transformToApply != null || alpha < 1.0f || !child.hasIdentityMatrix()) {
2199            int transX = 0;
2200            int transY = 0;
2201
2202            if (hasNoCache) {
2203                transX = -sx;
2204                transY = -sy;
2205            }
2206
2207            if (transformToApply != null) {
2208                if (concatMatrix) {
2209                    // Undo the scroll translation, apply the transformation matrix,
2210                    // then redo the scroll translate to get the correct result.
2211                    canvas.translate(-transX, -transY);
2212                    canvas.concat(transformToApply.getMatrix());
2213                    canvas.translate(transX, transY);
2214                    mGroupFlags |= FLAG_CLEAR_TRANSFORMATION;
2215                }
2216
2217                float transformAlpha = transformToApply.getAlpha();
2218                if (transformAlpha < 1.0f) {
2219                    alpha *= transformToApply.getAlpha();
2220                    mGroupFlags |= FLAG_CLEAR_TRANSFORMATION;
2221                }
2222            }
2223
2224            if (!child.hasIdentityMatrix()) {
2225                canvas.translate(-transX, -transY);
2226                canvas.concat(child.getMatrix());
2227                canvas.translate(transX, transY);
2228            }
2229
2230            if (alpha < 1.0f) {
2231                mGroupFlags |= FLAG_CLEAR_TRANSFORMATION;
2232
2233                if (hasNoCache) {
2234                    final int multipliedAlpha = (int) (255 * alpha);
2235                    if (!child.onSetAlpha(multipliedAlpha)) {
2236                        int layerFlags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG;
2237                        if ((flags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN) {
2238                            layerFlags |= Canvas.CLIP_TO_LAYER_SAVE_FLAG;
2239                        }
2240                        canvas.saveLayerAlpha(sx, sy, sx + cr - cl, sy + cb - ct, multipliedAlpha,
2241                                layerFlags);
2242                    } else {
2243                        child.mPrivateFlags |= ALPHA_SET;
2244                    }
2245                }
2246            }
2247        } else if ((child.mPrivateFlags & ALPHA_SET) == ALPHA_SET) {
2248            child.onSetAlpha(255);
2249            child.mPrivateFlags &= ~ALPHA_SET;
2250        }
2251
2252        if ((flags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN) {
2253            if (hasNoCache) {
2254                canvas.clipRect(sx, sy, sx + (cr - cl), sy + (cb - ct));
2255            } else {
2256                if (!scalingRequired) {
2257                    canvas.clipRect(0, 0, cr - cl, cb - ct);
2258                } else {
2259                    canvas.clipRect(0, 0, cache.getWidth(), cache.getHeight());
2260                }
2261            }
2262        }
2263
2264        if (hasNoCache) {
2265            if (!hasDisplayList) {
2266                // Fast path for layouts with no backgrounds
2267                if ((child.mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
2268                    if (ViewDebug.TRACE_HIERARCHY) {
2269                        ViewDebug.trace(this, ViewDebug.HierarchyTraceType.DRAW);
2270                    }
2271                    child.mPrivateFlags &= ~DIRTY_MASK;
2272                    child.dispatchDraw(canvas);
2273                } else {
2274                    child.draw(canvas);
2275                }
2276            } else {
2277                ((HardwareCanvas) canvas).drawDisplayList(displayList);
2278            }
2279        } else if (cache != null) {
2280            final Paint cachePaint = mCachePaint;
2281            if (alpha < 1.0f) {
2282                cachePaint.setAlpha((int) (alpha * 255));
2283                mGroupFlags |= FLAG_ALPHA_LOWER_THAN_ONE;
2284            } else if  ((flags & FLAG_ALPHA_LOWER_THAN_ONE) == FLAG_ALPHA_LOWER_THAN_ONE) {
2285                cachePaint.setAlpha(255);
2286                mGroupFlags &= ~FLAG_ALPHA_LOWER_THAN_ONE;
2287            }
2288            canvas.drawBitmap(cache, 0.0f, 0.0f, cachePaint);
2289        }
2290
2291        canvas.restoreToCount(restoreTo);
2292
2293        if (a != null && !more) {
2294            child.onSetAlpha(255);
2295            finishAnimatingView(child, a);
2296        }
2297
2298        return more;
2299    }
2300
2301    /**
2302     * By default, children are clipped to their bounds before drawing. This
2303     * allows view groups to override this behavior for animations, etc.
2304     *
2305     * @param clipChildren true to clip children to their bounds,
2306     *        false otherwise
2307     * @attr ref android.R.styleable#ViewGroup_clipChildren
2308     */
2309    public void setClipChildren(boolean clipChildren) {
2310        setBooleanFlag(FLAG_CLIP_CHILDREN, clipChildren);
2311    }
2312
2313    /**
2314     * By default, children are clipped to the padding of the ViewGroup. This
2315     * allows view groups to override this behavior
2316     *
2317     * @param clipToPadding true to clip children to the padding of the
2318     *        group, false otherwise
2319     * @attr ref android.R.styleable#ViewGroup_clipToPadding
2320     */
2321    public void setClipToPadding(boolean clipToPadding) {
2322        setBooleanFlag(FLAG_CLIP_TO_PADDING, clipToPadding);
2323    }
2324
2325    /**
2326     * {@inheritDoc}
2327     */
2328    @Override
2329    public void dispatchSetSelected(boolean selected) {
2330        final View[] children = mChildren;
2331        final int count = mChildrenCount;
2332        for (int i = 0; i < count; i++) {
2333
2334            children[i].setSelected(selected);
2335        }
2336    }
2337
2338    /**
2339     * {@inheritDoc}
2340     */
2341    @Override
2342    public void dispatchSetActivated(boolean activated) {
2343        final View[] children = mChildren;
2344        final int count = mChildrenCount;
2345        for (int i = 0; i < count; i++) {
2346
2347            children[i].setActivated(activated);
2348        }
2349    }
2350
2351    @Override
2352    protected void dispatchSetPressed(boolean pressed) {
2353        final View[] children = mChildren;
2354        final int count = mChildrenCount;
2355        for (int i = 0; i < count; i++) {
2356            children[i].setPressed(pressed);
2357        }
2358    }
2359
2360    /**
2361     * When this property is set to true, this ViewGroup supports static transformations on
2362     * children; this causes
2363     * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} to be
2364     * invoked when a child is drawn.
2365     *
2366     * Any subclass overriding
2367     * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} should
2368     * set this property to true.
2369     *
2370     * @param enabled True to enable static transformations on children, false otherwise.
2371     *
2372     * @see #FLAG_SUPPORT_STATIC_TRANSFORMATIONS
2373     */
2374    protected void setStaticTransformationsEnabled(boolean enabled) {
2375        setBooleanFlag(FLAG_SUPPORT_STATIC_TRANSFORMATIONS, enabled);
2376    }
2377
2378    /**
2379     * {@inheritDoc}
2380     *
2381     * @see #setStaticTransformationsEnabled(boolean)
2382     */
2383    protected boolean getChildStaticTransformation(View child, Transformation t) {
2384        return false;
2385    }
2386
2387    /**
2388     * {@hide}
2389     */
2390    @Override
2391    protected View findViewTraversal(int id) {
2392        if (id == mID) {
2393            return this;
2394        }
2395
2396        final View[] where = mChildren;
2397        final int len = mChildrenCount;
2398
2399        for (int i = 0; i < len; i++) {
2400            View v = where[i];
2401
2402            if ((v.mPrivateFlags & IS_ROOT_NAMESPACE) == 0) {
2403                v = v.findViewById(id);
2404
2405                if (v != null) {
2406                    return v;
2407                }
2408            }
2409        }
2410
2411        return null;
2412    }
2413
2414    /**
2415     * {@hide}
2416     */
2417    @Override
2418    protected View findViewWithTagTraversal(Object tag) {
2419        if (tag != null && tag.equals(mTag)) {
2420            return this;
2421        }
2422
2423        final View[] where = mChildren;
2424        final int len = mChildrenCount;
2425
2426        for (int i = 0; i < len; i++) {
2427            View v = where[i];
2428
2429            if ((v.mPrivateFlags & IS_ROOT_NAMESPACE) == 0) {
2430                v = v.findViewWithTag(tag);
2431
2432                if (v != null) {
2433                    return v;
2434                }
2435            }
2436        }
2437
2438        return null;
2439    }
2440
2441    /**
2442     * Adds a child view. If no layout parameters are already set on the child, the
2443     * default parameters for this ViewGroup are set on the child.
2444     *
2445     * @param child the child view to add
2446     *
2447     * @see #generateDefaultLayoutParams()
2448     */
2449    public void addView(View child) {
2450        addView(child, -1);
2451    }
2452
2453    /**
2454     * Adds a child view. If no layout parameters are already set on the child, the
2455     * default parameters for this ViewGroup are set on the child.
2456     *
2457     * @param child the child view to add
2458     * @param index the position at which to add the child
2459     *
2460     * @see #generateDefaultLayoutParams()
2461     */
2462    public void addView(View child, int index) {
2463        LayoutParams params = child.getLayoutParams();
2464        if (params == null) {
2465            params = generateDefaultLayoutParams();
2466            if (params == null) {
2467                throw new IllegalArgumentException("generateDefaultLayoutParams() cannot return null");
2468            }
2469        }
2470        addView(child, index, params);
2471    }
2472
2473    /**
2474     * Adds a child view with this ViewGroup's default layout parameters and the
2475     * specified width and height.
2476     *
2477     * @param child the child view to add
2478     */
2479    public void addView(View child, int width, int height) {
2480        final LayoutParams params = generateDefaultLayoutParams();
2481        params.width = width;
2482        params.height = height;
2483        addView(child, -1, params);
2484    }
2485
2486    /**
2487     * Adds a child view with the specified layout parameters.
2488     *
2489     * @param child the child view to add
2490     * @param params the layout parameters to set on the child
2491     */
2492    public void addView(View child, LayoutParams params) {
2493        addView(child, -1, params);
2494    }
2495
2496    /**
2497     * Adds a child view with the specified layout parameters.
2498     *
2499     * @param child the child view to add
2500     * @param index the position at which to add the child
2501     * @param params the layout parameters to set on the child
2502     */
2503    public void addView(View child, int index, LayoutParams params) {
2504        if (DBG) {
2505            System.out.println(this + " addView");
2506        }
2507
2508        // addViewInner() will call child.requestLayout() when setting the new LayoutParams
2509        // therefore, we call requestLayout() on ourselves before, so that the child's request
2510        // will be blocked at our level
2511        requestLayout();
2512        invalidate();
2513        addViewInner(child, index, params, false);
2514    }
2515
2516    /**
2517     * {@inheritDoc}
2518     */
2519    public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
2520        if (!checkLayoutParams(params)) {
2521            throw new IllegalArgumentException("Invalid LayoutParams supplied to " + this);
2522        }
2523        if (view.mParent != this) {
2524            throw new IllegalArgumentException("Given view not a child of " + this);
2525        }
2526        view.setLayoutParams(params);
2527    }
2528
2529    /**
2530     * {@inheritDoc}
2531     */
2532    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
2533        return  p != null;
2534    }
2535
2536    /**
2537     * Interface definition for a callback to be invoked when the hierarchy
2538     * within this view changed. The hierarchy changes whenever a child is added
2539     * to or removed from this view.
2540     */
2541    public interface OnHierarchyChangeListener {
2542        /**
2543         * Called when a new child is added to a parent view.
2544         *
2545         * @param parent the view in which a child was added
2546         * @param child the new child view added in the hierarchy
2547         */
2548        void onChildViewAdded(View parent, View child);
2549
2550        /**
2551         * Called when a child is removed from a parent view.
2552         *
2553         * @param parent the view from which the child was removed
2554         * @param child the child removed from the hierarchy
2555         */
2556        void onChildViewRemoved(View parent, View child);
2557    }
2558
2559    /**
2560     * Register a callback to be invoked when a child is added to or removed
2561     * from this view.
2562     *
2563     * @param listener the callback to invoke on hierarchy change
2564     */
2565    public void setOnHierarchyChangeListener(OnHierarchyChangeListener listener) {
2566        mOnHierarchyChangeListener = listener;
2567    }
2568
2569    /**
2570     * Adds a view during layout. This is useful if in your onLayout() method,
2571     * you need to add more views (as does the list view for example).
2572     *
2573     * If index is negative, it means put it at the end of the list.
2574     *
2575     * @param child the view to add to the group
2576     * @param index the index at which the child must be added
2577     * @param params the layout parameters to associate with the child
2578     * @return true if the child was added, false otherwise
2579     */
2580    protected boolean addViewInLayout(View child, int index, LayoutParams params) {
2581        return addViewInLayout(child, index, params, false);
2582    }
2583
2584    /**
2585     * Adds a view during layout. This is useful if in your onLayout() method,
2586     * you need to add more views (as does the list view for example).
2587     *
2588     * If index is negative, it means put it at the end of the list.
2589     *
2590     * @param child the view to add to the group
2591     * @param index the index at which the child must be added
2592     * @param params the layout parameters to associate with the child
2593     * @param preventRequestLayout if true, calling this method will not trigger a
2594     *        layout request on child
2595     * @return true if the child was added, false otherwise
2596     */
2597    protected boolean addViewInLayout(View child, int index, LayoutParams params,
2598            boolean preventRequestLayout) {
2599        child.mParent = null;
2600        addViewInner(child, index, params, preventRequestLayout);
2601        child.mPrivateFlags = (child.mPrivateFlags & ~DIRTY_MASK) | DRAWN;
2602        return true;
2603    }
2604
2605    /**
2606     * Prevents the specified child to be laid out during the next layout pass.
2607     *
2608     * @param child the child on which to perform the cleanup
2609     */
2610    protected void cleanupLayoutState(View child) {
2611        child.mPrivateFlags &= ~View.FORCE_LAYOUT;
2612    }
2613
2614    private void addViewInner(View child, int index, LayoutParams params,
2615            boolean preventRequestLayout) {
2616
2617        if (child.getParent() != null) {
2618            throw new IllegalStateException("The specified child already has a parent. " +
2619                    "You must call removeView() on the child's parent first.");
2620        }
2621
2622        if (mTransition != null) {
2623            mTransition.addChild(this, child);
2624        }
2625
2626        if (!checkLayoutParams(params)) {
2627            params = generateLayoutParams(params);
2628        }
2629
2630        if (preventRequestLayout) {
2631            child.mLayoutParams = params;
2632        } else {
2633            child.setLayoutParams(params);
2634        }
2635
2636        if (index < 0) {
2637            index = mChildrenCount;
2638        }
2639
2640        addInArray(child, index);
2641
2642        // tell our children
2643        if (preventRequestLayout) {
2644            child.assignParent(this);
2645        } else {
2646            child.mParent = this;
2647        }
2648
2649        if (child.hasFocus()) {
2650            requestChildFocus(child, child.findFocus());
2651        }
2652
2653        AttachInfo ai = mAttachInfo;
2654        if (ai != null) {
2655            boolean lastKeepOn = ai.mKeepScreenOn;
2656            ai.mKeepScreenOn = false;
2657            child.dispatchAttachedToWindow(mAttachInfo, (mViewFlags&VISIBILITY_MASK));
2658            if (ai.mKeepScreenOn) {
2659                needGlobalAttributesUpdate(true);
2660            }
2661            ai.mKeepScreenOn = lastKeepOn;
2662        }
2663
2664        if (mOnHierarchyChangeListener != null) {
2665            mOnHierarchyChangeListener.onChildViewAdded(this, child);
2666        }
2667
2668        if ((child.mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE) {
2669            mGroupFlags |= FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE;
2670        }
2671    }
2672
2673    private void addInArray(View child, int index) {
2674        View[] children = mChildren;
2675        final int count = mChildrenCount;
2676        final int size = children.length;
2677        if (index == count) {
2678            if (size == count) {
2679                mChildren = new View[size + ARRAY_CAPACITY_INCREMENT];
2680                System.arraycopy(children, 0, mChildren, 0, size);
2681                children = mChildren;
2682            }
2683            children[mChildrenCount++] = child;
2684        } else if (index < count) {
2685            if (size == count) {
2686                mChildren = new View[size + ARRAY_CAPACITY_INCREMENT];
2687                System.arraycopy(children, 0, mChildren, 0, index);
2688                System.arraycopy(children, index, mChildren, index + 1, count - index);
2689                children = mChildren;
2690            } else {
2691                System.arraycopy(children, index, children, index + 1, count - index);
2692            }
2693            children[index] = child;
2694            mChildrenCount++;
2695        } else {
2696            throw new IndexOutOfBoundsException("index=" + index + " count=" + count);
2697        }
2698    }
2699
2700    // This method also sets the child's mParent to null
2701    private void removeFromArray(int index) {
2702        final View[] children = mChildren;
2703        if (!(mTransitioningViews != null && mTransitioningViews.contains(children[index]))) {
2704            children[index].mParent = null;
2705        }
2706        final int count = mChildrenCount;
2707        if (index == count - 1) {
2708            children[--mChildrenCount] = null;
2709        } else if (index >= 0 && index < count) {
2710            System.arraycopy(children, index + 1, children, index, count - index - 1);
2711            children[--mChildrenCount] = null;
2712        } else {
2713            throw new IndexOutOfBoundsException();
2714        }
2715    }
2716
2717    // This method also sets the children's mParent to null
2718    private void removeFromArray(int start, int count) {
2719        final View[] children = mChildren;
2720        final int childrenCount = mChildrenCount;
2721
2722        start = Math.max(0, start);
2723        final int end = Math.min(childrenCount, start + count);
2724
2725        if (start == end) {
2726            return;
2727        }
2728
2729        if (end == childrenCount) {
2730            for (int i = start; i < end; i++) {
2731                children[i].mParent = null;
2732                children[i] = null;
2733            }
2734        } else {
2735            for (int i = start; i < end; i++) {
2736                children[i].mParent = null;
2737            }
2738
2739            // Since we're looping above, we might as well do the copy, but is arraycopy()
2740            // faster than the extra 2 bounds checks we would do in the loop?
2741            System.arraycopy(children, end, children, start, childrenCount - end);
2742
2743            for (int i = childrenCount - (end - start); i < childrenCount; i++) {
2744                children[i] = null;
2745            }
2746        }
2747
2748        mChildrenCount -= (end - start);
2749    }
2750
2751    private void bindLayoutAnimation(View child) {
2752        Animation a = mLayoutAnimationController.getAnimationForView(child);
2753        child.setAnimation(a);
2754    }
2755
2756    /**
2757     * Subclasses should override this method to set layout animation
2758     * parameters on the supplied child.
2759     *
2760     * @param child the child to associate with animation parameters
2761     * @param params the child's layout parameters which hold the animation
2762     *        parameters
2763     * @param index the index of the child in the view group
2764     * @param count the number of children in the view group
2765     */
2766    protected void attachLayoutAnimationParameters(View child,
2767            LayoutParams params, int index, int count) {
2768        LayoutAnimationController.AnimationParameters animationParams =
2769                    params.layoutAnimationParameters;
2770        if (animationParams == null) {
2771            animationParams = new LayoutAnimationController.AnimationParameters();
2772            params.layoutAnimationParameters = animationParams;
2773        }
2774
2775        animationParams.count = count;
2776        animationParams.index = index;
2777    }
2778
2779    /**
2780     * {@inheritDoc}
2781     */
2782    public void removeView(View view) {
2783        removeViewInternal(view);
2784        requestLayout();
2785        invalidate();
2786    }
2787
2788    /**
2789     * Removes a view during layout. This is useful if in your onLayout() method,
2790     * you need to remove more views.
2791     *
2792     * @param view the view to remove from the group
2793     */
2794    public void removeViewInLayout(View view) {
2795        removeViewInternal(view);
2796    }
2797
2798    /**
2799     * Removes a range of views during layout. This is useful if in your onLayout() method,
2800     * you need to remove more views.
2801     *
2802     * @param start the index of the first view to remove from the group
2803     * @param count the number of views to remove from the group
2804     */
2805    public void removeViewsInLayout(int start, int count) {
2806        removeViewsInternal(start, count);
2807    }
2808
2809    /**
2810     * Removes the view at the specified position in the group.
2811     *
2812     * @param index the position in the group of the view to remove
2813     */
2814    public void removeViewAt(int index) {
2815        removeViewInternal(index, getChildAt(index));
2816        requestLayout();
2817        invalidate();
2818    }
2819
2820    /**
2821     * Removes the specified range of views from the group.
2822     *
2823     * @param start the first position in the group of the range of views to remove
2824     * @param count the number of views to remove
2825     */
2826    public void removeViews(int start, int count) {
2827        removeViewsInternal(start, count);
2828        requestLayout();
2829        invalidate();
2830    }
2831
2832    private void removeViewInternal(View view) {
2833        final int index = indexOfChild(view);
2834        if (index >= 0) {
2835            removeViewInternal(index, view);
2836        }
2837    }
2838
2839    private void removeViewInternal(int index, View view) {
2840
2841        if (mTransition != null) {
2842            mTransition.removeChild(this, view);
2843        }
2844
2845        boolean clearChildFocus = false;
2846        if (view == mFocused) {
2847            view.clearFocusForRemoval();
2848            clearChildFocus = true;
2849        }
2850
2851        if (view.getAnimation() != null ||
2852                (mTransitioningViews != null && mTransitioningViews.contains(view))) {
2853            addDisappearingView(view);
2854        } else if (view.mAttachInfo != null) {
2855           view.dispatchDetachedFromWindow();
2856        }
2857
2858        if (mOnHierarchyChangeListener != null) {
2859            mOnHierarchyChangeListener.onChildViewRemoved(this, view);
2860        }
2861
2862        needGlobalAttributesUpdate(false);
2863
2864        removeFromArray(index);
2865
2866        if (clearChildFocus) {
2867            clearChildFocus(view);
2868        }
2869    }
2870
2871    /**
2872     * Sets the LayoutTransition object for this ViewGroup. If the LayoutTransition object is
2873     * not null, changes in layout which occur because of children being added to or removed from
2874     * the ViewGroup will be animated according to the animations defined in that LayoutTransition
2875     * object. By default, the transition object is null (so layout changes are not animated).
2876     *
2877     * @param transition The LayoutTransition object that will animated changes in layout. A value
2878     * of <code>null</code> means no transition will run on layout changes.
2879     * @attr ref android.R.styleable#ViewGroup_animateLayoutChanges
2880     */
2881    public void setLayoutTransition(LayoutTransition transition) {
2882        if (mTransition != null) {
2883            mTransition.removeTransitionListener(mLayoutTransitionListener);
2884        }
2885        mTransition = transition;
2886        if (mTransition != null) {
2887            mTransition.addTransitionListener(mLayoutTransitionListener);
2888        }
2889    }
2890
2891    /**
2892     * Gets the LayoutTransition object for this ViewGroup. If the LayoutTransition object is
2893     * not null, changes in layout which occur because of children being added to or removed from
2894     * the ViewGroup will be animated according to the animations defined in that LayoutTransition
2895     * object. By default, the transition object is null (so layout changes are not animated).
2896     *
2897     * @return LayoutTranstion The LayoutTransition object that will animated changes in layout.
2898     * A value of <code>null</code> means no transition will run on layout changes.
2899     */
2900    public LayoutTransition getLayoutTransition() {
2901        return mTransition;
2902    }
2903
2904    private void removeViewsInternal(int start, int count) {
2905        final OnHierarchyChangeListener onHierarchyChangeListener = mOnHierarchyChangeListener;
2906        final boolean notifyListener = onHierarchyChangeListener != null;
2907        final View focused = mFocused;
2908        final boolean detach = mAttachInfo != null;
2909        View clearChildFocus = null;
2910
2911        final View[] children = mChildren;
2912        final int end = start + count;
2913
2914        for (int i = start; i < end; i++) {
2915            final View view = children[i];
2916
2917            if (mTransition != null) {
2918                mTransition.removeChild(this, view);
2919            }
2920
2921            if (view == focused) {
2922                view.clearFocusForRemoval();
2923                clearChildFocus = view;
2924            }
2925
2926            if (view.getAnimation() != null ||
2927                (mTransitioningViews != null && mTransitioningViews.contains(view))) {
2928                addDisappearingView(view);
2929            } else if (detach) {
2930               view.dispatchDetachedFromWindow();
2931            }
2932
2933            needGlobalAttributesUpdate(false);
2934
2935            if (notifyListener) {
2936                onHierarchyChangeListener.onChildViewRemoved(this, view);
2937            }
2938        }
2939
2940        removeFromArray(start, count);
2941
2942        if (clearChildFocus != null) {
2943            clearChildFocus(clearChildFocus);
2944        }
2945    }
2946
2947    /**
2948     * Call this method to remove all child views from the
2949     * ViewGroup.
2950     */
2951    public void removeAllViews() {
2952        removeAllViewsInLayout();
2953        requestLayout();
2954        invalidate();
2955    }
2956
2957    /**
2958     * Called by a ViewGroup subclass to remove child views from itself,
2959     * when it must first know its size on screen before it can calculate how many
2960     * child views it will render. An example is a Gallery or a ListView, which
2961     * may "have" 50 children, but actually only render the number of children
2962     * that can currently fit inside the object on screen. Do not call
2963     * this method unless you are extending ViewGroup and understand the
2964     * view measuring and layout pipeline.
2965     */
2966    public void removeAllViewsInLayout() {
2967        final int count = mChildrenCount;
2968        if (count <= 0) {
2969            return;
2970        }
2971
2972        final View[] children = mChildren;
2973        mChildrenCount = 0;
2974
2975        final OnHierarchyChangeListener listener = mOnHierarchyChangeListener;
2976        final boolean notify = listener != null;
2977        final View focused = mFocused;
2978        final boolean detach = mAttachInfo != null;
2979        View clearChildFocus = null;
2980
2981        needGlobalAttributesUpdate(false);
2982
2983        for (int i = count - 1; i >= 0; i--) {
2984            final View view = children[i];
2985
2986            if (mTransition != null) {
2987                mTransition.removeChild(this, view);
2988            }
2989
2990            if (view == focused) {
2991                view.clearFocusForRemoval();
2992                clearChildFocus = view;
2993            }
2994
2995            if (view.getAnimation() != null ||
2996                    (mTransitioningViews != null && mTransitioningViews.contains(view))) {
2997                addDisappearingView(view);
2998            } else if (detach) {
2999               view.dispatchDetachedFromWindow();
3000            }
3001
3002            if (notify) {
3003                listener.onChildViewRemoved(this, view);
3004            }
3005
3006            view.mParent = null;
3007            children[i] = null;
3008        }
3009
3010        if (clearChildFocus != null) {
3011            clearChildFocus(clearChildFocus);
3012        }
3013    }
3014
3015    /**
3016     * Finishes the removal of a detached view. This method will dispatch the detached from
3017     * window event and notify the hierarchy change listener.
3018     *
3019     * @param child the child to be definitely removed from the view hierarchy
3020     * @param animate if true and the view has an animation, the view is placed in the
3021     *                disappearing views list, otherwise, it is detached from the window
3022     *
3023     * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
3024     * @see #detachAllViewsFromParent()
3025     * @see #detachViewFromParent(View)
3026     * @see #detachViewFromParent(int)
3027     */
3028    protected void removeDetachedView(View child, boolean animate) {
3029        if (mTransition != null) {
3030            mTransition.removeChild(this, child);
3031        }
3032
3033        if (child == mFocused) {
3034            child.clearFocus();
3035        }
3036
3037        if ((animate && child.getAnimation() != null) ||
3038                (mTransitioningViews != null && mTransitioningViews.contains(child))) {
3039            addDisappearingView(child);
3040        } else if (child.mAttachInfo != null) {
3041            child.dispatchDetachedFromWindow();
3042        }
3043
3044        if (mOnHierarchyChangeListener != null) {
3045            mOnHierarchyChangeListener.onChildViewRemoved(this, child);
3046        }
3047    }
3048
3049    /**
3050     * Attaches a view to this view group. Attaching a view assigns this group as the parent,
3051     * sets the layout parameters and puts the view in the list of children so it can be retrieved
3052     * by calling {@link #getChildAt(int)}.
3053     *
3054     * This method should be called only for view which were detached from their parent.
3055     *
3056     * @param child the child to attach
3057     * @param index the index at which the child should be attached
3058     * @param params the layout parameters of the child
3059     *
3060     * @see #removeDetachedView(View, boolean)
3061     * @see #detachAllViewsFromParent()
3062     * @see #detachViewFromParent(View)
3063     * @see #detachViewFromParent(int)
3064     */
3065    protected void attachViewToParent(View child, int index, LayoutParams params) {
3066        child.mLayoutParams = params;
3067
3068        if (index < 0) {
3069            index = mChildrenCount;
3070        }
3071
3072        addInArray(child, index);
3073
3074        child.mParent = this;
3075        child.mPrivateFlags = (child.mPrivateFlags & ~DIRTY_MASK & ~DRAWING_CACHE_VALID) | DRAWN;
3076
3077        if (child.hasFocus()) {
3078            requestChildFocus(child, child.findFocus());
3079        }
3080    }
3081
3082    /**
3083     * Detaches a view from its parent. Detaching a view should be temporary and followed
3084     * either by a call to {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
3085     * or a call to {@link #removeDetachedView(View, boolean)}. When a view is detached,
3086     * its parent is null and cannot be retrieved by a call to {@link #getChildAt(int)}.
3087     *
3088     * @param child the child to detach
3089     *
3090     * @see #detachViewFromParent(int)
3091     * @see #detachViewsFromParent(int, int)
3092     * @see #detachAllViewsFromParent()
3093     * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
3094     * @see #removeDetachedView(View, boolean)
3095     */
3096    protected void detachViewFromParent(View child) {
3097        removeFromArray(indexOfChild(child));
3098    }
3099
3100    /**
3101     * Detaches a view from its parent. Detaching a view should be temporary and followed
3102     * either by a call to {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
3103     * or a call to {@link #removeDetachedView(View, boolean)}. When a view is detached,
3104     * its parent is null and cannot be retrieved by a call to {@link #getChildAt(int)}.
3105     *
3106     * @param index the index of the child to detach
3107     *
3108     * @see #detachViewFromParent(View)
3109     * @see #detachAllViewsFromParent()
3110     * @see #detachViewsFromParent(int, int)
3111     * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
3112     * @see #removeDetachedView(View, boolean)
3113     */
3114    protected void detachViewFromParent(int index) {
3115        removeFromArray(index);
3116    }
3117
3118    /**
3119     * Detaches a range of view from their parent. Detaching a view should be temporary and followed
3120     * either by a call to {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
3121     * or a call to {@link #removeDetachedView(View, boolean)}. When a view is detached, its
3122     * parent is null and cannot be retrieved by a call to {@link #getChildAt(int)}.
3123     *
3124     * @param start the first index of the childrend range to detach
3125     * @param count the number of children to detach
3126     *
3127     * @see #detachViewFromParent(View)
3128     * @see #detachViewFromParent(int)
3129     * @see #detachAllViewsFromParent()
3130     * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
3131     * @see #removeDetachedView(View, boolean)
3132     */
3133    protected void detachViewsFromParent(int start, int count) {
3134        removeFromArray(start, count);
3135    }
3136
3137    /**
3138     * Detaches all views from the parent. Detaching a view should be temporary and followed
3139     * either by a call to {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
3140     * or a call to {@link #removeDetachedView(View, boolean)}. When a view is detached,
3141     * its parent is null and cannot be retrieved by a call to {@link #getChildAt(int)}.
3142     *
3143     * @see #detachViewFromParent(View)
3144     * @see #detachViewFromParent(int)
3145     * @see #detachViewsFromParent(int, int)
3146     * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
3147     * @see #removeDetachedView(View, boolean)
3148     */
3149    protected void detachAllViewsFromParent() {
3150        final int count = mChildrenCount;
3151        if (count <= 0) {
3152            return;
3153        }
3154
3155        final View[] children = mChildren;
3156        mChildrenCount = 0;
3157
3158        for (int i = count - 1; i >= 0; i--) {
3159            children[i].mParent = null;
3160            children[i] = null;
3161        }
3162    }
3163
3164    /**
3165     * Don't call or override this method. It is used for the implementation of
3166     * the view hierarchy.
3167     */
3168    public final void invalidateChild(View child, final Rect dirty) {
3169        if (ViewDebug.TRACE_HIERARCHY) {
3170            ViewDebug.trace(this, ViewDebug.HierarchyTraceType.INVALIDATE_CHILD);
3171        }
3172
3173        ViewParent parent = this;
3174
3175        final AttachInfo attachInfo = mAttachInfo;
3176        if (attachInfo != null) {
3177            final int[] location = attachInfo.mInvalidateChildLocation;
3178            location[CHILD_LEFT_INDEX] = child.mLeft;
3179            location[CHILD_TOP_INDEX] = child.mTop;
3180            Matrix childMatrix = child.getMatrix();
3181            if (!childMatrix.isIdentity()) {
3182                RectF boundingRect = attachInfo.mTmpTransformRect;
3183                boundingRect.set(dirty);
3184                childMatrix.mapRect(boundingRect);
3185                dirty.set((int) boundingRect.left, (int) boundingRect.top,
3186                        (int) (boundingRect.right + 0.5f),
3187                        (int) (boundingRect.bottom + 0.5f));
3188            }
3189
3190            // If the child is drawing an animation, we want to copy this flag onto
3191            // ourselves and the parent to make sure the invalidate request goes
3192            // through
3193            final boolean drawAnimation = (child.mPrivateFlags & DRAW_ANIMATION) == DRAW_ANIMATION;
3194
3195            // Check whether the child that requests the invalidate is fully opaque
3196            final boolean isOpaque = child.isOpaque() && !drawAnimation &&
3197                    child.getAnimation() != null;
3198            // Mark the child as dirty, using the appropriate flag
3199            // Make sure we do not set both flags at the same time
3200            final int opaqueFlag = isOpaque ? DIRTY_OPAQUE : DIRTY;
3201
3202            do {
3203                View view = null;
3204                if (parent instanceof View) {
3205                    view = (View) parent;
3206                }
3207
3208                if (drawAnimation) {
3209                    if (view != null) {
3210                        view.mPrivateFlags |= DRAW_ANIMATION;
3211                    } else if (parent instanceof ViewRoot) {
3212                        ((ViewRoot) parent).mIsAnimating = true;
3213                    }
3214                }
3215
3216                // If the parent is dirty opaque or not dirty, mark it dirty with the opaque
3217                // flag coming from the child that initiated the invalidate
3218                if (view != null && (view.mPrivateFlags & DIRTY_MASK) != DIRTY) {
3219                    view.mPrivateFlags = (view.mPrivateFlags & ~DIRTY_MASK) | opaqueFlag;
3220                }
3221
3222                parent = parent.invalidateChildInParent(location, dirty);
3223                if (view != null) {
3224                    // Account for transform on current parent
3225                    Matrix m = view.getMatrix();
3226                    if (!m.isIdentity()) {
3227                        RectF boundingRect = attachInfo.mTmpTransformRect;
3228                        boundingRect.set(dirty);
3229                        m.mapRect(boundingRect);
3230                        dirty.set((int) boundingRect.left, (int) boundingRect.top,
3231                                (int) (boundingRect.right + 0.5f),
3232                                (int) (boundingRect.bottom + 0.5f));
3233                    }
3234                }
3235            } while (parent != null);
3236        }
3237    }
3238
3239    /**
3240     * Don't call or override this method. It is used for the implementation of
3241     * the view hierarchy.
3242     *
3243     * This implementation returns null if this ViewGroup does not have a parent,
3244     * if this ViewGroup is already fully invalidated or if the dirty rectangle
3245     * does not intersect with this ViewGroup's bounds.
3246     */
3247    public ViewParent invalidateChildInParent(final int[] location, final Rect dirty) {
3248        if (ViewDebug.TRACE_HIERARCHY) {
3249            ViewDebug.trace(this, ViewDebug.HierarchyTraceType.INVALIDATE_CHILD_IN_PARENT);
3250        }
3251
3252        if ((mPrivateFlags & DRAWN) == DRAWN) {
3253            if ((mGroupFlags & (FLAG_OPTIMIZE_INVALIDATE | FLAG_ANIMATION_DONE)) !=
3254                        FLAG_OPTIMIZE_INVALIDATE) {
3255                dirty.offset(location[CHILD_LEFT_INDEX] - mScrollX,
3256                        location[CHILD_TOP_INDEX] - mScrollY);
3257
3258                final int left = mLeft;
3259                final int top = mTop;
3260
3261                if (dirty.intersect(0, 0, mRight - left, mBottom - top) ||
3262                        (mPrivateFlags & DRAW_ANIMATION) == DRAW_ANIMATION) {
3263                    mPrivateFlags &= ~DRAWING_CACHE_VALID;
3264
3265                    location[CHILD_LEFT_INDEX] = left;
3266                    location[CHILD_TOP_INDEX] = top;
3267
3268                    return mParent;
3269                }
3270            } else {
3271                mPrivateFlags &= ~DRAWN & ~DRAWING_CACHE_VALID;
3272
3273                location[CHILD_LEFT_INDEX] = mLeft;
3274                location[CHILD_TOP_INDEX] = mTop;
3275
3276                dirty.set(0, 0, mRight - location[CHILD_LEFT_INDEX],
3277                        mBottom - location[CHILD_TOP_INDEX]);
3278
3279                return mParent;
3280            }
3281        }
3282
3283        return null;
3284    }
3285
3286    /**
3287     * Offset a rectangle that is in a descendant's coordinate
3288     * space into our coordinate space.
3289     * @param descendant A descendant of this view
3290     * @param rect A rectangle defined in descendant's coordinate space.
3291     */
3292    public final void offsetDescendantRectToMyCoords(View descendant, Rect rect) {
3293        offsetRectBetweenParentAndChild(descendant, rect, true, false);
3294    }
3295
3296    /**
3297     * Offset a rectangle that is in our coordinate space into an ancestor's
3298     * coordinate space.
3299     * @param descendant A descendant of this view
3300     * @param rect A rectangle defined in descendant's coordinate space.
3301     */
3302    public final void offsetRectIntoDescendantCoords(View descendant, Rect rect) {
3303        offsetRectBetweenParentAndChild(descendant, rect, false, false);
3304    }
3305
3306    /**
3307     * Helper method that offsets a rect either from parent to descendant or
3308     * descendant to parent.
3309     */
3310    void offsetRectBetweenParentAndChild(View descendant, Rect rect,
3311            boolean offsetFromChildToParent, boolean clipToBounds) {
3312
3313        // already in the same coord system :)
3314        if (descendant == this) {
3315            return;
3316        }
3317
3318        ViewParent theParent = descendant.mParent;
3319
3320        // search and offset up to the parent
3321        while ((theParent != null)
3322                && (theParent instanceof View)
3323                && (theParent != this)) {
3324
3325            if (offsetFromChildToParent) {
3326                rect.offset(descendant.mLeft - descendant.mScrollX,
3327                        descendant.mTop - descendant.mScrollY);
3328                if (clipToBounds) {
3329                    View p = (View) theParent;
3330                    rect.intersect(0, 0, p.mRight - p.mLeft, p.mBottom - p.mTop);
3331                }
3332            } else {
3333                if (clipToBounds) {
3334                    View p = (View) theParent;
3335                    rect.intersect(0, 0, p.mRight - p.mLeft, p.mBottom - p.mTop);
3336                }
3337                rect.offset(descendant.mScrollX - descendant.mLeft,
3338                        descendant.mScrollY - descendant.mTop);
3339            }
3340
3341            descendant = (View) theParent;
3342            theParent = descendant.mParent;
3343        }
3344
3345        // now that we are up to this view, need to offset one more time
3346        // to get into our coordinate space
3347        if (theParent == this) {
3348            if (offsetFromChildToParent) {
3349                rect.offset(descendant.mLeft - descendant.mScrollX,
3350                        descendant.mTop - descendant.mScrollY);
3351            } else {
3352                rect.offset(descendant.mScrollX - descendant.mLeft,
3353                        descendant.mScrollY - descendant.mTop);
3354            }
3355        } else {
3356            throw new IllegalArgumentException("parameter must be a descendant of this view");
3357        }
3358    }
3359
3360    /**
3361     * Offset the vertical location of all children of this view by the specified number of pixels.
3362     *
3363     * @param offset the number of pixels to offset
3364     *
3365     * @hide
3366     */
3367    public void offsetChildrenTopAndBottom(int offset) {
3368        final int count = mChildrenCount;
3369        final View[] children = mChildren;
3370
3371        for (int i = 0; i < count; i++) {
3372            final View v = children[i];
3373            v.mTop += offset;
3374            v.mBottom += offset;
3375        }
3376    }
3377
3378    /**
3379     * {@inheritDoc}
3380     */
3381    public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) {
3382        int dx = child.mLeft - mScrollX;
3383        int dy = child.mTop - mScrollY;
3384        if (offset != null) {
3385            offset.x += dx;
3386            offset.y += dy;
3387        }
3388        r.offset(dx, dy);
3389        return r.intersect(0, 0, mRight - mLeft, mBottom - mTop) &&
3390               (mParent == null || mParent.getChildVisibleRect(this, r, offset));
3391    }
3392
3393    /**
3394     * {@inheritDoc}
3395     */
3396    @Override
3397    protected abstract void onLayout(boolean changed,
3398            int l, int t, int r, int b);
3399
3400    /**
3401     * Indicates whether the view group has the ability to animate its children
3402     * after the first layout.
3403     *
3404     * @return true if the children can be animated, false otherwise
3405     */
3406    protected boolean canAnimate() {
3407        return mLayoutAnimationController != null;
3408    }
3409
3410    /**
3411     * Runs the layout animation. Calling this method triggers a relayout of
3412     * this view group.
3413     */
3414    public void startLayoutAnimation() {
3415        if (mLayoutAnimationController != null) {
3416            mGroupFlags |= FLAG_RUN_ANIMATION;
3417            requestLayout();
3418        }
3419    }
3420
3421    /**
3422     * Schedules the layout animation to be played after the next layout pass
3423     * of this view group. This can be used to restart the layout animation
3424     * when the content of the view group changes or when the activity is
3425     * paused and resumed.
3426     */
3427    public void scheduleLayoutAnimation() {
3428        mGroupFlags |= FLAG_RUN_ANIMATION;
3429    }
3430
3431    /**
3432     * Sets the layout animation controller used to animate the group's
3433     * children after the first layout.
3434     *
3435     * @param controller the animation controller
3436     */
3437    public void setLayoutAnimation(LayoutAnimationController controller) {
3438        mLayoutAnimationController = controller;
3439        if (mLayoutAnimationController != null) {
3440            mGroupFlags |= FLAG_RUN_ANIMATION;
3441        }
3442    }
3443
3444    /**
3445     * Returns the layout animation controller used to animate the group's
3446     * children.
3447     *
3448     * @return the current animation controller
3449     */
3450    public LayoutAnimationController getLayoutAnimation() {
3451        return mLayoutAnimationController;
3452    }
3453
3454    /**
3455     * Indicates whether the children's drawing cache is used during a layout
3456     * animation. By default, the drawing cache is enabled but this will prevent
3457     * nested layout animations from working. To nest animations, you must disable
3458     * the cache.
3459     *
3460     * @return true if the animation cache is enabled, false otherwise
3461     *
3462     * @see #setAnimationCacheEnabled(boolean)
3463     * @see View#setDrawingCacheEnabled(boolean)
3464     */
3465    @ViewDebug.ExportedProperty
3466    public boolean isAnimationCacheEnabled() {
3467        return (mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE;
3468    }
3469
3470    /**
3471     * Enables or disables the children's drawing cache during a layout animation.
3472     * By default, the drawing cache is enabled but this will prevent nested
3473     * layout animations from working. To nest animations, you must disable the
3474     * cache.
3475     *
3476     * @param enabled true to enable the animation cache, false otherwise
3477     *
3478     * @see #isAnimationCacheEnabled()
3479     * @see View#setDrawingCacheEnabled(boolean)
3480     */
3481    public void setAnimationCacheEnabled(boolean enabled) {
3482        setBooleanFlag(FLAG_ANIMATION_CACHE, enabled);
3483    }
3484
3485    /**
3486     * Indicates whether this ViewGroup will always try to draw its children using their
3487     * drawing cache. By default this property is enabled.
3488     *
3489     * @return true if the animation cache is enabled, false otherwise
3490     *
3491     * @see #setAlwaysDrawnWithCacheEnabled(boolean)
3492     * @see #setChildrenDrawnWithCacheEnabled(boolean)
3493     * @see View#setDrawingCacheEnabled(boolean)
3494     */
3495    @ViewDebug.ExportedProperty(category = "drawing")
3496    public boolean isAlwaysDrawnWithCacheEnabled() {
3497        return (mGroupFlags & FLAG_ALWAYS_DRAWN_WITH_CACHE) == FLAG_ALWAYS_DRAWN_WITH_CACHE;
3498    }
3499
3500    /**
3501     * Indicates whether this ViewGroup will always try to draw its children using their
3502     * drawing cache. This property can be set to true when the cache rendering is
3503     * slightly different from the children's normal rendering. Renderings can be different,
3504     * for instance, when the cache's quality is set to low.
3505     *
3506     * When this property is disabled, the ViewGroup will use the drawing cache of its
3507     * children only when asked to. It's usually the task of subclasses to tell ViewGroup
3508     * when to start using the drawing cache and when to stop using it.
3509     *
3510     * @param always true to always draw with the drawing cache, false otherwise
3511     *
3512     * @see #isAlwaysDrawnWithCacheEnabled()
3513     * @see #setChildrenDrawnWithCacheEnabled(boolean)
3514     * @see View#setDrawingCacheEnabled(boolean)
3515     * @see View#setDrawingCacheQuality(int)
3516     */
3517    public void setAlwaysDrawnWithCacheEnabled(boolean always) {
3518        setBooleanFlag(FLAG_ALWAYS_DRAWN_WITH_CACHE, always);
3519    }
3520
3521    /**
3522     * Indicates whether the ViewGroup is currently drawing its children using
3523     * their drawing cache.
3524     *
3525     * @return true if children should be drawn with their cache, false otherwise
3526     *
3527     * @see #setAlwaysDrawnWithCacheEnabled(boolean)
3528     * @see #setChildrenDrawnWithCacheEnabled(boolean)
3529     */
3530    @ViewDebug.ExportedProperty(category = "drawing")
3531    protected boolean isChildrenDrawnWithCacheEnabled() {
3532        return (mGroupFlags & FLAG_CHILDREN_DRAWN_WITH_CACHE) == FLAG_CHILDREN_DRAWN_WITH_CACHE;
3533    }
3534
3535    /**
3536     * Tells the ViewGroup to draw its children using their drawing cache. This property
3537     * is ignored when {@link #isAlwaysDrawnWithCacheEnabled()} is true. A child's drawing cache
3538     * will be used only if it has been enabled.
3539     *
3540     * Subclasses should call this method to start and stop using the drawing cache when
3541     * they perform performance sensitive operations, like scrolling or animating.
3542     *
3543     * @param enabled true if children should be drawn with their cache, false otherwise
3544     *
3545     * @see #setAlwaysDrawnWithCacheEnabled(boolean)
3546     * @see #isChildrenDrawnWithCacheEnabled()
3547     */
3548    protected void setChildrenDrawnWithCacheEnabled(boolean enabled) {
3549        setBooleanFlag(FLAG_CHILDREN_DRAWN_WITH_CACHE, enabled);
3550    }
3551
3552    /**
3553     * Indicates whether the ViewGroup is drawing its children in the order defined by
3554     * {@link #getChildDrawingOrder(int, int)}.
3555     *
3556     * @return true if children drawing order is defined by {@link #getChildDrawingOrder(int, int)},
3557     *         false otherwise
3558     *
3559     * @see #setChildrenDrawingOrderEnabled(boolean)
3560     * @see #getChildDrawingOrder(int, int)
3561     */
3562    @ViewDebug.ExportedProperty(category = "drawing")
3563    protected boolean isChildrenDrawingOrderEnabled() {
3564        return (mGroupFlags & FLAG_USE_CHILD_DRAWING_ORDER) == FLAG_USE_CHILD_DRAWING_ORDER;
3565    }
3566
3567    /**
3568     * Tells the ViewGroup whether to draw its children in the order defined by the method
3569     * {@link #getChildDrawingOrder(int, int)}.
3570     *
3571     * @param enabled true if the order of the children when drawing is determined by
3572     *        {@link #getChildDrawingOrder(int, int)}, false otherwise
3573     *
3574     * @see #isChildrenDrawingOrderEnabled()
3575     * @see #getChildDrawingOrder(int, int)
3576     */
3577    protected void setChildrenDrawingOrderEnabled(boolean enabled) {
3578        setBooleanFlag(FLAG_USE_CHILD_DRAWING_ORDER, enabled);
3579    }
3580
3581    private void setBooleanFlag(int flag, boolean value) {
3582        if (value) {
3583            mGroupFlags |= flag;
3584        } else {
3585            mGroupFlags &= ~flag;
3586        }
3587    }
3588
3589    /**
3590     * Returns an integer indicating what types of drawing caches are kept in memory.
3591     *
3592     * @see #setPersistentDrawingCache(int)
3593     * @see #setAnimationCacheEnabled(boolean)
3594     *
3595     * @return one or a combination of {@link #PERSISTENT_NO_CACHE},
3596     *         {@link #PERSISTENT_ANIMATION_CACHE}, {@link #PERSISTENT_SCROLLING_CACHE}
3597     *         and {@link #PERSISTENT_ALL_CACHES}
3598     */
3599    @ViewDebug.ExportedProperty(category = "drawing", mapping = {
3600        @ViewDebug.IntToString(from = PERSISTENT_NO_CACHE,        to = "NONE"),
3601        @ViewDebug.IntToString(from = PERSISTENT_ANIMATION_CACHE, to = "ANIMATION"),
3602        @ViewDebug.IntToString(from = PERSISTENT_SCROLLING_CACHE, to = "SCROLLING"),
3603        @ViewDebug.IntToString(from = PERSISTENT_ALL_CACHES,      to = "ALL")
3604    })
3605    public int getPersistentDrawingCache() {
3606        return mPersistentDrawingCache;
3607    }
3608
3609    /**
3610     * Indicates what types of drawing caches should be kept in memory after
3611     * they have been created.
3612     *
3613     * @see #getPersistentDrawingCache()
3614     * @see #setAnimationCacheEnabled(boolean)
3615     *
3616     * @param drawingCacheToKeep one or a combination of {@link #PERSISTENT_NO_CACHE},
3617     *        {@link #PERSISTENT_ANIMATION_CACHE}, {@link #PERSISTENT_SCROLLING_CACHE}
3618     *        and {@link #PERSISTENT_ALL_CACHES}
3619     */
3620    public void setPersistentDrawingCache(int drawingCacheToKeep) {
3621        mPersistentDrawingCache = drawingCacheToKeep & PERSISTENT_ALL_CACHES;
3622    }
3623
3624    /**
3625     * Returns a new set of layout parameters based on the supplied attributes set.
3626     *
3627     * @param attrs the attributes to build the layout parameters from
3628     *
3629     * @return an instance of {@link android.view.ViewGroup.LayoutParams} or one
3630     *         of its descendants
3631     */
3632    public LayoutParams generateLayoutParams(AttributeSet attrs) {
3633        return new LayoutParams(getContext(), attrs);
3634    }
3635
3636    /**
3637     * Returns a safe set of layout parameters based on the supplied layout params.
3638     * When a ViewGroup is passed a View whose layout params do not pass the test of
3639     * {@link #checkLayoutParams(android.view.ViewGroup.LayoutParams)}, this method
3640     * is invoked. This method should return a new set of layout params suitable for
3641     * this ViewGroup, possibly by copying the appropriate attributes from the
3642     * specified set of layout params.
3643     *
3644     * @param p The layout parameters to convert into a suitable set of layout parameters
3645     *          for this ViewGroup.
3646     *
3647     * @return an instance of {@link android.view.ViewGroup.LayoutParams} or one
3648     *         of its descendants
3649     */
3650    protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
3651        return p;
3652    }
3653
3654    /**
3655     * Returns a set of default layout parameters. These parameters are requested
3656     * when the View passed to {@link #addView(View)} has no layout parameters
3657     * already set. If null is returned, an exception is thrown from addView.
3658     *
3659     * @return a set of default layout parameters or null
3660     */
3661    protected LayoutParams generateDefaultLayoutParams() {
3662        return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
3663    }
3664
3665    /**
3666     * @hide
3667     */
3668    @Override
3669    protected boolean dispatchConsistencyCheck(int consistency) {
3670        boolean result = super.dispatchConsistencyCheck(consistency);
3671
3672        final int count = mChildrenCount;
3673        final View[] children = mChildren;
3674        for (int i = 0; i < count; i++) {
3675            if (!children[i].dispatchConsistencyCheck(consistency)) result = false;
3676        }
3677
3678        return result;
3679    }
3680
3681    /**
3682     * @hide
3683     */
3684    @Override
3685    protected boolean onConsistencyCheck(int consistency) {
3686        boolean result = super.onConsistencyCheck(consistency);
3687
3688        final boolean checkLayout = (consistency & ViewDebug.CONSISTENCY_LAYOUT) != 0;
3689        final boolean checkDrawing = (consistency & ViewDebug.CONSISTENCY_DRAWING) != 0;
3690
3691        if (checkLayout) {
3692            final int count = mChildrenCount;
3693            final View[] children = mChildren;
3694            for (int i = 0; i < count; i++) {
3695                if (children[i].getParent() != this) {
3696                    result = false;
3697                    android.util.Log.d(ViewDebug.CONSISTENCY_LOG_TAG,
3698                            "View " + children[i] + " has no parent/a parent that is not " + this);
3699                }
3700            }
3701        }
3702
3703        if (checkDrawing) {
3704            // If this group is dirty, check that the parent is dirty as well
3705            if ((mPrivateFlags & DIRTY_MASK) != 0) {
3706                final ViewParent parent = getParent();
3707                if (parent != null && !(parent instanceof ViewRoot)) {
3708                    if ((((View) parent).mPrivateFlags & DIRTY_MASK) == 0) {
3709                        result = false;
3710                        android.util.Log.d(ViewDebug.CONSISTENCY_LOG_TAG,
3711                                "ViewGroup " + this + " is dirty but its parent is not: " + this);
3712                    }
3713                }
3714            }
3715        }
3716
3717        return result;
3718    }
3719
3720    /**
3721     * {@inheritDoc}
3722     */
3723    @Override
3724    protected void debug(int depth) {
3725        super.debug(depth);
3726        String output;
3727
3728        if (mFocused != null) {
3729            output = debugIndent(depth);
3730            output += "mFocused";
3731            Log.d(VIEW_LOG_TAG, output);
3732        }
3733        if (mChildrenCount != 0) {
3734            output = debugIndent(depth);
3735            output += "{";
3736            Log.d(VIEW_LOG_TAG, output);
3737        }
3738        int count = mChildrenCount;
3739        for (int i = 0; i < count; i++) {
3740            View child = mChildren[i];
3741            child.debug(depth + 1);
3742        }
3743
3744        if (mChildrenCount != 0) {
3745            output = debugIndent(depth);
3746            output += "}";
3747            Log.d(VIEW_LOG_TAG, output);
3748        }
3749    }
3750
3751    /**
3752     * Returns the position in the group of the specified child view.
3753     *
3754     * @param child the view for which to get the position
3755     * @return a positive integer representing the position of the view in the
3756     *         group, or -1 if the view does not exist in the group
3757     */
3758    public int indexOfChild(View child) {
3759        final int count = mChildrenCount;
3760        final View[] children = mChildren;
3761        for (int i = 0; i < count; i++) {
3762            if (children[i] == child) {
3763                return i;
3764            }
3765        }
3766        return -1;
3767    }
3768
3769    /**
3770     * Returns the number of children in the group.
3771     *
3772     * @return a positive integer representing the number of children in
3773     *         the group
3774     */
3775    public int getChildCount() {
3776        return mChildrenCount;
3777    }
3778
3779    /**
3780     * Returns the view at the specified position in the group.
3781     *
3782     * @param index the position at which to get the view from
3783     * @return the view at the specified position or null if the position
3784     *         does not exist within the group
3785     */
3786    public View getChildAt(int index) {
3787        try {
3788            return mChildren[index];
3789        } catch (IndexOutOfBoundsException ex) {
3790            return null;
3791        }
3792    }
3793
3794    /**
3795     * Ask all of the children of this view to measure themselves, taking into
3796     * account both the MeasureSpec requirements for this view and its padding.
3797     * We skip children that are in the GONE state The heavy lifting is done in
3798     * getChildMeasureSpec.
3799     *
3800     * @param widthMeasureSpec The width requirements for this view
3801     * @param heightMeasureSpec The height requirements for this view
3802     */
3803    protected void measureChildren(int widthMeasureSpec, int heightMeasureSpec) {
3804        final int size = mChildrenCount;
3805        final View[] children = mChildren;
3806        for (int i = 0; i < size; ++i) {
3807            final View child = children[i];
3808            if ((child.mViewFlags & VISIBILITY_MASK) != GONE) {
3809                measureChild(child, widthMeasureSpec, heightMeasureSpec);
3810            }
3811        }
3812    }
3813
3814    /**
3815     * Ask one of the children of this view to measure itself, taking into
3816     * account both the MeasureSpec requirements for this view and its padding.
3817     * The heavy lifting is done in getChildMeasureSpec.
3818     *
3819     * @param child The child to measure
3820     * @param parentWidthMeasureSpec The width requirements for this view
3821     * @param parentHeightMeasureSpec The height requirements for this view
3822     */
3823    protected void measureChild(View child, int parentWidthMeasureSpec,
3824            int parentHeightMeasureSpec) {
3825        final LayoutParams lp = child.getLayoutParams();
3826
3827        final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
3828                mPaddingLeft + mPaddingRight, lp.width);
3829        final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
3830                mPaddingTop + mPaddingBottom, lp.height);
3831
3832        child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
3833    }
3834
3835    /**
3836     * Ask one of the children of this view to measure itself, taking into
3837     * account both the MeasureSpec requirements for this view and its padding
3838     * and margins. The child must have MarginLayoutParams The heavy lifting is
3839     * done in getChildMeasureSpec.
3840     *
3841     * @param child The child to measure
3842     * @param parentWidthMeasureSpec The width requirements for this view
3843     * @param widthUsed Extra space that has been used up by the parent
3844     *        horizontally (possibly by other children of the parent)
3845     * @param parentHeightMeasureSpec The height requirements for this view
3846     * @param heightUsed Extra space that has been used up by the parent
3847     *        vertically (possibly by other children of the parent)
3848     */
3849    protected void measureChildWithMargins(View child,
3850            int parentWidthMeasureSpec, int widthUsed,
3851            int parentHeightMeasureSpec, int heightUsed) {
3852        final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
3853
3854        final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
3855                mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin
3856                        + widthUsed, lp.width);
3857        final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
3858                mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin
3859                        + heightUsed, lp.height);
3860
3861        child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
3862    }
3863
3864    /**
3865     * Does the hard part of measureChildren: figuring out the MeasureSpec to
3866     * pass to a particular child. This method figures out the right MeasureSpec
3867     * for one dimension (height or width) of one child view.
3868     *
3869     * The goal is to combine information from our MeasureSpec with the
3870     * LayoutParams of the child to get the best possible results. For example,
3871     * if the this view knows its size (because its MeasureSpec has a mode of
3872     * EXACTLY), and the child has indicated in its LayoutParams that it wants
3873     * to be the same size as the parent, the parent should ask the child to
3874     * layout given an exact size.
3875     *
3876     * @param spec The requirements for this view
3877     * @param padding The padding of this view for the current dimension and
3878     *        margins, if applicable
3879     * @param childDimension How big the child wants to be in the current
3880     *        dimension
3881     * @return a MeasureSpec integer for the child
3882     */
3883    public static int getChildMeasureSpec(int spec, int padding, int childDimension) {
3884        int specMode = MeasureSpec.getMode(spec);
3885        int specSize = MeasureSpec.getSize(spec);
3886
3887        int size = Math.max(0, specSize - padding);
3888
3889        int resultSize = 0;
3890        int resultMode = 0;
3891
3892        switch (specMode) {
3893        // Parent has imposed an exact size on us
3894        case MeasureSpec.EXACTLY:
3895            if (childDimension >= 0) {
3896                resultSize = childDimension;
3897                resultMode = MeasureSpec.EXACTLY;
3898            } else if (childDimension == LayoutParams.MATCH_PARENT) {
3899                // Child wants to be our size. So be it.
3900                resultSize = size;
3901                resultMode = MeasureSpec.EXACTLY;
3902            } else if (childDimension == LayoutParams.WRAP_CONTENT) {
3903                // Child wants to determine its own size. It can't be
3904                // bigger than us.
3905                resultSize = size;
3906                resultMode = MeasureSpec.AT_MOST;
3907            }
3908            break;
3909
3910        // Parent has imposed a maximum size on us
3911        case MeasureSpec.AT_MOST:
3912            if (childDimension >= 0) {
3913                // Child wants a specific size... so be it
3914                resultSize = childDimension;
3915                resultMode = MeasureSpec.EXACTLY;
3916            } else if (childDimension == LayoutParams.MATCH_PARENT) {
3917                // Child wants to be our size, but our size is not fixed.
3918                // Constrain child to not be bigger than us.
3919                resultSize = size;
3920                resultMode = MeasureSpec.AT_MOST;
3921            } else if (childDimension == LayoutParams.WRAP_CONTENT) {
3922                // Child wants to determine its own size. It can't be
3923                // bigger than us.
3924                resultSize = size;
3925                resultMode = MeasureSpec.AT_MOST;
3926            }
3927            break;
3928
3929        // Parent asked to see how big we want to be
3930        case MeasureSpec.UNSPECIFIED:
3931            if (childDimension >= 0) {
3932                // Child wants a specific size... let him have it
3933                resultSize = childDimension;
3934                resultMode = MeasureSpec.EXACTLY;
3935            } else if (childDimension == LayoutParams.MATCH_PARENT) {
3936                // Child wants to be our size... find out how big it should
3937                // be
3938                resultSize = 0;
3939                resultMode = MeasureSpec.UNSPECIFIED;
3940            } else if (childDimension == LayoutParams.WRAP_CONTENT) {
3941                // Child wants to determine its own size.... find out how
3942                // big it should be
3943                resultSize = 0;
3944                resultMode = MeasureSpec.UNSPECIFIED;
3945            }
3946            break;
3947        }
3948        return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
3949    }
3950
3951
3952    /**
3953     * Removes any pending animations for views that have been removed. Call
3954     * this if you don't want animations for exiting views to stack up.
3955     */
3956    public void clearDisappearingChildren() {
3957        if (mDisappearingChildren != null) {
3958            mDisappearingChildren.clear();
3959        }
3960    }
3961
3962    /**
3963     * Add a view which is removed from mChildren but still needs animation
3964     *
3965     * @param v View to add
3966     */
3967    private void addDisappearingView(View v) {
3968        ArrayList<View> disappearingChildren = mDisappearingChildren;
3969
3970        if (disappearingChildren == null) {
3971            disappearingChildren = mDisappearingChildren = new ArrayList<View>();
3972        }
3973
3974        disappearingChildren.add(v);
3975    }
3976
3977    /**
3978     * Cleanup a view when its animation is done. This may mean removing it from
3979     * the list of disappearing views.
3980     *
3981     * @param view The view whose animation has finished
3982     * @param animation The animation, cannot be null
3983     */
3984    private void finishAnimatingView(final View view, Animation animation) {
3985        final ArrayList<View> disappearingChildren = mDisappearingChildren;
3986        if (disappearingChildren != null) {
3987            if (disappearingChildren.contains(view)) {
3988                disappearingChildren.remove(view);
3989
3990                if (view.mAttachInfo != null) {
3991                    view.dispatchDetachedFromWindow();
3992                }
3993
3994                view.clearAnimation();
3995                mGroupFlags |= FLAG_INVALIDATE_REQUIRED;
3996            }
3997        }
3998
3999        if (animation != null && !animation.getFillAfter()) {
4000            view.clearAnimation();
4001        }
4002
4003        if ((view.mPrivateFlags & ANIMATION_STARTED) == ANIMATION_STARTED) {
4004            view.onAnimationEnd();
4005            // Should be performed by onAnimationEnd() but this avoid an infinite loop,
4006            // so we'd rather be safe than sorry
4007            view.mPrivateFlags &= ~ANIMATION_STARTED;
4008            // Draw one more frame after the animation is done
4009            mGroupFlags |= FLAG_INVALIDATE_REQUIRED;
4010        }
4011    }
4012
4013    /**
4014     * This method tells the ViewGroup that the given View object, which should have this
4015     * ViewGroup as its parent,
4016     * should be kept around  (re-displayed when the ViewGroup draws its children) even if it
4017     * is removed from its parent. This allows animations, such as those used by
4018     * {@link android.app.Fragment} and {@link android.animation.LayoutTransition} to animate
4019     * the removal of views. A call to this method should always be accompanied by a later call
4020     * to {@link #endViewTransition(View)}, such as after an animation on the View has finished,
4021     * so that the View finally gets removed.
4022     *
4023     * @param view The View object to be kept visible even if it gets removed from its parent.
4024     */
4025    public void startViewTransition(View view) {
4026        if (view.mParent == this) {
4027            if (mTransitioningViews == null) {
4028                mTransitioningViews = new ArrayList<View>();
4029            }
4030            mTransitioningViews.add(view);
4031        }
4032    }
4033
4034    /**
4035     * This method should always be called following an earlier call to
4036     * {@link #startViewTransition(View)}. The given View is finally removed from its parent
4037     * and will no longer be displayed. Note that this method does not perform the functionality
4038     * of removing a view from its parent; it just discontinues the display of a View that
4039     * has previously been removed.
4040     *
4041     * @return view The View object that has been removed but is being kept around in the visible
4042     * hierarchy by an earlier call to {@link #startViewTransition(View)}.
4043     */
4044    public void endViewTransition(View view) {
4045        if (mTransitioningViews != null) {
4046            mTransitioningViews.remove(view);
4047            final ArrayList<View> disappearingChildren = mDisappearingChildren;
4048            if (disappearingChildren != null && disappearingChildren.contains(view)) {
4049                disappearingChildren.remove(view);
4050                if (mVisibilityChangingChildren != null &&
4051                        mVisibilityChangingChildren.contains(view)) {
4052                    mVisibilityChangingChildren.remove(view);
4053                } else {
4054                    if (view.mAttachInfo != null) {
4055                        view.dispatchDetachedFromWindow();
4056                    }
4057                    if (view.mParent != null) {
4058                        view.mParent = null;
4059                    }
4060                }
4061                mGroupFlags |= FLAG_INVALIDATE_REQUIRED;
4062            }
4063        }
4064    }
4065
4066    private LayoutTransition.TransitionListener mLayoutTransitionListener =
4067            new LayoutTransition.TransitionListener() {
4068        @Override
4069        public void startTransition(LayoutTransition transition, ViewGroup container,
4070                View view, int transitionType) {
4071            // We only care about disappearing items, since we need special logic to keep
4072            // those items visible after they've been 'removed'
4073            if (transitionType == LayoutTransition.DISAPPEARING) {
4074                startViewTransition(view);
4075            }
4076        }
4077
4078        @Override
4079        public void endTransition(LayoutTransition transition, ViewGroup container,
4080                View view, int transitionType) {
4081            if (transitionType == LayoutTransition.DISAPPEARING && mTransitioningViews != null) {
4082                endViewTransition(view);
4083            }
4084        }
4085    };
4086
4087    /**
4088     * {@inheritDoc}
4089     */
4090    @Override
4091    public boolean gatherTransparentRegion(Region region) {
4092        // If no transparent regions requested, we are always opaque.
4093        final boolean meOpaque = (mPrivateFlags & View.REQUEST_TRANSPARENT_REGIONS) == 0;
4094        if (meOpaque && region == null) {
4095            // The caller doesn't care about the region, so stop now.
4096            return true;
4097        }
4098        super.gatherTransparentRegion(region);
4099        final View[] children = mChildren;
4100        final int count = mChildrenCount;
4101        boolean noneOfTheChildrenAreTransparent = true;
4102        for (int i = 0; i < count; i++) {
4103            final View child = children[i];
4104            if ((child.mViewFlags & VISIBILITY_MASK) != GONE || child.getAnimation() != null) {
4105                if (!child.gatherTransparentRegion(region)) {
4106                    noneOfTheChildrenAreTransparent = false;
4107                }
4108            }
4109        }
4110        return meOpaque || noneOfTheChildrenAreTransparent;
4111    }
4112
4113    /**
4114     * {@inheritDoc}
4115     */
4116    public void requestTransparentRegion(View child) {
4117        if (child != null) {
4118            child.mPrivateFlags |= View.REQUEST_TRANSPARENT_REGIONS;
4119            if (mParent != null) {
4120                mParent.requestTransparentRegion(this);
4121            }
4122        }
4123    }
4124
4125
4126    @Override
4127    protected boolean fitSystemWindows(Rect insets) {
4128        boolean done = super.fitSystemWindows(insets);
4129        if (!done) {
4130            final int count = mChildrenCount;
4131            final View[] children = mChildren;
4132            for (int i = 0; i < count; i++) {
4133                done = children[i].fitSystemWindows(insets);
4134                if (done) {
4135                    break;
4136                }
4137            }
4138        }
4139        return done;
4140    }
4141
4142    /**
4143     * Returns the animation listener to which layout animation events are
4144     * sent.
4145     *
4146     * @return an {@link android.view.animation.Animation.AnimationListener}
4147     */
4148    public Animation.AnimationListener getLayoutAnimationListener() {
4149        return mAnimationListener;
4150    }
4151
4152    @Override
4153    protected void drawableStateChanged() {
4154        super.drawableStateChanged();
4155
4156        if ((mGroupFlags & FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE) != 0) {
4157            if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0) {
4158                throw new IllegalStateException("addStateFromChildren cannot be enabled if a"
4159                        + " child has duplicateParentState set to true");
4160            }
4161
4162            final View[] children = mChildren;
4163            final int count = mChildrenCount;
4164
4165            for (int i = 0; i < count; i++) {
4166                final View child = children[i];
4167                if ((child.mViewFlags & DUPLICATE_PARENT_STATE) != 0) {
4168                    child.refreshDrawableState();
4169                }
4170            }
4171        }
4172    }
4173
4174    @Override
4175    protected int[] onCreateDrawableState(int extraSpace) {
4176        if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) == 0) {
4177            return super.onCreateDrawableState(extraSpace);
4178        }
4179
4180        int need = 0;
4181        int n = getChildCount();
4182        for (int i = 0; i < n; i++) {
4183            int[] childState = getChildAt(i).getDrawableState();
4184
4185            if (childState != null) {
4186                need += childState.length;
4187            }
4188        }
4189
4190        int[] state = super.onCreateDrawableState(extraSpace + need);
4191
4192        for (int i = 0; i < n; i++) {
4193            int[] childState = getChildAt(i).getDrawableState();
4194
4195            if (childState != null) {
4196                state = mergeDrawableStates(state, childState);
4197            }
4198        }
4199
4200        return state;
4201    }
4202
4203    /**
4204     * Sets whether this ViewGroup's drawable states also include
4205     * its children's drawable states.  This is used, for example, to
4206     * make a group appear to be focused when its child EditText or button
4207     * is focused.
4208     */
4209    public void setAddStatesFromChildren(boolean addsStates) {
4210        if (addsStates) {
4211            mGroupFlags |= FLAG_ADD_STATES_FROM_CHILDREN;
4212        } else {
4213            mGroupFlags &= ~FLAG_ADD_STATES_FROM_CHILDREN;
4214        }
4215
4216        refreshDrawableState();
4217    }
4218
4219    /**
4220     * Returns whether this ViewGroup's drawable states also include
4221     * its children's drawable states.  This is used, for example, to
4222     * make a group appear to be focused when its child EditText or button
4223     * is focused.
4224     */
4225    public boolean addStatesFromChildren() {
4226        return (mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0;
4227    }
4228
4229    /**
4230     * If {link #addStatesFromChildren} is true, refreshes this group's
4231     * drawable state (to include the states from its children).
4232     */
4233    public void childDrawableStateChanged(View child) {
4234        if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0) {
4235            refreshDrawableState();
4236        }
4237    }
4238
4239    /**
4240     * Specifies the animation listener to which layout animation events must
4241     * be sent. Only
4242     * {@link android.view.animation.Animation.AnimationListener#onAnimationStart(Animation)}
4243     * and
4244     * {@link android.view.animation.Animation.AnimationListener#onAnimationEnd(Animation)}
4245     * are invoked.
4246     *
4247     * @param animationListener the layout animation listener
4248     */
4249    public void setLayoutAnimationListener(Animation.AnimationListener animationListener) {
4250        mAnimationListener = animationListener;
4251    }
4252
4253    /**
4254     * LayoutParams are used by views to tell their parents how they want to be
4255     * laid out. See
4256     * {@link android.R.styleable#ViewGroup_Layout ViewGroup Layout Attributes}
4257     * for a list of all child view attributes that this class supports.
4258     *
4259     * <p>
4260     * The base LayoutParams class just describes how big the view wants to be
4261     * for both width and height. For each dimension, it can specify one of:
4262     * <ul>
4263     * <li>FILL_PARENT (renamed MATCH_PARENT in API Level 8 and higher), which
4264     * means that the view wants to be as big as its parent (minus padding)
4265     * <li> WRAP_CONTENT, which means that the view wants to be just big enough
4266     * to enclose its content (plus padding)
4267     * <li> an exact number
4268     * </ul>
4269     * There are subclasses of LayoutParams for different subclasses of
4270     * ViewGroup. For example, AbsoluteLayout has its own subclass of
4271     * LayoutParams which adds an X and Y value.
4272     *
4273     * @attr ref android.R.styleable#ViewGroup_Layout_layout_height
4274     * @attr ref android.R.styleable#ViewGroup_Layout_layout_width
4275     */
4276    public static class LayoutParams {
4277        /**
4278         * Special value for the height or width requested by a View.
4279         * FILL_PARENT means that the view wants to be as big as its parent,
4280         * minus the parent's padding, if any. This value is deprecated
4281         * starting in API Level 8 and replaced by {@link #MATCH_PARENT}.
4282         */
4283        @SuppressWarnings({"UnusedDeclaration"})
4284        @Deprecated
4285        public static final int FILL_PARENT = -1;
4286
4287        /**
4288         * Special value for the height or width requested by a View.
4289         * MATCH_PARENT means that the view wants to be as big as its parent,
4290         * minus the parent's padding, if any. Introduced in API Level 8.
4291         */
4292        public static final int MATCH_PARENT = -1;
4293
4294        /**
4295         * Special value for the height or width requested by a View.
4296         * WRAP_CONTENT means that the view wants to be just large enough to fit
4297         * its own internal content, taking its own padding into account.
4298         */
4299        public static final int WRAP_CONTENT = -2;
4300
4301        /**
4302         * Information about how wide the view wants to be. Can be one of the
4303         * constants FILL_PARENT (replaced by MATCH_PARENT ,
4304         * in API Level 8) or WRAP_CONTENT. or an exact size.
4305         */
4306        @ViewDebug.ExportedProperty(category = "layout", mapping = {
4307            @ViewDebug.IntToString(from = MATCH_PARENT, to = "MATCH_PARENT"),
4308            @ViewDebug.IntToString(from = WRAP_CONTENT, to = "WRAP_CONTENT")
4309        })
4310        public int width;
4311
4312        /**
4313         * Information about how tall the view wants to be. Can be one of the
4314         * constants FILL_PARENT (replaced by MATCH_PARENT ,
4315         * in API Level 8) or WRAP_CONTENT. or an exact size.
4316         */
4317        @ViewDebug.ExportedProperty(category = "layout", mapping = {
4318            @ViewDebug.IntToString(from = MATCH_PARENT, to = "MATCH_PARENT"),
4319            @ViewDebug.IntToString(from = WRAP_CONTENT, to = "WRAP_CONTENT")
4320        })
4321        public int height;
4322
4323        /**
4324         * Used to animate layouts.
4325         */
4326        public LayoutAnimationController.AnimationParameters layoutAnimationParameters;
4327
4328        /**
4329         * Creates a new set of layout parameters. The values are extracted from
4330         * the supplied attributes set and context. The XML attributes mapped
4331         * to this set of layout parameters are:
4332         *
4333         * <ul>
4334         *   <li><code>layout_width</code>: the width, either an exact value,
4335         *   {@link #WRAP_CONTENT}, or {@link #FILL_PARENT} (replaced by
4336         *   {@link #MATCH_PARENT} in API Level 8)</li>
4337         *   <li><code>layout_height</code>: the height, either an exact value,
4338         *   {@link #WRAP_CONTENT}, or {@link #FILL_PARENT} (replaced by
4339         *   {@link #MATCH_PARENT} in API Level 8)</li>
4340         * </ul>
4341         *
4342         * @param c the application environment
4343         * @param attrs the set of attributes from which to extract the layout
4344         *              parameters' values
4345         */
4346        public LayoutParams(Context c, AttributeSet attrs) {
4347            TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.ViewGroup_Layout);
4348            setBaseAttributes(a,
4349                    R.styleable.ViewGroup_Layout_layout_width,
4350                    R.styleable.ViewGroup_Layout_layout_height);
4351            a.recycle();
4352        }
4353
4354        /**
4355         * Creates a new set of layout parameters with the specified width
4356         * and height.
4357         *
4358         * @param width the width, either {@link #WRAP_CONTENT},
4359         *        {@link #FILL_PARENT} (replaced by {@link #MATCH_PARENT} in
4360         *        API Level 8), or a fixed size in pixels
4361         * @param height the height, either {@link #WRAP_CONTENT},
4362         *        {@link #FILL_PARENT} (replaced by {@link #MATCH_PARENT} in
4363         *        API Level 8), or a fixed size in pixels
4364         */
4365        public LayoutParams(int width, int height) {
4366            this.width = width;
4367            this.height = height;
4368        }
4369
4370        /**
4371         * Copy constructor. Clones the width and height values of the source.
4372         *
4373         * @param source The layout params to copy from.
4374         */
4375        public LayoutParams(LayoutParams source) {
4376            this.width = source.width;
4377            this.height = source.height;
4378        }
4379
4380        /**
4381         * Used internally by MarginLayoutParams.
4382         * @hide
4383         */
4384        LayoutParams() {
4385        }
4386
4387        /**
4388         * Extracts the layout parameters from the supplied attributes.
4389         *
4390         * @param a the style attributes to extract the parameters from
4391         * @param widthAttr the identifier of the width attribute
4392         * @param heightAttr the identifier of the height attribute
4393         */
4394        protected void setBaseAttributes(TypedArray a, int widthAttr, int heightAttr) {
4395            width = a.getLayoutDimension(widthAttr, "layout_width");
4396            height = a.getLayoutDimension(heightAttr, "layout_height");
4397        }
4398
4399        /**
4400         * Returns a String representation of this set of layout parameters.
4401         *
4402         * @param output the String to prepend to the internal representation
4403         * @return a String with the following format: output +
4404         *         "ViewGroup.LayoutParams={ width=WIDTH, height=HEIGHT }"
4405         *
4406         * @hide
4407         */
4408        public String debug(String output) {
4409            return output + "ViewGroup.LayoutParams={ width="
4410                    + sizeToString(width) + ", height=" + sizeToString(height) + " }";
4411        }
4412
4413        /**
4414         * Converts the specified size to a readable String.
4415         *
4416         * @param size the size to convert
4417         * @return a String instance representing the supplied size
4418         *
4419         * @hide
4420         */
4421        protected static String sizeToString(int size) {
4422            if (size == WRAP_CONTENT) {
4423                return "wrap-content";
4424            }
4425            if (size == MATCH_PARENT) {
4426                return "match-parent";
4427            }
4428            return String.valueOf(size);
4429        }
4430    }
4431
4432    /**
4433     * Per-child layout information for layouts that support margins.
4434     * See
4435     * {@link android.R.styleable#ViewGroup_MarginLayout ViewGroup Margin Layout Attributes}
4436     * for a list of all child view attributes that this class supports.
4437     */
4438    public static class MarginLayoutParams extends ViewGroup.LayoutParams {
4439        /**
4440         * The left margin in pixels of the child.
4441         */
4442        @ViewDebug.ExportedProperty(category = "layout")
4443        public int leftMargin;
4444
4445        /**
4446         * The top margin in pixels of the child.
4447         */
4448        @ViewDebug.ExportedProperty(category = "layout")
4449        public int topMargin;
4450
4451        /**
4452         * The right margin in pixels of the child.
4453         */
4454        @ViewDebug.ExportedProperty(category = "layout")
4455        public int rightMargin;
4456
4457        /**
4458         * The bottom margin in pixels of the child.
4459         */
4460        @ViewDebug.ExportedProperty(category = "layout")
4461        public int bottomMargin;
4462
4463        /**
4464         * Creates a new set of layout parameters. The values are extracted from
4465         * the supplied attributes set and context.
4466         *
4467         * @param c the application environment
4468         * @param attrs the set of attributes from which to extract the layout
4469         *              parameters' values
4470         */
4471        public MarginLayoutParams(Context c, AttributeSet attrs) {
4472            super();
4473
4474            TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.ViewGroup_MarginLayout);
4475            setBaseAttributes(a,
4476                    R.styleable.ViewGroup_MarginLayout_layout_width,
4477                    R.styleable.ViewGroup_MarginLayout_layout_height);
4478
4479            int margin = a.getDimensionPixelSize(
4480                    com.android.internal.R.styleable.ViewGroup_MarginLayout_layout_margin, -1);
4481            if (margin >= 0) {
4482                leftMargin = margin;
4483                topMargin = margin;
4484                rightMargin= margin;
4485                bottomMargin = margin;
4486            } else {
4487                leftMargin = a.getDimensionPixelSize(
4488                        R.styleable.ViewGroup_MarginLayout_layout_marginLeft, 0);
4489                topMargin = a.getDimensionPixelSize(
4490                        R.styleable.ViewGroup_MarginLayout_layout_marginTop, 0);
4491                rightMargin = a.getDimensionPixelSize(
4492                        R.styleable.ViewGroup_MarginLayout_layout_marginRight, 0);
4493                bottomMargin = a.getDimensionPixelSize(
4494                        R.styleable.ViewGroup_MarginLayout_layout_marginBottom, 0);
4495            }
4496
4497            a.recycle();
4498        }
4499
4500        /**
4501         * {@inheritDoc}
4502         */
4503        public MarginLayoutParams(int width, int height) {
4504            super(width, height);
4505        }
4506
4507        /**
4508         * Copy constructor. Clones the width, height and margin values of the source.
4509         *
4510         * @param source The layout params to copy from.
4511         */
4512        public MarginLayoutParams(MarginLayoutParams source) {
4513            this.width = source.width;
4514            this.height = source.height;
4515
4516            this.leftMargin = source.leftMargin;
4517            this.topMargin = source.topMargin;
4518            this.rightMargin = source.rightMargin;
4519            this.bottomMargin = source.bottomMargin;
4520        }
4521
4522        /**
4523         * {@inheritDoc}
4524         */
4525        public MarginLayoutParams(LayoutParams source) {
4526            super(source);
4527        }
4528
4529        /**
4530         * Sets the margins, in pixels.
4531         *
4532         * @param left the left margin size
4533         * @param top the top margin size
4534         * @param right the right margin size
4535         * @param bottom the bottom margin size
4536         *
4537         * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginLeft
4538         * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginTop
4539         * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginRight
4540         * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginBottom
4541         */
4542        public void setMargins(int left, int top, int right, int bottom) {
4543            leftMargin = left;
4544            topMargin = top;
4545            rightMargin = right;
4546            bottomMargin = bottom;
4547        }
4548    }
4549
4550    /* Describes a touched view and the ids of the pointers that it has captured.
4551     *
4552     * This code assumes that pointer ids are always in the range 0..31 such that
4553     * it can use a bitfield to track which pointer ids are present.
4554     * As it happens, the lower layers of the input dispatch pipeline also use the
4555     * same trick so the assumption should be safe here...
4556     */
4557    private static final class TouchTarget {
4558        private static final int MAX_RECYCLED = 32;
4559        private static final Object sRecycleLock = new Object();
4560        private static TouchTarget sRecycleBin;
4561        private static int sRecycledCount;
4562
4563        public static final int ALL_POINTER_IDS = -1; // all ones
4564
4565        // The touched child view.
4566        public View child;
4567
4568        // The combined bit mask of pointer ids for all pointers captured by the target.
4569        public int pointerIdBits;
4570
4571        // The next target in the target list.
4572        public TouchTarget next;
4573
4574        private TouchTarget() {
4575        }
4576
4577        public static TouchTarget obtain(View child, int pointerIdBits) {
4578            final TouchTarget target;
4579            synchronized (sRecycleLock) {
4580                if (sRecycleBin == null) {
4581                    target = new TouchTarget();
4582                } else {
4583                    target = sRecycleBin;
4584                    sRecycleBin = target.next;
4585                     sRecycledCount--;
4586                    target.next = null;
4587                }
4588            }
4589            target.child = child;
4590            target.pointerIdBits = pointerIdBits;
4591            return target;
4592        }
4593
4594        public void recycle() {
4595            synchronized (sRecycleLock) {
4596                if (sRecycledCount < MAX_RECYCLED) {
4597                    next = sRecycleBin;
4598                    sRecycleBin = this;
4599                    sRecycledCount += 1;
4600                }
4601            }
4602        }
4603    }
4604}
4605