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