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