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