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