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