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