OSDN Git Service

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