ViewGroup.java revision 599913d6e8e610665fad7edd7dfbd3cd48758b3a
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 android.content.Context;
21import android.content.res.Configuration;
22import android.content.res.TypedArray;
23import android.graphics.Bitmap;
24import android.graphics.Canvas;
25import android.graphics.Color;
26import android.graphics.Insets;
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.Build;
34import android.os.Parcelable;
35import android.os.SystemClock;
36import android.util.AttributeSet;
37import android.util.Log;
38import android.util.SparseArray;
39import android.view.accessibility.AccessibilityEvent;
40import android.view.accessibility.AccessibilityNodeInfo;
41import android.view.animation.Animation;
42import android.view.animation.AnimationUtils;
43import android.view.animation.LayoutAnimationController;
44import android.view.animation.Transformation;
45
46import com.android.internal.R;
47import com.android.internal.util.Predicate;
48
49import java.util.ArrayList;
50import java.util.Collections;
51import java.util.HashSet;
52
53/**
54 * <p>
55 * A <code>ViewGroup</code> is a special view that can contain other views
56 * (called children.) The view group is the base class for layouts and views
57 * containers. This class also defines the
58 * {@link android.view.ViewGroup.LayoutParams} class which serves as the base
59 * class for layouts parameters.
60 * </p>
61 *
62 * <p>
63 * Also see {@link LayoutParams} for layout attributes.
64 * </p>
65 *
66 * <div class="special reference">
67 * <h3>Developer Guides</h3>
68 * <p>For more information about creating user interface layouts, read the
69 * <a href="{@docRoot}guide/topics/ui/declaring-layout.html">XML Layouts</a> developer
70 * guide.</p></div>
71 *
72 * @attr ref android.R.styleable#ViewGroup_clipChildren
73 * @attr ref android.R.styleable#ViewGroup_clipToPadding
74 * @attr ref android.R.styleable#ViewGroup_layoutAnimation
75 * @attr ref android.R.styleable#ViewGroup_animationCache
76 * @attr ref android.R.styleable#ViewGroup_persistentDrawingCache
77 * @attr ref android.R.styleable#ViewGroup_alwaysDrawnWithCache
78 * @attr ref android.R.styleable#ViewGroup_addStatesFromChildren
79 * @attr ref android.R.styleable#ViewGroup_descendantFocusability
80 * @attr ref android.R.styleable#ViewGroup_animateLayoutChanges
81 */
82public abstract class ViewGroup extends View implements ViewParent, ViewManager {
83    private static final String TAG = "ViewGroup";
84
85    private static final boolean DBG = false;
86
87    /**
88     * Views which have been hidden or removed which need to be animated on
89     * their way out.
90     * This field should be made private, so it is hidden from the SDK.
91     * {@hide}
92     */
93    protected ArrayList<View> mDisappearingChildren;
94
95    /**
96     * Listener used to propagate events indicating when children are added
97     * and/or removed from a view group.
98     * This field should be made private, so it is hidden from the SDK.
99     * {@hide}
100     */
101    protected OnHierarchyChangeListener mOnHierarchyChangeListener;
102
103    // The view contained within this ViewGroup that has or contains focus.
104    private View mFocused;
105
106    /**
107     * A Transformation used when drawing children, to
108     * apply on the child being drawn.
109     */
110    final Transformation mChildTransformation = new Transformation();
111
112    /**
113     * Used to track the current invalidation region.
114     */
115    RectF mInvalidateRegion;
116
117    /**
118     * A Transformation used to calculate a correct
119     * invalidation area when the application is autoscaled.
120     */
121    Transformation mInvalidationTransformation;
122
123    // View currently under an ongoing drag
124    private View mCurrentDragView;
125
126    // Metadata about the ongoing drag
127    private DragEvent mCurrentDrag;
128    private HashSet<View> mDragNotifiedChildren;
129
130    // Does this group have a child that can accept the current drag payload?
131    private boolean mChildAcceptsDrag;
132
133    // Used during drag dispatch
134    private final PointF mLocalPoint = new PointF();
135
136    // Layout animation
137    private LayoutAnimationController mLayoutAnimationController;
138    private Animation.AnimationListener mAnimationListener;
139
140    // First touch target in the linked list of touch targets.
141    private TouchTarget mFirstTouchTarget;
142
143    // For debugging only.  You can see these in hierarchyviewer.
144    @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"})
145    @ViewDebug.ExportedProperty(category = "events")
146    private long mLastTouchDownTime;
147    @ViewDebug.ExportedProperty(category = "events")
148    private int mLastTouchDownIndex = -1;
149    @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"})
150    @ViewDebug.ExportedProperty(category = "events")
151    private float mLastTouchDownX;
152    @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"})
153    @ViewDebug.ExportedProperty(category = "events")
154    private float mLastTouchDownY;
155
156    // First hover target in the linked list of hover targets.
157    // The hover targets are children which have received ACTION_HOVER_ENTER.
158    // They might not have actually handled the hover event, but we will
159    // continue sending hover events to them as long as the pointer remains over
160    // their bounds and the view group does not intercept hover.
161    private HoverTarget mFirstHoverTarget;
162
163    // True if the view group itself received a hover event.
164    // It might not have actually handled the hover event.
165    private boolean mHoveredSelf;
166
167    /**
168     * Internal flags.
169     *
170     * This field should be made private, so it is hidden from the SDK.
171     * {@hide}
172     */
173    protected int mGroupFlags;
174
175    /*
176     * The layout mode: either {@link #CLIP_BOUNDS} or {@link #OPTICAL_BOUNDS}
177     */
178    private int mLayoutMode = CLIP_BOUNDS;
179
180    /**
181     * NOTE: If you change the flags below make sure to reflect the changes
182     *       the DisplayList class
183     */
184
185    // When set, ViewGroup invalidates only the child's rectangle
186    // Set by default
187    static final int FLAG_CLIP_CHILDREN = 0x1;
188
189    // When set, ViewGroup excludes the padding area from the invalidate rectangle
190    // Set by default
191    private static final int FLAG_CLIP_TO_PADDING = 0x2;
192
193    // When set, dispatchDraw() will invoke invalidate(); this is set by drawChild() when
194    // a child needs to be invalidated and FLAG_OPTIMIZE_INVALIDATE is set
195    static final int FLAG_INVALIDATE_REQUIRED  = 0x4;
196
197    // When set, dispatchDraw() will run the layout animation and unset the flag
198    private static final int FLAG_RUN_ANIMATION = 0x8;
199
200    // When set, there is either no layout animation on the ViewGroup or the layout
201    // animation is over
202    // Set by default
203    static final int FLAG_ANIMATION_DONE = 0x10;
204
205    // If set, this ViewGroup has padding; if unset there is no padding and we don't need
206    // to clip it, even if FLAG_CLIP_TO_PADDING is set
207    private static final int FLAG_PADDING_NOT_NULL = 0x20;
208
209    // When set, this ViewGroup caches its children in a Bitmap before starting a layout animation
210    // Set by default
211    private static final int FLAG_ANIMATION_CACHE = 0x40;
212
213    // When set, this ViewGroup converts calls to invalidate(Rect) to invalidate() during a
214    // layout animation; this avoid clobbering the hierarchy
215    // Automatically set when the layout animation starts, depending on the animation's
216    // characteristics
217    static final int FLAG_OPTIMIZE_INVALIDATE = 0x80;
218
219    // When set, the next call to drawChild() will clear mChildTransformation's matrix
220    static final int FLAG_CLEAR_TRANSFORMATION = 0x100;
221
222    // When set, this ViewGroup invokes mAnimationListener.onAnimationEnd() and removes
223    // the children's Bitmap caches if necessary
224    // This flag is set when the layout animation is over (after FLAG_ANIMATION_DONE is set)
225    private static final int FLAG_NOTIFY_ANIMATION_LISTENER = 0x200;
226
227    /**
228     * When set, the drawing method will call {@link #getChildDrawingOrder(int, int)}
229     * to get the index of the child to draw for that iteration.
230     *
231     * @hide
232     */
233    protected static final int FLAG_USE_CHILD_DRAWING_ORDER = 0x400;
234
235    /**
236     * When set, this ViewGroup supports static transformations on children; this causes
237     * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} to be
238     * invoked when a child is drawn.
239     *
240     * Any subclass overriding
241     * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} should
242     * set this flags in {@link #mGroupFlags}.
243     *
244     * {@hide}
245     */
246    protected static final int FLAG_SUPPORT_STATIC_TRANSFORMATIONS = 0x800;
247
248    // When the previous drawChild() invocation used an alpha value that was lower than
249    // 1.0 and set it in mCachePaint
250    static final int FLAG_ALPHA_LOWER_THAN_ONE = 0x1000;
251
252    /**
253     * When set, this ViewGroup's drawable states also include those
254     * of its children.
255     */
256    private static final int FLAG_ADD_STATES_FROM_CHILDREN = 0x2000;
257
258    /**
259     * When set, this ViewGroup tries to always draw its children using their drawing cache.
260     */
261    static final int FLAG_ALWAYS_DRAWN_WITH_CACHE = 0x4000;
262
263    /**
264     * When set, and if FLAG_ALWAYS_DRAWN_WITH_CACHE is not set, this ViewGroup will try to
265     * draw its children with their drawing cache.
266     */
267    static final int FLAG_CHILDREN_DRAWN_WITH_CACHE = 0x8000;
268
269    /**
270     * When set, this group will go through its list of children to notify them of
271     * any drawable state change.
272     */
273    private static final int FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE = 0x10000;
274
275    private static final int FLAG_MASK_FOCUSABILITY = 0x60000;
276
277    /**
278     * This view will get focus before any of its descendants.
279     */
280    public static final int FOCUS_BEFORE_DESCENDANTS = 0x20000;
281
282    /**
283     * This view will get focus only if none of its descendants want it.
284     */
285    public static final int FOCUS_AFTER_DESCENDANTS = 0x40000;
286
287    /**
288     * This view will block any of its descendants from getting focus, even
289     * if they are focusable.
290     */
291    public static final int FOCUS_BLOCK_DESCENDANTS = 0x60000;
292
293    /**
294     * Used to map between enum in attrubutes and flag values.
295     */
296    private static final int[] DESCENDANT_FOCUSABILITY_FLAGS =
297            {FOCUS_BEFORE_DESCENDANTS, FOCUS_AFTER_DESCENDANTS,
298                    FOCUS_BLOCK_DESCENDANTS};
299
300    /**
301     * When set, this ViewGroup should not intercept touch events.
302     * {@hide}
303     */
304    protected static final int FLAG_DISALLOW_INTERCEPT = 0x80000;
305
306    /**
307     * When set, this ViewGroup will split MotionEvents to multiple child Views when appropriate.
308     */
309    private static final int FLAG_SPLIT_MOTION_EVENTS = 0x200000;
310
311    /**
312     * When set, this ViewGroup will not dispatch onAttachedToWindow calls
313     * to children when adding new views. This is used to prevent multiple
314     * onAttached calls when a ViewGroup adds children in its own onAttached method.
315     */
316    private static final int FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW = 0x400000;
317
318    /**
319     * Indicates which types of drawing caches are to be kept in memory.
320     * This field should be made private, so it is hidden from the SDK.
321     * {@hide}
322     */
323    protected int mPersistentDrawingCache;
324
325    /**
326     * Used to indicate that no drawing cache should be kept in memory.
327     */
328    public static final int PERSISTENT_NO_CACHE = 0x0;
329
330    /**
331     * Used to indicate that the animation drawing cache should be kept in memory.
332     */
333    public static final int PERSISTENT_ANIMATION_CACHE = 0x1;
334
335    /**
336     * Used to indicate that the scrolling drawing cache should be kept in memory.
337     */
338    public static final int PERSISTENT_SCROLLING_CACHE = 0x2;
339
340    /**
341     * Used to indicate that all drawing caches should be kept in memory.
342     */
343    public static final int PERSISTENT_ALL_CACHES = 0x3;
344
345    // Layout Modes
346
347    /**
348     * This constant is a {@link #setLayoutMode(int) layoutMode}.
349     * Clip bounds are the raw values of {@link #getLeft() left}, {@link #getTop() top},
350     * {@link #getRight() right} and {@link #getBottom() bottom}.
351     *
352     * @hide
353     */
354    public static final int CLIP_BOUNDS = 0;
355
356    /**
357     * This constant is a {@link #setLayoutMode(int) layoutMode}.
358     * Optical bounds describe where a widget appears to be. They sit inside the clip
359     * bounds which need to cover a larger area to allow other effects,
360     * such as shadows and glows, to be drawn.
361     *
362     * @hide
363     */
364    public static final int OPTICAL_BOUNDS = 1;
365
366    /**
367     * We clip to padding when FLAG_CLIP_TO_PADDING and FLAG_PADDING_NOT_NULL
368     * are set at the same time.
369     */
370    protected static final int CLIP_TO_PADDING_MASK = FLAG_CLIP_TO_PADDING | FLAG_PADDING_NOT_NULL;
371
372    // Index of the child's left position in the mLocation array
373    private static final int CHILD_LEFT_INDEX = 0;
374    // Index of the child's top position in the mLocation array
375    private static final int CHILD_TOP_INDEX = 1;
376
377    // Child views of this ViewGroup
378    private View[] mChildren;
379    // Number of valid children in the mChildren array, the rest should be null or not
380    // considered as children
381
382    private boolean mLayoutSuppressed = false;
383
384    private int mChildrenCount;
385
386    private static final int ARRAY_INITIAL_CAPACITY = 12;
387    private static final int ARRAY_CAPACITY_INCREMENT = 12;
388
389    private static Paint sDebugPaint;
390    private static float[] sDebugLines;
391
392    // Used to draw cached views
393    Paint mCachePaint;
394
395    // Used to animate add/remove changes in layout
396    private LayoutTransition mTransition;
397
398    // The set of views that are currently being transitioned. This list is used to track views
399    // being removed that should not actually be removed from the parent yet because they are
400    // being animated.
401    private ArrayList<View> mTransitioningViews;
402
403    // List of children changing visibility. This is used to potentially keep rendering
404    // views during a transition when they otherwise would have become gone/invisible
405    private ArrayList<View> mVisibilityChangingChildren;
406
407    // Indicates how many of this container's child subtrees contain transient state
408    @ViewDebug.ExportedProperty(category = "layout")
409    private int mChildCountWithTransientState = 0;
410
411    public ViewGroup(Context context) {
412        super(context);
413        initViewGroup();
414    }
415
416    public ViewGroup(Context context, AttributeSet attrs) {
417        super(context, attrs);
418        initViewGroup();
419        initFromAttributes(context, attrs);
420    }
421
422    public ViewGroup(Context context, AttributeSet attrs, int defStyle) {
423        super(context, attrs, defStyle);
424        initViewGroup();
425        initFromAttributes(context, attrs);
426    }
427
428    private boolean debugDraw() {
429        return mAttachInfo != null && mAttachInfo.mDebugLayout;
430    }
431
432    private void initViewGroup() {
433        // ViewGroup doesn't draw by default
434        if (!debugDraw()) {
435            setFlags(WILL_NOT_DRAW, DRAW_MASK);
436        }
437        mGroupFlags |= FLAG_CLIP_CHILDREN;
438        mGroupFlags |= FLAG_CLIP_TO_PADDING;
439        mGroupFlags |= FLAG_ANIMATION_DONE;
440        mGroupFlags |= FLAG_ANIMATION_CACHE;
441        mGroupFlags |= FLAG_ALWAYS_DRAWN_WITH_CACHE;
442
443        if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB) {
444            mGroupFlags |= FLAG_SPLIT_MOTION_EVENTS;
445        }
446
447        setDescendantFocusability(FOCUS_BEFORE_DESCENDANTS);
448
449        mChildren = new View[ARRAY_INITIAL_CAPACITY];
450        mChildrenCount = 0;
451
452        mPersistentDrawingCache = PERSISTENT_SCROLLING_CACHE;
453    }
454
455    private void initFromAttributes(Context context, AttributeSet attrs) {
456        TypedArray a = context.obtainStyledAttributes(attrs,
457                R.styleable.ViewGroup);
458
459        final int N = a.getIndexCount();
460        for (int i = 0; i < N; i++) {
461            int attr = a.getIndex(i);
462            switch (attr) {
463                case R.styleable.ViewGroup_clipChildren:
464                    setClipChildren(a.getBoolean(attr, true));
465                    break;
466                case R.styleable.ViewGroup_clipToPadding:
467                    setClipToPadding(a.getBoolean(attr, true));
468                    break;
469                case R.styleable.ViewGroup_animationCache:
470                    setAnimationCacheEnabled(a.getBoolean(attr, true));
471                    break;
472                case R.styleable.ViewGroup_persistentDrawingCache:
473                    setPersistentDrawingCache(a.getInt(attr, PERSISTENT_SCROLLING_CACHE));
474                    break;
475                case R.styleable.ViewGroup_addStatesFromChildren:
476                    setAddStatesFromChildren(a.getBoolean(attr, false));
477                    break;
478                case R.styleable.ViewGroup_alwaysDrawnWithCache:
479                    setAlwaysDrawnWithCacheEnabled(a.getBoolean(attr, true));
480                    break;
481                case R.styleable.ViewGroup_layoutAnimation:
482                    int id = a.getResourceId(attr, -1);
483                    if (id > 0) {
484                        setLayoutAnimation(AnimationUtils.loadLayoutAnimation(mContext, id));
485                    }
486                    break;
487                case R.styleable.ViewGroup_descendantFocusability:
488                    setDescendantFocusability(DESCENDANT_FOCUSABILITY_FLAGS[a.getInt(attr, 0)]);
489                    break;
490                case R.styleable.ViewGroup_splitMotionEvents:
491                    setMotionEventSplittingEnabled(a.getBoolean(attr, false));
492                    break;
493                case R.styleable.ViewGroup_animateLayoutChanges:
494                    boolean animateLayoutChanges = a.getBoolean(attr, false);
495                    if (animateLayoutChanges) {
496                        setLayoutTransition(new LayoutTransition());
497                    }
498                    break;
499            }
500        }
501
502        a.recycle();
503    }
504
505    /**
506     * Gets the descendant focusability of this view group.  The descendant
507     * focusability defines the relationship between this view group and its
508     * descendants when looking for a view to take focus in
509     * {@link #requestFocus(int, android.graphics.Rect)}.
510     *
511     * @return one of {@link #FOCUS_BEFORE_DESCENDANTS}, {@link #FOCUS_AFTER_DESCENDANTS},
512     *   {@link #FOCUS_BLOCK_DESCENDANTS}.
513     */
514    @ViewDebug.ExportedProperty(category = "focus", mapping = {
515        @ViewDebug.IntToString(from = FOCUS_BEFORE_DESCENDANTS, to = "FOCUS_BEFORE_DESCENDANTS"),
516        @ViewDebug.IntToString(from = FOCUS_AFTER_DESCENDANTS, to = "FOCUS_AFTER_DESCENDANTS"),
517        @ViewDebug.IntToString(from = FOCUS_BLOCK_DESCENDANTS, to = "FOCUS_BLOCK_DESCENDANTS")
518    })
519    public int getDescendantFocusability() {
520        return mGroupFlags & FLAG_MASK_FOCUSABILITY;
521    }
522
523    /**
524     * Set the descendant focusability of this view group. This defines the relationship
525     * between this view group and its descendants when looking for a view to
526     * take focus in {@link #requestFocus(int, android.graphics.Rect)}.
527     *
528     * @param focusability one of {@link #FOCUS_BEFORE_DESCENDANTS}, {@link #FOCUS_AFTER_DESCENDANTS},
529     *   {@link #FOCUS_BLOCK_DESCENDANTS}.
530     */
531    public void setDescendantFocusability(int focusability) {
532        switch (focusability) {
533            case FOCUS_BEFORE_DESCENDANTS:
534            case FOCUS_AFTER_DESCENDANTS:
535            case FOCUS_BLOCK_DESCENDANTS:
536                break;
537            default:
538                throw new IllegalArgumentException("must be one of FOCUS_BEFORE_DESCENDANTS, "
539                        + "FOCUS_AFTER_DESCENDANTS, FOCUS_BLOCK_DESCENDANTS");
540        }
541        mGroupFlags &= ~FLAG_MASK_FOCUSABILITY;
542        mGroupFlags |= (focusability & FLAG_MASK_FOCUSABILITY);
543    }
544
545    /**
546     * {@inheritDoc}
547     */
548    @Override
549    void handleFocusGainInternal(int direction, Rect previouslyFocusedRect) {
550        if (mFocused != null) {
551            mFocused.unFocus();
552            mFocused = null;
553        }
554        super.handleFocusGainInternal(direction, previouslyFocusedRect);
555    }
556
557    /**
558     * {@inheritDoc}
559     */
560    public void requestChildFocus(View child, View focused) {
561        if (DBG) {
562            System.out.println(this + " requestChildFocus()");
563        }
564        if (getDescendantFocusability() == FOCUS_BLOCK_DESCENDANTS) {
565            return;
566        }
567
568        // Unfocus us, if necessary
569        super.unFocus();
570
571        // We had a previous notion of who had focus. Clear it.
572        if (mFocused != child) {
573            if (mFocused != null) {
574                mFocused.unFocus();
575            }
576
577            mFocused = child;
578        }
579        if (mParent != null) {
580            mParent.requestChildFocus(this, focused);
581        }
582    }
583
584    /**
585     * {@inheritDoc}
586     */
587    public void focusableViewAvailable(View v) {
588        if (mParent != null
589                // shortcut: don't report a new focusable view if we block our descendants from
590                // getting focus
591                && (getDescendantFocusability() != FOCUS_BLOCK_DESCENDANTS)
592                // shortcut: don't report a new focusable view if we already are focused
593                // (and we don't prefer our descendants)
594                //
595                // note: knowing that mFocused is non-null is not a good enough reason
596                // to break the traversal since in that case we'd actually have to find
597                // the focused view and make sure it wasn't FOCUS_AFTER_DESCENDANTS and
598                // an ancestor of v; this will get checked for at ViewAncestor
599                && !(isFocused() && getDescendantFocusability() != FOCUS_AFTER_DESCENDANTS)) {
600            mParent.focusableViewAvailable(v);
601        }
602    }
603
604    /**
605     * {@inheritDoc}
606     */
607    public boolean showContextMenuForChild(View originalView) {
608        return mParent != null && mParent.showContextMenuForChild(originalView);
609    }
610
611    /**
612     * {@inheritDoc}
613     */
614    public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback) {
615        return mParent != null ? mParent.startActionModeForChild(originalView, callback) : null;
616    }
617
618    /**
619     * Find the nearest view in the specified direction that wants to take
620     * focus.
621     *
622     * @param focused The view that currently has focus
623     * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and
624     *        FOCUS_RIGHT, or 0 for not applicable.
625     */
626    public View focusSearch(View focused, int direction) {
627        if (isRootNamespace()) {
628            // root namespace means we should consider ourselves the top of the
629            // tree for focus searching; otherwise we could be focus searching
630            // into other tabs.  see LocalActivityManager and TabHost for more info
631            return FocusFinder.getInstance().findNextFocus(this, focused, direction);
632        } else if (mParent != null) {
633            return mParent.focusSearch(focused, direction);
634        }
635        return null;
636    }
637
638    /**
639     * {@inheritDoc}
640     */
641    public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
642        return false;
643    }
644
645    /**
646     * {@inheritDoc}
647     */
648    @Override
649    public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event) {
650        ViewParent parent = mParent;
651        if (parent == null) {
652            return false;
653        }
654        final boolean propagate = onRequestSendAccessibilityEvent(child, event);
655        if (!propagate) {
656            return false;
657        }
658        return parent.requestSendAccessibilityEvent(this, event);
659    }
660
661    /**
662     * Called when a child has requested sending an {@link AccessibilityEvent} and
663     * gives an opportunity to its parent to augment the event.
664     * <p>
665     * If an {@link android.view.View.AccessibilityDelegate} has been specified via calling
666     * {@link android.view.View#setAccessibilityDelegate(android.view.View.AccessibilityDelegate)} its
667     * {@link android.view.View.AccessibilityDelegate#onRequestSendAccessibilityEvent(ViewGroup, View, AccessibilityEvent)}
668     * is responsible for handling this call.
669     * </p>
670     *
671     * @param child The child which requests sending the event.
672     * @param event The event to be sent.
673     * @return True if the event should be sent.
674     *
675     * @see #requestSendAccessibilityEvent(View, AccessibilityEvent)
676     */
677    public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
678        if (mAccessibilityDelegate != null) {
679            return mAccessibilityDelegate.onRequestSendAccessibilityEvent(this, child, event);
680        } else {
681            return onRequestSendAccessibilityEventInternal(child, event);
682        }
683    }
684
685    /**
686     * @see #onRequestSendAccessibilityEvent(View, AccessibilityEvent)
687     *
688     * Note: Called from the default {@link View.AccessibilityDelegate}.
689     */
690    boolean onRequestSendAccessibilityEventInternal(View child, AccessibilityEvent event) {
691        return true;
692    }
693
694    /**
695     * Called when a child view has changed whether or not it is tracking transient state.
696     *
697     * @hide
698     */
699    public void childHasTransientStateChanged(View child, boolean childHasTransientState) {
700        final boolean oldHasTransientState = hasTransientState();
701        if (childHasTransientState) {
702            mChildCountWithTransientState++;
703        } else {
704            mChildCountWithTransientState--;
705        }
706
707        final boolean newHasTransientState = hasTransientState();
708        if (mParent != null && oldHasTransientState != newHasTransientState) {
709            try {
710                mParent.childHasTransientStateChanged(this, newHasTransientState);
711            } catch (AbstractMethodError e) {
712                Log.e(TAG, mParent.getClass().getSimpleName() +
713                        " does not fully implement ViewParent", e);
714            }
715        }
716    }
717
718    /**
719     * @hide
720     */
721    @Override
722    public boolean hasTransientState() {
723        return mChildCountWithTransientState > 0 || super.hasTransientState();
724    }
725
726    /**
727     * {@inheritDoc}
728     */
729    @Override
730    public boolean dispatchUnhandledMove(View focused, int direction) {
731        return mFocused != null &&
732                mFocused.dispatchUnhandledMove(focused, direction);
733    }
734
735    /**
736     * {@inheritDoc}
737     */
738    public void clearChildFocus(View child) {
739        if (DBG) {
740            System.out.println(this + " clearChildFocus()");
741        }
742
743        mFocused = null;
744        if (mParent != null) {
745            mParent.clearChildFocus(this);
746        }
747    }
748
749    /**
750     * {@inheritDoc}
751     */
752    @Override
753    public void clearFocus() {
754        if (DBG) {
755            System.out.println(this + " clearFocus()");
756        }
757        if (mFocused == null) {
758            super.clearFocus();
759        } else {
760            View focused = mFocused;
761            mFocused = null;
762            focused.clearFocus();
763        }
764    }
765
766    /**
767     * {@inheritDoc}
768     */
769    @Override
770    void unFocus() {
771        if (DBG) {
772            System.out.println(this + " unFocus()");
773        }
774        if (mFocused == null) {
775            super.unFocus();
776        } else {
777            mFocused.unFocus();
778            mFocused = null;
779        }
780    }
781
782    /**
783     * Returns the focused child of this view, if any. The child may have focus
784     * or contain focus.
785     *
786     * @return the focused child or null.
787     */
788    public View getFocusedChild() {
789        return mFocused;
790    }
791
792    /**
793     * Returns true if this view has or contains focus
794     *
795     * @return true if this view has or contains focus
796     */
797    @Override
798    public boolean hasFocus() {
799        return (mPrivateFlags & FOCUSED) != 0 || mFocused != null;
800    }
801
802    /*
803     * (non-Javadoc)
804     *
805     * @see android.view.View#findFocus()
806     */
807    @Override
808    public View findFocus() {
809        if (DBG) {
810            System.out.println("Find focus in " + this + ": flags="
811                    + isFocused() + ", child=" + mFocused);
812        }
813
814        if (isFocused()) {
815            return this;
816        }
817
818        if (mFocused != null) {
819            return mFocused.findFocus();
820        }
821        return null;
822    }
823
824    /**
825     * {@inheritDoc}
826     */
827    @Override
828    public boolean hasFocusable() {
829        if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) {
830            return false;
831        }
832
833        if (isFocusable()) {
834            return true;
835        }
836
837        final int descendantFocusability = getDescendantFocusability();
838        if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS) {
839            final int count = mChildrenCount;
840            final View[] children = mChildren;
841
842            for (int i = 0; i < count; i++) {
843                final View child = children[i];
844                if (child.hasFocusable()) {
845                    return true;
846                }
847            }
848        }
849
850        return false;
851    }
852
853    /**
854     * {@inheritDoc}
855     */
856    @Override
857    public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
858        final int focusableCount = views.size();
859
860        final int descendantFocusability = getDescendantFocusability();
861
862        if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS) {
863            final int count = mChildrenCount;
864            final View[] children = mChildren;
865
866            for (int i = 0; i < count; i++) {
867                final View child = children[i];
868                if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
869                    child.addFocusables(views, direction, focusableMode);
870                }
871            }
872        }
873
874        // we add ourselves (if focusable) in all cases except for when we are
875        // FOCUS_AFTER_DESCENDANTS and there are some descendants focusable.  this is
876        // to avoid the focus search finding layouts when a more precise search
877        // among the focusable children would be more interesting.
878        if (descendantFocusability != FOCUS_AFTER_DESCENDANTS
879                // No focusable descendants
880                || (focusableCount == views.size())) {
881            super.addFocusables(views, direction, focusableMode);
882        }
883    }
884
885    @Override
886    public void findViewsWithText(ArrayList<View> outViews, CharSequence text, int flags) {
887        super.findViewsWithText(outViews, text, flags);
888        final int childrenCount = mChildrenCount;
889        final View[] children = mChildren;
890        for (int i = 0; i < childrenCount; i++) {
891            View child = children[i];
892            if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE
893                    && (child.mPrivateFlags & IS_ROOT_NAMESPACE) == 0) {
894                child.findViewsWithText(outViews, text, flags);
895            }
896        }
897    }
898
899    @Override
900    View findViewByAccessibilityIdTraversal(int accessibilityId) {
901        View foundView = super.findViewByAccessibilityIdTraversal(accessibilityId);
902        if (foundView != null) {
903            return foundView;
904        }
905        final int childrenCount = mChildrenCount;
906        final View[] children = mChildren;
907        for (int i = 0; i < childrenCount; i++) {
908            View child = children[i];
909            foundView = child.findViewByAccessibilityIdTraversal(accessibilityId);
910            if (foundView != null) {
911                return foundView;
912            }
913        }
914        return null;
915    }
916
917    /**
918     * {@inheritDoc}
919     */
920    @Override
921    public void dispatchWindowFocusChanged(boolean hasFocus) {
922        super.dispatchWindowFocusChanged(hasFocus);
923        final int count = mChildrenCount;
924        final View[] children = mChildren;
925        for (int i = 0; i < count; i++) {
926            children[i].dispatchWindowFocusChanged(hasFocus);
927        }
928    }
929
930    /**
931     * {@inheritDoc}
932     */
933    @Override
934    public void addTouchables(ArrayList<View> views) {
935        super.addTouchables(views);
936
937        final int count = mChildrenCount;
938        final View[] children = mChildren;
939
940        for (int i = 0; i < count; i++) {
941            final View child = children[i];
942            if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
943                child.addTouchables(views);
944            }
945        }
946    }
947
948    /**
949     * @hide
950     */
951    @Override
952    public void makeOptionalFitsSystemWindows() {
953        super.makeOptionalFitsSystemWindows();
954        final int count = mChildrenCount;
955        final View[] children = mChildren;
956        for (int i = 0; i < count; i++) {
957            children[i].makeOptionalFitsSystemWindows();
958        }
959    }
960
961    /**
962     * {@inheritDoc}
963     */
964    @Override
965    public void dispatchDisplayHint(int hint) {
966        super.dispatchDisplayHint(hint);
967        final int count = mChildrenCount;
968        final View[] children = mChildren;
969        for (int i = 0; i < count; i++) {
970            children[i].dispatchDisplayHint(hint);
971        }
972    }
973
974    /**
975     * Called when a view's visibility has changed. Notify the parent to take any appropriate
976     * action.
977     *
978     * @param child The view whose visibility has changed
979     * @param oldVisibility The previous visibility value (GONE, INVISIBLE, or VISIBLE).
980     * @param newVisibility The new visibility value (GONE, INVISIBLE, or VISIBLE).
981     * @hide
982     */
983    protected void onChildVisibilityChanged(View child, int oldVisibility, int newVisibility) {
984        if (mTransition != null) {
985            if (newVisibility == VISIBLE) {
986                mTransition.showChild(this, child, oldVisibility);
987            } else {
988                mTransition.hideChild(this, child, newVisibility);
989                if (mTransitioningViews != null && mTransitioningViews.contains(child)) {
990                    // Only track this on disappearing views - appearing views are already visible
991                    // and don't need special handling during drawChild()
992                    if (mVisibilityChangingChildren == null) {
993                        mVisibilityChangingChildren = new ArrayList<View>();
994                    }
995                    mVisibilityChangingChildren.add(child);
996                    addDisappearingView(child);
997                }
998            }
999        }
1000
1001        // in all cases, for drags
1002        if (mCurrentDrag != null) {
1003            if (newVisibility == VISIBLE) {
1004                notifyChildOfDrag(child);
1005            }
1006        }
1007    }
1008
1009    /**
1010     * {@inheritDoc}
1011     */
1012    @Override
1013    protected void dispatchVisibilityChanged(View changedView, int visibility) {
1014        super.dispatchVisibilityChanged(changedView, visibility);
1015        final int count = mChildrenCount;
1016        final View[] children = mChildren;
1017        for (int i = 0; i < count; i++) {
1018            children[i].dispatchVisibilityChanged(changedView, visibility);
1019        }
1020    }
1021
1022    /**
1023     * {@inheritDoc}
1024     */
1025    @Override
1026    public void dispatchWindowVisibilityChanged(int visibility) {
1027        super.dispatchWindowVisibilityChanged(visibility);
1028        final int count = mChildrenCount;
1029        final View[] children = mChildren;
1030        for (int i = 0; i < count; i++) {
1031            children[i].dispatchWindowVisibilityChanged(visibility);
1032        }
1033    }
1034
1035    /**
1036     * {@inheritDoc}
1037     */
1038    @Override
1039    public void dispatchConfigurationChanged(Configuration newConfig) {
1040        super.dispatchConfigurationChanged(newConfig);
1041        final int count = mChildrenCount;
1042        final View[] children = mChildren;
1043        for (int i = 0; i < count; i++) {
1044            children[i].dispatchConfigurationChanged(newConfig);
1045        }
1046    }
1047
1048    /**
1049     * {@inheritDoc}
1050     */
1051    public void recomputeViewAttributes(View child) {
1052        if (mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) {
1053            ViewParent parent = mParent;
1054            if (parent != null) parent.recomputeViewAttributes(this);
1055        }
1056    }
1057
1058    @Override
1059    void dispatchCollectViewAttributes(AttachInfo attachInfo, int visibility) {
1060        if ((visibility & VISIBILITY_MASK) == VISIBLE) {
1061            super.dispatchCollectViewAttributes(attachInfo, visibility);
1062            final int count = mChildrenCount;
1063            final View[] children = mChildren;
1064            for (int i = 0; i < count; i++) {
1065                final View child = children[i];
1066                child.dispatchCollectViewAttributes(attachInfo,
1067                        visibility | (child.mViewFlags&VISIBILITY_MASK));
1068            }
1069        }
1070    }
1071
1072    /**
1073     * {@inheritDoc}
1074     */
1075    public void bringChildToFront(View child) {
1076        int index = indexOfChild(child);
1077        if (index >= 0) {
1078            removeFromArray(index);
1079            addInArray(child, mChildrenCount);
1080            child.mParent = this;
1081        }
1082    }
1083
1084    /**
1085     * {@inheritDoc}
1086     */
1087    // TODO: Write real docs
1088    @Override
1089    public boolean dispatchDragEvent(DragEvent event) {
1090        boolean retval = false;
1091        final float tx = event.mX;
1092        final float ty = event.mY;
1093
1094        ViewRootImpl root = getViewRootImpl();
1095
1096        // Dispatch down the view hierarchy
1097        switch (event.mAction) {
1098        case DragEvent.ACTION_DRAG_STARTED: {
1099            // clear state to recalculate which views we drag over
1100            mCurrentDragView = null;
1101
1102            // Set up our tracking of drag-started notifications
1103            mCurrentDrag = DragEvent.obtain(event);
1104            if (mDragNotifiedChildren == null) {
1105                mDragNotifiedChildren = new HashSet<View>();
1106            } else {
1107                mDragNotifiedChildren.clear();
1108            }
1109
1110            // Now dispatch down to our children, caching the responses
1111            mChildAcceptsDrag = false;
1112            final int count = mChildrenCount;
1113            final View[] children = mChildren;
1114            for (int i = 0; i < count; i++) {
1115                final View child = children[i];
1116                child.mPrivateFlags2 &= ~View.DRAG_MASK;
1117                if (child.getVisibility() == VISIBLE) {
1118                    final boolean handled = notifyChildOfDrag(children[i]);
1119                    if (handled) {
1120                        mChildAcceptsDrag = true;
1121                    }
1122                }
1123            }
1124
1125            // Return HANDLED if one of our children can accept the drag
1126            if (mChildAcceptsDrag) {
1127                retval = true;
1128            }
1129        } break;
1130
1131        case DragEvent.ACTION_DRAG_ENDED: {
1132            // Release the bookkeeping now that the drag lifecycle has ended
1133            if (mDragNotifiedChildren != null) {
1134                for (View child : mDragNotifiedChildren) {
1135                    // If a child was notified about an ongoing drag, it's told that it's over
1136                    child.dispatchDragEvent(event);
1137                    child.mPrivateFlags2 &= ~View.DRAG_MASK;
1138                    child.refreshDrawableState();
1139                }
1140
1141                mDragNotifiedChildren.clear();
1142                mCurrentDrag.recycle();
1143                mCurrentDrag = null;
1144            }
1145
1146            // We consider drag-ended to have been handled if one of our children
1147            // had offered to handle the drag.
1148            if (mChildAcceptsDrag) {
1149                retval = true;
1150            }
1151        } break;
1152
1153        case DragEvent.ACTION_DRAG_LOCATION: {
1154            // Find the [possibly new] drag target
1155            final View target = findFrontmostDroppableChildAt(event.mX, event.mY, mLocalPoint);
1156
1157            // If we've changed apparent drag target, tell the view root which view
1158            // we're over now [for purposes of the eventual drag-recipient-changed
1159            // notifications to the framework] and tell the new target that the drag
1160            // has entered its bounds.  The root will see setDragFocus() calls all
1161            // the way down to the final leaf view that is handling the LOCATION event
1162            // before reporting the new potential recipient to the framework.
1163            if (mCurrentDragView != target) {
1164                root.setDragFocus(target);
1165
1166                final int action = event.mAction;
1167                // If we've dragged off of a child view, send it the EXITED message
1168                if (mCurrentDragView != null) {
1169                    final View view = mCurrentDragView;
1170                    event.mAction = DragEvent.ACTION_DRAG_EXITED;
1171                    view.dispatchDragEvent(event);
1172                    view.mPrivateFlags2 &= ~View.DRAG_HOVERED;
1173                    view.refreshDrawableState();
1174                }
1175                mCurrentDragView = target;
1176
1177                // If we've dragged over a new child view, send it the ENTERED message
1178                if (target != null) {
1179                    event.mAction = DragEvent.ACTION_DRAG_ENTERED;
1180                    target.dispatchDragEvent(event);
1181                    target.mPrivateFlags2 |= View.DRAG_HOVERED;
1182                    target.refreshDrawableState();
1183                }
1184                event.mAction = action;  // restore the event's original state
1185            }
1186
1187            // Dispatch the actual drag location notice, localized into its coordinates
1188            if (target != null) {
1189                event.mX = mLocalPoint.x;
1190                event.mY = mLocalPoint.y;
1191
1192                retval = target.dispatchDragEvent(event);
1193
1194                event.mX = tx;
1195                event.mY = ty;
1196            }
1197        } break;
1198
1199        /* Entered / exited dispatch
1200         *
1201         * DRAG_ENTERED is not dispatched downwards from ViewGroup.  The reason for this is
1202         * that we're about to get the corresponding LOCATION event, which we will use to
1203         * determine which of our children is the new target; at that point we will
1204         * push a DRAG_ENTERED down to the new target child [which may itself be a ViewGroup].
1205         *
1206         * DRAG_EXITED *is* dispatched all the way down immediately: once we know the
1207         * drag has left this ViewGroup, we know by definition that every contained subview
1208         * is also no longer under the drag point.
1209         */
1210
1211        case DragEvent.ACTION_DRAG_EXITED: {
1212            if (mCurrentDragView != null) {
1213                final View view = mCurrentDragView;
1214                view.dispatchDragEvent(event);
1215                view.mPrivateFlags2 &= ~View.DRAG_HOVERED;
1216                view.refreshDrawableState();
1217
1218                mCurrentDragView = null;
1219            }
1220        } break;
1221
1222        case DragEvent.ACTION_DROP: {
1223            if (ViewDebug.DEBUG_DRAG) Log.d(View.VIEW_LOG_TAG, "Drop event: " + event);
1224            View target = findFrontmostDroppableChildAt(event.mX, event.mY, mLocalPoint);
1225            if (target != null) {
1226                if (ViewDebug.DEBUG_DRAG) Log.d(View.VIEW_LOG_TAG, "   dispatch drop to " + target);
1227                event.mX = mLocalPoint.x;
1228                event.mY = mLocalPoint.y;
1229                retval = target.dispatchDragEvent(event);
1230                event.mX = tx;
1231                event.mY = ty;
1232            } else {
1233                if (ViewDebug.DEBUG_DRAG) {
1234                    Log.d(View.VIEW_LOG_TAG, "   not dropped on an accepting view");
1235                }
1236            }
1237        } break;
1238        }
1239
1240        // If none of our children could handle the event, try here
1241        if (!retval) {
1242            // Call up to the View implementation that dispatches to installed listeners
1243            retval = super.dispatchDragEvent(event);
1244        }
1245        return retval;
1246    }
1247
1248    // Find the frontmost child view that lies under the given point, and calculate
1249    // the position within its own local coordinate system.
1250    View findFrontmostDroppableChildAt(float x, float y, PointF outLocalPoint) {
1251        final int count = mChildrenCount;
1252        final View[] children = mChildren;
1253        for (int i = count - 1; i >= 0; i--) {
1254            final View child = children[i];
1255            if (!child.canAcceptDrag()) {
1256                continue;
1257            }
1258
1259            if (isTransformedTouchPointInView(x, y, child, outLocalPoint)) {
1260                return child;
1261            }
1262        }
1263        return null;
1264    }
1265
1266    boolean notifyChildOfDrag(View child) {
1267        if (ViewDebug.DEBUG_DRAG) {
1268            Log.d(View.VIEW_LOG_TAG, "Sending drag-started to view: " + child);
1269        }
1270
1271        boolean canAccept = false;
1272        if (! mDragNotifiedChildren.contains(child)) {
1273            mDragNotifiedChildren.add(child);
1274            canAccept = child.dispatchDragEvent(mCurrentDrag);
1275            if (canAccept && !child.canAcceptDrag()) {
1276                child.mPrivateFlags2 |= View.DRAG_CAN_ACCEPT;
1277                child.refreshDrawableState();
1278            }
1279        }
1280        return canAccept;
1281    }
1282
1283    @Override
1284    public void dispatchWindowSystemUiVisiblityChanged(int visible) {
1285        super.dispatchWindowSystemUiVisiblityChanged(visible);
1286
1287        final int count = mChildrenCount;
1288        final View[] children = mChildren;
1289        for (int i=0; i <count; i++) {
1290            final View child = children[i];
1291            child.dispatchWindowSystemUiVisiblityChanged(visible);
1292        }
1293    }
1294
1295    @Override
1296    public void dispatchSystemUiVisibilityChanged(int visible) {
1297        super.dispatchSystemUiVisibilityChanged(visible);
1298
1299        final int count = mChildrenCount;
1300        final View[] children = mChildren;
1301        for (int i=0; i <count; i++) {
1302            final View child = children[i];
1303            child.dispatchSystemUiVisibilityChanged(visible);
1304        }
1305    }
1306
1307    @Override
1308    boolean updateLocalSystemUiVisibility(int localValue, int localChanges) {
1309        boolean changed = super.updateLocalSystemUiVisibility(localValue, localChanges);
1310
1311        final int count = mChildrenCount;
1312        final View[] children = mChildren;
1313        for (int i=0; i <count; i++) {
1314            final View child = children[i];
1315            changed |= child.updateLocalSystemUiVisibility(localValue, localChanges);
1316        }
1317        return changed;
1318    }
1319
1320    /**
1321     * {@inheritDoc}
1322     */
1323    @Override
1324    public boolean dispatchKeyEventPreIme(KeyEvent event) {
1325        if ((mPrivateFlags & (FOCUSED | HAS_BOUNDS)) == (FOCUSED | HAS_BOUNDS)) {
1326            return super.dispatchKeyEventPreIme(event);
1327        } else if (mFocused != null && (mFocused.mPrivateFlags & HAS_BOUNDS) == HAS_BOUNDS) {
1328            return mFocused.dispatchKeyEventPreIme(event);
1329        }
1330        return false;
1331    }
1332
1333    /**
1334     * {@inheritDoc}
1335     */
1336    @Override
1337    public boolean dispatchKeyEvent(KeyEvent event) {
1338        if (mInputEventConsistencyVerifier != null) {
1339            mInputEventConsistencyVerifier.onKeyEvent(event, 1);
1340        }
1341
1342        if ((mPrivateFlags & (FOCUSED | HAS_BOUNDS)) == (FOCUSED | HAS_BOUNDS)) {
1343            if (super.dispatchKeyEvent(event)) {
1344                return true;
1345            }
1346        } else if (mFocused != null && (mFocused.mPrivateFlags & HAS_BOUNDS) == HAS_BOUNDS) {
1347            if (mFocused.dispatchKeyEvent(event)) {
1348                return true;
1349            }
1350        }
1351
1352        if (mInputEventConsistencyVerifier != null) {
1353            mInputEventConsistencyVerifier.onUnhandledEvent(event, 1);
1354        }
1355        return false;
1356    }
1357
1358    /**
1359     * {@inheritDoc}
1360     */
1361    @Override
1362    public boolean dispatchKeyShortcutEvent(KeyEvent event) {
1363        if ((mPrivateFlags & (FOCUSED | HAS_BOUNDS)) == (FOCUSED | HAS_BOUNDS)) {
1364            return super.dispatchKeyShortcutEvent(event);
1365        } else if (mFocused != null && (mFocused.mPrivateFlags & HAS_BOUNDS) == HAS_BOUNDS) {
1366            return mFocused.dispatchKeyShortcutEvent(event);
1367        }
1368        return false;
1369    }
1370
1371    /**
1372     * {@inheritDoc}
1373     */
1374    @Override
1375    public boolean dispatchTrackballEvent(MotionEvent event) {
1376        if (mInputEventConsistencyVerifier != null) {
1377            mInputEventConsistencyVerifier.onTrackballEvent(event, 1);
1378        }
1379
1380        if ((mPrivateFlags & (FOCUSED | HAS_BOUNDS)) == (FOCUSED | HAS_BOUNDS)) {
1381            if (super.dispatchTrackballEvent(event)) {
1382                return true;
1383            }
1384        } else if (mFocused != null && (mFocused.mPrivateFlags & HAS_BOUNDS) == HAS_BOUNDS) {
1385            if (mFocused.dispatchTrackballEvent(event)) {
1386                return true;
1387            }
1388        }
1389
1390        if (mInputEventConsistencyVerifier != null) {
1391            mInputEventConsistencyVerifier.onUnhandledEvent(event, 1);
1392        }
1393        return false;
1394    }
1395
1396    /**
1397     * {@inheritDoc}
1398     */
1399    @SuppressWarnings({"ConstantConditions"})
1400    @Override
1401    protected boolean dispatchHoverEvent(MotionEvent event) {
1402        final int action = event.getAction();
1403
1404        // First check whether the view group wants to intercept the hover event.
1405        final boolean interceptHover = onInterceptHoverEvent(event);
1406        event.setAction(action); // restore action in case it was changed
1407
1408        MotionEvent eventNoHistory = event;
1409        boolean handled = false;
1410
1411        // Send events to the hovered children and build a new list of hover targets until
1412        // one is found that handles the event.
1413        HoverTarget firstOldHoverTarget = mFirstHoverTarget;
1414        mFirstHoverTarget = null;
1415        if (!interceptHover && action != MotionEvent.ACTION_HOVER_EXIT) {
1416            final float x = event.getX();
1417            final float y = event.getY();
1418            final int childrenCount = mChildrenCount;
1419            if (childrenCount != 0) {
1420                final View[] children = mChildren;
1421                HoverTarget lastHoverTarget = null;
1422                for (int i = childrenCount - 1; i >= 0; i--) {
1423                    final View child = children[i];
1424                    if (!canViewReceivePointerEvents(child)
1425                            || !isTransformedTouchPointInView(x, y, child, null)) {
1426                        continue;
1427                    }
1428
1429                    // Obtain a hover target for this child.  Dequeue it from the
1430                    // old hover target list if the child was previously hovered.
1431                    HoverTarget hoverTarget = firstOldHoverTarget;
1432                    final boolean wasHovered;
1433                    for (HoverTarget predecessor = null; ;) {
1434                        if (hoverTarget == null) {
1435                            hoverTarget = HoverTarget.obtain(child);
1436                            wasHovered = false;
1437                            break;
1438                        }
1439
1440                        if (hoverTarget.child == child) {
1441                            if (predecessor != null) {
1442                                predecessor.next = hoverTarget.next;
1443                            } else {
1444                                firstOldHoverTarget = hoverTarget.next;
1445                            }
1446                            hoverTarget.next = null;
1447                            wasHovered = true;
1448                            break;
1449                        }
1450
1451                        predecessor = hoverTarget;
1452                        hoverTarget = hoverTarget.next;
1453                    }
1454
1455                    // Enqueue the hover target onto the new hover target list.
1456                    if (lastHoverTarget != null) {
1457                        lastHoverTarget.next = hoverTarget;
1458                    } else {
1459                        lastHoverTarget = hoverTarget;
1460                        mFirstHoverTarget = hoverTarget;
1461                    }
1462
1463                    // Dispatch the event to the child.
1464                    if (action == MotionEvent.ACTION_HOVER_ENTER) {
1465                        if (!wasHovered) {
1466                            // Send the enter as is.
1467                            handled |= dispatchTransformedGenericPointerEvent(
1468                                    event, child); // enter
1469                        }
1470                    } else if (action == MotionEvent.ACTION_HOVER_MOVE) {
1471                        if (!wasHovered) {
1472                            // Synthesize an enter from a move.
1473                            eventNoHistory = obtainMotionEventNoHistoryOrSelf(eventNoHistory);
1474                            eventNoHistory.setAction(MotionEvent.ACTION_HOVER_ENTER);
1475                            handled |= dispatchTransformedGenericPointerEvent(
1476                                    eventNoHistory, child); // enter
1477                            eventNoHistory.setAction(action);
1478
1479                            handled |= dispatchTransformedGenericPointerEvent(
1480                                    eventNoHistory, child); // move
1481                        } else {
1482                            // Send the move as is.
1483                            handled |= dispatchTransformedGenericPointerEvent(event, child);
1484                        }
1485                    }
1486                    if (handled) {
1487                        break;
1488                    }
1489                }
1490            }
1491        }
1492
1493        // Send exit events to all previously hovered children that are no longer hovered.
1494        while (firstOldHoverTarget != null) {
1495            final View child = firstOldHoverTarget.child;
1496
1497            // Exit the old hovered child.
1498            if (action == MotionEvent.ACTION_HOVER_EXIT) {
1499                // Send the exit as is.
1500                handled |= dispatchTransformedGenericPointerEvent(
1501                        event, child); // exit
1502            } else {
1503                // Synthesize an exit from a move or enter.
1504                // Ignore the result because hover focus has moved to a different view.
1505                if (action == MotionEvent.ACTION_HOVER_MOVE) {
1506                    dispatchTransformedGenericPointerEvent(
1507                            event, child); // move
1508                }
1509                eventNoHistory = obtainMotionEventNoHistoryOrSelf(eventNoHistory);
1510                eventNoHistory.setAction(MotionEvent.ACTION_HOVER_EXIT);
1511                dispatchTransformedGenericPointerEvent(
1512                        eventNoHistory, child); // exit
1513                eventNoHistory.setAction(action);
1514            }
1515
1516            final HoverTarget nextOldHoverTarget = firstOldHoverTarget.next;
1517            firstOldHoverTarget.recycle();
1518            firstOldHoverTarget = nextOldHoverTarget;
1519        }
1520
1521        // Send events to the view group itself if no children have handled it.
1522        boolean newHoveredSelf = !handled;
1523        if (newHoveredSelf == mHoveredSelf) {
1524            if (newHoveredSelf) {
1525                // Send event to the view group as before.
1526                handled |= super.dispatchHoverEvent(event);
1527            }
1528        } else {
1529            if (mHoveredSelf) {
1530                // Exit the view group.
1531                if (action == MotionEvent.ACTION_HOVER_EXIT) {
1532                    // Send the exit as is.
1533                    handled |= super.dispatchHoverEvent(event); // exit
1534                } else {
1535                    // Synthesize an exit from a move or enter.
1536                    // Ignore the result because hover focus is moving to a different view.
1537                    if (action == MotionEvent.ACTION_HOVER_MOVE) {
1538                        super.dispatchHoverEvent(event); // move
1539                    }
1540                    eventNoHistory = obtainMotionEventNoHistoryOrSelf(eventNoHistory);
1541                    eventNoHistory.setAction(MotionEvent.ACTION_HOVER_EXIT);
1542                    super.dispatchHoverEvent(eventNoHistory); // exit
1543                    eventNoHistory.setAction(action);
1544                }
1545                mHoveredSelf = false;
1546            }
1547
1548            if (newHoveredSelf) {
1549                // Enter the view group.
1550                if (action == MotionEvent.ACTION_HOVER_ENTER) {
1551                    // Send the enter as is.
1552                    handled |= super.dispatchHoverEvent(event); // enter
1553                    mHoveredSelf = true;
1554                } else if (action == MotionEvent.ACTION_HOVER_MOVE) {
1555                    // Synthesize an enter from a move.
1556                    eventNoHistory = obtainMotionEventNoHistoryOrSelf(eventNoHistory);
1557                    eventNoHistory.setAction(MotionEvent.ACTION_HOVER_ENTER);
1558                    handled |= super.dispatchHoverEvent(eventNoHistory); // enter
1559                    eventNoHistory.setAction(action);
1560
1561                    handled |= super.dispatchHoverEvent(eventNoHistory); // move
1562                    mHoveredSelf = true;
1563                }
1564            }
1565        }
1566
1567        // Recycle the copy of the event that we made.
1568        if (eventNoHistory != event) {
1569            eventNoHistory.recycle();
1570        }
1571
1572        // Done.
1573        return handled;
1574    }
1575
1576    private void exitHoverTargets() {
1577        if (mHoveredSelf || mFirstHoverTarget != null) {
1578            final long now = SystemClock.uptimeMillis();
1579            MotionEvent event = MotionEvent.obtain(now, now,
1580                    MotionEvent.ACTION_HOVER_EXIT, 0.0f, 0.0f, 0);
1581            event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
1582            dispatchHoverEvent(event);
1583            event.recycle();
1584        }
1585    }
1586
1587    private void cancelHoverTarget(View view) {
1588        HoverTarget predecessor = null;
1589        HoverTarget target = mFirstHoverTarget;
1590        while (target != null) {
1591            final HoverTarget next = target.next;
1592            if (target.child == view) {
1593                if (predecessor == null) {
1594                    mFirstHoverTarget = next;
1595                } else {
1596                    predecessor.next = next;
1597                }
1598                target.recycle();
1599
1600                final long now = SystemClock.uptimeMillis();
1601                MotionEvent event = MotionEvent.obtain(now, now,
1602                        MotionEvent.ACTION_HOVER_EXIT, 0.0f, 0.0f, 0);
1603                event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
1604                view.dispatchHoverEvent(event);
1605                event.recycle();
1606                return;
1607            }
1608            predecessor = target;
1609            target = next;
1610        }
1611    }
1612
1613    /** @hide */
1614    @Override
1615    protected boolean hasHoveredChild() {
1616        return mFirstHoverTarget != null;
1617    }
1618
1619    @Override
1620    public void addChildrenForAccessibility(ArrayList<View> childrenForAccessibility) {
1621        ChildListForAccessibility children = ChildListForAccessibility.obtain(this, true);
1622        try {
1623            final int childrenCount = children.getChildCount();
1624            for (int i = 0; i < childrenCount; i++) {
1625                View child = children.getChildAt(i);
1626                if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
1627                    if (child.includeForAccessibility()) {
1628                        childrenForAccessibility.add(child);
1629                    } else {
1630                        child.addChildrenForAccessibility(childrenForAccessibility);
1631                    }
1632                }
1633            }
1634        } finally {
1635            children.recycle();
1636        }
1637    }
1638
1639    /**
1640     * @hide
1641     */
1642    @Override
1643    public void childAccessibilityStateChanged(View child) {
1644        if (mParent != null) {
1645            mParent.childAccessibilityStateChanged(child);
1646        }
1647    }
1648
1649    /**
1650     * Implement this method to intercept hover events before they are handled
1651     * by child views.
1652     * <p>
1653     * This method is called before dispatching a hover event to a child of
1654     * the view group or to the view group's own {@link #onHoverEvent} to allow
1655     * the view group a chance to intercept the hover event.
1656     * This method can also be used to watch all pointer motions that occur within
1657     * the bounds of the view group even when the pointer is hovering over
1658     * a child of the view group rather than over the view group itself.
1659     * </p><p>
1660     * The view group can prevent its children from receiving hover events by
1661     * implementing this method and returning <code>true</code> to indicate
1662     * that it would like to intercept hover events.  The view group must
1663     * continuously return <code>true</code> from {@link #onInterceptHoverEvent}
1664     * for as long as it wishes to continue intercepting hover events from
1665     * its children.
1666     * </p><p>
1667     * Interception preserves the invariant that at most one view can be
1668     * hovered at a time by transferring hover focus from the currently hovered
1669     * child to the view group or vice-versa as needed.
1670     * </p><p>
1671     * If this method returns <code>true</code> and a child is already hovered, then the
1672     * child view will first receive a hover exit event and then the view group
1673     * itself will receive a hover enter event in {@link #onHoverEvent}.
1674     * Likewise, if this method had previously returned <code>true</code> to intercept hover
1675     * events and instead returns <code>false</code> while the pointer is hovering
1676     * within the bounds of one of a child, then the view group will first receive a
1677     * hover exit event in {@link #onHoverEvent} and then the hovered child will
1678     * receive a hover enter event.
1679     * </p><p>
1680     * The default implementation always returns false.
1681     * </p>
1682     *
1683     * @param event The motion event that describes the hover.
1684     * @return True if the view group would like to intercept the hover event
1685     * and prevent its children from receiving it.
1686     */
1687    public boolean onInterceptHoverEvent(MotionEvent event) {
1688        return false;
1689    }
1690
1691    private static MotionEvent obtainMotionEventNoHistoryOrSelf(MotionEvent event) {
1692        if (event.getHistorySize() == 0) {
1693            return event;
1694        }
1695        return MotionEvent.obtainNoHistory(event);
1696    }
1697
1698    /**
1699     * {@inheritDoc}
1700     */
1701    @Override
1702    protected boolean dispatchGenericPointerEvent(MotionEvent event) {
1703        // Send the event to the child under the pointer.
1704        final int childrenCount = mChildrenCount;
1705        if (childrenCount != 0) {
1706            final View[] children = mChildren;
1707            final float x = event.getX();
1708            final float y = event.getY();
1709
1710            for (int i = childrenCount - 1; i >= 0; i--) {
1711                final View child = children[i];
1712                if (!canViewReceivePointerEvents(child)
1713                        || !isTransformedTouchPointInView(x, y, child, null)) {
1714                    continue;
1715                }
1716
1717                if (dispatchTransformedGenericPointerEvent(event, child)) {
1718                    return true;
1719                }
1720            }
1721        }
1722
1723        // No child handled the event.  Send it to this view group.
1724        return super.dispatchGenericPointerEvent(event);
1725    }
1726
1727    /**
1728     * {@inheritDoc}
1729     */
1730    @Override
1731    protected boolean dispatchGenericFocusedEvent(MotionEvent event) {
1732        // Send the event to the focused child or to this view group if it has focus.
1733        if ((mPrivateFlags & (FOCUSED | HAS_BOUNDS)) == (FOCUSED | HAS_BOUNDS)) {
1734            return super.dispatchGenericFocusedEvent(event);
1735        } else if (mFocused != null && (mFocused.mPrivateFlags & HAS_BOUNDS) == HAS_BOUNDS) {
1736            return mFocused.dispatchGenericMotionEvent(event);
1737        }
1738        return false;
1739    }
1740
1741    /**
1742     * Dispatches a generic pointer event to a child, taking into account
1743     * transformations that apply to the child.
1744     *
1745     * @param event The event to send.
1746     * @param child The view to send the event to.
1747     * @return {@code true} if the child handled the event.
1748     */
1749    private boolean dispatchTransformedGenericPointerEvent(MotionEvent event, View child) {
1750        final float offsetX = mScrollX - child.mLeft;
1751        final float offsetY = mScrollY - child.mTop;
1752
1753        boolean handled;
1754        if (!child.hasIdentityMatrix()) {
1755            MotionEvent transformedEvent = MotionEvent.obtain(event);
1756            transformedEvent.offsetLocation(offsetX, offsetY);
1757            transformedEvent.transform(child.getInverseMatrix());
1758            handled = child.dispatchGenericMotionEvent(transformedEvent);
1759            transformedEvent.recycle();
1760        } else {
1761            event.offsetLocation(offsetX, offsetY);
1762            handled = child.dispatchGenericMotionEvent(event);
1763            event.offsetLocation(-offsetX, -offsetY);
1764        }
1765        return handled;
1766    }
1767
1768    /**
1769     * {@inheritDoc}
1770     */
1771    @Override
1772    public boolean dispatchTouchEvent(MotionEvent ev) {
1773        if (mInputEventConsistencyVerifier != null) {
1774            mInputEventConsistencyVerifier.onTouchEvent(ev, 1);
1775        }
1776
1777        boolean handled = false;
1778        if (onFilterTouchEventForSecurity(ev)) {
1779            final int action = ev.getAction();
1780            final int actionMasked = action & MotionEvent.ACTION_MASK;
1781
1782            // Handle an initial down.
1783            if (actionMasked == MotionEvent.ACTION_DOWN) {
1784                // Throw away all previous state when starting a new touch gesture.
1785                // The framework may have dropped the up or cancel event for the previous gesture
1786                // due to an app switch, ANR, or some other state change.
1787                cancelAndClearTouchTargets(ev);
1788                resetTouchState();
1789            }
1790
1791            // Check for interception.
1792            final boolean intercepted;
1793            if (actionMasked == MotionEvent.ACTION_DOWN
1794                    || mFirstTouchTarget != null) {
1795                final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
1796                if (!disallowIntercept) {
1797                    intercepted = onInterceptTouchEvent(ev);
1798                    ev.setAction(action); // restore action in case it was changed
1799                } else {
1800                    intercepted = false;
1801                }
1802            } else {
1803                // There are no touch targets and this action is not an initial down
1804                // so this view group continues to intercept touches.
1805                intercepted = true;
1806            }
1807
1808            // Check for cancelation.
1809            final boolean canceled = resetCancelNextUpFlag(this)
1810                    || actionMasked == MotionEvent.ACTION_CANCEL;
1811
1812            // Update list of touch targets for pointer down, if needed.
1813            final boolean split = (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) != 0;
1814            TouchTarget newTouchTarget = null;
1815            boolean alreadyDispatchedToNewTouchTarget = false;
1816            if (!canceled && !intercepted) {
1817                if (actionMasked == MotionEvent.ACTION_DOWN
1818                        || (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN)
1819                        || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
1820                    final int actionIndex = ev.getActionIndex(); // always 0 for down
1821                    final int idBitsToAssign = split ? 1 << ev.getPointerId(actionIndex)
1822                            : TouchTarget.ALL_POINTER_IDS;
1823
1824                    // Clean up earlier touch targets for this pointer id in case they
1825                    // have become out of sync.
1826                    removePointersFromTouchTargets(idBitsToAssign);
1827
1828                    final int childrenCount = mChildrenCount;
1829                    if (childrenCount != 0) {
1830                        // Find a child that can receive the event.
1831                        // Scan children from front to back.
1832                        final View[] children = mChildren;
1833                        final float x = ev.getX(actionIndex);
1834                        final float y = ev.getY(actionIndex);
1835
1836                        for (int i = childrenCount - 1; i >= 0; i--) {
1837                            final View child = children[i];
1838                            if (!canViewReceivePointerEvents(child)
1839                                    || !isTransformedTouchPointInView(x, y, child, null)) {
1840                                continue;
1841                            }
1842
1843                            newTouchTarget = getTouchTarget(child);
1844                            if (newTouchTarget != null) {
1845                                // Child is already receiving touch within its bounds.
1846                                // Give it the new pointer in addition to the ones it is handling.
1847                                newTouchTarget.pointerIdBits |= idBitsToAssign;
1848                                break;
1849                            }
1850
1851                            resetCancelNextUpFlag(child);
1852                            if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
1853                                // Child wants to receive touch within its bounds.
1854                                mLastTouchDownTime = ev.getDownTime();
1855                                mLastTouchDownIndex = i;
1856                                mLastTouchDownX = ev.getX();
1857                                mLastTouchDownY = ev.getY();
1858                                newTouchTarget = addTouchTarget(child, idBitsToAssign);
1859                                alreadyDispatchedToNewTouchTarget = true;
1860                                break;
1861                            }
1862                        }
1863                    }
1864
1865                    if (newTouchTarget == null && mFirstTouchTarget != null) {
1866                        // Did not find a child to receive the event.
1867                        // Assign the pointer to the least recently added target.
1868                        newTouchTarget = mFirstTouchTarget;
1869                        while (newTouchTarget.next != null) {
1870                            newTouchTarget = newTouchTarget.next;
1871                        }
1872                        newTouchTarget.pointerIdBits |= idBitsToAssign;
1873                    }
1874                }
1875            }
1876
1877            // Dispatch to touch targets.
1878            if (mFirstTouchTarget == null) {
1879                // No touch targets so treat this as an ordinary view.
1880                handled = dispatchTransformedTouchEvent(ev, canceled, null,
1881                        TouchTarget.ALL_POINTER_IDS);
1882            } else {
1883                // Dispatch to touch targets, excluding the new touch target if we already
1884                // dispatched to it.  Cancel touch targets if necessary.
1885                TouchTarget predecessor = null;
1886                TouchTarget target = mFirstTouchTarget;
1887                while (target != null) {
1888                    final TouchTarget next = target.next;
1889                    if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) {
1890                        handled = true;
1891                    } else {
1892                        final boolean cancelChild = resetCancelNextUpFlag(target.child)
1893                        || intercepted;
1894                        if (dispatchTransformedTouchEvent(ev, cancelChild,
1895                                target.child, target.pointerIdBits)) {
1896                            handled = true;
1897                        }
1898                        if (cancelChild) {
1899                            if (predecessor == null) {
1900                                mFirstTouchTarget = next;
1901                            } else {
1902                                predecessor.next = next;
1903                            }
1904                            target.recycle();
1905                            target = next;
1906                            continue;
1907                        }
1908                    }
1909                    predecessor = target;
1910                    target = next;
1911                }
1912            }
1913
1914            // Update list of touch targets for pointer up or cancel, if needed.
1915            if (canceled
1916                    || actionMasked == MotionEvent.ACTION_UP
1917                    || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
1918                resetTouchState();
1919            } else if (split && actionMasked == MotionEvent.ACTION_POINTER_UP) {
1920                final int actionIndex = ev.getActionIndex();
1921                final int idBitsToRemove = 1 << ev.getPointerId(actionIndex);
1922                removePointersFromTouchTargets(idBitsToRemove);
1923            }
1924        }
1925
1926        if (!handled && mInputEventConsistencyVerifier != null) {
1927            mInputEventConsistencyVerifier.onUnhandledEvent(ev, 1);
1928        }
1929        return handled;
1930    }
1931
1932    /**
1933     * Resets all touch state in preparation for a new cycle.
1934     */
1935    private void resetTouchState() {
1936        clearTouchTargets();
1937        resetCancelNextUpFlag(this);
1938        mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
1939    }
1940
1941    /**
1942     * Resets the cancel next up flag.
1943     * Returns true if the flag was previously set.
1944     */
1945    private static boolean resetCancelNextUpFlag(View view) {
1946        if ((view.mPrivateFlags & CANCEL_NEXT_UP_EVENT) != 0) {
1947            view.mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT;
1948            return true;
1949        }
1950        return false;
1951    }
1952
1953    /**
1954     * Clears all touch targets.
1955     */
1956    private void clearTouchTargets() {
1957        TouchTarget target = mFirstTouchTarget;
1958        if (target != null) {
1959            do {
1960                TouchTarget next = target.next;
1961                target.recycle();
1962                target = next;
1963            } while (target != null);
1964            mFirstTouchTarget = null;
1965        }
1966    }
1967
1968    /**
1969     * Cancels and clears all touch targets.
1970     */
1971    private void cancelAndClearTouchTargets(MotionEvent event) {
1972        if (mFirstTouchTarget != null) {
1973            boolean syntheticEvent = false;
1974            if (event == null) {
1975                final long now = SystemClock.uptimeMillis();
1976                event = MotionEvent.obtain(now, now,
1977                        MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
1978                event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
1979                syntheticEvent = true;
1980            }
1981
1982            for (TouchTarget target = mFirstTouchTarget; target != null; target = target.next) {
1983                resetCancelNextUpFlag(target.child);
1984                dispatchTransformedTouchEvent(event, true, target.child, target.pointerIdBits);
1985            }
1986            clearTouchTargets();
1987
1988            if (syntheticEvent) {
1989                event.recycle();
1990            }
1991        }
1992    }
1993
1994    /**
1995     * Gets the touch target for specified child view.
1996     * Returns null if not found.
1997     */
1998    private TouchTarget getTouchTarget(View child) {
1999        for (TouchTarget target = mFirstTouchTarget; target != null; target = target.next) {
2000            if (target.child == child) {
2001                return target;
2002            }
2003        }
2004        return null;
2005    }
2006
2007    /**
2008     * Adds a touch target for specified child to the beginning of the list.
2009     * Assumes the target child is not already present.
2010     */
2011    private TouchTarget addTouchTarget(View child, int pointerIdBits) {
2012        TouchTarget target = TouchTarget.obtain(child, pointerIdBits);
2013        target.next = mFirstTouchTarget;
2014        mFirstTouchTarget = target;
2015        return target;
2016    }
2017
2018    /**
2019     * Removes the pointer ids from consideration.
2020     */
2021    private void removePointersFromTouchTargets(int pointerIdBits) {
2022        TouchTarget predecessor = null;
2023        TouchTarget target = mFirstTouchTarget;
2024        while (target != null) {
2025            final TouchTarget next = target.next;
2026            if ((target.pointerIdBits & pointerIdBits) != 0) {
2027                target.pointerIdBits &= ~pointerIdBits;
2028                if (target.pointerIdBits == 0) {
2029                    if (predecessor == null) {
2030                        mFirstTouchTarget = next;
2031                    } else {
2032                        predecessor.next = next;
2033                    }
2034                    target.recycle();
2035                    target = next;
2036                    continue;
2037                }
2038            }
2039            predecessor = target;
2040            target = next;
2041        }
2042    }
2043
2044    private void cancelTouchTarget(View view) {
2045        TouchTarget predecessor = null;
2046        TouchTarget target = mFirstTouchTarget;
2047        while (target != null) {
2048            final TouchTarget next = target.next;
2049            if (target.child == view) {
2050                if (predecessor == null) {
2051                    mFirstTouchTarget = next;
2052                } else {
2053                    predecessor.next = next;
2054                }
2055                target.recycle();
2056
2057                final long now = SystemClock.uptimeMillis();
2058                MotionEvent event = MotionEvent.obtain(now, now,
2059                        MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
2060                event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
2061                view.dispatchTouchEvent(event);
2062                event.recycle();
2063                return;
2064            }
2065            predecessor = target;
2066            target = next;
2067        }
2068    }
2069
2070    /**
2071     * Returns true if a child view can receive pointer events.
2072     * @hide
2073     */
2074    private static boolean canViewReceivePointerEvents(View child) {
2075        return (child.mViewFlags & VISIBILITY_MASK) == VISIBLE
2076                || child.getAnimation() != null;
2077    }
2078
2079    /**
2080     * Returns true if a child view contains the specified point when transformed
2081     * into its coordinate space.
2082     * Child must not be null.
2083     * @hide
2084     */
2085    protected boolean isTransformedTouchPointInView(float x, float y, View child,
2086            PointF outLocalPoint) {
2087        float localX = x + mScrollX - child.mLeft;
2088        float localY = y + mScrollY - child.mTop;
2089        if (! child.hasIdentityMatrix() && mAttachInfo != null) {
2090            final float[] localXY = mAttachInfo.mTmpTransformLocation;
2091            localXY[0] = localX;
2092            localXY[1] = localY;
2093            child.getInverseMatrix().mapPoints(localXY);
2094            localX = localXY[0];
2095            localY = localXY[1];
2096        }
2097        final boolean isInView = child.pointInView(localX, localY);
2098        if (isInView && outLocalPoint != null) {
2099            outLocalPoint.set(localX, localY);
2100        }
2101        return isInView;
2102    }
2103
2104    /**
2105     * Transforms a motion event into the coordinate space of a particular child view,
2106     * filters out irrelevant pointer ids, and overrides its action if necessary.
2107     * If child is null, assumes the MotionEvent will be sent to this ViewGroup instead.
2108     */
2109    private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,
2110            View child, int desiredPointerIdBits) {
2111        final boolean handled;
2112
2113        // Canceling motions is a special case.  We don't need to perform any transformations
2114        // or filtering.  The important part is the action, not the contents.
2115        final int oldAction = event.getAction();
2116        if (cancel || oldAction == MotionEvent.ACTION_CANCEL) {
2117            event.setAction(MotionEvent.ACTION_CANCEL);
2118            if (child == null) {
2119                handled = super.dispatchTouchEvent(event);
2120            } else {
2121                handled = child.dispatchTouchEvent(event);
2122            }
2123            event.setAction(oldAction);
2124            return handled;
2125        }
2126
2127        // Calculate the number of pointers to deliver.
2128        final int oldPointerIdBits = event.getPointerIdBits();
2129        final int newPointerIdBits = oldPointerIdBits & desiredPointerIdBits;
2130
2131        // If for some reason we ended up in an inconsistent state where it looks like we
2132        // might produce a motion event with no pointers in it, then drop the event.
2133        if (newPointerIdBits == 0) {
2134            return false;
2135        }
2136
2137        // If the number of pointers is the same and we don't need to perform any fancy
2138        // irreversible transformations, then we can reuse the motion event for this
2139        // dispatch as long as we are careful to revert any changes we make.
2140        // Otherwise we need to make a copy.
2141        final MotionEvent transformedEvent;
2142        if (newPointerIdBits == oldPointerIdBits) {
2143            if (child == null || child.hasIdentityMatrix()) {
2144                if (child == null) {
2145                    handled = super.dispatchTouchEvent(event);
2146                } else {
2147                    final float offsetX = mScrollX - child.mLeft;
2148                    final float offsetY = mScrollY - child.mTop;
2149                    event.offsetLocation(offsetX, offsetY);
2150
2151                    handled = child.dispatchTouchEvent(event);
2152
2153                    event.offsetLocation(-offsetX, -offsetY);
2154                }
2155                return handled;
2156            }
2157            transformedEvent = MotionEvent.obtain(event);
2158        } else {
2159            transformedEvent = event.split(newPointerIdBits);
2160        }
2161
2162        // Perform any necessary transformations and dispatch.
2163        if (child == null) {
2164            handled = super.dispatchTouchEvent(transformedEvent);
2165        } else {
2166            final float offsetX = mScrollX - child.mLeft;
2167            final float offsetY = mScrollY - child.mTop;
2168            transformedEvent.offsetLocation(offsetX, offsetY);
2169            if (! child.hasIdentityMatrix()) {
2170                transformedEvent.transform(child.getInverseMatrix());
2171            }
2172
2173            handled = child.dispatchTouchEvent(transformedEvent);
2174        }
2175
2176        // Done.
2177        transformedEvent.recycle();
2178        return handled;
2179    }
2180
2181    /**
2182     * Enable or disable the splitting of MotionEvents to multiple children during touch event
2183     * dispatch. This behavior is enabled by default for applications that target an
2184     * SDK version of {@link Build.VERSION_CODES#HONEYCOMB} or newer.
2185     *
2186     * <p>When this option is enabled MotionEvents may be split and dispatched to different child
2187     * views depending on where each pointer initially went down. This allows for user interactions
2188     * such as scrolling two panes of content independently, chording of buttons, and performing
2189     * independent gestures on different pieces of content.
2190     *
2191     * @param split <code>true</code> to allow MotionEvents to be split and dispatched to multiple
2192     *              child views. <code>false</code> to only allow one child view to be the target of
2193     *              any MotionEvent received by this ViewGroup.
2194     */
2195    public void setMotionEventSplittingEnabled(boolean split) {
2196        // TODO Applications really shouldn't change this setting mid-touch event,
2197        // but perhaps this should handle that case and send ACTION_CANCELs to any child views
2198        // with gestures in progress when this is changed.
2199        if (split) {
2200            mGroupFlags |= FLAG_SPLIT_MOTION_EVENTS;
2201        } else {
2202            mGroupFlags &= ~FLAG_SPLIT_MOTION_EVENTS;
2203        }
2204    }
2205
2206    /**
2207     * Returns true if MotionEvents dispatched to this ViewGroup can be split to multiple children.
2208     * @return true if MotionEvents dispatched to this ViewGroup can be split to multiple children.
2209     */
2210    public boolean isMotionEventSplittingEnabled() {
2211        return (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) == FLAG_SPLIT_MOTION_EVENTS;
2212    }
2213
2214    /**
2215     * {@inheritDoc}
2216     */
2217    public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
2218
2219        if (disallowIntercept == ((mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0)) {
2220            // We're already in this state, assume our ancestors are too
2221            return;
2222        }
2223
2224        if (disallowIntercept) {
2225            mGroupFlags |= FLAG_DISALLOW_INTERCEPT;
2226        } else {
2227            mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
2228        }
2229
2230        // Pass it up to our parent
2231        if (mParent != null) {
2232            mParent.requestDisallowInterceptTouchEvent(disallowIntercept);
2233        }
2234    }
2235
2236    /**
2237     * Implement this method to intercept all touch screen motion events.  This
2238     * allows you to watch events as they are dispatched to your children, and
2239     * take ownership of the current gesture at any point.
2240     *
2241     * <p>Using this function takes some care, as it has a fairly complicated
2242     * interaction with {@link View#onTouchEvent(MotionEvent)
2243     * View.onTouchEvent(MotionEvent)}, and using it requires implementing
2244     * that method as well as this one in the correct way.  Events will be
2245     * received in the following order:
2246     *
2247     * <ol>
2248     * <li> You will receive the down event here.
2249     * <li> The down event will be handled either by a child of this view
2250     * group, or given to your own onTouchEvent() method to handle; this means
2251     * you should implement onTouchEvent() to return true, so you will
2252     * continue to see the rest of the gesture (instead of looking for
2253     * a parent view to handle it).  Also, by returning true from
2254     * onTouchEvent(), you will not receive any following
2255     * events in onInterceptTouchEvent() and all touch processing must
2256     * happen in onTouchEvent() like normal.
2257     * <li> For as long as you return false from this function, each following
2258     * event (up to and including the final up) will be delivered first here
2259     * and then to the target's onTouchEvent().
2260     * <li> If you return true from here, you will not receive any
2261     * following events: the target view will receive the same event but
2262     * with the action {@link MotionEvent#ACTION_CANCEL}, and all further
2263     * events will be delivered to your onTouchEvent() method and no longer
2264     * appear here.
2265     * </ol>
2266     *
2267     * @param ev The motion event being dispatched down the hierarchy.
2268     * @return Return true to steal motion events from the children and have
2269     * them dispatched to this ViewGroup through onTouchEvent().
2270     * The current target will receive an ACTION_CANCEL event, and no further
2271     * messages will be delivered here.
2272     */
2273    public boolean onInterceptTouchEvent(MotionEvent ev) {
2274        return false;
2275    }
2276
2277    /**
2278     * {@inheritDoc}
2279     *
2280     * Looks for a view to give focus to respecting the setting specified by
2281     * {@link #getDescendantFocusability()}.
2282     *
2283     * Uses {@link #onRequestFocusInDescendants(int, android.graphics.Rect)} to
2284     * find focus within the children of this group when appropriate.
2285     *
2286     * @see #FOCUS_BEFORE_DESCENDANTS
2287     * @see #FOCUS_AFTER_DESCENDANTS
2288     * @see #FOCUS_BLOCK_DESCENDANTS
2289     * @see #onRequestFocusInDescendants(int, android.graphics.Rect)
2290     */
2291    @Override
2292    public boolean requestFocus(int direction, Rect previouslyFocusedRect) {
2293        if (DBG) {
2294            System.out.println(this + " ViewGroup.requestFocus direction="
2295                    + direction);
2296        }
2297        int descendantFocusability = getDescendantFocusability();
2298
2299        switch (descendantFocusability) {
2300            case FOCUS_BLOCK_DESCENDANTS:
2301                return super.requestFocus(direction, previouslyFocusedRect);
2302            case FOCUS_BEFORE_DESCENDANTS: {
2303                final boolean took = super.requestFocus(direction, previouslyFocusedRect);
2304                return took ? took : onRequestFocusInDescendants(direction, previouslyFocusedRect);
2305            }
2306            case FOCUS_AFTER_DESCENDANTS: {
2307                final boolean took = onRequestFocusInDescendants(direction, previouslyFocusedRect);
2308                return took ? took : super.requestFocus(direction, previouslyFocusedRect);
2309            }
2310            default:
2311                throw new IllegalStateException("descendant focusability must be "
2312                        + "one of FOCUS_BEFORE_DESCENDANTS, FOCUS_AFTER_DESCENDANTS, FOCUS_BLOCK_DESCENDANTS "
2313                        + "but is " + descendantFocusability);
2314        }
2315    }
2316
2317    /**
2318     * Look for a descendant to call {@link View#requestFocus} on.
2319     * Called by {@link ViewGroup#requestFocus(int, android.graphics.Rect)}
2320     * when it wants to request focus within its children.  Override this to
2321     * customize how your {@link ViewGroup} requests focus within its children.
2322     * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT
2323     * @param previouslyFocusedRect The rectangle (in this View's coordinate system)
2324     *        to give a finer grained hint about where focus is coming from.  May be null
2325     *        if there is no hint.
2326     * @return Whether focus was taken.
2327     */
2328    @SuppressWarnings({"ConstantConditions"})
2329    protected boolean onRequestFocusInDescendants(int direction,
2330            Rect previouslyFocusedRect) {
2331        int index;
2332        int increment;
2333        int end;
2334        int count = mChildrenCount;
2335        if ((direction & FOCUS_FORWARD) != 0) {
2336            index = 0;
2337            increment = 1;
2338            end = count;
2339        } else {
2340            index = count - 1;
2341            increment = -1;
2342            end = -1;
2343        }
2344        final View[] children = mChildren;
2345        for (int i = index; i != end; i += increment) {
2346            View child = children[i];
2347            if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
2348                if (child.requestFocus(direction, previouslyFocusedRect)) {
2349                    return true;
2350                }
2351            }
2352        }
2353        return false;
2354    }
2355
2356    /**
2357     * {@inheritDoc}
2358     *
2359     * @hide
2360     */
2361    @Override
2362    public void dispatchStartTemporaryDetach() {
2363        super.dispatchStartTemporaryDetach();
2364        final int count = mChildrenCount;
2365        final View[] children = mChildren;
2366        for (int i = 0; i < count; i++) {
2367            children[i].dispatchStartTemporaryDetach();
2368        }
2369    }
2370
2371    /**
2372     * {@inheritDoc}
2373     *
2374     * @hide
2375     */
2376    @Override
2377    public void dispatchFinishTemporaryDetach() {
2378        super.dispatchFinishTemporaryDetach();
2379        final int count = mChildrenCount;
2380        final View[] children = mChildren;
2381        for (int i = 0; i < count; i++) {
2382            children[i].dispatchFinishTemporaryDetach();
2383        }
2384    }
2385
2386    /**
2387     * {@inheritDoc}
2388     */
2389    @Override
2390    void dispatchAttachedToWindow(AttachInfo info, int visibility) {
2391        mGroupFlags |= FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW;
2392        super.dispatchAttachedToWindow(info, visibility);
2393        mGroupFlags &= ~FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW;
2394
2395        final int count = mChildrenCount;
2396        final View[] children = mChildren;
2397        for (int i = 0; i < count; i++) {
2398            final View child = children[i];
2399            child.dispatchAttachedToWindow(info,
2400                    visibility | (child.mViewFlags&VISIBILITY_MASK));
2401        }
2402    }
2403
2404    @Override
2405    void dispatchScreenStateChanged(int screenState) {
2406        super.dispatchScreenStateChanged(screenState);
2407
2408        final int count = mChildrenCount;
2409        final View[] children = mChildren;
2410        for (int i = 0; i < count; i++) {
2411            children[i].dispatchScreenStateChanged(screenState);
2412        }
2413    }
2414
2415    @Override
2416    boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) {
2417        boolean handled = false;
2418        if (includeForAccessibility()) {
2419            handled = super.dispatchPopulateAccessibilityEventInternal(event);
2420            if (handled) {
2421                return handled;
2422            }
2423        }
2424        // Let our children have a shot in populating the event.
2425        ChildListForAccessibility children = ChildListForAccessibility.obtain(this, true);
2426        try {
2427            final int childCount = children.getChildCount();
2428            for (int i = 0; i < childCount; i++) {
2429                View child = children.getChildAt(i);
2430                if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
2431                    handled = child.dispatchPopulateAccessibilityEvent(event);
2432                    if (handled) {
2433                        return handled;
2434                    }
2435                }
2436            }
2437        } finally {
2438            children.recycle();
2439        }
2440        return false;
2441    }
2442
2443    @Override
2444    void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
2445        super.onInitializeAccessibilityNodeInfoInternal(info);
2446        if (mAttachInfo != null) {
2447            ArrayList<View> childrenForAccessibility = mAttachInfo.mTempArrayList;
2448            childrenForAccessibility.clear();
2449            addChildrenForAccessibility(childrenForAccessibility);
2450            final int childrenForAccessibilityCount = childrenForAccessibility.size();
2451            for (int i = 0; i < childrenForAccessibilityCount; i++) {
2452                View child = childrenForAccessibility.get(i);
2453                info.addChild(child);
2454            }
2455            childrenForAccessibility.clear();
2456        }
2457    }
2458
2459    @Override
2460    void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
2461        super.onInitializeAccessibilityEventInternal(event);
2462        event.setClassName(ViewGroup.class.getName());
2463    }
2464
2465    /**
2466     * @hide
2467     */
2468    @Override
2469    public void resetAccessibilityStateChanged() {
2470        super.resetAccessibilityStateChanged();
2471        View[] children = mChildren;
2472        final int childCount = mChildrenCount;
2473        for (int i = 0; i < childCount; i++) {
2474            View child = children[i];
2475            child.resetAccessibilityStateChanged();
2476        }
2477    }
2478
2479    /**
2480     * {@inheritDoc}
2481     */
2482    @Override
2483    void dispatchDetachedFromWindow() {
2484        // If we still have a touch target, we are still in the process of
2485        // dispatching motion events to a child; we need to get rid of that
2486        // child to avoid dispatching events to it after the window is torn
2487        // down. To make sure we keep the child in a consistent state, we
2488        // first send it an ACTION_CANCEL motion event.
2489        cancelAndClearTouchTargets(null);
2490
2491        // Similarly, set ACTION_EXIT to all hover targets and clear them.
2492        exitHoverTargets();
2493
2494        // In case view is detached while transition is running
2495        mLayoutSuppressed = false;
2496
2497        // Tear down our drag tracking
2498        mDragNotifiedChildren = null;
2499        if (mCurrentDrag != null) {
2500            mCurrentDrag.recycle();
2501            mCurrentDrag = null;
2502        }
2503
2504        final int count = mChildrenCount;
2505        final View[] children = mChildren;
2506        for (int i = 0; i < count; i++) {
2507            children[i].dispatchDetachedFromWindow();
2508        }
2509        super.dispatchDetachedFromWindow();
2510    }
2511
2512    /**
2513     * {@inheritDoc}
2514     */
2515    @Override
2516    public void setPadding(int left, int top, int right, int bottom) {
2517        super.setPadding(left, top, right, bottom);
2518
2519        if ((mPaddingLeft | mPaddingTop | mPaddingRight | mPaddingBottom) != 0) {
2520            mGroupFlags |= FLAG_PADDING_NOT_NULL;
2521        } else {
2522            mGroupFlags &= ~FLAG_PADDING_NOT_NULL;
2523        }
2524    }
2525
2526    /**
2527     * {@inheritDoc}
2528     */
2529    @Override
2530    protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {
2531        super.dispatchSaveInstanceState(container);
2532        final int count = mChildrenCount;
2533        final View[] children = mChildren;
2534        for (int i = 0; i < count; i++) {
2535            View c = children[i];
2536            if ((c.mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED) {
2537                c.dispatchSaveInstanceState(container);
2538            }
2539        }
2540    }
2541
2542    /**
2543     * Perform dispatching of a {@link #saveHierarchyState(android.util.SparseArray)}  freeze()}
2544     * to only this view, not to its children.  For use when overriding
2545     * {@link #dispatchSaveInstanceState(android.util.SparseArray)}  dispatchFreeze()} to allow
2546     * subclasses to freeze their own state but not the state of their children.
2547     *
2548     * @param container the container
2549     */
2550    protected void dispatchFreezeSelfOnly(SparseArray<Parcelable> container) {
2551        super.dispatchSaveInstanceState(container);
2552    }
2553
2554    /**
2555     * {@inheritDoc}
2556     */
2557    @Override
2558    protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {
2559        super.dispatchRestoreInstanceState(container);
2560        final int count = mChildrenCount;
2561        final View[] children = mChildren;
2562        for (int i = 0; i < count; i++) {
2563            View c = children[i];
2564            if ((c.mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED) {
2565                c.dispatchRestoreInstanceState(container);
2566            }
2567        }
2568    }
2569
2570    /**
2571     * Perform dispatching of a {@link #restoreHierarchyState(android.util.SparseArray)}
2572     * to only this view, not to its children.  For use when overriding
2573     * {@link #dispatchRestoreInstanceState(android.util.SparseArray)} to allow
2574     * subclasses to thaw their own state but not the state of their children.
2575     *
2576     * @param container the container
2577     */
2578    protected void dispatchThawSelfOnly(SparseArray<Parcelable> container) {
2579        super.dispatchRestoreInstanceState(container);
2580    }
2581
2582    /**
2583     * Enables or disables the drawing cache for each child of this view group.
2584     *
2585     * @param enabled true to enable the cache, false to dispose of it
2586     */
2587    protected void setChildrenDrawingCacheEnabled(boolean enabled) {
2588        if (enabled || (mPersistentDrawingCache & PERSISTENT_ALL_CACHES) != PERSISTENT_ALL_CACHES) {
2589            final View[] children = mChildren;
2590            final int count = mChildrenCount;
2591            for (int i = 0; i < count; i++) {
2592                children[i].setDrawingCacheEnabled(enabled);
2593            }
2594        }
2595    }
2596
2597    @Override
2598    protected void onAnimationStart() {
2599        super.onAnimationStart();
2600
2601        // When this ViewGroup's animation starts, build the cache for the children
2602        if ((mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE) {
2603            final int count = mChildrenCount;
2604            final View[] children = mChildren;
2605            final boolean buildCache = !isHardwareAccelerated();
2606
2607            for (int i = 0; i < count; i++) {
2608                final View child = children[i];
2609                if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
2610                    child.setDrawingCacheEnabled(true);
2611                    if (buildCache) {
2612                        child.buildDrawingCache(true);
2613                    }
2614                }
2615            }
2616
2617            mGroupFlags |= FLAG_CHILDREN_DRAWN_WITH_CACHE;
2618        }
2619    }
2620
2621    @Override
2622    protected void onAnimationEnd() {
2623        super.onAnimationEnd();
2624
2625        // When this ViewGroup's animation ends, destroy the cache of the children
2626        if ((mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE) {
2627            mGroupFlags &= ~FLAG_CHILDREN_DRAWN_WITH_CACHE;
2628
2629            if ((mPersistentDrawingCache & PERSISTENT_ANIMATION_CACHE) == 0) {
2630                setChildrenDrawingCacheEnabled(false);
2631            }
2632        }
2633    }
2634
2635    @Override
2636    Bitmap createSnapshot(Bitmap.Config quality, int backgroundColor, boolean skipChildren) {
2637        int count = mChildrenCount;
2638        int[] visibilities = null;
2639
2640        if (skipChildren) {
2641            visibilities = new int[count];
2642            for (int i = 0; i < count; i++) {
2643                View child = getChildAt(i);
2644                visibilities[i] = child.getVisibility();
2645                if (visibilities[i] == View.VISIBLE) {
2646                    child.setVisibility(INVISIBLE);
2647                }
2648            }
2649        }
2650
2651        Bitmap b = super.createSnapshot(quality, backgroundColor, skipChildren);
2652
2653        if (skipChildren) {
2654            for (int i = 0; i < count; i++) {
2655                getChildAt(i).setVisibility(visibilities[i]);
2656            }
2657        }
2658
2659        return b;
2660    }
2661
2662    private static void drawRect(Canvas canvas, int x1, int y1, int x2, int y2, int color) {
2663        Paint paint = getDebugPaint();
2664        paint.setColor(color);
2665
2666        canvas.drawLines(getDebugLines(x1, y1, x2, y2), paint);
2667    }
2668
2669    /**
2670     * @hide
2671     */
2672    protected void onDebugDrawMargins(Canvas canvas) {
2673        for (int i = 0; i < getChildCount(); i++) {
2674            View c = getChildAt(i);
2675            c.getLayoutParams().onDebugDraw(c, canvas);
2676        }
2677    }
2678
2679    /**
2680     * @hide
2681     */
2682    protected void onDebugDraw(Canvas canvas) {
2683        // Draw optical bounds
2684        if (getLayoutMode() == OPTICAL_BOUNDS) {
2685            for (int i = 0; i < getChildCount(); i++) {
2686                View c = getChildAt(i);
2687                Insets insets = c.getOpticalInsets();
2688                drawRect(canvas,
2689                        c.getLeft() + insets.left,
2690                        c.getTop() + insets.top,
2691                        c.getRight() - insets.right,
2692                        c.getBottom() - insets.bottom, Color.RED);
2693            }
2694        }
2695
2696        // Draw margins
2697        onDebugDrawMargins(canvas);
2698
2699        // Draw bounds
2700        for (int i = 0; i < getChildCount(); i++) {
2701            View c = getChildAt(i);
2702            drawRect(canvas, c.getLeft(), c.getTop(), c.getRight(), c.getBottom(), Color.BLUE);
2703        }
2704    }
2705
2706    /**
2707     * {@inheritDoc}
2708     */
2709    @Override
2710    protected void dispatchDraw(Canvas canvas) {
2711        final int count = mChildrenCount;
2712        final View[] children = mChildren;
2713        int flags = mGroupFlags;
2714
2715        if ((flags & FLAG_RUN_ANIMATION) != 0 && canAnimate()) {
2716            final boolean cache = (mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE;
2717
2718            final boolean buildCache = !isHardwareAccelerated();
2719            for (int i = 0; i < count; i++) {
2720                final View child = children[i];
2721                if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
2722                    final LayoutParams params = child.getLayoutParams();
2723                    attachLayoutAnimationParameters(child, params, i, count);
2724                    bindLayoutAnimation(child);
2725                    if (cache) {
2726                        child.setDrawingCacheEnabled(true);
2727                        if (buildCache) {
2728                            child.buildDrawingCache(true);
2729                        }
2730                    }
2731                }
2732            }
2733
2734            final LayoutAnimationController controller = mLayoutAnimationController;
2735            if (controller.willOverlap()) {
2736                mGroupFlags |= FLAG_OPTIMIZE_INVALIDATE;
2737            }
2738
2739            controller.start();
2740
2741            mGroupFlags &= ~FLAG_RUN_ANIMATION;
2742            mGroupFlags &= ~FLAG_ANIMATION_DONE;
2743
2744            if (cache) {
2745                mGroupFlags |= FLAG_CHILDREN_DRAWN_WITH_CACHE;
2746            }
2747
2748            if (mAnimationListener != null) {
2749                mAnimationListener.onAnimationStart(controller.getAnimation());
2750            }
2751        }
2752
2753        int saveCount = 0;
2754        final boolean clipToPadding = (flags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK;
2755        if (clipToPadding) {
2756            saveCount = canvas.save();
2757            canvas.clipRect(mScrollX + mPaddingLeft, mScrollY + mPaddingTop,
2758                    mScrollX + mRight - mLeft - mPaddingRight,
2759                    mScrollY + mBottom - mTop - mPaddingBottom);
2760
2761        }
2762
2763        // We will draw our child's animation, let's reset the flag
2764        mPrivateFlags &= ~DRAW_ANIMATION;
2765        mGroupFlags &= ~FLAG_INVALIDATE_REQUIRED;
2766
2767        boolean more = false;
2768        final long drawingTime = getDrawingTime();
2769
2770        if ((flags & FLAG_USE_CHILD_DRAWING_ORDER) == 0) {
2771            for (int i = 0; i < count; i++) {
2772                final View child = children[i];
2773                if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
2774                    more |= drawChild(canvas, child, drawingTime);
2775                }
2776            }
2777        } else {
2778            for (int i = 0; i < count; i++) {
2779                final View child = children[getChildDrawingOrder(count, i)];
2780                if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
2781                    more |= drawChild(canvas, child, drawingTime);
2782                }
2783            }
2784        }
2785
2786        // Draw any disappearing views that have animations
2787        if (mDisappearingChildren != null) {
2788            final ArrayList<View> disappearingChildren = mDisappearingChildren;
2789            final int disappearingCount = disappearingChildren.size() - 1;
2790            // Go backwards -- we may delete as animations finish
2791            for (int i = disappearingCount; i >= 0; i--) {
2792                final View child = disappearingChildren.get(i);
2793                more |= drawChild(canvas, child, drawingTime);
2794            }
2795        }
2796
2797        if (debugDraw()) {
2798            onDebugDraw(canvas);
2799        }
2800
2801        if (clipToPadding) {
2802            canvas.restoreToCount(saveCount);
2803        }
2804
2805        // mGroupFlags might have been updated by drawChild()
2806        flags = mGroupFlags;
2807
2808        if ((flags & FLAG_INVALIDATE_REQUIRED) == FLAG_INVALIDATE_REQUIRED) {
2809            invalidate(true);
2810        }
2811
2812        if ((flags & FLAG_ANIMATION_DONE) == 0 && (flags & FLAG_NOTIFY_ANIMATION_LISTENER) == 0 &&
2813                mLayoutAnimationController.isDone() && !more) {
2814            // We want to erase the drawing cache and notify the listener after the
2815            // next frame is drawn because one extra invalidate() is caused by
2816            // drawChild() after the animation is over
2817            mGroupFlags |= FLAG_NOTIFY_ANIMATION_LISTENER;
2818            final Runnable end = new Runnable() {
2819               public void run() {
2820                   notifyAnimationListener();
2821               }
2822            };
2823            post(end);
2824        }
2825    }
2826
2827    /**
2828     * Returns the index of the child to draw for this iteration. Override this
2829     * if you want to change the drawing order of children. By default, it
2830     * returns i.
2831     * <p>
2832     * NOTE: In order for this method to be called, you must enable child ordering
2833     * first by calling {@link #setChildrenDrawingOrderEnabled(boolean)}.
2834     *
2835     * @param i The current iteration.
2836     * @return The index of the child to draw this iteration.
2837     *
2838     * @see #setChildrenDrawingOrderEnabled(boolean)
2839     * @see #isChildrenDrawingOrderEnabled()
2840     */
2841    protected int getChildDrawingOrder(int childCount, int i) {
2842        return i;
2843    }
2844
2845    private void notifyAnimationListener() {
2846        mGroupFlags &= ~FLAG_NOTIFY_ANIMATION_LISTENER;
2847        mGroupFlags |= FLAG_ANIMATION_DONE;
2848
2849        if (mAnimationListener != null) {
2850           final Runnable end = new Runnable() {
2851               public void run() {
2852                   mAnimationListener.onAnimationEnd(mLayoutAnimationController.getAnimation());
2853               }
2854           };
2855           post(end);
2856        }
2857
2858        if ((mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE) {
2859            mGroupFlags &= ~FLAG_CHILDREN_DRAWN_WITH_CACHE;
2860            if ((mPersistentDrawingCache & PERSISTENT_ANIMATION_CACHE) == 0) {
2861                setChildrenDrawingCacheEnabled(false);
2862            }
2863        }
2864
2865        invalidate(true);
2866    }
2867
2868    /**
2869     * This method is used to cause children of this ViewGroup to restore or recreate their
2870     * display lists. It is called by getDisplayList() when the parent ViewGroup does not need
2871     * to recreate its own display list, which would happen if it went through the normal
2872     * draw/dispatchDraw mechanisms.
2873     *
2874     * @hide
2875     */
2876    @Override
2877    protected void dispatchGetDisplayList() {
2878        final int count = mChildrenCount;
2879        final View[] children = mChildren;
2880        for (int i = 0; i < count; i++) {
2881            final View child = children[i];
2882            if (((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) &&
2883                    child.hasStaticLayer()) {
2884                child.mRecreateDisplayList = (child.mPrivateFlags & INVALIDATED) == INVALIDATED;
2885                child.mPrivateFlags &= ~INVALIDATED;
2886                child.getDisplayList();
2887                child.mRecreateDisplayList = false;
2888            }
2889        }
2890    }
2891
2892    /**
2893     * Draw one child of this View Group. This method is responsible for getting
2894     * the canvas in the right state. This includes clipping, translating so
2895     * that the child's scrolled origin is at 0, 0, and applying any animation
2896     * transformations.
2897     *
2898     * @param canvas The canvas on which to draw the child
2899     * @param child Who to draw
2900     * @param drawingTime The time at which draw is occurring
2901     * @return True if an invalidate() was issued
2902     */
2903    protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
2904        return child.draw(canvas, this, drawingTime);
2905    }
2906
2907    /**
2908     * By default, children are clipped to their bounds before drawing. This
2909     * allows view groups to override this behavior for animations, etc.
2910     *
2911     * @param clipChildren true to clip children to their bounds,
2912     *        false otherwise
2913     * @attr ref android.R.styleable#ViewGroup_clipChildren
2914     */
2915    public void setClipChildren(boolean clipChildren) {
2916        boolean previousValue = (mGroupFlags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN;
2917        if (clipChildren != previousValue) {
2918            setBooleanFlag(FLAG_CLIP_CHILDREN, clipChildren);
2919            for (int i = 0; i < mChildrenCount; ++i) {
2920                View child = getChildAt(i);
2921                if (child.mDisplayList != null) {
2922                    child.mDisplayList.setClipChildren(clipChildren);
2923                }
2924            }
2925        }
2926    }
2927
2928    /**
2929     * By default, children are clipped to the padding of the ViewGroup. This
2930     * allows view groups to override this behavior
2931     *
2932     * @param clipToPadding true to clip children to the padding of the
2933     *        group, false otherwise
2934     * @attr ref android.R.styleable#ViewGroup_clipToPadding
2935     */
2936    public void setClipToPadding(boolean clipToPadding) {
2937        setBooleanFlag(FLAG_CLIP_TO_PADDING, clipToPadding);
2938    }
2939
2940    /**
2941     * {@inheritDoc}
2942     */
2943    @Override
2944    public void dispatchSetSelected(boolean selected) {
2945        final View[] children = mChildren;
2946        final int count = mChildrenCount;
2947        for (int i = 0; i < count; i++) {
2948            children[i].setSelected(selected);
2949        }
2950    }
2951
2952    /**
2953     * {@inheritDoc}
2954     */
2955    @Override
2956    public void dispatchSetActivated(boolean activated) {
2957        final View[] children = mChildren;
2958        final int count = mChildrenCount;
2959        for (int i = 0; i < count; i++) {
2960            children[i].setActivated(activated);
2961        }
2962    }
2963
2964    @Override
2965    protected void dispatchSetPressed(boolean pressed) {
2966        final View[] children = mChildren;
2967        final int count = mChildrenCount;
2968        for (int i = 0; i < count; i++) {
2969            final View child = children[i];
2970            // Children that are clickable on their own should not
2971            // show a pressed state when their parent view does.
2972            // Clearing a pressed state always propagates.
2973            if (!pressed || (!child.isClickable() && !child.isLongClickable())) {
2974                child.setPressed(pressed);
2975            }
2976        }
2977    }
2978
2979    /**
2980     * When this property is set to true, this ViewGroup supports static transformations on
2981     * children; this causes
2982     * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} to be
2983     * invoked when a child is drawn.
2984     *
2985     * Any subclass overriding
2986     * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} should
2987     * set this property to true.
2988     *
2989     * @param enabled True to enable static transformations on children, false otherwise.
2990     *
2991     * @see #getChildStaticTransformation(View, android.view.animation.Transformation)
2992     */
2993    protected void setStaticTransformationsEnabled(boolean enabled) {
2994        setBooleanFlag(FLAG_SUPPORT_STATIC_TRANSFORMATIONS, enabled);
2995    }
2996
2997    /**
2998     * Sets  <code>t</code> to be the static transformation of the child, if set, returning a
2999     * boolean to indicate whether a static transform was set. The default implementation
3000     * simply returns <code>false</code>; subclasses may override this method for different
3001     * behavior. {@link #setStaticTransformationsEnabled(boolean)} must be set to true
3002     * for this method to be called.
3003     *
3004     * @param child The child view whose static transform is being requested
3005     * @param t The Transformation which will hold the result
3006     * @return true if the transformation was set, false otherwise
3007     * @see #setStaticTransformationsEnabled(boolean)
3008     */
3009    protected boolean getChildStaticTransformation(View child, Transformation t) {
3010        return false;
3011    }
3012
3013    /**
3014     * {@hide}
3015     */
3016    @Override
3017    protected View findViewTraversal(int id) {
3018        if (id == mID) {
3019            return this;
3020        }
3021
3022        final View[] where = mChildren;
3023        final int len = mChildrenCount;
3024
3025        for (int i = 0; i < len; i++) {
3026            View v = where[i];
3027
3028            if ((v.mPrivateFlags & IS_ROOT_NAMESPACE) == 0) {
3029                v = v.findViewById(id);
3030
3031                if (v != null) {
3032                    return v;
3033                }
3034            }
3035        }
3036
3037        return null;
3038    }
3039
3040    /**
3041     * {@hide}
3042     */
3043    @Override
3044    protected View findViewWithTagTraversal(Object tag) {
3045        if (tag != null && tag.equals(mTag)) {
3046            return this;
3047        }
3048
3049        final View[] where = mChildren;
3050        final int len = mChildrenCount;
3051
3052        for (int i = 0; i < len; i++) {
3053            View v = where[i];
3054
3055            if ((v.mPrivateFlags & IS_ROOT_NAMESPACE) == 0) {
3056                v = v.findViewWithTag(tag);
3057
3058                if (v != null) {
3059                    return v;
3060                }
3061            }
3062        }
3063
3064        return null;
3065    }
3066
3067    /**
3068     * {@hide}
3069     */
3070    @Override
3071    protected View findViewByPredicateTraversal(Predicate<View> predicate, View childToSkip) {
3072        if (predicate.apply(this)) {
3073            return this;
3074        }
3075
3076        final View[] where = mChildren;
3077        final int len = mChildrenCount;
3078
3079        for (int i = 0; i < len; i++) {
3080            View v = where[i];
3081
3082            if (v != childToSkip && (v.mPrivateFlags & IS_ROOT_NAMESPACE) == 0) {
3083                v = v.findViewByPredicate(predicate);
3084
3085                if (v != null) {
3086                    return v;
3087                }
3088            }
3089        }
3090
3091        return null;
3092    }
3093
3094    /**
3095     * <p>Adds a child view. If no layout parameters are already set on the child, the
3096     * default parameters for this ViewGroup are set on the child.</p>
3097     *
3098     * <p><strong>Note:</strong> do not invoke this method from
3099     * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3100     * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
3101     *
3102     * @param child the child view to add
3103     *
3104     * @see #generateDefaultLayoutParams()
3105     */
3106    public void addView(View child) {
3107        addView(child, -1);
3108    }
3109
3110    /**
3111     * Adds a child view. If no layout parameters are already set on the child, the
3112     * default parameters for this ViewGroup are set on the child.
3113     *
3114     * <p><strong>Note:</strong> do not invoke this method from
3115     * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3116     * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
3117     *
3118     * @param child the child view to add
3119     * @param index the position at which to add the child
3120     *
3121     * @see #generateDefaultLayoutParams()
3122     */
3123    public void addView(View child, int index) {
3124        LayoutParams params = child.getLayoutParams();
3125        if (params == null) {
3126            params = generateDefaultLayoutParams();
3127            if (params == null) {
3128                throw new IllegalArgumentException("generateDefaultLayoutParams() cannot return null");
3129            }
3130        }
3131        addView(child, index, params);
3132    }
3133
3134    /**
3135     * Adds a child view with this ViewGroup's default layout parameters and the
3136     * specified width and height.
3137     *
3138     * <p><strong>Note:</strong> do not invoke this method from
3139     * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3140     * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
3141     *
3142     * @param child the child view to add
3143     */
3144    public void addView(View child, int width, int height) {
3145        final LayoutParams params = generateDefaultLayoutParams();
3146        params.width = width;
3147        params.height = height;
3148        addView(child, -1, params);
3149    }
3150
3151    /**
3152     * Adds a child view with the specified layout parameters.
3153     *
3154     * <p><strong>Note:</strong> do not invoke this method from
3155     * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3156     * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
3157     *
3158     * @param child the child view to add
3159     * @param params the layout parameters to set on the child
3160     */
3161    public void addView(View child, LayoutParams params) {
3162        addView(child, -1, params);
3163    }
3164
3165    /**
3166     * Adds a child view with the specified layout parameters.
3167     *
3168     * <p><strong>Note:</strong> do not invoke this method from
3169     * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3170     * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
3171     *
3172     * @param child the child view to add
3173     * @param index the position at which to add the child
3174     * @param params the layout parameters to set on the child
3175     */
3176    public void addView(View child, int index, LayoutParams params) {
3177        if (DBG) {
3178            System.out.println(this + " addView");
3179        }
3180
3181        // addViewInner() will call child.requestLayout() when setting the new LayoutParams
3182        // therefore, we call requestLayout() on ourselves before, so that the child's request
3183        // will be blocked at our level
3184        requestLayout();
3185        invalidate(true);
3186        addViewInner(child, index, params, false);
3187    }
3188
3189    /**
3190     * {@inheritDoc}
3191     */
3192    public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
3193        if (!checkLayoutParams(params)) {
3194            throw new IllegalArgumentException("Invalid LayoutParams supplied to " + this);
3195        }
3196        if (view.mParent != this) {
3197            throw new IllegalArgumentException("Given view not a child of " + this);
3198        }
3199        view.setLayoutParams(params);
3200    }
3201
3202    /**
3203     * {@inheritDoc}
3204     */
3205    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
3206        return  p != null;
3207    }
3208
3209    /**
3210     * Interface definition for a callback to be invoked when the hierarchy
3211     * within this view changed. The hierarchy changes whenever a child is added
3212     * to or removed from this view.
3213     */
3214    public interface OnHierarchyChangeListener {
3215        /**
3216         * Called when a new child is added to a parent view.
3217         *
3218         * @param parent the view in which a child was added
3219         * @param child the new child view added in the hierarchy
3220         */
3221        void onChildViewAdded(View parent, View child);
3222
3223        /**
3224         * Called when a child is removed from a parent view.
3225         *
3226         * @param parent the view from which the child was removed
3227         * @param child the child removed from the hierarchy
3228         */
3229        void onChildViewRemoved(View parent, View child);
3230    }
3231
3232    /**
3233     * Register a callback to be invoked when a child is added to or removed
3234     * from this view.
3235     *
3236     * @param listener the callback to invoke on hierarchy change
3237     */
3238    public void setOnHierarchyChangeListener(OnHierarchyChangeListener listener) {
3239        mOnHierarchyChangeListener = listener;
3240    }
3241
3242    /**
3243     * @hide
3244     */
3245    protected void onViewAdded(View child) {
3246        if (mOnHierarchyChangeListener != null) {
3247            mOnHierarchyChangeListener.onChildViewAdded(this, child);
3248        }
3249    }
3250
3251    /**
3252     * @hide
3253     */
3254    protected void onViewRemoved(View child) {
3255        if (mOnHierarchyChangeListener != null) {
3256            mOnHierarchyChangeListener.onChildViewRemoved(this, child);
3257        }
3258    }
3259
3260    /**
3261     * Adds a view during layout. This is useful if in your onLayout() method,
3262     * you need to add more views (as does the list view for example).
3263     *
3264     * If index is negative, it means put it at the end of the list.
3265     *
3266     * @param child the view to add to the group
3267     * @param index the index at which the child must be added
3268     * @param params the layout parameters to associate with the child
3269     * @return true if the child was added, false otherwise
3270     */
3271    protected boolean addViewInLayout(View child, int index, LayoutParams params) {
3272        return addViewInLayout(child, index, params, false);
3273    }
3274
3275    /**
3276     * Adds a view during layout. This is useful if in your onLayout() method,
3277     * you need to add more views (as does the list view for example).
3278     *
3279     * If index is negative, it means put it at the end of the list.
3280     *
3281     * @param child the view to add to the group
3282     * @param index the index at which the child must be added
3283     * @param params the layout parameters to associate with the child
3284     * @param preventRequestLayout if true, calling this method will not trigger a
3285     *        layout request on child
3286     * @return true if the child was added, false otherwise
3287     */
3288    protected boolean addViewInLayout(View child, int index, LayoutParams params,
3289            boolean preventRequestLayout) {
3290        child.mParent = null;
3291        addViewInner(child, index, params, preventRequestLayout);
3292        child.mPrivateFlags = (child.mPrivateFlags & ~DIRTY_MASK) | DRAWN;
3293        return true;
3294    }
3295
3296    /**
3297     * Prevents the specified child to be laid out during the next layout pass.
3298     *
3299     * @param child the child on which to perform the cleanup
3300     */
3301    protected void cleanupLayoutState(View child) {
3302        child.mPrivateFlags &= ~View.FORCE_LAYOUT;
3303    }
3304
3305    private void addViewInner(View child, int index, LayoutParams params,
3306            boolean preventRequestLayout) {
3307
3308        if (mTransition != null) {
3309            // Don't prevent other add transitions from completing, but cancel remove
3310            // transitions to let them complete the process before we add to the container
3311            mTransition.cancel(LayoutTransition.DISAPPEARING);
3312        }
3313
3314        if (child.getParent() != null) {
3315            throw new IllegalStateException("The specified child already has a parent. " +
3316                    "You must call removeView() on the child's parent first.");
3317        }
3318
3319        if (mTransition != null) {
3320            mTransition.addChild(this, child);
3321        }
3322
3323        if (!checkLayoutParams(params)) {
3324            params = generateLayoutParams(params);
3325        }
3326
3327        if (preventRequestLayout) {
3328            child.mLayoutParams = params;
3329        } else {
3330            child.setLayoutParams(params);
3331        }
3332
3333        if (index < 0) {
3334            index = mChildrenCount;
3335        }
3336
3337        addInArray(child, index);
3338
3339        // tell our children
3340        if (preventRequestLayout) {
3341            child.assignParent(this);
3342        } else {
3343            child.mParent = this;
3344        }
3345
3346        if (child.hasFocus()) {
3347            requestChildFocus(child, child.findFocus());
3348        }
3349
3350        AttachInfo ai = mAttachInfo;
3351        if (ai != null && (mGroupFlags & FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW) == 0) {
3352            boolean lastKeepOn = ai.mKeepScreenOn;
3353            ai.mKeepScreenOn = false;
3354            child.dispatchAttachedToWindow(mAttachInfo, (mViewFlags&VISIBILITY_MASK));
3355            if (ai.mKeepScreenOn) {
3356                needGlobalAttributesUpdate(true);
3357            }
3358            ai.mKeepScreenOn = lastKeepOn;
3359        }
3360
3361        onViewAdded(child);
3362
3363        if ((child.mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE) {
3364            mGroupFlags |= FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE;
3365        }
3366
3367        if (child.hasTransientState()) {
3368            childHasTransientStateChanged(child, true);
3369        }
3370    }
3371
3372    private void addInArray(View child, int index) {
3373        View[] children = mChildren;
3374        final int count = mChildrenCount;
3375        final int size = children.length;
3376        if (index == count) {
3377            if (size == count) {
3378                mChildren = new View[size + ARRAY_CAPACITY_INCREMENT];
3379                System.arraycopy(children, 0, mChildren, 0, size);
3380                children = mChildren;
3381            }
3382            children[mChildrenCount++] = child;
3383        } else if (index < count) {
3384            if (size == count) {
3385                mChildren = new View[size + ARRAY_CAPACITY_INCREMENT];
3386                System.arraycopy(children, 0, mChildren, 0, index);
3387                System.arraycopy(children, index, mChildren, index + 1, count - index);
3388                children = mChildren;
3389            } else {
3390                System.arraycopy(children, index, children, index + 1, count - index);
3391            }
3392            children[index] = child;
3393            mChildrenCount++;
3394            if (mLastTouchDownIndex >= index) {
3395                mLastTouchDownIndex++;
3396            }
3397        } else {
3398            throw new IndexOutOfBoundsException("index=" + index + " count=" + count);
3399        }
3400    }
3401
3402    // This method also sets the child's mParent to null
3403    private void removeFromArray(int index) {
3404        final View[] children = mChildren;
3405        if (!(mTransitioningViews != null && mTransitioningViews.contains(children[index]))) {
3406            children[index].mParent = null;
3407        }
3408        final int count = mChildrenCount;
3409        if (index == count - 1) {
3410            children[--mChildrenCount] = null;
3411        } else if (index >= 0 && index < count) {
3412            System.arraycopy(children, index + 1, children, index, count - index - 1);
3413            children[--mChildrenCount] = null;
3414        } else {
3415            throw new IndexOutOfBoundsException();
3416        }
3417        if (mLastTouchDownIndex == index) {
3418            mLastTouchDownTime = 0;
3419            mLastTouchDownIndex = -1;
3420        } else if (mLastTouchDownIndex > index) {
3421            mLastTouchDownIndex--;
3422        }
3423    }
3424
3425    // This method also sets the children's mParent to null
3426    private void removeFromArray(int start, int count) {
3427        final View[] children = mChildren;
3428        final int childrenCount = mChildrenCount;
3429
3430        start = Math.max(0, start);
3431        final int end = Math.min(childrenCount, start + count);
3432
3433        if (start == end) {
3434            return;
3435        }
3436
3437        if (end == childrenCount) {
3438            for (int i = start; i < end; i++) {
3439                children[i].mParent = null;
3440                children[i] = null;
3441            }
3442        } else {
3443            for (int i = start; i < end; i++) {
3444                children[i].mParent = null;
3445            }
3446
3447            // Since we're looping above, we might as well do the copy, but is arraycopy()
3448            // faster than the extra 2 bounds checks we would do in the loop?
3449            System.arraycopy(children, end, children, start, childrenCount - end);
3450
3451            for (int i = childrenCount - (end - start); i < childrenCount; i++) {
3452                children[i] = null;
3453            }
3454        }
3455
3456        mChildrenCount -= (end - start);
3457    }
3458
3459    private void bindLayoutAnimation(View child) {
3460        Animation a = mLayoutAnimationController.getAnimationForView(child);
3461        child.setAnimation(a);
3462    }
3463
3464    /**
3465     * Subclasses should override this method to set layout animation
3466     * parameters on the supplied child.
3467     *
3468     * @param child the child to associate with animation parameters
3469     * @param params the child's layout parameters which hold the animation
3470     *        parameters
3471     * @param index the index of the child in the view group
3472     * @param count the number of children in the view group
3473     */
3474    protected void attachLayoutAnimationParameters(View child,
3475            LayoutParams params, int index, int count) {
3476        LayoutAnimationController.AnimationParameters animationParams =
3477                    params.layoutAnimationParameters;
3478        if (animationParams == null) {
3479            animationParams = new LayoutAnimationController.AnimationParameters();
3480            params.layoutAnimationParameters = animationParams;
3481        }
3482
3483        animationParams.count = count;
3484        animationParams.index = index;
3485    }
3486
3487    /**
3488     * {@inheritDoc}
3489     *
3490     * <p><strong>Note:</strong> do not invoke this method from
3491     * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3492     * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
3493     */
3494    public void removeView(View view) {
3495        removeViewInternal(view);
3496        requestLayout();
3497        invalidate(true);
3498    }
3499
3500    /**
3501     * Removes a view during layout. This is useful if in your onLayout() method,
3502     * you need to remove more views.
3503     *
3504     * <p><strong>Note:</strong> do not invoke this method from
3505     * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3506     * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
3507     *
3508     * @param view the view to remove from the group
3509     */
3510    public void removeViewInLayout(View view) {
3511        removeViewInternal(view);
3512    }
3513
3514    /**
3515     * Removes a range of views during layout. This is useful if in your onLayout() method,
3516     * you need to remove more views.
3517     *
3518     * <p><strong>Note:</strong> do not invoke this method from
3519     * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3520     * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
3521     *
3522     * @param start the index of the first view to remove from the group
3523     * @param count the number of views to remove from the group
3524     */
3525    public void removeViewsInLayout(int start, int count) {
3526        removeViewsInternal(start, count);
3527    }
3528
3529    /**
3530     * Removes the view at the specified position in the group.
3531     *
3532     * <p><strong>Note:</strong> do not invoke this method from
3533     * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3534     * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
3535     *
3536     * @param index the position in the group of the view to remove
3537     */
3538    public void removeViewAt(int index) {
3539        removeViewInternal(index, getChildAt(index));
3540        requestLayout();
3541        invalidate(true);
3542    }
3543
3544    /**
3545     * Removes the specified range of views from the group.
3546     *
3547     * <p><strong>Note:</strong> do not invoke this method from
3548     * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3549     * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
3550     *
3551     * @param start the first position in the group of the range of views to remove
3552     * @param count the number of views to remove
3553     */
3554    public void removeViews(int start, int count) {
3555        removeViewsInternal(start, count);
3556        requestLayout();
3557        invalidate(true);
3558    }
3559
3560    private void removeViewInternal(View view) {
3561        final int index = indexOfChild(view);
3562        if (index >= 0) {
3563            removeViewInternal(index, view);
3564        }
3565    }
3566
3567    private void removeViewInternal(int index, View view) {
3568
3569        if (mTransition != null) {
3570            mTransition.removeChild(this, view);
3571        }
3572
3573        boolean clearChildFocus = false;
3574        if (view == mFocused) {
3575            view.unFocus();
3576            clearChildFocus = true;
3577        }
3578
3579        view.clearAccessibilityFocus();
3580
3581        cancelTouchTarget(view);
3582        cancelHoverTarget(view);
3583
3584        if (view.getAnimation() != null ||
3585                (mTransitioningViews != null && mTransitioningViews.contains(view))) {
3586            addDisappearingView(view);
3587        } else if (view.mAttachInfo != null) {
3588           view.dispatchDetachedFromWindow();
3589        }
3590
3591        if (view.hasTransientState()) {
3592            childHasTransientStateChanged(view, false);
3593        }
3594
3595        onViewRemoved(view);
3596
3597        needGlobalAttributesUpdate(false);
3598
3599        removeFromArray(index);
3600
3601        if (clearChildFocus) {
3602            clearChildFocus(view);
3603            ensureInputFocusOnFirstFocusable();
3604        }
3605
3606        if (view.isAccessibilityFocused()) {
3607            view.clearAccessibilityFocus();
3608        }
3609    }
3610
3611    /**
3612     * Sets the LayoutTransition object for this ViewGroup. If the LayoutTransition object is
3613     * not null, changes in layout which occur because of children being added to or removed from
3614     * the ViewGroup will be animated according to the animations defined in that LayoutTransition
3615     * object. By default, the transition object is null (so layout changes are not animated).
3616     *
3617     * @param transition The LayoutTransition object that will animated changes in layout. A value
3618     * of <code>null</code> means no transition will run on layout changes.
3619     * @attr ref android.R.styleable#ViewGroup_animateLayoutChanges
3620     */
3621    public void setLayoutTransition(LayoutTransition transition) {
3622        if (mTransition != null) {
3623            mTransition.removeTransitionListener(mLayoutTransitionListener);
3624        }
3625        mTransition = transition;
3626        if (mTransition != null) {
3627            mTransition.addTransitionListener(mLayoutTransitionListener);
3628        }
3629    }
3630
3631    /**
3632     * Gets the LayoutTransition object for this ViewGroup. If the LayoutTransition object is
3633     * not null, changes in layout which occur because of children being added to or removed from
3634     * the ViewGroup will be animated according to the animations defined in that LayoutTransition
3635     * object. By default, the transition object is null (so layout changes are not animated).
3636     *
3637     * @return LayoutTranstion The LayoutTransition object that will animated changes in layout.
3638     * A value of <code>null</code> means no transition will run on layout changes.
3639     */
3640    public LayoutTransition getLayoutTransition() {
3641        return mTransition;
3642    }
3643
3644    private void removeViewsInternal(int start, int count) {
3645        final View focused = mFocused;
3646        final boolean detach = mAttachInfo != null;
3647        View clearChildFocus = null;
3648
3649        final View[] children = mChildren;
3650        final int end = start + count;
3651
3652        for (int i = start; i < end; i++) {
3653            final View view = children[i];
3654
3655            if (mTransition != null) {
3656                mTransition.removeChild(this, view);
3657            }
3658
3659            if (view == focused) {
3660                view.unFocus();
3661                clearChildFocus = view;
3662            }
3663
3664            view.clearAccessibilityFocus();
3665
3666            cancelTouchTarget(view);
3667            cancelHoverTarget(view);
3668
3669            if (view.getAnimation() != null ||
3670                (mTransitioningViews != null && mTransitioningViews.contains(view))) {
3671                addDisappearingView(view);
3672            } else if (detach) {
3673               view.dispatchDetachedFromWindow();
3674            }
3675
3676            if (view.hasTransientState()) {
3677                childHasTransientStateChanged(view, false);
3678            }
3679
3680            needGlobalAttributesUpdate(false);
3681
3682            onViewRemoved(view);
3683        }
3684
3685        removeFromArray(start, count);
3686
3687        if (clearChildFocus != null) {
3688            clearChildFocus(clearChildFocus);
3689            ensureInputFocusOnFirstFocusable();
3690        }
3691    }
3692
3693    /**
3694     * Call this method to remove all child views from the
3695     * ViewGroup.
3696     *
3697     * <p><strong>Note:</strong> do not invoke this method from
3698     * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3699     * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
3700     */
3701    public void removeAllViews() {
3702        removeAllViewsInLayout();
3703        requestLayout();
3704        invalidate(true);
3705    }
3706
3707    /**
3708     * Called by a ViewGroup subclass to remove child views from itself,
3709     * when it must first know its size on screen before it can calculate how many
3710     * child views it will render. An example is a Gallery or a ListView, which
3711     * may "have" 50 children, but actually only render the number of children
3712     * that can currently fit inside the object on screen. Do not call
3713     * this method unless you are extending ViewGroup and understand the
3714     * view measuring and layout pipeline.
3715     *
3716     * <p><strong>Note:</strong> do not invoke this method from
3717     * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3718     * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
3719     */
3720    public void removeAllViewsInLayout() {
3721        final int count = mChildrenCount;
3722        if (count <= 0) {
3723            return;
3724        }
3725
3726        final View[] children = mChildren;
3727        mChildrenCount = 0;
3728
3729        final View focused = mFocused;
3730        final boolean detach = mAttachInfo != null;
3731        View clearChildFocus = null;
3732
3733        needGlobalAttributesUpdate(false);
3734
3735        for (int i = count - 1; i >= 0; i--) {
3736            final View view = children[i];
3737
3738            if (mTransition != null) {
3739                mTransition.removeChild(this, view);
3740            }
3741
3742            if (view == focused) {
3743                view.unFocus();
3744                clearChildFocus = view;
3745            }
3746
3747            view.clearAccessibilityFocus();
3748
3749            cancelTouchTarget(view);
3750            cancelHoverTarget(view);
3751
3752            if (view.getAnimation() != null ||
3753                    (mTransitioningViews != null && mTransitioningViews.contains(view))) {
3754                addDisappearingView(view);
3755            } else if (detach) {
3756               view.dispatchDetachedFromWindow();
3757            }
3758
3759            if (view.hasTransientState()) {
3760                childHasTransientStateChanged(view, false);
3761            }
3762
3763            onViewRemoved(view);
3764
3765            view.mParent = null;
3766            children[i] = null;
3767        }
3768
3769        if (clearChildFocus != null) {
3770            clearChildFocus(clearChildFocus);
3771            ensureInputFocusOnFirstFocusable();
3772        }
3773    }
3774
3775    /**
3776     * Finishes the removal of a detached view. This method will dispatch the detached from
3777     * window event and notify the hierarchy change listener.
3778     *
3779     * @param child the child to be definitely removed from the view hierarchy
3780     * @param animate if true and the view has an animation, the view is placed in the
3781     *                disappearing views list, otherwise, it is detached from the window
3782     *
3783     * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
3784     * @see #detachAllViewsFromParent()
3785     * @see #detachViewFromParent(View)
3786     * @see #detachViewFromParent(int)
3787     */
3788    protected void removeDetachedView(View child, boolean animate) {
3789        if (mTransition != null) {
3790            mTransition.removeChild(this, child);
3791        }
3792
3793        if (child == mFocused) {
3794            child.clearFocus();
3795        }
3796
3797        child.clearAccessibilityFocus();
3798
3799        cancelTouchTarget(child);
3800        cancelHoverTarget(child);
3801
3802        if ((animate && child.getAnimation() != null) ||
3803                (mTransitioningViews != null && mTransitioningViews.contains(child))) {
3804            addDisappearingView(child);
3805        } else if (child.mAttachInfo != null) {
3806            child.dispatchDetachedFromWindow();
3807        }
3808
3809        if (child.hasTransientState()) {
3810            childHasTransientStateChanged(child, false);
3811        }
3812
3813        onViewRemoved(child);
3814    }
3815
3816    /**
3817     * Attaches a view to this view group. Attaching a view assigns this group as the parent,
3818     * sets the layout parameters and puts the view in the list of children so it can be retrieved
3819     * by calling {@link #getChildAt(int)}.
3820     *
3821     * This method should be called only for view which were detached from their parent.
3822     *
3823     * @param child the child to attach
3824     * @param index the index at which the child should be attached
3825     * @param params the layout parameters of the child
3826     *
3827     * @see #removeDetachedView(View, boolean)
3828     * @see #detachAllViewsFromParent()
3829     * @see #detachViewFromParent(View)
3830     * @see #detachViewFromParent(int)
3831     */
3832    protected void attachViewToParent(View child, int index, LayoutParams params) {
3833        child.mLayoutParams = params;
3834
3835        if (index < 0) {
3836            index = mChildrenCount;
3837        }
3838
3839        addInArray(child, index);
3840
3841        child.mParent = this;
3842        child.mPrivateFlags = (child.mPrivateFlags & ~DIRTY_MASK & ~DRAWING_CACHE_VALID) |
3843                DRAWN | INVALIDATED;
3844        this.mPrivateFlags |= INVALIDATED;
3845
3846        if (child.hasFocus()) {
3847            requestChildFocus(child, child.findFocus());
3848        }
3849    }
3850
3851    /**
3852     * Detaches a view from its parent. Detaching a view should be temporary and followed
3853     * either by a call to {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
3854     * or a call to {@link #removeDetachedView(View, boolean)}. When a view is detached,
3855     * its parent is null and cannot be retrieved by a call to {@link #getChildAt(int)}.
3856     *
3857     * @param child the child to detach
3858     *
3859     * @see #detachViewFromParent(int)
3860     * @see #detachViewsFromParent(int, int)
3861     * @see #detachAllViewsFromParent()
3862     * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
3863     * @see #removeDetachedView(View, boolean)
3864     */
3865    protected void detachViewFromParent(View child) {
3866        removeFromArray(indexOfChild(child));
3867    }
3868
3869    /**
3870     * Detaches a view from its parent. Detaching a view should be temporary and followed
3871     * either by a call to {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
3872     * or a call to {@link #removeDetachedView(View, boolean)}. When a view is detached,
3873     * its parent is null and cannot be retrieved by a call to {@link #getChildAt(int)}.
3874     *
3875     * @param index the index of the child to detach
3876     *
3877     * @see #detachViewFromParent(View)
3878     * @see #detachAllViewsFromParent()
3879     * @see #detachViewsFromParent(int, int)
3880     * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
3881     * @see #removeDetachedView(View, boolean)
3882     */
3883    protected void detachViewFromParent(int index) {
3884        removeFromArray(index);
3885    }
3886
3887    /**
3888     * Detaches a range of view from their parent. Detaching a view should be temporary and followed
3889     * either by a call to {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
3890     * or a call to {@link #removeDetachedView(View, boolean)}. When a view is detached, its
3891     * parent is null and cannot be retrieved by a call to {@link #getChildAt(int)}.
3892     *
3893     * @param start the first index of the childrend range to detach
3894     * @param count the number of children to detach
3895     *
3896     * @see #detachViewFromParent(View)
3897     * @see #detachViewFromParent(int)
3898     * @see #detachAllViewsFromParent()
3899     * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
3900     * @see #removeDetachedView(View, boolean)
3901     */
3902    protected void detachViewsFromParent(int start, int count) {
3903        removeFromArray(start, count);
3904    }
3905
3906    /**
3907     * Detaches all views from the parent. Detaching a view should be temporary and followed
3908     * either by a call to {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
3909     * or a call to {@link #removeDetachedView(View, boolean)}. When a view is detached,
3910     * its parent is null and cannot be retrieved by a call to {@link #getChildAt(int)}.
3911     *
3912     * @see #detachViewFromParent(View)
3913     * @see #detachViewFromParent(int)
3914     * @see #detachViewsFromParent(int, int)
3915     * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
3916     * @see #removeDetachedView(View, boolean)
3917     */
3918    protected void detachAllViewsFromParent() {
3919        final int count = mChildrenCount;
3920        if (count <= 0) {
3921            return;
3922        }
3923
3924        final View[] children = mChildren;
3925        mChildrenCount = 0;
3926
3927        for (int i = count - 1; i >= 0; i--) {
3928            children[i].mParent = null;
3929            children[i] = null;
3930        }
3931    }
3932
3933    /**
3934     * Don't call or override this method. It is used for the implementation of
3935     * the view hierarchy.
3936     */
3937    public final void invalidateChild(View child, final Rect dirty) {
3938        ViewParent parent = this;
3939
3940        final AttachInfo attachInfo = mAttachInfo;
3941        if (attachInfo != null) {
3942            // If the child is drawing an animation, we want to copy this flag onto
3943            // ourselves and the parent to make sure the invalidate request goes
3944            // through
3945            final boolean drawAnimation = (child.mPrivateFlags & DRAW_ANIMATION) == DRAW_ANIMATION;
3946
3947            // Check whether the child that requests the invalidate is fully opaque
3948            // Views being animated or transformed are not considered opaque because we may
3949            // be invalidating their old position and need the parent to paint behind them.
3950            Matrix childMatrix = child.getMatrix();
3951            final boolean isOpaque = child.isOpaque() && !drawAnimation &&
3952                    child.getAnimation() == null && childMatrix.isIdentity();
3953            // Mark the child as dirty, using the appropriate flag
3954            // Make sure we do not set both flags at the same time
3955            int opaqueFlag = isOpaque ? DIRTY_OPAQUE : DIRTY;
3956
3957            if (child.mLayerType != LAYER_TYPE_NONE) {
3958                mPrivateFlags |= INVALIDATED;
3959                mPrivateFlags &= ~DRAWING_CACHE_VALID;
3960                child.mLocalDirtyRect.union(dirty);
3961            }
3962
3963            final int[] location = attachInfo.mInvalidateChildLocation;
3964            location[CHILD_LEFT_INDEX] = child.mLeft;
3965            location[CHILD_TOP_INDEX] = child.mTop;
3966            if (!childMatrix.isIdentity() ||
3967                    (mGroupFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) {
3968                RectF boundingRect = attachInfo.mTmpTransformRect;
3969                boundingRect.set(dirty);
3970                Matrix transformMatrix;
3971                if ((mGroupFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) {
3972                    Transformation t = attachInfo.mTmpTransformation;
3973                    boolean transformed = getChildStaticTransformation(child, t);
3974                    if (transformed) {
3975                        transformMatrix = attachInfo.mTmpMatrix;
3976                        transformMatrix.set(t.getMatrix());
3977                        if (!childMatrix.isIdentity()) {
3978                            transformMatrix.preConcat(childMatrix);
3979                        }
3980                    } else {
3981                        transformMatrix = childMatrix;
3982                    }
3983                } else {
3984                    transformMatrix = childMatrix;
3985                }
3986                transformMatrix.mapRect(boundingRect);
3987                dirty.set((int) (boundingRect.left - 0.5f),
3988                        (int) (boundingRect.top - 0.5f),
3989                        (int) (boundingRect.right + 0.5f),
3990                        (int) (boundingRect.bottom + 0.5f));
3991            }
3992
3993            do {
3994                View view = null;
3995                if (parent instanceof View) {
3996                    view = (View) parent;
3997                }
3998
3999                if (drawAnimation) {
4000                    if (view != null) {
4001                        view.mPrivateFlags |= DRAW_ANIMATION;
4002                    } else if (parent instanceof ViewRootImpl) {
4003                        ((ViewRootImpl) parent).mIsAnimating = true;
4004                    }
4005                }
4006
4007                // If the parent is dirty opaque or not dirty, mark it dirty with the opaque
4008                // flag coming from the child that initiated the invalidate
4009                if (view != null) {
4010                    if ((view.mViewFlags & FADING_EDGE_MASK) != 0 &&
4011                            view.getSolidColor() == 0) {
4012                        opaqueFlag = DIRTY;
4013                    }
4014                    if ((view.mPrivateFlags & DIRTY_MASK) != DIRTY) {
4015                        view.mPrivateFlags = (view.mPrivateFlags & ~DIRTY_MASK) | opaqueFlag;
4016                    }
4017                }
4018
4019                parent = parent.invalidateChildInParent(location, dirty);
4020                if (view != null) {
4021                    // Account for transform on current parent
4022                    Matrix m = view.getMatrix();
4023                    if (!m.isIdentity()) {
4024                        RectF boundingRect = attachInfo.mTmpTransformRect;
4025                        boundingRect.set(dirty);
4026                        m.mapRect(boundingRect);
4027                        dirty.set((int) (boundingRect.left - 0.5f),
4028                                (int) (boundingRect.top - 0.5f),
4029                                (int) (boundingRect.right + 0.5f),
4030                                (int) (boundingRect.bottom + 0.5f));
4031                    }
4032                }
4033            } while (parent != null);
4034        }
4035    }
4036
4037    /**
4038     * Don't call or override this method. It is used for the implementation of
4039     * the view hierarchy.
4040     *
4041     * This implementation returns null if this ViewGroup does not have a parent,
4042     * if this ViewGroup is already fully invalidated or if the dirty rectangle
4043     * does not intersect with this ViewGroup's bounds.
4044     */
4045    public ViewParent invalidateChildInParent(final int[] location, final Rect dirty) {
4046        if ((mPrivateFlags & DRAWN) == DRAWN ||
4047                (mPrivateFlags & DRAWING_CACHE_VALID) == DRAWING_CACHE_VALID) {
4048            if ((mGroupFlags & (FLAG_OPTIMIZE_INVALIDATE | FLAG_ANIMATION_DONE)) !=
4049                        FLAG_OPTIMIZE_INVALIDATE) {
4050                dirty.offset(location[CHILD_LEFT_INDEX] - mScrollX,
4051                        location[CHILD_TOP_INDEX] - mScrollY);
4052
4053                final int left = mLeft;
4054                final int top = mTop;
4055
4056                if ((mGroupFlags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN) {
4057                    if (!dirty.intersect(0, 0, mRight - left, mBottom - top)) {
4058                        dirty.setEmpty();
4059                    }
4060                }
4061                mPrivateFlags &= ~DRAWING_CACHE_VALID;
4062
4063                location[CHILD_LEFT_INDEX] = left;
4064                location[CHILD_TOP_INDEX] = top;
4065
4066                if (mLayerType != LAYER_TYPE_NONE) {
4067                    mPrivateFlags |= INVALIDATED;
4068                    mLocalDirtyRect.union(dirty);
4069                }
4070
4071                return mParent;
4072
4073            } else {
4074                mPrivateFlags &= ~DRAWN & ~DRAWING_CACHE_VALID;
4075
4076                location[CHILD_LEFT_INDEX] = mLeft;
4077                location[CHILD_TOP_INDEX] = mTop;
4078                if ((mGroupFlags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN) {
4079                    dirty.set(0, 0, mRight - mLeft, mBottom - mTop);
4080                } else {
4081                    // in case the dirty rect extends outside the bounds of this container
4082                    dirty.union(0, 0, mRight - mLeft, mBottom - mTop);
4083                }
4084
4085                if (mLayerType != LAYER_TYPE_NONE) {
4086                    mPrivateFlags |= INVALIDATED;
4087                    mLocalDirtyRect.union(dirty);
4088                }
4089
4090                return mParent;
4091            }
4092        }
4093
4094        return null;
4095    }
4096
4097    /**
4098     * Quick invalidation method called by View.invalidateViewProperty. This doesn't set the
4099     * DRAWN flags and doesn't handle the Animation logic that the default invalidation methods
4100     * do; all we want to do here is schedule a traversal with the appropriate dirty rect.
4101     *
4102     * @hide
4103     */
4104    public void invalidateChildFast(View child, final Rect dirty) {
4105        ViewParent parent = this;
4106
4107        final AttachInfo attachInfo = mAttachInfo;
4108        if (attachInfo != null) {
4109            if (child.mLayerType != LAYER_TYPE_NONE) {
4110                child.mLocalDirtyRect.union(dirty);
4111            }
4112
4113            int left = child.mLeft;
4114            int top = child.mTop;
4115            if (!child.getMatrix().isIdentity()) {
4116                child.transformRect(dirty);
4117            }
4118
4119            do {
4120                if (parent instanceof ViewGroup) {
4121                    ViewGroup parentVG = (ViewGroup) parent;
4122                    if (parentVG.mLayerType != LAYER_TYPE_NONE) {
4123                        // Layered parents should be recreated, not just re-issued
4124                        parentVG.invalidate();
4125                        parent = null;
4126                    } else {
4127                        parent = parentVG.invalidateChildInParentFast(left, top, dirty);
4128                        left = parentVG.mLeft;
4129                        top = parentVG.mTop;
4130                    }
4131                } else {
4132                    // Reached the top; this calls into the usual invalidate method in
4133                    // ViewRootImpl, which schedules a traversal
4134                    final int[] location = attachInfo.mInvalidateChildLocation;
4135                    location[0] = left;
4136                    location[1] = top;
4137                    parent = parent.invalidateChildInParent(location, dirty);
4138                }
4139            } while (parent != null);
4140        }
4141    }
4142
4143    /**
4144     * Quick invalidation method that simply transforms the dirty rect into the parent's
4145     * coordinate system, pruning the invalidation if the parent has already been invalidated.
4146     */
4147    private ViewParent invalidateChildInParentFast(int left, int top, final Rect dirty) {
4148        if ((mPrivateFlags & DRAWN) == DRAWN ||
4149                (mPrivateFlags & DRAWING_CACHE_VALID) == DRAWING_CACHE_VALID) {
4150            dirty.offset(left - mScrollX, top - mScrollY);
4151
4152            if ((mGroupFlags & FLAG_CLIP_CHILDREN) == 0 ||
4153                    dirty.intersect(0, 0, mRight - mLeft, mBottom - mTop)) {
4154
4155                if (mLayerType != LAYER_TYPE_NONE) {
4156                    mLocalDirtyRect.union(dirty);
4157                }
4158                if (!getMatrix().isIdentity()) {
4159                    transformRect(dirty);
4160                }
4161
4162                return mParent;
4163            }
4164        }
4165
4166        return null;
4167    }
4168
4169    /**
4170     * Offset a rectangle that is in a descendant's coordinate
4171     * space into our coordinate space.
4172     * @param descendant A descendant of this view
4173     * @param rect A rectangle defined in descendant's coordinate space.
4174     */
4175    public final void offsetDescendantRectToMyCoords(View descendant, Rect rect) {
4176        offsetRectBetweenParentAndChild(descendant, rect, true, false);
4177    }
4178
4179    /**
4180     * Offset a rectangle that is in our coordinate space into an ancestor's
4181     * coordinate space.
4182     * @param descendant A descendant of this view
4183     * @param rect A rectangle defined in descendant's coordinate space.
4184     */
4185    public final void offsetRectIntoDescendantCoords(View descendant, Rect rect) {
4186        offsetRectBetweenParentAndChild(descendant, rect, false, false);
4187    }
4188
4189    /**
4190     * Helper method that offsets a rect either from parent to descendant or
4191     * descendant to parent.
4192     */
4193    void offsetRectBetweenParentAndChild(View descendant, Rect rect,
4194            boolean offsetFromChildToParent, boolean clipToBounds) {
4195
4196        // already in the same coord system :)
4197        if (descendant == this) {
4198            return;
4199        }
4200
4201        ViewParent theParent = descendant.mParent;
4202
4203        // search and offset up to the parent
4204        while ((theParent != null)
4205                && (theParent instanceof View)
4206                && (theParent != this)) {
4207
4208            if (offsetFromChildToParent) {
4209                rect.offset(descendant.mLeft - descendant.mScrollX,
4210                        descendant.mTop - descendant.mScrollY);
4211                if (clipToBounds) {
4212                    View p = (View) theParent;
4213                    rect.intersect(0, 0, p.mRight - p.mLeft, p.mBottom - p.mTop);
4214                }
4215            } else {
4216                if (clipToBounds) {
4217                    View p = (View) theParent;
4218                    rect.intersect(0, 0, p.mRight - p.mLeft, p.mBottom - p.mTop);
4219                }
4220                rect.offset(descendant.mScrollX - descendant.mLeft,
4221                        descendant.mScrollY - descendant.mTop);
4222            }
4223
4224            descendant = (View) theParent;
4225            theParent = descendant.mParent;
4226        }
4227
4228        // now that we are up to this view, need to offset one more time
4229        // to get into our coordinate space
4230        if (theParent == this) {
4231            if (offsetFromChildToParent) {
4232                rect.offset(descendant.mLeft - descendant.mScrollX,
4233                        descendant.mTop - descendant.mScrollY);
4234            } else {
4235                rect.offset(descendant.mScrollX - descendant.mLeft,
4236                        descendant.mScrollY - descendant.mTop);
4237            }
4238        } else {
4239            throw new IllegalArgumentException("parameter must be a descendant of this view");
4240        }
4241    }
4242
4243    /**
4244     * Offset the vertical location of all children of this view by the specified number of pixels.
4245     *
4246     * @param offset the number of pixels to offset
4247     *
4248     * @hide
4249     */
4250    public void offsetChildrenTopAndBottom(int offset) {
4251        final int count = mChildrenCount;
4252        final View[] children = mChildren;
4253
4254        for (int i = 0; i < count; i++) {
4255            final View v = children[i];
4256            v.mTop += offset;
4257            v.mBottom += offset;
4258            if (v.mDisplayList != null) {
4259                v.mDisplayList.offsetTopBottom(offset);
4260                invalidateViewProperty(false, false);
4261            }
4262        }
4263    }
4264
4265    /**
4266     * {@inheritDoc}
4267     */
4268    public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) {
4269        // It doesn't make a whole lot of sense to call this on a view that isn't attached,
4270        // but for some simple tests it can be useful. If we don't have attach info this
4271        // will allocate memory.
4272        final RectF rect = mAttachInfo != null ? mAttachInfo.mTmpTransformRect : new RectF();
4273        rect.set(r);
4274
4275        if (!child.hasIdentityMatrix()) {
4276           child.getMatrix().mapRect(rect);
4277        }
4278
4279        int dx = child.mLeft - mScrollX;
4280        int dy = child.mTop - mScrollY;
4281
4282        rect.offset(dx, dy);
4283
4284        if (offset != null) {
4285            if (!child.hasIdentityMatrix()) {
4286                float[] position = mAttachInfo != null ? mAttachInfo.mTmpTransformLocation
4287                        : new float[2];
4288                position[0] = offset.x;
4289                position[1] = offset.y;
4290                child.getMatrix().mapPoints(position);
4291                offset.x = (int) (position[0] + 0.5f);
4292                offset.y = (int) (position[1] + 0.5f);
4293            }
4294            offset.x += dx;
4295            offset.y += dy;
4296        }
4297
4298        if (rect.intersect(0, 0, mRight - mLeft, mBottom - mTop)) {
4299            if (mParent == null) return true;
4300            r.set((int) (rect.left + 0.5f), (int) (rect.top + 0.5f),
4301                    (int) (rect.right + 0.5f), (int) (rect.bottom + 0.5f));
4302            return mParent.getChildVisibleRect(this, r, offset);
4303        }
4304
4305        return false;
4306    }
4307
4308    /**
4309     * {@inheritDoc}
4310     */
4311    @Override
4312    public final void layout(int l, int t, int r, int b) {
4313        if (mTransition == null || !mTransition.isChangingLayout()) {
4314            if (mTransition != null) {
4315                mTransition.layoutChange(this);
4316            }
4317            super.layout(l, t, r, b);
4318        } else {
4319            // record the fact that we noop'd it; request layout when transition finishes
4320            mLayoutSuppressed = true;
4321        }
4322    }
4323
4324    /**
4325     * {@inheritDoc}
4326     */
4327    @Override
4328    protected abstract void onLayout(boolean changed,
4329            int l, int t, int r, int b);
4330
4331    /**
4332     * Indicates whether the view group has the ability to animate its children
4333     * after the first layout.
4334     *
4335     * @return true if the children can be animated, false otherwise
4336     */
4337    protected boolean canAnimate() {
4338        return mLayoutAnimationController != null;
4339    }
4340
4341    /**
4342     * Runs the layout animation. Calling this method triggers a relayout of
4343     * this view group.
4344     */
4345    public void startLayoutAnimation() {
4346        if (mLayoutAnimationController != null) {
4347            mGroupFlags |= FLAG_RUN_ANIMATION;
4348            requestLayout();
4349        }
4350    }
4351
4352    /**
4353     * Schedules the layout animation to be played after the next layout pass
4354     * of this view group. This can be used to restart the layout animation
4355     * when the content of the view group changes or when the activity is
4356     * paused and resumed.
4357     */
4358    public void scheduleLayoutAnimation() {
4359        mGroupFlags |= FLAG_RUN_ANIMATION;
4360    }
4361
4362    /**
4363     * Sets the layout animation controller used to animate the group's
4364     * children after the first layout.
4365     *
4366     * @param controller the animation controller
4367     */
4368    public void setLayoutAnimation(LayoutAnimationController controller) {
4369        mLayoutAnimationController = controller;
4370        if (mLayoutAnimationController != null) {
4371            mGroupFlags |= FLAG_RUN_ANIMATION;
4372        }
4373    }
4374
4375    /**
4376     * Returns the layout animation controller used to animate the group's
4377     * children.
4378     *
4379     * @return the current animation controller
4380     */
4381    public LayoutAnimationController getLayoutAnimation() {
4382        return mLayoutAnimationController;
4383    }
4384
4385    /**
4386     * Indicates whether the children's drawing cache is used during a layout
4387     * animation. By default, the drawing cache is enabled but this will prevent
4388     * nested layout animations from working. To nest animations, you must disable
4389     * the cache.
4390     *
4391     * @return true if the animation cache is enabled, false otherwise
4392     *
4393     * @see #setAnimationCacheEnabled(boolean)
4394     * @see View#setDrawingCacheEnabled(boolean)
4395     */
4396    @ViewDebug.ExportedProperty
4397    public boolean isAnimationCacheEnabled() {
4398        return (mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE;
4399    }
4400
4401    /**
4402     * Enables or disables the children's drawing cache during a layout animation.
4403     * By default, the drawing cache is enabled but this will prevent nested
4404     * layout animations from working. To nest animations, you must disable the
4405     * cache.
4406     *
4407     * @param enabled true to enable the animation cache, false otherwise
4408     *
4409     * @see #isAnimationCacheEnabled()
4410     * @see View#setDrawingCacheEnabled(boolean)
4411     */
4412    public void setAnimationCacheEnabled(boolean enabled) {
4413        setBooleanFlag(FLAG_ANIMATION_CACHE, enabled);
4414    }
4415
4416    /**
4417     * Indicates whether this ViewGroup will always try to draw its children using their
4418     * drawing cache. By default this property is enabled.
4419     *
4420     * @return true if the animation cache is enabled, false otherwise
4421     *
4422     * @see #setAlwaysDrawnWithCacheEnabled(boolean)
4423     * @see #setChildrenDrawnWithCacheEnabled(boolean)
4424     * @see View#setDrawingCacheEnabled(boolean)
4425     */
4426    @ViewDebug.ExportedProperty(category = "drawing")
4427    public boolean isAlwaysDrawnWithCacheEnabled() {
4428        return (mGroupFlags & FLAG_ALWAYS_DRAWN_WITH_CACHE) == FLAG_ALWAYS_DRAWN_WITH_CACHE;
4429    }
4430
4431    /**
4432     * Indicates whether this ViewGroup will always try to draw its children using their
4433     * drawing cache. This property can be set to true when the cache rendering is
4434     * slightly different from the children's normal rendering. Renderings can be different,
4435     * for instance, when the cache's quality is set to low.
4436     *
4437     * When this property is disabled, the ViewGroup will use the drawing cache of its
4438     * children only when asked to. It's usually the task of subclasses to tell ViewGroup
4439     * when to start using the drawing cache and when to stop using it.
4440     *
4441     * @param always true to always draw with the drawing cache, false otherwise
4442     *
4443     * @see #isAlwaysDrawnWithCacheEnabled()
4444     * @see #setChildrenDrawnWithCacheEnabled(boolean)
4445     * @see View#setDrawingCacheEnabled(boolean)
4446     * @see View#setDrawingCacheQuality(int)
4447     */
4448    public void setAlwaysDrawnWithCacheEnabled(boolean always) {
4449        setBooleanFlag(FLAG_ALWAYS_DRAWN_WITH_CACHE, always);
4450    }
4451
4452    /**
4453     * Indicates whether the ViewGroup is currently drawing its children using
4454     * their drawing cache.
4455     *
4456     * @return true if children should be drawn with their cache, false otherwise
4457     *
4458     * @see #setAlwaysDrawnWithCacheEnabled(boolean)
4459     * @see #setChildrenDrawnWithCacheEnabled(boolean)
4460     */
4461    @ViewDebug.ExportedProperty(category = "drawing")
4462    protected boolean isChildrenDrawnWithCacheEnabled() {
4463        return (mGroupFlags & FLAG_CHILDREN_DRAWN_WITH_CACHE) == FLAG_CHILDREN_DRAWN_WITH_CACHE;
4464    }
4465
4466    /**
4467     * Tells the ViewGroup to draw its children using their drawing cache. This property
4468     * is ignored when {@link #isAlwaysDrawnWithCacheEnabled()} is true. A child's drawing cache
4469     * will be used only if it has been enabled.
4470     *
4471     * Subclasses should call this method to start and stop using the drawing cache when
4472     * they perform performance sensitive operations, like scrolling or animating.
4473     *
4474     * @param enabled true if children should be drawn with their cache, false otherwise
4475     *
4476     * @see #setAlwaysDrawnWithCacheEnabled(boolean)
4477     * @see #isChildrenDrawnWithCacheEnabled()
4478     */
4479    protected void setChildrenDrawnWithCacheEnabled(boolean enabled) {
4480        setBooleanFlag(FLAG_CHILDREN_DRAWN_WITH_CACHE, enabled);
4481    }
4482
4483    /**
4484     * Indicates whether the ViewGroup is drawing its children in the order defined by
4485     * {@link #getChildDrawingOrder(int, int)}.
4486     *
4487     * @return true if children drawing order is defined by {@link #getChildDrawingOrder(int, int)},
4488     *         false otherwise
4489     *
4490     * @see #setChildrenDrawingOrderEnabled(boolean)
4491     * @see #getChildDrawingOrder(int, int)
4492     */
4493    @ViewDebug.ExportedProperty(category = "drawing")
4494    protected boolean isChildrenDrawingOrderEnabled() {
4495        return (mGroupFlags & FLAG_USE_CHILD_DRAWING_ORDER) == FLAG_USE_CHILD_DRAWING_ORDER;
4496    }
4497
4498    /**
4499     * Tells the ViewGroup whether to draw its children in the order defined by the method
4500     * {@link #getChildDrawingOrder(int, int)}.
4501     *
4502     * @param enabled true if the order of the children when drawing is determined by
4503     *        {@link #getChildDrawingOrder(int, int)}, false otherwise
4504     *
4505     * @see #isChildrenDrawingOrderEnabled()
4506     * @see #getChildDrawingOrder(int, int)
4507     */
4508    protected void setChildrenDrawingOrderEnabled(boolean enabled) {
4509        setBooleanFlag(FLAG_USE_CHILD_DRAWING_ORDER, enabled);
4510    }
4511
4512    private void setBooleanFlag(int flag, boolean value) {
4513        if (value) {
4514            mGroupFlags |= flag;
4515        } else {
4516            mGroupFlags &= ~flag;
4517        }
4518    }
4519
4520    /**
4521     * Returns an integer indicating what types of drawing caches are kept in memory.
4522     *
4523     * @see #setPersistentDrawingCache(int)
4524     * @see #setAnimationCacheEnabled(boolean)
4525     *
4526     * @return one or a combination of {@link #PERSISTENT_NO_CACHE},
4527     *         {@link #PERSISTENT_ANIMATION_CACHE}, {@link #PERSISTENT_SCROLLING_CACHE}
4528     *         and {@link #PERSISTENT_ALL_CACHES}
4529     */
4530    @ViewDebug.ExportedProperty(category = "drawing", mapping = {
4531        @ViewDebug.IntToString(from = PERSISTENT_NO_CACHE,        to = "NONE"),
4532        @ViewDebug.IntToString(from = PERSISTENT_ANIMATION_CACHE, to = "ANIMATION"),
4533        @ViewDebug.IntToString(from = PERSISTENT_SCROLLING_CACHE, to = "SCROLLING"),
4534        @ViewDebug.IntToString(from = PERSISTENT_ALL_CACHES,      to = "ALL")
4535    })
4536    public int getPersistentDrawingCache() {
4537        return mPersistentDrawingCache;
4538    }
4539
4540    /**
4541     * Indicates what types of drawing caches should be kept in memory after
4542     * they have been created.
4543     *
4544     * @see #getPersistentDrawingCache()
4545     * @see #setAnimationCacheEnabled(boolean)
4546     *
4547     * @param drawingCacheToKeep one or a combination of {@link #PERSISTENT_NO_CACHE},
4548     *        {@link #PERSISTENT_ANIMATION_CACHE}, {@link #PERSISTENT_SCROLLING_CACHE}
4549     *        and {@link #PERSISTENT_ALL_CACHES}
4550     */
4551    public void setPersistentDrawingCache(int drawingCacheToKeep) {
4552        mPersistentDrawingCache = drawingCacheToKeep & PERSISTENT_ALL_CACHES;
4553    }
4554
4555    /**
4556     * Returns the basis of alignment during layout operations on this view group:
4557     * either {@link #CLIP_BOUNDS} or {@link #OPTICAL_BOUNDS}.
4558     *
4559     * @return the layout mode to use during layout operations
4560     *
4561     * @see #setLayoutMode(int)
4562     *
4563     * @hide
4564     */
4565    public int getLayoutMode() {
4566        return mLayoutMode;
4567    }
4568
4569    /**
4570     * Sets the basis of alignment during the layout of this view group.
4571     * Valid values are either {@link #CLIP_BOUNDS} or {@link #OPTICAL_BOUNDS}.
4572     * <p>
4573     * The default is {@link #CLIP_BOUNDS}.
4574     *
4575     * @param layoutMode the layout mode to use during layout operations
4576     *
4577     * @see #getLayoutMode()
4578     *
4579     * @hide
4580     */
4581    public void setLayoutMode(int layoutMode) {
4582        if (mLayoutMode != layoutMode) {
4583            mLayoutMode = layoutMode;
4584            requestLayout();
4585        }
4586    }
4587
4588    /**
4589     * Returns a new set of layout parameters based on the supplied attributes set.
4590     *
4591     * @param attrs the attributes to build the layout parameters from
4592     *
4593     * @return an instance of {@link android.view.ViewGroup.LayoutParams} or one
4594     *         of its descendants
4595     */
4596    public LayoutParams generateLayoutParams(AttributeSet attrs) {
4597        return new LayoutParams(getContext(), attrs);
4598    }
4599
4600    /**
4601     * Returns a safe set of layout parameters based on the supplied layout params.
4602     * When a ViewGroup is passed a View whose layout params do not pass the test of
4603     * {@link #checkLayoutParams(android.view.ViewGroup.LayoutParams)}, this method
4604     * is invoked. This method should return a new set of layout params suitable for
4605     * this ViewGroup, possibly by copying the appropriate attributes from the
4606     * specified set of layout params.
4607     *
4608     * @param p The layout parameters to convert into a suitable set of layout parameters
4609     *          for this ViewGroup.
4610     *
4611     * @return an instance of {@link android.view.ViewGroup.LayoutParams} or one
4612     *         of its descendants
4613     */
4614    protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
4615        return p;
4616    }
4617
4618    /**
4619     * Returns a set of default layout parameters. These parameters are requested
4620     * when the View passed to {@link #addView(View)} has no layout parameters
4621     * already set. If null is returned, an exception is thrown from addView.
4622     *
4623     * @return a set of default layout parameters or null
4624     */
4625    protected LayoutParams generateDefaultLayoutParams() {
4626        return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
4627    }
4628
4629    /**
4630     * {@inheritDoc}
4631     */
4632    @Override
4633    protected void debug(int depth) {
4634        super.debug(depth);
4635        String output;
4636
4637        if (mFocused != null) {
4638            output = debugIndent(depth);
4639            output += "mFocused";
4640            Log.d(VIEW_LOG_TAG, output);
4641        }
4642        if (mChildrenCount != 0) {
4643            output = debugIndent(depth);
4644            output += "{";
4645            Log.d(VIEW_LOG_TAG, output);
4646        }
4647        int count = mChildrenCount;
4648        for (int i = 0; i < count; i++) {
4649            View child = mChildren[i];
4650            child.debug(depth + 1);
4651        }
4652
4653        if (mChildrenCount != 0) {
4654            output = debugIndent(depth);
4655            output += "}";
4656            Log.d(VIEW_LOG_TAG, output);
4657        }
4658    }
4659
4660    /**
4661     * Returns the position in the group of the specified child view.
4662     *
4663     * @param child the view for which to get the position
4664     * @return a positive integer representing the position of the view in the
4665     *         group, or -1 if the view does not exist in the group
4666     */
4667    public int indexOfChild(View child) {
4668        final int count = mChildrenCount;
4669        final View[] children = mChildren;
4670        for (int i = 0; i < count; i++) {
4671            if (children[i] == child) {
4672                return i;
4673            }
4674        }
4675        return -1;
4676    }
4677
4678    /**
4679     * Returns the number of children in the group.
4680     *
4681     * @return a positive integer representing the number of children in
4682     *         the group
4683     */
4684    public int getChildCount() {
4685        return mChildrenCount;
4686    }
4687
4688    /**
4689     * Returns the view at the specified position in the group.
4690     *
4691     * @param index the position at which to get the view from
4692     * @return the view at the specified position or null if the position
4693     *         does not exist within the group
4694     */
4695    public View getChildAt(int index) {
4696        if (index < 0 || index >= mChildrenCount) {
4697            return null;
4698        }
4699        return mChildren[index];
4700    }
4701
4702    /**
4703     * Ask all of the children of this view to measure themselves, taking into
4704     * account both the MeasureSpec requirements for this view and its padding.
4705     * We skip children that are in the GONE state The heavy lifting is done in
4706     * getChildMeasureSpec.
4707     *
4708     * @param widthMeasureSpec The width requirements for this view
4709     * @param heightMeasureSpec The height requirements for this view
4710     */
4711    protected void measureChildren(int widthMeasureSpec, int heightMeasureSpec) {
4712        final int size = mChildrenCount;
4713        final View[] children = mChildren;
4714        for (int i = 0; i < size; ++i) {
4715            final View child = children[i];
4716            if ((child.mViewFlags & VISIBILITY_MASK) != GONE) {
4717                measureChild(child, widthMeasureSpec, heightMeasureSpec);
4718            }
4719        }
4720    }
4721
4722    /**
4723     * Ask one of the children of this view to measure itself, taking into
4724     * account both the MeasureSpec requirements for this view and its padding.
4725     * The heavy lifting is done in getChildMeasureSpec.
4726     *
4727     * @param child The child to measure
4728     * @param parentWidthMeasureSpec The width requirements for this view
4729     * @param parentHeightMeasureSpec The height requirements for this view
4730     */
4731    protected void measureChild(View child, int parentWidthMeasureSpec,
4732            int parentHeightMeasureSpec) {
4733        final LayoutParams lp = child.getLayoutParams();
4734
4735        final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
4736                mPaddingLeft + mPaddingRight, lp.width);
4737        final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
4738                mPaddingTop + mPaddingBottom, lp.height);
4739
4740        child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
4741    }
4742
4743    /**
4744     * Ask one of the children of this view to measure itself, taking into
4745     * account both the MeasureSpec requirements for this view and its padding
4746     * and margins. The child must have MarginLayoutParams The heavy lifting is
4747     * done in getChildMeasureSpec.
4748     *
4749     * @param child The child to measure
4750     * @param parentWidthMeasureSpec The width requirements for this view
4751     * @param widthUsed Extra space that has been used up by the parent
4752     *        horizontally (possibly by other children of the parent)
4753     * @param parentHeightMeasureSpec The height requirements for this view
4754     * @param heightUsed Extra space that has been used up by the parent
4755     *        vertically (possibly by other children of the parent)
4756     */
4757    protected void measureChildWithMargins(View child,
4758            int parentWidthMeasureSpec, int widthUsed,
4759            int parentHeightMeasureSpec, int heightUsed) {
4760        final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
4761
4762        final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
4763                mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin
4764                        + widthUsed, lp.width);
4765        final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
4766                mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin
4767                        + heightUsed, lp.height);
4768
4769        child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
4770    }
4771
4772    /**
4773     * Does the hard part of measureChildren: figuring out the MeasureSpec to
4774     * pass to a particular child. This method figures out the right MeasureSpec
4775     * for one dimension (height or width) of one child view.
4776     *
4777     * The goal is to combine information from our MeasureSpec with the
4778     * LayoutParams of the child to get the best possible results. For example,
4779     * if the this view knows its size (because its MeasureSpec has a mode of
4780     * EXACTLY), and the child has indicated in its LayoutParams that it wants
4781     * to be the same size as the parent, the parent should ask the child to
4782     * layout given an exact size.
4783     *
4784     * @param spec The requirements for this view
4785     * @param padding The padding of this view for the current dimension and
4786     *        margins, if applicable
4787     * @param childDimension How big the child wants to be in the current
4788     *        dimension
4789     * @return a MeasureSpec integer for the child
4790     */
4791    public static int getChildMeasureSpec(int spec, int padding, int childDimension) {
4792        int specMode = MeasureSpec.getMode(spec);
4793        int specSize = MeasureSpec.getSize(spec);
4794
4795        int size = Math.max(0, specSize - padding);
4796
4797        int resultSize = 0;
4798        int resultMode = 0;
4799
4800        switch (specMode) {
4801        // Parent has imposed an exact size on us
4802        case MeasureSpec.EXACTLY:
4803            if (childDimension >= 0) {
4804                resultSize = childDimension;
4805                resultMode = MeasureSpec.EXACTLY;
4806            } else if (childDimension == LayoutParams.MATCH_PARENT) {
4807                // Child wants to be our size. So be it.
4808                resultSize = size;
4809                resultMode = MeasureSpec.EXACTLY;
4810            } else if (childDimension == LayoutParams.WRAP_CONTENT) {
4811                // Child wants to determine its own size. It can't be
4812                // bigger than us.
4813                resultSize = size;
4814                resultMode = MeasureSpec.AT_MOST;
4815            }
4816            break;
4817
4818        // Parent has imposed a maximum size on us
4819        case MeasureSpec.AT_MOST:
4820            if (childDimension >= 0) {
4821                // Child wants a specific size... so be it
4822                resultSize = childDimension;
4823                resultMode = MeasureSpec.EXACTLY;
4824            } else if (childDimension == LayoutParams.MATCH_PARENT) {
4825                // Child wants to be our size, but our size is not fixed.
4826                // Constrain child to not be bigger than us.
4827                resultSize = size;
4828                resultMode = MeasureSpec.AT_MOST;
4829            } else if (childDimension == LayoutParams.WRAP_CONTENT) {
4830                // Child wants to determine its own size. It can't be
4831                // bigger than us.
4832                resultSize = size;
4833                resultMode = MeasureSpec.AT_MOST;
4834            }
4835            break;
4836
4837        // Parent asked to see how big we want to be
4838        case MeasureSpec.UNSPECIFIED:
4839            if (childDimension >= 0) {
4840                // Child wants a specific size... let him have it
4841                resultSize = childDimension;
4842                resultMode = MeasureSpec.EXACTLY;
4843            } else if (childDimension == LayoutParams.MATCH_PARENT) {
4844                // Child wants to be our size... find out how big it should
4845                // be
4846                resultSize = 0;
4847                resultMode = MeasureSpec.UNSPECIFIED;
4848            } else if (childDimension == LayoutParams.WRAP_CONTENT) {
4849                // Child wants to determine its own size.... find out how
4850                // big it should be
4851                resultSize = 0;
4852                resultMode = MeasureSpec.UNSPECIFIED;
4853            }
4854            break;
4855        }
4856        return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
4857    }
4858
4859
4860    /**
4861     * Removes any pending animations for views that have been removed. Call
4862     * this if you don't want animations for exiting views to stack up.
4863     */
4864    public void clearDisappearingChildren() {
4865        if (mDisappearingChildren != null) {
4866            mDisappearingChildren.clear();
4867            invalidate();
4868        }
4869    }
4870
4871    /**
4872     * Add a view which is removed from mChildren but still needs animation
4873     *
4874     * @param v View to add
4875     */
4876    private void addDisappearingView(View v) {
4877        ArrayList<View> disappearingChildren = mDisappearingChildren;
4878
4879        if (disappearingChildren == null) {
4880            disappearingChildren = mDisappearingChildren = new ArrayList<View>();
4881        }
4882
4883        disappearingChildren.add(v);
4884    }
4885
4886    /**
4887     * Cleanup a view when its animation is done. This may mean removing it from
4888     * the list of disappearing views.
4889     *
4890     * @param view The view whose animation has finished
4891     * @param animation The animation, cannot be null
4892     */
4893    void finishAnimatingView(final View view, Animation animation) {
4894        final ArrayList<View> disappearingChildren = mDisappearingChildren;
4895        if (disappearingChildren != null) {
4896            if (disappearingChildren.contains(view)) {
4897                disappearingChildren.remove(view);
4898
4899                if (view.mAttachInfo != null) {
4900                    view.dispatchDetachedFromWindow();
4901                }
4902
4903                view.clearAnimation();
4904                mGroupFlags |= FLAG_INVALIDATE_REQUIRED;
4905            }
4906        }
4907
4908        if (animation != null && !animation.getFillAfter()) {
4909            view.clearAnimation();
4910        }
4911
4912        if ((view.mPrivateFlags & ANIMATION_STARTED) == ANIMATION_STARTED) {
4913            view.onAnimationEnd();
4914            // Should be performed by onAnimationEnd() but this avoid an infinite loop,
4915            // so we'd rather be safe than sorry
4916            view.mPrivateFlags &= ~ANIMATION_STARTED;
4917            // Draw one more frame after the animation is done
4918            mGroupFlags |= FLAG_INVALIDATE_REQUIRED;
4919        }
4920    }
4921
4922    /**
4923     * Utility function called by View during invalidation to determine whether a view that
4924     * is invisible or gone should still be invalidated because it is being transitioned (and
4925     * therefore still needs to be drawn).
4926     */
4927    boolean isViewTransitioning(View view) {
4928        return (mTransitioningViews != null && mTransitioningViews.contains(view));
4929    }
4930
4931    /**
4932     * This method tells the ViewGroup that the given View object, which should have this
4933     * ViewGroup as its parent,
4934     * should be kept around  (re-displayed when the ViewGroup draws its children) even if it
4935     * is removed from its parent. This allows animations, such as those used by
4936     * {@link android.app.Fragment} and {@link android.animation.LayoutTransition} to animate
4937     * the removal of views. A call to this method should always be accompanied by a later call
4938     * to {@link #endViewTransition(View)}, such as after an animation on the View has finished,
4939     * so that the View finally gets removed.
4940     *
4941     * @param view The View object to be kept visible even if it gets removed from its parent.
4942     */
4943    public void startViewTransition(View view) {
4944        if (view.mParent == this) {
4945            if (mTransitioningViews == null) {
4946                mTransitioningViews = new ArrayList<View>();
4947            }
4948            mTransitioningViews.add(view);
4949        }
4950    }
4951
4952    /**
4953     * This method should always be called following an earlier call to
4954     * {@link #startViewTransition(View)}. The given View is finally removed from its parent
4955     * and will no longer be displayed. Note that this method does not perform the functionality
4956     * of removing a view from its parent; it just discontinues the display of a View that
4957     * has previously been removed.
4958     *
4959     * @return view The View object that has been removed but is being kept around in the visible
4960     * hierarchy by an earlier call to {@link #startViewTransition(View)}.
4961     */
4962    public void endViewTransition(View view) {
4963        if (mTransitioningViews != null) {
4964            mTransitioningViews.remove(view);
4965            final ArrayList<View> disappearingChildren = mDisappearingChildren;
4966            if (disappearingChildren != null && disappearingChildren.contains(view)) {
4967                disappearingChildren.remove(view);
4968                if (mVisibilityChangingChildren != null &&
4969                        mVisibilityChangingChildren.contains(view)) {
4970                    mVisibilityChangingChildren.remove(view);
4971                } else {
4972                    if (view.mAttachInfo != null) {
4973                        view.dispatchDetachedFromWindow();
4974                    }
4975                    if (view.mParent != null) {
4976                        view.mParent = null;
4977                    }
4978                }
4979                invalidate();
4980            }
4981        }
4982    }
4983
4984    private LayoutTransition.TransitionListener mLayoutTransitionListener =
4985            new LayoutTransition.TransitionListener() {
4986        @Override
4987        public void startTransition(LayoutTransition transition, ViewGroup container,
4988                View view, int transitionType) {
4989            // We only care about disappearing items, since we need special logic to keep
4990            // those items visible after they've been 'removed'
4991            if (transitionType == LayoutTransition.DISAPPEARING) {
4992                startViewTransition(view);
4993            }
4994        }
4995
4996        @Override
4997        public void endTransition(LayoutTransition transition, ViewGroup container,
4998                View view, int transitionType) {
4999            if (mLayoutSuppressed && !transition.isChangingLayout()) {
5000                requestLayout();
5001                mLayoutSuppressed = false;
5002            }
5003            if (transitionType == LayoutTransition.DISAPPEARING && mTransitioningViews != null) {
5004                endViewTransition(view);
5005            }
5006        }
5007    };
5008
5009    /**
5010     * {@inheritDoc}
5011     */
5012    @Override
5013    public boolean gatherTransparentRegion(Region region) {
5014        // If no transparent regions requested, we are always opaque.
5015        final boolean meOpaque = (mPrivateFlags & View.REQUEST_TRANSPARENT_REGIONS) == 0;
5016        if (meOpaque && region == null) {
5017            // The caller doesn't care about the region, so stop now.
5018            return true;
5019        }
5020        super.gatherTransparentRegion(region);
5021        final View[] children = mChildren;
5022        final int count = mChildrenCount;
5023        boolean noneOfTheChildrenAreTransparent = true;
5024        for (int i = 0; i < count; i++) {
5025            final View child = children[i];
5026            if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
5027                if (!child.gatherTransparentRegion(region)) {
5028                    noneOfTheChildrenAreTransparent = false;
5029                }
5030            }
5031        }
5032        return meOpaque || noneOfTheChildrenAreTransparent;
5033    }
5034
5035    /**
5036     * {@inheritDoc}
5037     */
5038    public void requestTransparentRegion(View child) {
5039        if (child != null) {
5040            child.mPrivateFlags |= View.REQUEST_TRANSPARENT_REGIONS;
5041            if (mParent != null) {
5042                mParent.requestTransparentRegion(this);
5043            }
5044        }
5045    }
5046
5047
5048    @Override
5049    protected boolean fitSystemWindows(Rect insets) {
5050        boolean done = super.fitSystemWindows(insets);
5051        if (!done) {
5052            final int count = mChildrenCount;
5053            final View[] children = mChildren;
5054            for (int i = 0; i < count; i++) {
5055                done = children[i].fitSystemWindows(insets);
5056                if (done) {
5057                    break;
5058                }
5059            }
5060        }
5061        return done;
5062    }
5063
5064    /**
5065     * Returns the animation listener to which layout animation events are
5066     * sent.
5067     *
5068     * @return an {@link android.view.animation.Animation.AnimationListener}
5069     */
5070    public Animation.AnimationListener getLayoutAnimationListener() {
5071        return mAnimationListener;
5072    }
5073
5074    @Override
5075    protected void drawableStateChanged() {
5076        super.drawableStateChanged();
5077
5078        if ((mGroupFlags & FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE) != 0) {
5079            if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0) {
5080                throw new IllegalStateException("addStateFromChildren cannot be enabled if a"
5081                        + " child has duplicateParentState set to true");
5082            }
5083
5084            final View[] children = mChildren;
5085            final int count = mChildrenCount;
5086
5087            for (int i = 0; i < count; i++) {
5088                final View child = children[i];
5089                if ((child.mViewFlags & DUPLICATE_PARENT_STATE) != 0) {
5090                    child.refreshDrawableState();
5091                }
5092            }
5093        }
5094    }
5095
5096    @Override
5097    public void jumpDrawablesToCurrentState() {
5098        super.jumpDrawablesToCurrentState();
5099        final View[] children = mChildren;
5100        final int count = mChildrenCount;
5101        for (int i = 0; i < count; i++) {
5102            children[i].jumpDrawablesToCurrentState();
5103        }
5104    }
5105
5106    @Override
5107    protected int[] onCreateDrawableState(int extraSpace) {
5108        if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) == 0) {
5109            return super.onCreateDrawableState(extraSpace);
5110        }
5111
5112        int need = 0;
5113        int n = getChildCount();
5114        for (int i = 0; i < n; i++) {
5115            int[] childState = getChildAt(i).getDrawableState();
5116
5117            if (childState != null) {
5118                need += childState.length;
5119            }
5120        }
5121
5122        int[] state = super.onCreateDrawableState(extraSpace + need);
5123
5124        for (int i = 0; i < n; i++) {
5125            int[] childState = getChildAt(i).getDrawableState();
5126
5127            if (childState != null) {
5128                state = mergeDrawableStates(state, childState);
5129            }
5130        }
5131
5132        return state;
5133    }
5134
5135    /**
5136     * Sets whether this ViewGroup's drawable states also include
5137     * its children's drawable states.  This is used, for example, to
5138     * make a group appear to be focused when its child EditText or button
5139     * is focused.
5140     */
5141    public void setAddStatesFromChildren(boolean addsStates) {
5142        if (addsStates) {
5143            mGroupFlags |= FLAG_ADD_STATES_FROM_CHILDREN;
5144        } else {
5145            mGroupFlags &= ~FLAG_ADD_STATES_FROM_CHILDREN;
5146        }
5147
5148        refreshDrawableState();
5149    }
5150
5151    /**
5152     * Returns whether this ViewGroup's drawable states also include
5153     * its children's drawable states.  This is used, for example, to
5154     * make a group appear to be focused when its child EditText or button
5155     * is focused.
5156     */
5157    public boolean addStatesFromChildren() {
5158        return (mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0;
5159    }
5160
5161    /**
5162     * If {link #addStatesFromChildren} is true, refreshes this group's
5163     * drawable state (to include the states from its children).
5164     */
5165    public void childDrawableStateChanged(View child) {
5166        if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0) {
5167            refreshDrawableState();
5168        }
5169    }
5170
5171    /**
5172     * Specifies the animation listener to which layout animation events must
5173     * be sent. Only
5174     * {@link android.view.animation.Animation.AnimationListener#onAnimationStart(Animation)}
5175     * and
5176     * {@link android.view.animation.Animation.AnimationListener#onAnimationEnd(Animation)}
5177     * are invoked.
5178     *
5179     * @param animationListener the layout animation listener
5180     */
5181    public void setLayoutAnimationListener(Animation.AnimationListener animationListener) {
5182        mAnimationListener = animationListener;
5183    }
5184
5185    /**
5186     * This method is called by LayoutTransition when there are 'changing' animations that need
5187     * to start after the layout/setup phase. The request is forwarded to the ViewAncestor, who
5188     * starts all pending transitions prior to the drawing phase in the current traversal.
5189     *
5190     * @param transition The LayoutTransition to be started on the next traversal.
5191     *
5192     * @hide
5193     */
5194    public void requestTransitionStart(LayoutTransition transition) {
5195        ViewRootImpl viewAncestor = getViewRootImpl();
5196        if (viewAncestor != null) {
5197            viewAncestor.requestTransitionStart(transition);
5198        }
5199    }
5200
5201    @Override
5202    public void onResolvedLayoutDirectionReset() {
5203        // Take care of resetting the children resolution too
5204        final int count = getChildCount();
5205        for (int i = 0; i < count; i++) {
5206            final View child = getChildAt(i);
5207            if (child.getLayoutDirection() == LAYOUT_DIRECTION_INHERIT) {
5208                child.resetResolvedLayoutDirection();
5209            }
5210        }
5211    }
5212
5213    @Override
5214    public void onResolvedTextDirectionReset() {
5215        // Take care of resetting the children resolution too
5216        final int count = getChildCount();
5217        for (int i = 0; i < count; i++) {
5218            final View child = getChildAt(i);
5219            if (child.getTextDirection() == TEXT_DIRECTION_INHERIT) {
5220                child.resetResolvedTextDirection();
5221            }
5222        }
5223    }
5224
5225    @Override
5226    public void onResolvedTextAlignmentReset() {
5227        // Take care of resetting the children resolution too
5228        final int count = getChildCount();
5229        for (int i = 0; i < count; i++) {
5230            final View child = getChildAt(i);
5231            if (child.getTextAlignment() == TEXT_ALIGNMENT_INHERIT) {
5232                child.resetResolvedTextAlignment();
5233            }
5234        }
5235    }
5236
5237    /**
5238     * Return true if the pressed state should be delayed for children or descendants of this
5239     * ViewGroup. Generally, this should be done for containers that can scroll, such as a List.
5240     * This prevents the pressed state from appearing when the user is actually trying to scroll
5241     * the content.
5242     *
5243     * The default implementation returns true for compatibility reasons. Subclasses that do
5244     * not scroll should generally override this method and return false.
5245     */
5246    public boolean shouldDelayChildPressedState() {
5247        return true;
5248    }
5249
5250    /** @hide */
5251    protected void onSetLayoutParams(View child, LayoutParams layoutParams) {
5252    }
5253
5254    /**
5255     * LayoutParams are used by views to tell their parents how they want to be
5256     * laid out. See
5257     * {@link android.R.styleable#ViewGroup_Layout ViewGroup Layout Attributes}
5258     * for a list of all child view attributes that this class supports.
5259     *
5260     * <p>
5261     * The base LayoutParams class just describes how big the view wants to be
5262     * for both width and height. For each dimension, it can specify one of:
5263     * <ul>
5264     * <li>FILL_PARENT (renamed MATCH_PARENT in API Level 8 and higher), which
5265     * means that the view wants to be as big as its parent (minus padding)
5266     * <li> WRAP_CONTENT, which means that the view wants to be just big enough
5267     * to enclose its content (plus padding)
5268     * <li> an exact number
5269     * </ul>
5270     * There are subclasses of LayoutParams for different subclasses of
5271     * ViewGroup. For example, AbsoluteLayout has its own subclass of
5272     * LayoutParams which adds an X and Y value.</p>
5273     *
5274     * <div class="special reference">
5275     * <h3>Developer Guides</h3>
5276     * <p>For more information about creating user interface layouts, read the
5277     * <a href="{@docRoot}guide/topics/ui/declaring-layout.html">XML Layouts</a> developer
5278     * guide.</p></div>
5279     *
5280     * @attr ref android.R.styleable#ViewGroup_Layout_layout_height
5281     * @attr ref android.R.styleable#ViewGroup_Layout_layout_width
5282     */
5283    public static class LayoutParams {
5284        /**
5285         * Special value for the height or width requested by a View.
5286         * FILL_PARENT means that the view wants to be as big as its parent,
5287         * minus the parent's padding, if any. This value is deprecated
5288         * starting in API Level 8 and replaced by {@link #MATCH_PARENT}.
5289         */
5290        @SuppressWarnings({"UnusedDeclaration"})
5291        @Deprecated
5292        public static final int FILL_PARENT = -1;
5293
5294        /**
5295         * Special value for the height or width requested by a View.
5296         * MATCH_PARENT means that the view wants to be as big as its parent,
5297         * minus the parent's padding, if any. Introduced in API Level 8.
5298         */
5299        public static final int MATCH_PARENT = -1;
5300
5301        /**
5302         * Special value for the height or width requested by a View.
5303         * WRAP_CONTENT means that the view wants to be just large enough to fit
5304         * its own internal content, taking its own padding into account.
5305         */
5306        public static final int WRAP_CONTENT = -2;
5307
5308        /**
5309         * Information about how wide the view wants to be. Can be one of the
5310         * constants FILL_PARENT (replaced by MATCH_PARENT ,
5311         * in API Level 8) or WRAP_CONTENT. or an exact size.
5312         */
5313        @ViewDebug.ExportedProperty(category = "layout", mapping = {
5314            @ViewDebug.IntToString(from = MATCH_PARENT, to = "MATCH_PARENT"),
5315            @ViewDebug.IntToString(from = WRAP_CONTENT, to = "WRAP_CONTENT")
5316        })
5317        public int width;
5318
5319        /**
5320         * Information about how tall the view wants to be. Can be one of the
5321         * constants FILL_PARENT (replaced by MATCH_PARENT ,
5322         * in API Level 8) or WRAP_CONTENT. or an exact size.
5323         */
5324        @ViewDebug.ExportedProperty(category = "layout", mapping = {
5325            @ViewDebug.IntToString(from = MATCH_PARENT, to = "MATCH_PARENT"),
5326            @ViewDebug.IntToString(from = WRAP_CONTENT, to = "WRAP_CONTENT")
5327        })
5328        public int height;
5329
5330        /**
5331         * Used to animate layouts.
5332         */
5333        public LayoutAnimationController.AnimationParameters layoutAnimationParameters;
5334
5335        /**
5336         * Creates a new set of layout parameters. The values are extracted from
5337         * the supplied attributes set and context. The XML attributes mapped
5338         * to this set of layout parameters are:
5339         *
5340         * <ul>
5341         *   <li><code>layout_width</code>: the width, either an exact value,
5342         *   {@link #WRAP_CONTENT}, or {@link #FILL_PARENT} (replaced by
5343         *   {@link #MATCH_PARENT} in API Level 8)</li>
5344         *   <li><code>layout_height</code>: the height, either an exact value,
5345         *   {@link #WRAP_CONTENT}, or {@link #FILL_PARENT} (replaced by
5346         *   {@link #MATCH_PARENT} in API Level 8)</li>
5347         * </ul>
5348         *
5349         * @param c the application environment
5350         * @param attrs the set of attributes from which to extract the layout
5351         *              parameters' values
5352         */
5353        public LayoutParams(Context c, AttributeSet attrs) {
5354            TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.ViewGroup_Layout);
5355            setBaseAttributes(a,
5356                    R.styleable.ViewGroup_Layout_layout_width,
5357                    R.styleable.ViewGroup_Layout_layout_height);
5358            a.recycle();
5359        }
5360
5361        /**
5362         * Creates a new set of layout parameters with the specified width
5363         * and height.
5364         *
5365         * @param width the width, either {@link #WRAP_CONTENT},
5366         *        {@link #FILL_PARENT} (replaced by {@link #MATCH_PARENT} in
5367         *        API Level 8), or a fixed size in pixels
5368         * @param height the height, either {@link #WRAP_CONTENT},
5369         *        {@link #FILL_PARENT} (replaced by {@link #MATCH_PARENT} in
5370         *        API Level 8), or a fixed size in pixels
5371         */
5372        public LayoutParams(int width, int height) {
5373            this.width = width;
5374            this.height = height;
5375        }
5376
5377        /**
5378         * Copy constructor. Clones the width and height values of the source.
5379         *
5380         * @param source The layout params to copy from.
5381         */
5382        public LayoutParams(LayoutParams source) {
5383            this.width = source.width;
5384            this.height = source.height;
5385        }
5386
5387        /**
5388         * Used internally by MarginLayoutParams.
5389         * @hide
5390         */
5391        LayoutParams() {
5392        }
5393
5394        /**
5395         * Extracts the <code>width</code> and <code>height</code> layout parameters
5396         * from the supplied TypedArray, <code>a</code>, and assigns them
5397         * to the appropriate fields. If, <code>a</code>, does not contain an
5398         * entry for either attribute, the value, {@link ViewGroup.LayoutParams#WRAP_CONTENT},
5399         * is used as a default.
5400         *
5401         * @param a the style attributes to extract the parameters from
5402         * @param widthAttr the identifier of the width attribute
5403         * @param heightAttr the identifier of the height attribute
5404         */
5405        protected void setBaseAttributes(TypedArray a, int widthAttr, int heightAttr) {
5406            width = a.getLayoutDimension(widthAttr, WRAP_CONTENT);
5407            height = a.getLayoutDimension(heightAttr, WRAP_CONTENT);
5408        }
5409
5410        /**
5411         * Resolve layout parameters depending on the layout direction. Subclasses that care about
5412         * layoutDirection changes should override this method. The default implementation does
5413         * nothing.
5414         *
5415         * @param layoutDirection the direction of the layout
5416         *
5417         * {@link View#LAYOUT_DIRECTION_LTR}
5418         * {@link View#LAYOUT_DIRECTION_RTL}
5419         */
5420        public void onResolveLayoutDirection(int layoutDirection) {
5421        }
5422
5423        /**
5424         * Returns a String representation of this set of layout parameters.
5425         *
5426         * @param output the String to prepend to the internal representation
5427         * @return a String with the following format: output +
5428         *         "ViewGroup.LayoutParams={ width=WIDTH, height=HEIGHT }"
5429         *
5430         * @hide
5431         */
5432        public String debug(String output) {
5433            return output + "ViewGroup.LayoutParams={ width="
5434                    + sizeToString(width) + ", height=" + sizeToString(height) + " }";
5435        }
5436
5437        /**
5438         * Use {@code canvas} to draw suitable debugging annotations for these LayoutParameters.
5439         *
5440         * @param view the view that contains these layout parameters
5441         * @param canvas the canvas on which to draw
5442         *
5443         * @hide
5444         */
5445        public void onDebugDraw(View view, Canvas canvas) {
5446        }
5447
5448        /**
5449         * Converts the specified size to a readable String.
5450         *
5451         * @param size the size to convert
5452         * @return a String instance representing the supplied size
5453         *
5454         * @hide
5455         */
5456        protected static String sizeToString(int size) {
5457            if (size == WRAP_CONTENT) {
5458                return "wrap-content";
5459            }
5460            if (size == MATCH_PARENT) {
5461                return "match-parent";
5462            }
5463            return String.valueOf(size);
5464        }
5465    }
5466
5467    /**
5468     * Per-child layout information for layouts that support margins.
5469     * See
5470     * {@link android.R.styleable#ViewGroup_MarginLayout ViewGroup Margin Layout Attributes}
5471     * for a list of all child view attributes that this class supports.
5472     */
5473    public static class MarginLayoutParams extends ViewGroup.LayoutParams {
5474        /**
5475         * The left margin in pixels of the child.
5476         * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
5477         * to this field.
5478         */
5479        @ViewDebug.ExportedProperty(category = "layout")
5480        public int leftMargin;
5481
5482        /**
5483         * The top margin in pixels of the child.
5484         * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
5485         * to this field.
5486         */
5487        @ViewDebug.ExportedProperty(category = "layout")
5488        public int topMargin;
5489
5490        /**
5491         * The right margin in pixels of the child.
5492         * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
5493         * to this field.
5494         */
5495        @ViewDebug.ExportedProperty(category = "layout")
5496        public int rightMargin;
5497
5498        /**
5499         * The bottom margin in pixels of the child.
5500         * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
5501         * to this field.
5502         */
5503        @ViewDebug.ExportedProperty(category = "layout")
5504        public int bottomMargin;
5505
5506        /**
5507         * The start margin in pixels of the child.
5508         * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
5509         * to this field.
5510         */
5511        @ViewDebug.ExportedProperty(category = "layout")
5512        public int startMargin = DEFAULT_RELATIVE;
5513
5514        /**
5515         * The end margin in pixels of the child.
5516         * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
5517         * to this field.
5518         */
5519        @ViewDebug.ExportedProperty(category = "layout")
5520        public int endMargin = DEFAULT_RELATIVE;
5521
5522        /**
5523         * The default start and end margin.
5524         */
5525        static private final int DEFAULT_RELATIVE = Integer.MIN_VALUE;
5526
5527        private int initialLeftMargin;
5528        private int initialRightMargin;
5529
5530        private int layoutDirection;
5531
5532        /**
5533         * Creates a new set of layout parameters. The values are extracted from
5534         * the supplied attributes set and context.
5535         *
5536         * @param c the application environment
5537         * @param attrs the set of attributes from which to extract the layout
5538         *              parameters' values
5539         */
5540        public MarginLayoutParams(Context c, AttributeSet attrs) {
5541            super();
5542
5543            TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.ViewGroup_MarginLayout);
5544            setBaseAttributes(a,
5545                    R.styleable.ViewGroup_MarginLayout_layout_width,
5546                    R.styleable.ViewGroup_MarginLayout_layout_height);
5547
5548            int margin = a.getDimensionPixelSize(
5549                    com.android.internal.R.styleable.ViewGroup_MarginLayout_layout_margin, -1);
5550            if (margin >= 0) {
5551                leftMargin = margin;
5552                topMargin = margin;
5553                rightMargin= margin;
5554                bottomMargin = margin;
5555            } else {
5556                leftMargin = a.getDimensionPixelSize(
5557                        R.styleable.ViewGroup_MarginLayout_layout_marginLeft, 0);
5558                topMargin = a.getDimensionPixelSize(
5559                        R.styleable.ViewGroup_MarginLayout_layout_marginTop, 0);
5560                rightMargin = a.getDimensionPixelSize(
5561                        R.styleable.ViewGroup_MarginLayout_layout_marginRight, 0);
5562                bottomMargin = a.getDimensionPixelSize(
5563                        R.styleable.ViewGroup_MarginLayout_layout_marginBottom, 0);
5564                startMargin = a.getDimensionPixelSize(
5565                        R.styleable.ViewGroup_MarginLayout_layout_marginStart, DEFAULT_RELATIVE);
5566                endMargin = a.getDimensionPixelSize(
5567                        R.styleable.ViewGroup_MarginLayout_layout_marginEnd, DEFAULT_RELATIVE);
5568            }
5569
5570            initialLeftMargin = leftMargin;
5571            initialRightMargin = rightMargin;
5572
5573            // LTR by default
5574            layoutDirection = View.LAYOUT_DIRECTION_LTR;
5575
5576            a.recycle();
5577        }
5578
5579        /**
5580         * {@inheritDoc}
5581         */
5582        public MarginLayoutParams(int width, int height) {
5583            super(width, height);
5584        }
5585
5586        /**
5587         * Copy constructor. Clones the width, height and margin values of the source.
5588         *
5589         * @param source The layout params to copy from.
5590         */
5591        public MarginLayoutParams(MarginLayoutParams source) {
5592            this.width = source.width;
5593            this.height = source.height;
5594
5595            this.leftMargin = source.leftMargin;
5596            this.topMargin = source.topMargin;
5597            this.rightMargin = source.rightMargin;
5598            this.bottomMargin = source.bottomMargin;
5599            this.startMargin = source.startMargin;
5600            this.endMargin = source.endMargin;
5601
5602            this.initialLeftMargin = source.leftMargin;
5603            this.initialRightMargin = source.rightMargin;
5604
5605            this.layoutDirection = source.layoutDirection;
5606        }
5607
5608        /**
5609         * {@inheritDoc}
5610         */
5611        public MarginLayoutParams(LayoutParams source) {
5612            super(source);
5613        }
5614
5615        /**
5616         * Sets the margins, in pixels. A call to {@link android.view.View#requestLayout()} needs
5617         * to be done so that the new margins are taken into account. Left and right margins may be
5618         * overriden by {@link android.view.View#requestLayout()} depending on layout direction.
5619         *
5620         * @param left the left margin size
5621         * @param top the top margin size
5622         * @param right the right margin size
5623         * @param bottom the bottom margin size
5624         *
5625         * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginLeft
5626         * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginTop
5627         * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginRight
5628         * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginBottom
5629         */
5630        public void setMargins(int left, int top, int right, int bottom) {
5631            leftMargin = left;
5632            topMargin = top;
5633            rightMargin = right;
5634            bottomMargin = bottom;
5635            initialLeftMargin = left;
5636            initialRightMargin = right;
5637        }
5638
5639        /**
5640         * Sets the relative margins, in pixels. A call to {@link android.view.View#requestLayout()}
5641         * needs to be done so that the new relative margins are taken into account. Left and right
5642         * margins may be overriden by {@link android.view.View#requestLayout()} depending on layout
5643         * direction.
5644         *
5645         * @param start the start margin size
5646         * @param top the top margin size
5647         * @param end the right margin size
5648         * @param bottom the bottom margin size
5649         *
5650         * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart
5651         * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginTop
5652         * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd
5653         * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginBottom
5654         *
5655         * @hide
5656         */
5657        public void setMarginsRelative(int start, int top, int end, int bottom) {
5658            startMargin = start;
5659            topMargin = top;
5660            endMargin = end;
5661            bottomMargin = bottom;
5662            initialLeftMargin = 0;
5663            initialRightMargin = 0;
5664        }
5665
5666        /**
5667         * Returns the start margin in pixels.
5668         *
5669         * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart
5670         *
5671         * @return the start margin in pixels.
5672         */
5673        public int getMarginStart() {
5674            if (startMargin != DEFAULT_RELATIVE) return startMargin;
5675            switch(layoutDirection) {
5676                case View.LAYOUT_DIRECTION_RTL:
5677                    return rightMargin;
5678                case View.LAYOUT_DIRECTION_LTR:
5679                default:
5680                    return leftMargin;
5681            }
5682        }
5683
5684        /**
5685         * Returns the end margin in pixels.
5686         *
5687         * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd
5688         *
5689         * @return the end margin in pixels.
5690         */
5691        public int getMarginEnd() {
5692            if (endMargin != DEFAULT_RELATIVE) return endMargin;
5693            switch(layoutDirection) {
5694                case View.LAYOUT_DIRECTION_RTL:
5695                    return leftMargin;
5696                case View.LAYOUT_DIRECTION_LTR:
5697                default:
5698                    return rightMargin;
5699            }
5700        }
5701
5702        /**
5703         * Check if margins are relative.
5704         *
5705         * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart
5706         * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd
5707         *
5708         * @return true if either marginStart or marginEnd has been set
5709         */
5710        public boolean isMarginRelative() {
5711            return (startMargin != DEFAULT_RELATIVE) || (endMargin != DEFAULT_RELATIVE);
5712        }
5713
5714        /**
5715         * This will be called by {@link android.view.View#requestLayout()}. Left and Right margins
5716         * may be overridden depending on layout direction.
5717         */
5718        @Override
5719        public void onResolveLayoutDirection(int layoutDirection) {
5720            this.layoutDirection = layoutDirection;
5721
5722            if (!isMarginRelative()) return;
5723
5724            switch(layoutDirection) {
5725                case View.LAYOUT_DIRECTION_RTL:
5726                    leftMargin = (endMargin > DEFAULT_RELATIVE) ? endMargin : initialLeftMargin;
5727                    rightMargin = (startMargin > DEFAULT_RELATIVE) ? startMargin : initialRightMargin;
5728                    break;
5729                case View.LAYOUT_DIRECTION_LTR:
5730                default:
5731                    leftMargin = (startMargin > DEFAULT_RELATIVE) ? startMargin : initialLeftMargin;
5732                    rightMargin = (endMargin > DEFAULT_RELATIVE) ? endMargin : initialRightMargin;
5733                    break;
5734            }
5735        }
5736
5737        /**
5738         * @hide
5739         */
5740        @Override
5741        public void onDebugDraw(View view, Canvas canvas) {
5742            drawRect(canvas,
5743                    view.getLeft() - leftMargin,
5744                    view.getTop() - topMargin,
5745                    view.getRight() + rightMargin,
5746                    view.getBottom() + bottomMargin, Color.MAGENTA);
5747        }
5748    }
5749
5750    /* Describes a touched view and the ids of the pointers that it has captured.
5751     *
5752     * This code assumes that pointer ids are always in the range 0..31 such that
5753     * it can use a bitfield to track which pointer ids are present.
5754     * As it happens, the lower layers of the input dispatch pipeline also use the
5755     * same trick so the assumption should be safe here...
5756     */
5757    private static final class TouchTarget {
5758        private static final int MAX_RECYCLED = 32;
5759        private static final Object sRecycleLock = new Object();
5760        private static TouchTarget sRecycleBin;
5761        private static int sRecycledCount;
5762
5763        public static final int ALL_POINTER_IDS = -1; // all ones
5764
5765        // The touched child view.
5766        public View child;
5767
5768        // The combined bit mask of pointer ids for all pointers captured by the target.
5769        public int pointerIdBits;
5770
5771        // The next target in the target list.
5772        public TouchTarget next;
5773
5774        private TouchTarget() {
5775        }
5776
5777        public static TouchTarget obtain(View child, int pointerIdBits) {
5778            final TouchTarget target;
5779            synchronized (sRecycleLock) {
5780                if (sRecycleBin == null) {
5781                    target = new TouchTarget();
5782                } else {
5783                    target = sRecycleBin;
5784                    sRecycleBin = target.next;
5785                     sRecycledCount--;
5786                    target.next = null;
5787                }
5788            }
5789            target.child = child;
5790            target.pointerIdBits = pointerIdBits;
5791            return target;
5792        }
5793
5794        public void recycle() {
5795            synchronized (sRecycleLock) {
5796                if (sRecycledCount < MAX_RECYCLED) {
5797                    next = sRecycleBin;
5798                    sRecycleBin = this;
5799                    sRecycledCount += 1;
5800                } else {
5801                    next = null;
5802                }
5803                child = null;
5804            }
5805        }
5806    }
5807
5808    /* Describes a hovered view. */
5809    private static final class HoverTarget {
5810        private static final int MAX_RECYCLED = 32;
5811        private static final Object sRecycleLock = new Object();
5812        private static HoverTarget sRecycleBin;
5813        private static int sRecycledCount;
5814
5815        // The hovered child view.
5816        public View child;
5817
5818        // The next target in the target list.
5819        public HoverTarget next;
5820
5821        private HoverTarget() {
5822        }
5823
5824        public static HoverTarget obtain(View child) {
5825            final HoverTarget target;
5826            synchronized (sRecycleLock) {
5827                if (sRecycleBin == null) {
5828                    target = new HoverTarget();
5829                } else {
5830                    target = sRecycleBin;
5831                    sRecycleBin = target.next;
5832                     sRecycledCount--;
5833                    target.next = null;
5834                }
5835            }
5836            target.child = child;
5837            return target;
5838        }
5839
5840        public void recycle() {
5841            synchronized (sRecycleLock) {
5842                if (sRecycledCount < MAX_RECYCLED) {
5843                    next = sRecycleBin;
5844                    sRecycleBin = this;
5845                    sRecycledCount += 1;
5846                } else {
5847                    next = null;
5848                }
5849                child = null;
5850            }
5851        }
5852    }
5853
5854    /**
5855     * Pooled class that orderes the children of a ViewGroup from start
5856     * to end based on how they are laid out and the layout direction.
5857     */
5858    static class ChildListForAccessibility {
5859
5860        private static final int MAX_POOL_SIZE = 32;
5861
5862        private static final Object sPoolLock = new Object();
5863
5864        private static ChildListForAccessibility sPool;
5865
5866        private static int sPoolSize;
5867
5868        private boolean mIsPooled;
5869
5870        private ChildListForAccessibility mNext;
5871
5872        private final ArrayList<View> mChildren = new ArrayList<View>();
5873
5874        private final ArrayList<ViewLocationHolder> mHolders = new ArrayList<ViewLocationHolder>();
5875
5876        public static ChildListForAccessibility obtain(ViewGroup parent, boolean sort) {
5877            ChildListForAccessibility list = null;
5878            synchronized (sPoolLock) {
5879                if (sPool != null) {
5880                    list = sPool;
5881                    sPool = list.mNext;
5882                    list.mNext = null;
5883                    list.mIsPooled = false;
5884                    sPoolSize--;
5885                } else {
5886                    list = new ChildListForAccessibility();
5887                }
5888                list.init(parent, sort);
5889                return list;
5890            }
5891        }
5892
5893        public void recycle() {
5894            if (mIsPooled) {
5895                throw new IllegalStateException("Instance already recycled.");
5896            }
5897            clear();
5898            synchronized (sPoolLock) {
5899                if (sPoolSize < MAX_POOL_SIZE) {
5900                    mNext = sPool;
5901                    mIsPooled = true;
5902                    sPool = this;
5903                    sPoolSize++;
5904                }
5905            }
5906        }
5907
5908        public int getChildCount() {
5909            return mChildren.size();
5910        }
5911
5912        public View getChildAt(int index) {
5913            return mChildren.get(index);
5914        }
5915
5916        public int getChildIndex(View child) {
5917            return mChildren.indexOf(child);
5918        }
5919
5920        private void init(ViewGroup parent, boolean sort) {
5921            ArrayList<View> children = mChildren;
5922            final int childCount = parent.getChildCount();
5923            for (int i = 0; i < childCount; i++) {
5924                View child = parent.getChildAt(i);
5925                children.add(child);
5926            }
5927            if (sort) {
5928                ArrayList<ViewLocationHolder> holders = mHolders;
5929                for (int i = 0; i < childCount; i++) {
5930                    View child = children.get(i);
5931                    ViewLocationHolder holder = ViewLocationHolder.obtain(parent, child);
5932                    holders.add(holder);
5933                }
5934                Collections.sort(holders);
5935                for (int i = 0; i < childCount; i++) {
5936                    ViewLocationHolder holder = holders.get(i);
5937                    children.set(i, holder.mView);
5938                    holder.recycle();
5939                }
5940                holders.clear();
5941            }
5942        }
5943
5944        private void clear() {
5945            mChildren.clear();
5946        }
5947    }
5948
5949    /**
5950     * Pooled class that holds a View and its location with respect to
5951     * a specified root. This enables sorting of views based on their
5952     * coordinates without recomputing the position relative to the root
5953     * on every comparison.
5954     */
5955    static class ViewLocationHolder implements Comparable<ViewLocationHolder> {
5956
5957        private static final int MAX_POOL_SIZE = 32;
5958
5959        private static final Object sPoolLock = new Object();
5960
5961        private static ViewLocationHolder sPool;
5962
5963        private static int sPoolSize;
5964
5965        private boolean mIsPooled;
5966
5967        private ViewLocationHolder mNext;
5968
5969        private final Rect mLocation = new Rect();
5970
5971        public View mView;
5972
5973        private int mLayoutDirection;
5974
5975        public static ViewLocationHolder obtain(ViewGroup root, View view) {
5976            ViewLocationHolder holder = null;
5977            synchronized (sPoolLock) {
5978                if (sPool != null) {
5979                    holder = sPool;
5980                    sPool = holder.mNext;
5981                    holder.mNext = null;
5982                    holder.mIsPooled = false;
5983                    sPoolSize--;
5984                } else {
5985                    holder = new ViewLocationHolder();
5986                }
5987                holder.init(root, view);
5988                return holder;
5989            }
5990        }
5991
5992        public void recycle() {
5993            if (mIsPooled) {
5994                throw new IllegalStateException("Instance already recycled.");
5995            }
5996            clear();
5997            synchronized (sPoolLock) {
5998                if (sPoolSize < MAX_POOL_SIZE) {
5999                    mNext = sPool;
6000                    mIsPooled = true;
6001                    sPool = this;
6002                    sPoolSize++;
6003                }
6004            }
6005        }
6006
6007        @Override
6008        public int compareTo(ViewLocationHolder another) {
6009            // This instance is greater than an invalid argument.
6010            if (another == null) {
6011                return 1;
6012            }
6013            if (getClass() != another.getClass()) {
6014                return 1;
6015            }
6016            // First is above second.
6017            if (mLocation.bottom - another.mLocation.top <= 0) {
6018                return -1;
6019            }
6020            // First is below second.
6021            if (mLocation.top - another.mLocation.bottom >= 0) {
6022                return 1;
6023            }
6024            // LTR
6025            if (mLayoutDirection == LAYOUT_DIRECTION_LTR) {
6026                final int leftDifference = mLocation.left - another.mLocation.left;
6027                // First more to the left than second.
6028                if (leftDifference != 0) {
6029                    return leftDifference;
6030                }
6031            } else { // RTL
6032                final int rightDifference = mLocation.right - another.mLocation.right;
6033                // First more to the right than second.
6034                if (rightDifference != 0) {
6035                    return -rightDifference;
6036                }
6037            }
6038            // Break tie by top.
6039            final int topDiference = mLocation.top - another.mLocation.top;
6040            if (topDiference != 0) {
6041                return topDiference;
6042            }
6043            // Break tie by height.
6044            final int heightDiference = mLocation.height() - another.mLocation.height();
6045            if (heightDiference != 0) {
6046                return -heightDiference;
6047            }
6048            // Break tie by width.
6049            final int widthDiference = mLocation.width() - another.mLocation.width();
6050            if (widthDiference != 0) {
6051                return -widthDiference;
6052            }
6053            // Just break the tie somehow. The accessibliity ids are unique
6054            // and stable, hence this is deterministic tie breaking.
6055            return mView.getAccessibilityViewId() - another.mView.getAccessibilityViewId();
6056        }
6057
6058        private void init(ViewGroup root, View view) {
6059            Rect viewLocation = mLocation;
6060            view.getDrawingRect(viewLocation);
6061            root.offsetDescendantRectToMyCoords(view, viewLocation);
6062            mView = view;
6063            mLayoutDirection = root.getResolvedLayoutDirection();
6064        }
6065
6066        private void clear() {
6067            mView = null;
6068            mLocation.set(0, 0, 0, 0);
6069        }
6070    }
6071
6072    private static Paint getDebugPaint() {
6073        if (sDebugPaint == null) {
6074            sDebugPaint = new Paint();
6075            sDebugPaint.setAntiAlias(false);
6076        }
6077        return sDebugPaint;
6078    }
6079
6080    private static float[] getDebugLines(int x1, int y1, int x2, int y2) {
6081        if (sDebugLines== null) {
6082            sDebugLines = new float[16];
6083        }
6084
6085        x2--;
6086        y2--;
6087
6088        sDebugLines[0] = x1;
6089        sDebugLines[1] = y1;
6090        sDebugLines[2] = x2;
6091        sDebugLines[3] = y1;
6092
6093        sDebugLines[4] = x2;
6094        sDebugLines[5] = y1;
6095        sDebugLines[6] = x2;
6096        sDebugLines[7] = y2 + 1;
6097
6098        sDebugLines[8] = x2 + 1;
6099        sDebugLines[9] = y2;
6100        sDebugLines[10] = x1;
6101        sDebugLines[11] = y2;
6102
6103        sDebugLines[12]  = x1;
6104        sDebugLines[13]  = y2;
6105        sDebugLines[14] = x1;
6106        sDebugLines[15] = y1;
6107
6108        return sDebugLines;
6109    }
6110}
6111