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