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