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