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