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