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