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