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