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