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