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