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