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