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