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