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