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