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