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