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