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