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