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