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