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