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