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