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