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