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