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