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