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