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