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