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