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