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