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