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