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