ViewGroup.java revision 9c17fe693deb0cc84099b619185472f192c2b52d
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 float x = ev.getX(actionIndex);
1872                    final float y = ev.getY(actionIndex);
1873
1874                    if (mOverlay != null) {
1875                        ViewOverlay overlay = (ViewOverlay) mOverlay;
1876                        // Check to see whether the overlay can handle the event
1877                        final View child = mOverlay;
1878                        if (canViewReceivePointerEvents(child) &&
1879                                isTransformedTouchPointInView(x, y, child, null)) {
1880                            newTouchTarget = getTouchTarget(child);
1881                            if (newTouchTarget != null) {
1882                                newTouchTarget.pointerIdBits |= idBitsToAssign;
1883                            } else {
1884                                resetCancelNextUpFlag(child);
1885                                if (dispatchTransformedTouchEvent(ev, false, child,
1886                                        idBitsToAssign)) {
1887                                    mLastTouchDownTime = ev.getDownTime();
1888                                    mLastTouchDownX = ev.getX();
1889                                    mLastTouchDownY = ev.getY();
1890                                    newTouchTarget = addTouchTarget(child, idBitsToAssign);
1891                                    alreadyDispatchedToNewTouchTarget = true;
1892                                }
1893                            }
1894                        }
1895                    }
1896
1897                    final int childrenCount = mChildrenCount;
1898                    if (newTouchTarget == null && childrenCount != 0) {
1899                        // Find a child that can receive the event.
1900                        // Scan children from front to back.
1901                        final View[] children = mChildren;
1902
1903                        final boolean customOrder = isChildrenDrawingOrderEnabled();
1904                        for (int i = childrenCount - 1; i >= 0; i--) {
1905                            final int childIndex = customOrder ?
1906                                    getChildDrawingOrder(childrenCount, i) : i;
1907                            final View child = children[childIndex];
1908                            if (!canViewReceivePointerEvents(child)
1909                                    || !isTransformedTouchPointInView(x, y, child, null)) {
1910                                continue;
1911                            }
1912
1913                            newTouchTarget = getTouchTarget(child);
1914                            if (newTouchTarget != null) {
1915                                // Child is already receiving touch within its bounds.
1916                                // Give it the new pointer in addition to the ones it is handling.
1917                                newTouchTarget.pointerIdBits |= idBitsToAssign;
1918                                break;
1919                            }
1920
1921                            resetCancelNextUpFlag(child);
1922                            if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
1923                                // Child wants to receive touch within its bounds.
1924                                mLastTouchDownTime = ev.getDownTime();
1925                                mLastTouchDownIndex = childIndex;
1926                                mLastTouchDownX = ev.getX();
1927                                mLastTouchDownY = ev.getY();
1928                                newTouchTarget = addTouchTarget(child, idBitsToAssign);
1929                                alreadyDispatchedToNewTouchTarget = true;
1930                                break;
1931                            }
1932                        }
1933                    }
1934
1935                    if (newTouchTarget == null && mFirstTouchTarget != null) {
1936                        // Did not find a child to receive the event.
1937                        // Assign the pointer to the least recently added target.
1938                        newTouchTarget = mFirstTouchTarget;
1939                        while (newTouchTarget.next != null) {
1940                            newTouchTarget = newTouchTarget.next;
1941                        }
1942                        newTouchTarget.pointerIdBits |= idBitsToAssign;
1943                    }
1944                }
1945            }
1946
1947            // Dispatch to touch targets.
1948            if (mFirstTouchTarget == null) {
1949                // No touch targets so treat this as an ordinary view.
1950                handled = dispatchTransformedTouchEvent(ev, canceled, null,
1951                        TouchTarget.ALL_POINTER_IDS);
1952            } else {
1953                // Dispatch to touch targets, excluding the new touch target if we already
1954                // dispatched to it.  Cancel touch targets if necessary.
1955                TouchTarget predecessor = null;
1956                TouchTarget target = mFirstTouchTarget;
1957                while (target != null) {
1958                    final TouchTarget next = target.next;
1959                    if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) {
1960                        handled = true;
1961                    } else {
1962                        final boolean cancelChild = resetCancelNextUpFlag(target.child)
1963                                || intercepted;
1964                        if (dispatchTransformedTouchEvent(ev, cancelChild,
1965                                target.child, target.pointerIdBits)) {
1966                            handled = true;
1967                        }
1968                        if (cancelChild) {
1969                            if (predecessor == null) {
1970                                mFirstTouchTarget = next;
1971                            } else {
1972                                predecessor.next = next;
1973                            }
1974                            target.recycle();
1975                            target = next;
1976                            continue;
1977                        }
1978                    }
1979                    predecessor = target;
1980                    target = next;
1981                }
1982            }
1983
1984            // Update list of touch targets for pointer up or cancel, if needed.
1985            if (canceled
1986                    || actionMasked == MotionEvent.ACTION_UP
1987                    || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
1988                resetTouchState();
1989            } else if (split && actionMasked == MotionEvent.ACTION_POINTER_UP) {
1990                final int actionIndex = ev.getActionIndex();
1991                final int idBitsToRemove = 1 << ev.getPointerId(actionIndex);
1992                removePointersFromTouchTargets(idBitsToRemove);
1993            }
1994        }
1995
1996        if (!handled && mInputEventConsistencyVerifier != null) {
1997            mInputEventConsistencyVerifier.onUnhandledEvent(ev, 1);
1998        }
1999        return handled;
2000    }
2001
2002    /**
2003     * Resets all touch state in preparation for a new cycle.
2004     */
2005    private void resetTouchState() {
2006        clearTouchTargets();
2007        resetCancelNextUpFlag(this);
2008        mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
2009    }
2010
2011    /**
2012     * Resets the cancel next up flag.
2013     * Returns true if the flag was previously set.
2014     */
2015    private static boolean resetCancelNextUpFlag(View view) {
2016        if ((view.mPrivateFlags & PFLAG_CANCEL_NEXT_UP_EVENT) != 0) {
2017            view.mPrivateFlags &= ~PFLAG_CANCEL_NEXT_UP_EVENT;
2018            return true;
2019        }
2020        return false;
2021    }
2022
2023    /**
2024     * Clears all touch targets.
2025     */
2026    private void clearTouchTargets() {
2027        TouchTarget target = mFirstTouchTarget;
2028        if (target != null) {
2029            do {
2030                TouchTarget next = target.next;
2031                target.recycle();
2032                target = next;
2033            } while (target != null);
2034            mFirstTouchTarget = null;
2035        }
2036    }
2037
2038    /**
2039     * Cancels and clears all touch targets.
2040     */
2041    private void cancelAndClearTouchTargets(MotionEvent event) {
2042        if (mFirstTouchTarget != null) {
2043            boolean syntheticEvent = false;
2044            if (event == null) {
2045                final long now = SystemClock.uptimeMillis();
2046                event = MotionEvent.obtain(now, now,
2047                        MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
2048                event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
2049                syntheticEvent = true;
2050            }
2051
2052            for (TouchTarget target = mFirstTouchTarget; target != null; target = target.next) {
2053                resetCancelNextUpFlag(target.child);
2054                dispatchTransformedTouchEvent(event, true, target.child, target.pointerIdBits);
2055            }
2056            clearTouchTargets();
2057
2058            if (syntheticEvent) {
2059                event.recycle();
2060            }
2061        }
2062    }
2063
2064    /**
2065     * Gets the touch target for specified child view.
2066     * Returns null if not found.
2067     */
2068    private TouchTarget getTouchTarget(View child) {
2069        for (TouchTarget target = mFirstTouchTarget; target != null; target = target.next) {
2070            if (target.child == child) {
2071                return target;
2072            }
2073        }
2074        return null;
2075    }
2076
2077    /**
2078     * Adds a touch target for specified child to the beginning of the list.
2079     * Assumes the target child is not already present.
2080     */
2081    private TouchTarget addTouchTarget(View child, int pointerIdBits) {
2082        TouchTarget target = TouchTarget.obtain(child, pointerIdBits);
2083        target.next = mFirstTouchTarget;
2084        mFirstTouchTarget = target;
2085        return target;
2086    }
2087
2088    /**
2089     * Removes the pointer ids from consideration.
2090     */
2091    private void removePointersFromTouchTargets(int pointerIdBits) {
2092        TouchTarget predecessor = null;
2093        TouchTarget target = mFirstTouchTarget;
2094        while (target != null) {
2095            final TouchTarget next = target.next;
2096            if ((target.pointerIdBits & pointerIdBits) != 0) {
2097                target.pointerIdBits &= ~pointerIdBits;
2098                if (target.pointerIdBits == 0) {
2099                    if (predecessor == null) {
2100                        mFirstTouchTarget = next;
2101                    } else {
2102                        predecessor.next = next;
2103                    }
2104                    target.recycle();
2105                    target = next;
2106                    continue;
2107                }
2108            }
2109            predecessor = target;
2110            target = next;
2111        }
2112    }
2113
2114    private void cancelTouchTarget(View view) {
2115        TouchTarget predecessor = null;
2116        TouchTarget target = mFirstTouchTarget;
2117        while (target != null) {
2118            final TouchTarget next = target.next;
2119            if (target.child == view) {
2120                if (predecessor == null) {
2121                    mFirstTouchTarget = next;
2122                } else {
2123                    predecessor.next = next;
2124                }
2125                target.recycle();
2126
2127                final long now = SystemClock.uptimeMillis();
2128                MotionEvent event = MotionEvent.obtain(now, now,
2129                        MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
2130                event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
2131                view.dispatchTouchEvent(event);
2132                event.recycle();
2133                return;
2134            }
2135            predecessor = target;
2136            target = next;
2137        }
2138    }
2139
2140    /**
2141     * Returns true if a child view can receive pointer events.
2142     * @hide
2143     */
2144    private static boolean canViewReceivePointerEvents(View child) {
2145        return (child.mViewFlags & VISIBILITY_MASK) == VISIBLE
2146                || child.getAnimation() != null;
2147    }
2148
2149    /**
2150     * Returns true if a child view contains the specified point when transformed
2151     * into its coordinate space.
2152     * Child must not be null.
2153     * @hide
2154     */
2155    protected boolean isTransformedTouchPointInView(float x, float y, View child,
2156            PointF outLocalPoint) {
2157        float localX = x + mScrollX - child.mLeft;
2158        float localY = y + mScrollY - child.mTop;
2159        if (! child.hasIdentityMatrix() && mAttachInfo != null) {
2160            final float[] localXY = mAttachInfo.mTmpTransformLocation;
2161            localXY[0] = localX;
2162            localXY[1] = localY;
2163            child.getInverseMatrix().mapPoints(localXY);
2164            localX = localXY[0];
2165            localY = localXY[1];
2166        }
2167        final boolean isInView = child.pointInView(localX, localY);
2168        if (isInView && outLocalPoint != null) {
2169            outLocalPoint.set(localX, localY);
2170        }
2171        return isInView;
2172    }
2173
2174    /**
2175     * Transforms a motion event into the coordinate space of a particular child view,
2176     * filters out irrelevant pointer ids, and overrides its action if necessary.
2177     * If child is null, assumes the MotionEvent will be sent to this ViewGroup instead.
2178     */
2179    private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,
2180            View child, int desiredPointerIdBits) {
2181        final boolean handled;
2182
2183        // Canceling motions is a special case.  We don't need to perform any transformations
2184        // or filtering.  The important part is the action, not the contents.
2185        final int oldAction = event.getAction();
2186        if (cancel || oldAction == MotionEvent.ACTION_CANCEL) {
2187            event.setAction(MotionEvent.ACTION_CANCEL);
2188            if (child == null) {
2189                handled = super.dispatchTouchEvent(event);
2190            } else {
2191                handled = child.dispatchTouchEvent(event);
2192            }
2193            event.setAction(oldAction);
2194            return handled;
2195        }
2196
2197        // Calculate the number of pointers to deliver.
2198        final int oldPointerIdBits = event.getPointerIdBits();
2199        final int newPointerIdBits = oldPointerIdBits & desiredPointerIdBits;
2200
2201        // If for some reason we ended up in an inconsistent state where it looks like we
2202        // might produce a motion event with no pointers in it, then drop the event.
2203        if (newPointerIdBits == 0) {
2204            return false;
2205        }
2206
2207        // If the number of pointers is the same and we don't need to perform any fancy
2208        // irreversible transformations, then we can reuse the motion event for this
2209        // dispatch as long as we are careful to revert any changes we make.
2210        // Otherwise we need to make a copy.
2211        final MotionEvent transformedEvent;
2212        if (newPointerIdBits == oldPointerIdBits) {
2213            if (child == null || child.hasIdentityMatrix()) {
2214                if (child == null) {
2215                    handled = super.dispatchTouchEvent(event);
2216                } else {
2217                    final float offsetX = mScrollX - child.mLeft;
2218                    final float offsetY = mScrollY - child.mTop;
2219                    event.offsetLocation(offsetX, offsetY);
2220
2221                    handled = child.dispatchTouchEvent(event);
2222
2223                    event.offsetLocation(-offsetX, -offsetY);
2224                }
2225                return handled;
2226            }
2227            transformedEvent = MotionEvent.obtain(event);
2228        } else {
2229            transformedEvent = event.split(newPointerIdBits);
2230        }
2231
2232        // Perform any necessary transformations and dispatch.
2233        if (child == null) {
2234            handled = super.dispatchTouchEvent(transformedEvent);
2235        } else {
2236            final float offsetX = mScrollX - child.mLeft;
2237            final float offsetY = mScrollY - child.mTop;
2238            transformedEvent.offsetLocation(offsetX, offsetY);
2239            if (! child.hasIdentityMatrix()) {
2240                transformedEvent.transform(child.getInverseMatrix());
2241            }
2242
2243            handled = child.dispatchTouchEvent(transformedEvent);
2244        }
2245
2246        // Done.
2247        transformedEvent.recycle();
2248        return handled;
2249    }
2250
2251    /**
2252     * Enable or disable the splitting of MotionEvents to multiple children during touch event
2253     * dispatch. This behavior is enabled by default for applications that target an
2254     * SDK version of {@link Build.VERSION_CODES#HONEYCOMB} or newer.
2255     *
2256     * <p>When this option is enabled MotionEvents may be split and dispatched to different child
2257     * views depending on where each pointer initially went down. This allows for user interactions
2258     * such as scrolling two panes of content independently, chording of buttons, and performing
2259     * independent gestures on different pieces of content.
2260     *
2261     * @param split <code>true</code> to allow MotionEvents to be split and dispatched to multiple
2262     *              child views. <code>false</code> to only allow one child view to be the target of
2263     *              any MotionEvent received by this ViewGroup.
2264     */
2265    public void setMotionEventSplittingEnabled(boolean split) {
2266        // TODO Applications really shouldn't change this setting mid-touch event,
2267        // but perhaps this should handle that case and send ACTION_CANCELs to any child views
2268        // with gestures in progress when this is changed.
2269        if (split) {
2270            mGroupFlags |= FLAG_SPLIT_MOTION_EVENTS;
2271        } else {
2272            mGroupFlags &= ~FLAG_SPLIT_MOTION_EVENTS;
2273        }
2274    }
2275
2276    /**
2277     * Returns true if MotionEvents dispatched to this ViewGroup can be split to multiple children.
2278     * @return true if MotionEvents dispatched to this ViewGroup can be split to multiple children.
2279     */
2280    public boolean isMotionEventSplittingEnabled() {
2281        return (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) == FLAG_SPLIT_MOTION_EVENTS;
2282    }
2283
2284    /**
2285     * {@inheritDoc}
2286     */
2287    public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
2288
2289        if (disallowIntercept == ((mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0)) {
2290            // We're already in this state, assume our ancestors are too
2291            return;
2292        }
2293
2294        if (disallowIntercept) {
2295            mGroupFlags |= FLAG_DISALLOW_INTERCEPT;
2296        } else {
2297            mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
2298        }
2299
2300        // Pass it up to our parent
2301        if (mParent != null) {
2302            mParent.requestDisallowInterceptTouchEvent(disallowIntercept);
2303        }
2304    }
2305
2306    /**
2307     * Implement this method to intercept all touch screen motion events.  This
2308     * allows you to watch events as they are dispatched to your children, and
2309     * take ownership of the current gesture at any point.
2310     *
2311     * <p>Using this function takes some care, as it has a fairly complicated
2312     * interaction with {@link View#onTouchEvent(MotionEvent)
2313     * View.onTouchEvent(MotionEvent)}, and using it requires implementing
2314     * that method as well as this one in the correct way.  Events will be
2315     * received in the following order:
2316     *
2317     * <ol>
2318     * <li> You will receive the down event here.
2319     * <li> The down event will be handled either by a child of this view
2320     * group, or given to your own onTouchEvent() method to handle; this means
2321     * you should implement onTouchEvent() to return true, so you will
2322     * continue to see the rest of the gesture (instead of looking for
2323     * a parent view to handle it).  Also, by returning true from
2324     * onTouchEvent(), you will not receive any following
2325     * events in onInterceptTouchEvent() and all touch processing must
2326     * happen in onTouchEvent() like normal.
2327     * <li> For as long as you return false from this function, each following
2328     * event (up to and including the final up) will be delivered first here
2329     * and then to the target's onTouchEvent().
2330     * <li> If you return true from here, you will not receive any
2331     * following events: the target view will receive the same event but
2332     * with the action {@link MotionEvent#ACTION_CANCEL}, and all further
2333     * events will be delivered to your onTouchEvent() method and no longer
2334     * appear here.
2335     * </ol>
2336     *
2337     * @param ev The motion event being dispatched down the hierarchy.
2338     * @return Return true to steal motion events from the children and have
2339     * them dispatched to this ViewGroup through onTouchEvent().
2340     * The current target will receive an ACTION_CANCEL event, and no further
2341     * messages will be delivered here.
2342     */
2343    public boolean onInterceptTouchEvent(MotionEvent ev) {
2344        return false;
2345    }
2346
2347    /**
2348     * {@inheritDoc}
2349     *
2350     * Looks for a view to give focus to respecting the setting specified by
2351     * {@link #getDescendantFocusability()}.
2352     *
2353     * Uses {@link #onRequestFocusInDescendants(int, android.graphics.Rect)} to
2354     * find focus within the children of this group when appropriate.
2355     *
2356     * @see #FOCUS_BEFORE_DESCENDANTS
2357     * @see #FOCUS_AFTER_DESCENDANTS
2358     * @see #FOCUS_BLOCK_DESCENDANTS
2359     * @see #onRequestFocusInDescendants(int, android.graphics.Rect)
2360     */
2361    @Override
2362    public boolean requestFocus(int direction, Rect previouslyFocusedRect) {
2363        if (DBG) {
2364            System.out.println(this + " ViewGroup.requestFocus direction="
2365                    + direction);
2366        }
2367        int descendantFocusability = getDescendantFocusability();
2368
2369        switch (descendantFocusability) {
2370            case FOCUS_BLOCK_DESCENDANTS:
2371                return super.requestFocus(direction, previouslyFocusedRect);
2372            case FOCUS_BEFORE_DESCENDANTS: {
2373                final boolean took = super.requestFocus(direction, previouslyFocusedRect);
2374                return took ? took : onRequestFocusInDescendants(direction, previouslyFocusedRect);
2375            }
2376            case FOCUS_AFTER_DESCENDANTS: {
2377                final boolean took = onRequestFocusInDescendants(direction, previouslyFocusedRect);
2378                return took ? took : super.requestFocus(direction, previouslyFocusedRect);
2379            }
2380            default:
2381                throw new IllegalStateException("descendant focusability must be "
2382                        + "one of FOCUS_BEFORE_DESCENDANTS, FOCUS_AFTER_DESCENDANTS, FOCUS_BLOCK_DESCENDANTS "
2383                        + "but is " + descendantFocusability);
2384        }
2385    }
2386
2387    /**
2388     * Look for a descendant to call {@link View#requestFocus} on.
2389     * Called by {@link ViewGroup#requestFocus(int, android.graphics.Rect)}
2390     * when it wants to request focus within its children.  Override this to
2391     * customize how your {@link ViewGroup} requests focus within its children.
2392     * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT
2393     * @param previouslyFocusedRect The rectangle (in this View's coordinate system)
2394     *        to give a finer grained hint about where focus is coming from.  May be null
2395     *        if there is no hint.
2396     * @return Whether focus was taken.
2397     */
2398    @SuppressWarnings({"ConstantConditions"})
2399    protected boolean onRequestFocusInDescendants(int direction,
2400            Rect previouslyFocusedRect) {
2401        int index;
2402        int increment;
2403        int end;
2404        int count = mChildrenCount;
2405        if ((direction & FOCUS_FORWARD) != 0) {
2406            index = 0;
2407            increment = 1;
2408            end = count;
2409        } else {
2410            index = count - 1;
2411            increment = -1;
2412            end = -1;
2413        }
2414        final View[] children = mChildren;
2415        for (int i = index; i != end; i += increment) {
2416            View child = children[i];
2417            if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
2418                if (child.requestFocus(direction, previouslyFocusedRect)) {
2419                    return true;
2420                }
2421            }
2422        }
2423        return false;
2424    }
2425
2426    /**
2427     * {@inheritDoc}
2428     *
2429     * @hide
2430     */
2431    @Override
2432    public void dispatchStartTemporaryDetach() {
2433        super.dispatchStartTemporaryDetach();
2434        final int count = mChildrenCount;
2435        final View[] children = mChildren;
2436        for (int i = 0; i < count; i++) {
2437            children[i].dispatchStartTemporaryDetach();
2438        }
2439    }
2440
2441    /**
2442     * {@inheritDoc}
2443     *
2444     * @hide
2445     */
2446    @Override
2447    public void dispatchFinishTemporaryDetach() {
2448        super.dispatchFinishTemporaryDetach();
2449        final int count = mChildrenCount;
2450        final View[] children = mChildren;
2451        for (int i = 0; i < count; i++) {
2452            children[i].dispatchFinishTemporaryDetach();
2453        }
2454    }
2455
2456    /**
2457     * {@inheritDoc}
2458     */
2459    @Override
2460    void dispatchAttachedToWindow(AttachInfo info, int visibility) {
2461        mGroupFlags |= FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW;
2462        super.dispatchAttachedToWindow(info, visibility);
2463        mGroupFlags &= ~FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW;
2464
2465        final int count = mChildrenCount;
2466        final View[] children = mChildren;
2467        for (int i = 0; i < count; i++) {
2468            final View child = children[i];
2469            child.dispatchAttachedToWindow(info,
2470                    visibility | (child.mViewFlags & VISIBILITY_MASK));
2471        }
2472    }
2473
2474    @Override
2475    void dispatchScreenStateChanged(int screenState) {
2476        super.dispatchScreenStateChanged(screenState);
2477
2478        final int count = mChildrenCount;
2479        final View[] children = mChildren;
2480        for (int i = 0; i < count; i++) {
2481            children[i].dispatchScreenStateChanged(screenState);
2482        }
2483    }
2484
2485    @Override
2486    boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) {
2487        boolean handled = false;
2488        if (includeForAccessibility()) {
2489            handled = super.dispatchPopulateAccessibilityEventInternal(event);
2490            if (handled) {
2491                return handled;
2492            }
2493        }
2494        // Let our children have a shot in populating the event.
2495        ChildListForAccessibility children = ChildListForAccessibility.obtain(this, true);
2496        try {
2497            final int childCount = children.getChildCount();
2498            for (int i = 0; i < childCount; i++) {
2499                View child = children.getChildAt(i);
2500                if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
2501                    handled = child.dispatchPopulateAccessibilityEvent(event);
2502                    if (handled) {
2503                        return handled;
2504                    }
2505                }
2506            }
2507        } finally {
2508            children.recycle();
2509        }
2510        return false;
2511    }
2512
2513    @Override
2514    void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
2515        super.onInitializeAccessibilityNodeInfoInternal(info);
2516        if (mAttachInfo != null) {
2517            ArrayList<View> childrenForAccessibility = mAttachInfo.mTempArrayList;
2518            childrenForAccessibility.clear();
2519            addChildrenForAccessibility(childrenForAccessibility);
2520            final int childrenForAccessibilityCount = childrenForAccessibility.size();
2521            for (int i = 0; i < childrenForAccessibilityCount; i++) {
2522                View child = childrenForAccessibility.get(i);
2523                info.addChild(child);
2524            }
2525            childrenForAccessibility.clear();
2526        }
2527    }
2528
2529    @Override
2530    void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
2531        super.onInitializeAccessibilityEventInternal(event);
2532        event.setClassName(ViewGroup.class.getName());
2533    }
2534
2535    /**
2536     * @hide
2537     */
2538    @Override
2539    public void resetAccessibilityStateChanged() {
2540        super.resetAccessibilityStateChanged();
2541        View[] children = mChildren;
2542        final int childCount = mChildrenCount;
2543        for (int i = 0; i < childCount; i++) {
2544            View child = children[i];
2545            child.resetAccessibilityStateChanged();
2546        }
2547    }
2548
2549    /**
2550     * {@inheritDoc}
2551     */
2552    @Override
2553    void dispatchDetachedFromWindow() {
2554        // If we still have a touch target, we are still in the process of
2555        // dispatching motion events to a child; we need to get rid of that
2556        // child to avoid dispatching events to it after the window is torn
2557        // down. To make sure we keep the child in a consistent state, we
2558        // first send it an ACTION_CANCEL motion event.
2559        cancelAndClearTouchTargets(null);
2560
2561        // Similarly, set ACTION_EXIT to all hover targets and clear them.
2562        exitHoverTargets();
2563
2564        // In case view is detached while transition is running
2565        mLayoutSuppressed = false;
2566
2567        // Tear down our drag tracking
2568        mDragNotifiedChildren = null;
2569        if (mCurrentDrag != null) {
2570            mCurrentDrag.recycle();
2571            mCurrentDrag = null;
2572        }
2573
2574        final int count = mChildrenCount;
2575        final View[] children = mChildren;
2576        for (int i = 0; i < count; i++) {
2577            children[i].dispatchDetachedFromWindow();
2578        }
2579        super.dispatchDetachedFromWindow();
2580    }
2581
2582    /**
2583     * @hide
2584     */
2585    @Override
2586    protected void internalSetPadding(int left, int top, int right, int bottom) {
2587        super.internalSetPadding(left, top, right, bottom);
2588
2589        if ((mPaddingLeft | mPaddingTop | mPaddingRight | mPaddingBottom) != 0) {
2590            mGroupFlags |= FLAG_PADDING_NOT_NULL;
2591        } else {
2592            mGroupFlags &= ~FLAG_PADDING_NOT_NULL;
2593        }
2594    }
2595
2596    /**
2597     * {@inheritDoc}
2598     */
2599    @Override
2600    protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {
2601        super.dispatchSaveInstanceState(container);
2602        final int count = mChildrenCount;
2603        final View[] children = mChildren;
2604        for (int i = 0; i < count; i++) {
2605            View c = children[i];
2606            if ((c.mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED) {
2607                c.dispatchSaveInstanceState(container);
2608            }
2609        }
2610    }
2611
2612    /**
2613     * Perform dispatching of a {@link #saveHierarchyState(android.util.SparseArray)}  freeze()}
2614     * to only this view, not to its children.  For use when overriding
2615     * {@link #dispatchSaveInstanceState(android.util.SparseArray)}  dispatchFreeze()} to allow
2616     * subclasses to freeze their own state but not the state of their children.
2617     *
2618     * @param container the container
2619     */
2620    protected void dispatchFreezeSelfOnly(SparseArray<Parcelable> container) {
2621        super.dispatchSaveInstanceState(container);
2622    }
2623
2624    /**
2625     * {@inheritDoc}
2626     */
2627    @Override
2628    protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {
2629        super.dispatchRestoreInstanceState(container);
2630        final int count = mChildrenCount;
2631        final View[] children = mChildren;
2632        for (int i = 0; i < count; i++) {
2633            View c = children[i];
2634            if ((c.mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED) {
2635                c.dispatchRestoreInstanceState(container);
2636            }
2637        }
2638    }
2639
2640    /**
2641     * Perform dispatching of a {@link #restoreHierarchyState(android.util.SparseArray)}
2642     * to only this view, not to its children.  For use when overriding
2643     * {@link #dispatchRestoreInstanceState(android.util.SparseArray)} to allow
2644     * subclasses to thaw their own state but not the state of their children.
2645     *
2646     * @param container the container
2647     */
2648    protected void dispatchThawSelfOnly(SparseArray<Parcelable> container) {
2649        super.dispatchRestoreInstanceState(container);
2650    }
2651
2652    /**
2653     * Enables or disables the drawing cache for each child of this view group.
2654     *
2655     * @param enabled true to enable the cache, false to dispose of it
2656     */
2657    protected void setChildrenDrawingCacheEnabled(boolean enabled) {
2658        if (enabled || (mPersistentDrawingCache & PERSISTENT_ALL_CACHES) != PERSISTENT_ALL_CACHES) {
2659            final View[] children = mChildren;
2660            final int count = mChildrenCount;
2661            for (int i = 0; i < count; i++) {
2662                children[i].setDrawingCacheEnabled(enabled);
2663            }
2664        }
2665    }
2666
2667    @Override
2668    protected void onAnimationStart() {
2669        super.onAnimationStart();
2670
2671        // When this ViewGroup's animation starts, build the cache for the children
2672        if ((mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE) {
2673            final int count = mChildrenCount;
2674            final View[] children = mChildren;
2675            final boolean buildCache = !isHardwareAccelerated();
2676
2677            for (int i = 0; i < count; i++) {
2678                final View child = children[i];
2679                if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
2680                    child.setDrawingCacheEnabled(true);
2681                    if (buildCache) {
2682                        child.buildDrawingCache(true);
2683                    }
2684                }
2685            }
2686
2687            mGroupFlags |= FLAG_CHILDREN_DRAWN_WITH_CACHE;
2688        }
2689    }
2690
2691    @Override
2692    protected void onAnimationEnd() {
2693        super.onAnimationEnd();
2694
2695        // When this ViewGroup's animation ends, destroy the cache of the children
2696        if ((mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE) {
2697            mGroupFlags &= ~FLAG_CHILDREN_DRAWN_WITH_CACHE;
2698
2699            if ((mPersistentDrawingCache & PERSISTENT_ANIMATION_CACHE) == 0) {
2700                setChildrenDrawingCacheEnabled(false);
2701            }
2702        }
2703    }
2704
2705    @Override
2706    Bitmap createSnapshot(Bitmap.Config quality, int backgroundColor, boolean skipChildren) {
2707        int count = mChildrenCount;
2708        int[] visibilities = null;
2709
2710        if (skipChildren) {
2711            visibilities = new int[count];
2712            for (int i = 0; i < count; i++) {
2713                View child = getChildAt(i);
2714                visibilities[i] = child.getVisibility();
2715                if (visibilities[i] == View.VISIBLE) {
2716                    child.setVisibility(INVISIBLE);
2717                }
2718            }
2719        }
2720
2721        Bitmap b = super.createSnapshot(quality, backgroundColor, skipChildren);
2722
2723        if (skipChildren) {
2724            for (int i = 0; i < count; i++) {
2725                getChildAt(i).setVisibility(visibilities[i]);
2726            }
2727        }
2728
2729        return b;
2730    }
2731
2732    /** Return true if this ViewGroup is laying out using optical bounds. */
2733    boolean isLayoutModeOptical() {
2734        return mLayoutMode == LAYOUT_MODE_OPTICAL_BOUNDS;
2735    }
2736
2737    Insets computeOpticalInsets() {
2738        if (isLayoutModeOptical()) {
2739            int left = 0;
2740            int top = 0;
2741            int right = 0;
2742            int bottom = 0;
2743            for (int i = 0; i < mChildrenCount; i++) {
2744                View child = getChildAt(i);
2745                if (child.getVisibility() == VISIBLE) {
2746                    Insets insets = child.getOpticalInsets();
2747                    left =   Math.max(left,   insets.left);
2748                    top =    Math.max(top,    insets.top);
2749                    right =  Math.max(right,  insets.right);
2750                    bottom = Math.max(bottom, insets.bottom);
2751                }
2752            }
2753            return Insets.of(left, top, right, bottom);
2754        } else {
2755            return Insets.NONE;
2756        }
2757    }
2758
2759    private static void fillRect(Canvas canvas, Paint paint, int x1, int y1, int x2, int y2) {
2760        if (x1 != x2 && y1 != y2) {
2761            if (x1 > x2) {
2762                int tmp = x1; x1 = x2; x2 = tmp;
2763            }
2764            if (y1 > y2) {
2765                int tmp = y1; y1 = y2; y2 = tmp;
2766            }
2767            canvas.drawRect(x1, y1, x2, y2, paint);
2768        }
2769    }
2770
2771    private static int sign(int x) {
2772        return (x >= 0) ? 1 : -1;
2773    }
2774
2775    private static void drawCorner(Canvas c, Paint paint, int x1, int y1, int dx, int dy, int lw) {
2776        fillRect(c, paint, x1, y1, x1 + dx, y1 + lw * sign(dy));
2777        fillRect(c, paint, x1, y1, x1 + lw * sign(dx), y1 + dy);
2778    }
2779
2780    private int dipsToPixels(int dips) {
2781        float scale = getContext().getResources().getDisplayMetrics().density;
2782        return (int) (dips * scale + 0.5f);
2783    }
2784
2785    private void drawRectCorners(Canvas canvas, int x1, int y1, int x2, int y2, Paint paint,
2786                                 int lineLength, int lineWidth) {
2787        drawCorner(canvas, paint, x1, y1, lineLength, lineLength, lineWidth);
2788        drawCorner(canvas, paint, x1, y2, lineLength, -lineLength, lineWidth);
2789        drawCorner(canvas, paint, x2, y1, -lineLength, lineLength, lineWidth);
2790        drawCorner(canvas, paint, x2, y2, -lineLength, -lineLength, lineWidth);
2791    }
2792
2793    private static void fillDifference(Canvas canvas,
2794            int x2, int y2, int x3, int y3,
2795            int dx1, int dy1, int dx2, int dy2, Paint paint) {
2796        int x1 = x2 - dx1;
2797        int y1 = y2 - dy1;
2798
2799        int x4 = x3 + dx2;
2800        int y4 = y3 + dy2;
2801
2802        fillRect(canvas, paint, x1, y1, x4, y2);
2803        fillRect(canvas, paint, x1, y2, x2, y3);
2804        fillRect(canvas, paint, x3, y2, x4, y3);
2805        fillRect(canvas, paint, x1, y3, x4, y4);
2806    }
2807
2808    /**
2809     * @hide
2810     */
2811    protected void onDebugDrawMargins(Canvas canvas, Paint paint) {
2812        for (int i = 0; i < getChildCount(); i++) {
2813            View c = getChildAt(i);
2814            c.getLayoutParams().onDebugDraw(c, canvas, paint);
2815        }
2816    }
2817
2818    /**
2819     * @hide
2820     */
2821    protected void onDebugDraw(Canvas canvas) {
2822        Paint paint = getDebugPaint();
2823
2824        // Draw optical bounds
2825        {
2826            paint.setColor(Color.RED);
2827            paint.setStyle(Paint.Style.STROKE);
2828
2829            for (int i = 0; i < getChildCount(); i++) {
2830                View c = getChildAt(i);
2831                Insets insets = c.getOpticalInsets();
2832
2833                drawRect(canvas, paint,
2834                        c.getLeft()   + insets.left,
2835                        c.getTop()    + insets.top,
2836                        c.getRight()  - insets.right  - 1,
2837                        c.getBottom() - insets.bottom - 1);
2838            }
2839        }
2840
2841        // Draw margins
2842        {
2843            paint.setColor(Color.argb(63, 255, 0, 255));
2844            paint.setStyle(Paint.Style.FILL);
2845
2846            onDebugDrawMargins(canvas, paint);
2847        }
2848
2849        // Draw clip bounds
2850        {
2851            paint.setColor(Color.rgb(63, 127, 255));
2852            paint.setStyle(Paint.Style.FILL);
2853
2854            int lineLength = dipsToPixels(8);
2855            int lineWidth = dipsToPixels(1);
2856            for (int i = 0; i < getChildCount(); i++) {
2857                View c = getChildAt(i);
2858                drawRectCorners(canvas, c.getLeft(), c.getTop(), c.getRight(), c.getBottom(),
2859                        paint, lineLength, lineWidth);
2860            }
2861        }
2862    }
2863
2864    /**
2865     * {@inheritDoc}
2866     */
2867    @Override
2868    protected void dispatchDraw(Canvas canvas) {
2869        final int count = mChildrenCount;
2870        final View[] children = mChildren;
2871        int flags = mGroupFlags;
2872
2873        if ((flags & FLAG_RUN_ANIMATION) != 0 && canAnimate()) {
2874            final boolean cache = (mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE;
2875
2876            final boolean buildCache = !isHardwareAccelerated();
2877            for (int i = 0; i < count; i++) {
2878                final View child = children[i];
2879                if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
2880                    final LayoutParams params = child.getLayoutParams();
2881                    attachLayoutAnimationParameters(child, params, i, count);
2882                    bindLayoutAnimation(child);
2883                    if (cache) {
2884                        child.setDrawingCacheEnabled(true);
2885                        if (buildCache) {
2886                            child.buildDrawingCache(true);
2887                        }
2888                    }
2889                }
2890            }
2891
2892            final LayoutAnimationController controller = mLayoutAnimationController;
2893            if (controller.willOverlap()) {
2894                mGroupFlags |= FLAG_OPTIMIZE_INVALIDATE;
2895            }
2896
2897            controller.start();
2898
2899            mGroupFlags &= ~FLAG_RUN_ANIMATION;
2900            mGroupFlags &= ~FLAG_ANIMATION_DONE;
2901
2902            if (cache) {
2903                mGroupFlags |= FLAG_CHILDREN_DRAWN_WITH_CACHE;
2904            }
2905
2906            if (mAnimationListener != null) {
2907                mAnimationListener.onAnimationStart(controller.getAnimation());
2908            }
2909        }
2910
2911        int saveCount = 0;
2912        final boolean clipToPadding = (flags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK;
2913        if (clipToPadding) {
2914            saveCount = canvas.save();
2915            canvas.clipRect(mScrollX + mPaddingLeft, mScrollY + mPaddingTop,
2916                    mScrollX + mRight - mLeft - mPaddingRight,
2917                    mScrollY + mBottom - mTop - mPaddingBottom);
2918
2919        }
2920
2921        // We will draw our child's animation, let's reset the flag
2922        mPrivateFlags &= ~PFLAG_DRAW_ANIMATION;
2923        mGroupFlags &= ~FLAG_INVALIDATE_REQUIRED;
2924
2925        boolean more = false;
2926        final long drawingTime = getDrawingTime();
2927
2928        if ((flags & FLAG_USE_CHILD_DRAWING_ORDER) == 0) {
2929            for (int i = 0; i < count; i++) {
2930                final View child = children[i];
2931                if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
2932                    more |= drawChild(canvas, child, drawingTime);
2933                }
2934            }
2935        } else {
2936            for (int i = 0; i < count; i++) {
2937                final View child = children[getChildDrawingOrder(count, i)];
2938                if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
2939                    more |= drawChild(canvas, child, drawingTime);
2940                }
2941            }
2942        }
2943
2944        // Draw any disappearing views that have animations
2945        if (mDisappearingChildren != null) {
2946            final ArrayList<View> disappearingChildren = mDisappearingChildren;
2947            final int disappearingCount = disappearingChildren.size() - 1;
2948            // Go backwards -- we may delete as animations finish
2949            for (int i = disappearingCount; i >= 0; i--) {
2950                final View child = disappearingChildren.get(i);
2951                more |= drawChild(canvas, child, drawingTime);
2952            }
2953        }
2954
2955        if (debugDraw()) {
2956            onDebugDraw(canvas);
2957        }
2958
2959        if (clipToPadding) {
2960            canvas.restoreToCount(saveCount);
2961        }
2962
2963        // mGroupFlags might have been updated by drawChild()
2964        flags = mGroupFlags;
2965
2966        if ((flags & FLAG_INVALIDATE_REQUIRED) == FLAG_INVALIDATE_REQUIRED) {
2967            invalidate(true);
2968        }
2969
2970        if ((flags & FLAG_ANIMATION_DONE) == 0 && (flags & FLAG_NOTIFY_ANIMATION_LISTENER) == 0 &&
2971                mLayoutAnimationController.isDone() && !more) {
2972            // We want to erase the drawing cache and notify the listener after the
2973            // next frame is drawn because one extra invalidate() is caused by
2974            // drawChild() after the animation is over
2975            mGroupFlags |= FLAG_NOTIFY_ANIMATION_LISTENER;
2976            final Runnable end = new Runnable() {
2977               public void run() {
2978                   notifyAnimationListener();
2979               }
2980            };
2981            post(end);
2982        }
2983    }
2984
2985    /**
2986     * Returns the index of the child to draw for this iteration. Override this
2987     * if you want to change the drawing order of children. By default, it
2988     * returns i.
2989     * <p>
2990     * NOTE: In order for this method to be called, you must enable child ordering
2991     * first by calling {@link #setChildrenDrawingOrderEnabled(boolean)}.
2992     *
2993     * @param i The current iteration.
2994     * @return The index of the child to draw this iteration.
2995     *
2996     * @see #setChildrenDrawingOrderEnabled(boolean)
2997     * @see #isChildrenDrawingOrderEnabled()
2998     */
2999    protected int getChildDrawingOrder(int childCount, int i) {
3000        return i;
3001    }
3002
3003    private void notifyAnimationListener() {
3004        mGroupFlags &= ~FLAG_NOTIFY_ANIMATION_LISTENER;
3005        mGroupFlags |= FLAG_ANIMATION_DONE;
3006
3007        if (mAnimationListener != null) {
3008           final Runnable end = new Runnable() {
3009               public void run() {
3010                   mAnimationListener.onAnimationEnd(mLayoutAnimationController.getAnimation());
3011               }
3012           };
3013           post(end);
3014        }
3015
3016        if ((mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE) {
3017            mGroupFlags &= ~FLAG_CHILDREN_DRAWN_WITH_CACHE;
3018            if ((mPersistentDrawingCache & PERSISTENT_ANIMATION_CACHE) == 0) {
3019                setChildrenDrawingCacheEnabled(false);
3020            }
3021        }
3022
3023        invalidate(true);
3024    }
3025
3026    /**
3027     * This method is used to cause children of this ViewGroup to restore or recreate their
3028     * display lists. It is called by getDisplayList() when the parent ViewGroup does not need
3029     * to recreate its own display list, which would happen if it went through the normal
3030     * draw/dispatchDraw mechanisms.
3031     *
3032     * @hide
3033     */
3034    @Override
3035    protected void dispatchGetDisplayList() {
3036        final int count = mChildrenCount;
3037        final View[] children = mChildren;
3038        for (int i = 0; i < count; i++) {
3039            final View child = children[i];
3040            if (((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) &&
3041                    child.hasStaticLayer()) {
3042                child.mRecreateDisplayList = (child.mPrivateFlags & PFLAG_INVALIDATED)
3043                        == PFLAG_INVALIDATED;
3044                child.mPrivateFlags &= ~PFLAG_INVALIDATED;
3045                child.getDisplayList();
3046                child.mRecreateDisplayList = false;
3047            }
3048        }
3049        if (mOverlay != null) {
3050            mOverlay.mRecreateDisplayList = (mOverlay.mPrivateFlags & PFLAG_INVALIDATED)
3051                    == PFLAG_INVALIDATED;
3052            mOverlay.mPrivateFlags &= ~PFLAG_INVALIDATED;
3053            mOverlay.getDisplayList();
3054            mOverlay.mRecreateDisplayList = false;
3055        }
3056    }
3057
3058    /**
3059     * Draw one child of this View Group. This method is responsible for getting
3060     * the canvas in the right state. This includes clipping, translating so
3061     * that the child's scrolled origin is at 0, 0, and applying any animation
3062     * transformations.
3063     *
3064     * @param canvas The canvas on which to draw the child
3065     * @param child Who to draw
3066     * @param drawingTime The time at which draw is occurring
3067     * @return True if an invalidate() was issued
3068     */
3069    protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
3070        return child.draw(canvas, this, drawingTime);
3071    }
3072
3073    /**
3074     * By default, children are clipped to their bounds before drawing. This
3075     * allows view groups to override this behavior for animations, etc.
3076     *
3077     * @param clipChildren true to clip children to their bounds,
3078     *        false otherwise
3079     * @attr ref android.R.styleable#ViewGroup_clipChildren
3080     */
3081    public void setClipChildren(boolean clipChildren) {
3082        boolean previousValue = (mGroupFlags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN;
3083        if (clipChildren != previousValue) {
3084            setBooleanFlag(FLAG_CLIP_CHILDREN, clipChildren);
3085            for (int i = 0; i < mChildrenCount; ++i) {
3086                View child = getChildAt(i);
3087                if (child.mDisplayList != null) {
3088                    child.mDisplayList.setClipChildren(clipChildren);
3089                }
3090            }
3091        }
3092    }
3093
3094    /**
3095     * By default, children are clipped to the padding of the ViewGroup. This
3096     * allows view groups to override this behavior
3097     *
3098     * @param clipToPadding true to clip children to the padding of the
3099     *        group, false otherwise
3100     * @attr ref android.R.styleable#ViewGroup_clipToPadding
3101     */
3102    public void setClipToPadding(boolean clipToPadding) {
3103        setBooleanFlag(FLAG_CLIP_TO_PADDING, clipToPadding);
3104    }
3105
3106    /**
3107     * {@inheritDoc}
3108     */
3109    @Override
3110    public void dispatchSetSelected(boolean selected) {
3111        final View[] children = mChildren;
3112        final int count = mChildrenCount;
3113        for (int i = 0; i < count; i++) {
3114            children[i].setSelected(selected);
3115        }
3116    }
3117
3118    /**
3119     * {@inheritDoc}
3120     */
3121    @Override
3122    public void dispatchSetActivated(boolean activated) {
3123        final View[] children = mChildren;
3124        final int count = mChildrenCount;
3125        for (int i = 0; i < count; i++) {
3126            children[i].setActivated(activated);
3127        }
3128    }
3129
3130    @Override
3131    protected void dispatchSetPressed(boolean pressed) {
3132        final View[] children = mChildren;
3133        final int count = mChildrenCount;
3134        for (int i = 0; i < count; i++) {
3135            final View child = children[i];
3136            // Children that are clickable on their own should not
3137            // show a pressed state when their parent view does.
3138            // Clearing a pressed state always propagates.
3139            if (!pressed || (!child.isClickable() && !child.isLongClickable())) {
3140                child.setPressed(pressed);
3141            }
3142        }
3143    }
3144
3145    /**
3146     * When this property is set to true, this ViewGroup supports static transformations on
3147     * children; this causes
3148     * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} to be
3149     * invoked when a child is drawn.
3150     *
3151     * Any subclass overriding
3152     * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} should
3153     * set this property to true.
3154     *
3155     * @param enabled True to enable static transformations on children, false otherwise.
3156     *
3157     * @see #getChildStaticTransformation(View, android.view.animation.Transformation)
3158     */
3159    protected void setStaticTransformationsEnabled(boolean enabled) {
3160        setBooleanFlag(FLAG_SUPPORT_STATIC_TRANSFORMATIONS, enabled);
3161    }
3162
3163    /**
3164     * Sets  <code>t</code> to be the static transformation of the child, if set, returning a
3165     * boolean to indicate whether a static transform was set. The default implementation
3166     * simply returns <code>false</code>; subclasses may override this method for different
3167     * behavior. {@link #setStaticTransformationsEnabled(boolean)} must be set to true
3168     * for this method to be called.
3169     *
3170     * @param child The child view whose static transform is being requested
3171     * @param t The Transformation which will hold the result
3172     * @return true if the transformation was set, false otherwise
3173     * @see #setStaticTransformationsEnabled(boolean)
3174     */
3175    protected boolean getChildStaticTransformation(View child, Transformation t) {
3176        return false;
3177    }
3178
3179    /**
3180     * {@hide}
3181     */
3182    @Override
3183    protected View findViewTraversal(int id) {
3184        if (id == mID) {
3185            return this;
3186        }
3187
3188        final View[] where = mChildren;
3189        final int len = mChildrenCount;
3190
3191        for (int i = 0; i < len; i++) {
3192            View v = where[i];
3193
3194            if ((v.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) {
3195                v = v.findViewById(id);
3196
3197                if (v != null) {
3198                    return v;
3199                }
3200            }
3201        }
3202
3203        return null;
3204    }
3205
3206    /**
3207     * {@hide}
3208     */
3209    @Override
3210    protected View findViewWithTagTraversal(Object tag) {
3211        if (tag != null && tag.equals(mTag)) {
3212            return this;
3213        }
3214
3215        final View[] where = mChildren;
3216        final int len = mChildrenCount;
3217
3218        for (int i = 0; i < len; i++) {
3219            View v = where[i];
3220
3221            if ((v.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) {
3222                v = v.findViewWithTag(tag);
3223
3224                if (v != null) {
3225                    return v;
3226                }
3227            }
3228        }
3229
3230        return null;
3231    }
3232
3233    /**
3234     * {@hide}
3235     */
3236    @Override
3237    protected View findViewByPredicateTraversal(Predicate<View> predicate, View childToSkip) {
3238        if (predicate.apply(this)) {
3239            return this;
3240        }
3241
3242        final View[] where = mChildren;
3243        final int len = mChildrenCount;
3244
3245        for (int i = 0; i < len; i++) {
3246            View v = where[i];
3247
3248            if (v != childToSkip && (v.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) {
3249                v = v.findViewByPredicate(predicate);
3250
3251                if (v != null) {
3252                    return v;
3253                }
3254            }
3255        }
3256
3257        return null;
3258    }
3259
3260    /**
3261     * <p>Adds a child view. If no layout parameters are already set on the child, the
3262     * default parameters for this ViewGroup are set on the child.</p>
3263     *
3264     * <p><strong>Note:</strong> do not invoke this method from
3265     * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3266     * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
3267     *
3268     * @param child the child view to add
3269     *
3270     * @see #generateDefaultLayoutParams()
3271     */
3272    public void addView(View child) {
3273        addView(child, -1);
3274    }
3275
3276    /**
3277     * Adds a child view. If no layout parameters are already set on the child, the
3278     * default parameters for this ViewGroup are set on the child.
3279     *
3280     * <p><strong>Note:</strong> do not invoke this method from
3281     * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3282     * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
3283     *
3284     * @param child the child view to add
3285     * @param index the position at which to add the child
3286     *
3287     * @see #generateDefaultLayoutParams()
3288     */
3289    public void addView(View child, int index) {
3290        LayoutParams params = child.getLayoutParams();
3291        if (params == null) {
3292            params = generateDefaultLayoutParams();
3293            if (params == null) {
3294                throw new IllegalArgumentException("generateDefaultLayoutParams() cannot return null");
3295            }
3296        }
3297        addView(child, index, params);
3298    }
3299
3300    /**
3301     * Adds a child view with this ViewGroup's default layout parameters and the
3302     * specified width and height.
3303     *
3304     * <p><strong>Note:</strong> do not invoke this method from
3305     * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3306     * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
3307     *
3308     * @param child the child view to add
3309     */
3310    public void addView(View child, int width, int height) {
3311        final LayoutParams params = generateDefaultLayoutParams();
3312        params.width = width;
3313        params.height = height;
3314        addView(child, -1, params);
3315    }
3316
3317    /**
3318     * Adds a child view with the specified layout parameters.
3319     *
3320     * <p><strong>Note:</strong> do not invoke this method from
3321     * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3322     * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
3323     *
3324     * @param child the child view to add
3325     * @param params the layout parameters to set on the child
3326     */
3327    public void addView(View child, LayoutParams params) {
3328        addView(child, -1, params);
3329    }
3330
3331    /**
3332     * Adds a child view with the specified layout parameters.
3333     *
3334     * <p><strong>Note:</strong> do not invoke this method from
3335     * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3336     * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
3337     *
3338     * @param child the child view to add
3339     * @param index the position at which to add the child
3340     * @param params the layout parameters to set on the child
3341     */
3342    public void addView(View child, int index, LayoutParams params) {
3343        if (DBG) {
3344            System.out.println(this + " addView");
3345        }
3346
3347        // addViewInner() will call child.requestLayout() when setting the new LayoutParams
3348        // therefore, we call requestLayout() on ourselves before, so that the child's request
3349        // will be blocked at our level
3350        requestLayout();
3351        invalidate(true);
3352        addViewInner(child, index, params, false);
3353    }
3354
3355    /**
3356     * {@inheritDoc}
3357     */
3358    public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
3359        if (!checkLayoutParams(params)) {
3360            throw new IllegalArgumentException("Invalid LayoutParams supplied to " + this);
3361        }
3362        if (view.mParent != this) {
3363            throw new IllegalArgumentException("Given view not a child of " + this);
3364        }
3365        view.setLayoutParams(params);
3366    }
3367
3368    /**
3369     * {@inheritDoc}
3370     */
3371    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
3372        return  p != null;
3373    }
3374
3375    /**
3376     * Interface definition for a callback to be invoked when the hierarchy
3377     * within this view changed. The hierarchy changes whenever a child is added
3378     * to or removed from this view.
3379     */
3380    public interface OnHierarchyChangeListener {
3381        /**
3382         * Called when a new child is added to a parent view.
3383         *
3384         * @param parent the view in which a child was added
3385         * @param child the new child view added in the hierarchy
3386         */
3387        void onChildViewAdded(View parent, View child);
3388
3389        /**
3390         * Called when a child is removed from a parent view.
3391         *
3392         * @param parent the view from which the child was removed
3393         * @param child the child removed from the hierarchy
3394         */
3395        void onChildViewRemoved(View parent, View child);
3396    }
3397
3398    /**
3399     * Register a callback to be invoked when a child is added to or removed
3400     * from this view.
3401     *
3402     * @param listener the callback to invoke on hierarchy change
3403     */
3404    public void setOnHierarchyChangeListener(OnHierarchyChangeListener listener) {
3405        mOnHierarchyChangeListener = listener;
3406    }
3407
3408    /**
3409     * @hide
3410     */
3411    protected void onViewAdded(View child) {
3412        if (mOnHierarchyChangeListener != null) {
3413            mOnHierarchyChangeListener.onChildViewAdded(this, child);
3414        }
3415    }
3416
3417    /**
3418     * @hide
3419     */
3420    protected void onViewRemoved(View child) {
3421        if (mOnHierarchyChangeListener != null) {
3422            mOnHierarchyChangeListener.onChildViewRemoved(this, child);
3423        }
3424    }
3425
3426    /**
3427     * Adds a view during layout. This is useful if in your onLayout() method,
3428     * you need to add more views (as does the list view for example).
3429     *
3430     * If index is negative, it means put it at the end of the list.
3431     *
3432     * @param child the view to add to the group
3433     * @param index the index at which the child must be added
3434     * @param params the layout parameters to associate with the child
3435     * @return true if the child was added, false otherwise
3436     */
3437    protected boolean addViewInLayout(View child, int index, LayoutParams params) {
3438        return addViewInLayout(child, index, params, false);
3439    }
3440
3441    /**
3442     * Adds a view during layout. This is useful if in your onLayout() method,
3443     * you need to add more views (as does the list view for example).
3444     *
3445     * If index is negative, it means put it at the end of the list.
3446     *
3447     * @param child the view to add to the group
3448     * @param index the index at which the child must be added
3449     * @param params the layout parameters to associate with the child
3450     * @param preventRequestLayout if true, calling this method will not trigger a
3451     *        layout request on child
3452     * @return true if the child was added, false otherwise
3453     */
3454    protected boolean addViewInLayout(View child, int index, LayoutParams params,
3455            boolean preventRequestLayout) {
3456        child.mParent = null;
3457        addViewInner(child, index, params, preventRequestLayout);
3458        child.mPrivateFlags = (child.mPrivateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN;
3459        return true;
3460    }
3461
3462    /**
3463     * Prevents the specified child to be laid out during the next layout pass.
3464     *
3465     * @param child the child on which to perform the cleanup
3466     */
3467    protected void cleanupLayoutState(View child) {
3468        child.mPrivateFlags &= ~View.PFLAG_FORCE_LAYOUT;
3469    }
3470
3471    private void addViewInner(View child, int index, LayoutParams params,
3472            boolean preventRequestLayout) {
3473
3474        if (mTransition != null) {
3475            // Don't prevent other add transitions from completing, but cancel remove
3476            // transitions to let them complete the process before we add to the container
3477            mTransition.cancel(LayoutTransition.DISAPPEARING);
3478        }
3479
3480        if (child.getParent() != null) {
3481            throw new IllegalStateException("The specified child already has a parent. " +
3482                    "You must call removeView() on the child's parent first.");
3483        }
3484
3485        if (mTransition != null) {
3486            mTransition.addChild(this, child);
3487        }
3488
3489        if (!checkLayoutParams(params)) {
3490            params = generateLayoutParams(params);
3491        }
3492
3493        if (preventRequestLayout) {
3494            child.mLayoutParams = params;
3495        } else {
3496            child.setLayoutParams(params);
3497        }
3498
3499        if (index < 0) {
3500            index = mChildrenCount;
3501        }
3502
3503        addInArray(child, index);
3504
3505        // tell our children
3506        if (preventRequestLayout) {
3507            child.assignParent(this);
3508        } else {
3509            child.mParent = this;
3510        }
3511
3512        if (child.hasFocus()) {
3513            requestChildFocus(child, child.findFocus());
3514        }
3515
3516        AttachInfo ai = mAttachInfo;
3517        if (ai != null && (mGroupFlags & FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW) == 0) {
3518            boolean lastKeepOn = ai.mKeepScreenOn;
3519            ai.mKeepScreenOn = false;
3520            child.dispatchAttachedToWindow(mAttachInfo, (mViewFlags&VISIBILITY_MASK));
3521            if (ai.mKeepScreenOn) {
3522                needGlobalAttributesUpdate(true);
3523            }
3524            ai.mKeepScreenOn = lastKeepOn;
3525        }
3526
3527        if (child.isLayoutDirectionInherited()) {
3528            child.resetRtlProperties();
3529        }
3530
3531        onViewAdded(child);
3532
3533        if ((child.mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE) {
3534            mGroupFlags |= FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE;
3535        }
3536
3537        if (child.hasTransientState()) {
3538            childHasTransientStateChanged(child, true);
3539        }
3540    }
3541
3542    private void addInArray(View child, int index) {
3543        View[] children = mChildren;
3544        final int count = mChildrenCount;
3545        final int size = children.length;
3546        if (index == count) {
3547            if (size == count) {
3548                mChildren = new View[size + ARRAY_CAPACITY_INCREMENT];
3549                System.arraycopy(children, 0, mChildren, 0, size);
3550                children = mChildren;
3551            }
3552            children[mChildrenCount++] = child;
3553        } else if (index < count) {
3554            if (size == count) {
3555                mChildren = new View[size + ARRAY_CAPACITY_INCREMENT];
3556                System.arraycopy(children, 0, mChildren, 0, index);
3557                System.arraycopy(children, index, mChildren, index + 1, count - index);
3558                children = mChildren;
3559            } else {
3560                System.arraycopy(children, index, children, index + 1, count - index);
3561            }
3562            children[index] = child;
3563            mChildrenCount++;
3564            if (mLastTouchDownIndex >= index) {
3565                mLastTouchDownIndex++;
3566            }
3567        } else {
3568            throw new IndexOutOfBoundsException("index=" + index + " count=" + count);
3569        }
3570    }
3571
3572    // This method also sets the child's mParent to null
3573    private void removeFromArray(int index) {
3574        final View[] children = mChildren;
3575        if (!(mTransitioningViews != null && mTransitioningViews.contains(children[index]))) {
3576            children[index].mParent = null;
3577        }
3578        final int count = mChildrenCount;
3579        if (index == count - 1) {
3580            children[--mChildrenCount] = null;
3581        } else if (index >= 0 && index < count) {
3582            System.arraycopy(children, index + 1, children, index, count - index - 1);
3583            children[--mChildrenCount] = null;
3584        } else {
3585            throw new IndexOutOfBoundsException();
3586        }
3587        if (mLastTouchDownIndex == index) {
3588            mLastTouchDownTime = 0;
3589            mLastTouchDownIndex = -1;
3590        } else if (mLastTouchDownIndex > index) {
3591            mLastTouchDownIndex--;
3592        }
3593    }
3594
3595    // This method also sets the children's mParent to null
3596    private void removeFromArray(int start, int count) {
3597        final View[] children = mChildren;
3598        final int childrenCount = mChildrenCount;
3599
3600        start = Math.max(0, start);
3601        final int end = Math.min(childrenCount, start + count);
3602
3603        if (start == end) {
3604            return;
3605        }
3606
3607        if (end == childrenCount) {
3608            for (int i = start; i < end; i++) {
3609                children[i].mParent = null;
3610                children[i] = null;
3611            }
3612        } else {
3613            for (int i = start; i < end; i++) {
3614                children[i].mParent = null;
3615            }
3616
3617            // Since we're looping above, we might as well do the copy, but is arraycopy()
3618            // faster than the extra 2 bounds checks we would do in the loop?
3619            System.arraycopy(children, end, children, start, childrenCount - end);
3620
3621            for (int i = childrenCount - (end - start); i < childrenCount; i++) {
3622                children[i] = null;
3623            }
3624        }
3625
3626        mChildrenCount -= (end - start);
3627    }
3628
3629    private void bindLayoutAnimation(View child) {
3630        Animation a = mLayoutAnimationController.getAnimationForView(child);
3631        child.setAnimation(a);
3632    }
3633
3634    /**
3635     * Subclasses should override this method to set layout animation
3636     * parameters on the supplied child.
3637     *
3638     * @param child the child to associate with animation parameters
3639     * @param params the child's layout parameters which hold the animation
3640     *        parameters
3641     * @param index the index of the child in the view group
3642     * @param count the number of children in the view group
3643     */
3644    protected void attachLayoutAnimationParameters(View child,
3645            LayoutParams params, int index, int count) {
3646        LayoutAnimationController.AnimationParameters animationParams =
3647                    params.layoutAnimationParameters;
3648        if (animationParams == null) {
3649            animationParams = new LayoutAnimationController.AnimationParameters();
3650            params.layoutAnimationParameters = animationParams;
3651        }
3652
3653        animationParams.count = count;
3654        animationParams.index = index;
3655    }
3656
3657    /**
3658     * {@inheritDoc}
3659     *
3660     * <p><strong>Note:</strong> do not invoke this method from
3661     * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3662     * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
3663     */
3664    public void removeView(View view) {
3665        removeViewInternal(view);
3666        requestLayout();
3667        invalidate(true);
3668    }
3669
3670    /**
3671     * Removes a view during layout. This is useful if in your onLayout() method,
3672     * you need to remove more views.
3673     *
3674     * <p><strong>Note:</strong> do not invoke this method from
3675     * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3676     * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
3677     *
3678     * @param view the view to remove from the group
3679     */
3680    public void removeViewInLayout(View view) {
3681        removeViewInternal(view);
3682    }
3683
3684    /**
3685     * Removes a range of views during layout. This is useful if in your onLayout() method,
3686     * you need to remove more views.
3687     *
3688     * <p><strong>Note:</strong> do not invoke this method from
3689     * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3690     * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
3691     *
3692     * @param start the index of the first view to remove from the group
3693     * @param count the number of views to remove from the group
3694     */
3695    public void removeViewsInLayout(int start, int count) {
3696        removeViewsInternal(start, count);
3697    }
3698
3699    /**
3700     * Removes the view at the specified position in the group.
3701     *
3702     * <p><strong>Note:</strong> do not invoke this method from
3703     * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3704     * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
3705     *
3706     * @param index the position in the group of the view to remove
3707     */
3708    public void removeViewAt(int index) {
3709        removeViewInternal(index, getChildAt(index));
3710        requestLayout();
3711        invalidate(true);
3712    }
3713
3714    /**
3715     * Removes the specified range of views from the group.
3716     *
3717     * <p><strong>Note:</strong> do not invoke this method from
3718     * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3719     * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
3720     *
3721     * @param start the first position in the group of the range of views to remove
3722     * @param count the number of views to remove
3723     */
3724    public void removeViews(int start, int count) {
3725        removeViewsInternal(start, count);
3726        requestLayout();
3727        invalidate(true);
3728    }
3729
3730    private void removeViewInternal(View view) {
3731        final int index = indexOfChild(view);
3732        if (index >= 0) {
3733            removeViewInternal(index, view);
3734        }
3735    }
3736
3737    private void removeViewInternal(int index, View view) {
3738
3739        if (mTransition != null) {
3740            mTransition.removeChild(this, view);
3741        }
3742
3743        boolean clearChildFocus = false;
3744        if (view == mFocused) {
3745            view.unFocus();
3746            clearChildFocus = true;
3747        }
3748
3749        if (view.isAccessibilityFocused()) {
3750            view.clearAccessibilityFocus();
3751        }
3752
3753        cancelTouchTarget(view);
3754        cancelHoverTarget(view);
3755
3756        if (view.getAnimation() != null ||
3757                (mTransitioningViews != null && mTransitioningViews.contains(view))) {
3758            addDisappearingView(view);
3759        } else if (view.mAttachInfo != null) {
3760           view.dispatchDetachedFromWindow();
3761        }
3762
3763        if (view.hasTransientState()) {
3764            childHasTransientStateChanged(view, false);
3765        }
3766
3767        needGlobalAttributesUpdate(false);
3768
3769        removeFromArray(index);
3770
3771        if (clearChildFocus) {
3772            clearChildFocus(view);
3773            if (!rootViewRequestFocus()) {
3774                notifyGlobalFocusCleared(this);
3775            }
3776        }
3777
3778        onViewRemoved(view);
3779    }
3780
3781    /**
3782     * Sets the LayoutTransition object for this ViewGroup. If the LayoutTransition object is
3783     * not null, changes in layout which occur because of children being added to or removed from
3784     * the ViewGroup will be animated according to the animations defined in that LayoutTransition
3785     * object. By default, the transition object is null (so layout changes are not animated).
3786     *
3787     * @param transition The LayoutTransition object that will animated changes in layout. A value
3788     * of <code>null</code> means no transition will run on layout changes.
3789     * @attr ref android.R.styleable#ViewGroup_animateLayoutChanges
3790     */
3791    public void setLayoutTransition(LayoutTransition transition) {
3792        if (mTransition != null) {
3793            mTransition.removeTransitionListener(mLayoutTransitionListener);
3794        }
3795        mTransition = transition;
3796        if (mTransition != null) {
3797            mTransition.addTransitionListener(mLayoutTransitionListener);
3798        }
3799    }
3800
3801    /**
3802     * Gets the LayoutTransition object for this ViewGroup. If the LayoutTransition object is
3803     * not null, changes in layout which occur because of children being added to or removed from
3804     * the ViewGroup will be animated according to the animations defined in that LayoutTransition
3805     * object. By default, the transition object is null (so layout changes are not animated).
3806     *
3807     * @return LayoutTranstion The LayoutTransition object that will animated changes in layout.
3808     * A value of <code>null</code> means no transition will run on layout changes.
3809     */
3810    public LayoutTransition getLayoutTransition() {
3811        return mTransition;
3812    }
3813
3814    private void removeViewsInternal(int start, int count) {
3815        final View focused = mFocused;
3816        final boolean detach = mAttachInfo != null;
3817        boolean clearChildFocus = false;
3818
3819        final View[] children = mChildren;
3820        final int end = start + count;
3821
3822        for (int i = start; i < end; i++) {
3823            final View view = children[i];
3824
3825            if (mTransition != null) {
3826                mTransition.removeChild(this, view);
3827            }
3828
3829            if (view == focused) {
3830                view.unFocus();
3831                clearChildFocus = true;
3832            }
3833
3834            if (view.isAccessibilityFocused()) {
3835                view.clearAccessibilityFocus();
3836            }
3837
3838            cancelTouchTarget(view);
3839            cancelHoverTarget(view);
3840
3841            if (view.getAnimation() != null ||
3842                (mTransitioningViews != null && mTransitioningViews.contains(view))) {
3843                addDisappearingView(view);
3844            } else if (detach) {
3845               view.dispatchDetachedFromWindow();
3846            }
3847
3848            if (view.hasTransientState()) {
3849                childHasTransientStateChanged(view, false);
3850            }
3851
3852            needGlobalAttributesUpdate(false);
3853
3854            onViewRemoved(view);
3855        }
3856
3857        removeFromArray(start, count);
3858
3859        if (clearChildFocus) {
3860            clearChildFocus(focused);
3861            if (!rootViewRequestFocus()) {
3862                notifyGlobalFocusCleared(focused);
3863            }
3864        }
3865    }
3866
3867    /**
3868     * Call this method to remove all child views from the
3869     * ViewGroup.
3870     *
3871     * <p><strong>Note:</strong> do not invoke this method from
3872     * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3873     * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
3874     */
3875    public void removeAllViews() {
3876        removeAllViewsInLayout();
3877        requestLayout();
3878        invalidate(true);
3879    }
3880
3881    /**
3882     * Called by a ViewGroup subclass to remove child views from itself,
3883     * when it must first know its size on screen before it can calculate how many
3884     * child views it will render. An example is a Gallery or a ListView, which
3885     * may "have" 50 children, but actually only render the number of children
3886     * that can currently fit inside the object on screen. Do not call
3887     * this method unless you are extending ViewGroup and understand the
3888     * view measuring and layout pipeline.
3889     *
3890     * <p><strong>Note:</strong> do not invoke this method from
3891     * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3892     * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
3893     */
3894    public void removeAllViewsInLayout() {
3895        final int count = mChildrenCount;
3896        if (count <= 0) {
3897            return;
3898        }
3899
3900        final View[] children = mChildren;
3901        mChildrenCount = 0;
3902
3903        final View focused = mFocused;
3904        final boolean detach = mAttachInfo != null;
3905        boolean clearChildFocus = false;
3906
3907        needGlobalAttributesUpdate(false);
3908
3909        for (int i = count - 1; i >= 0; i--) {
3910            final View view = children[i];
3911
3912            if (mTransition != null) {
3913                mTransition.removeChild(this, view);
3914            }
3915
3916            if (view == focused) {
3917                view.unFocus();
3918                clearChildFocus = true;
3919            }
3920
3921            if (view.isAccessibilityFocused()) {
3922                view.clearAccessibilityFocus();
3923            }
3924
3925            cancelTouchTarget(view);
3926            cancelHoverTarget(view);
3927
3928            if (view.getAnimation() != null ||
3929                    (mTransitioningViews != null && mTransitioningViews.contains(view))) {
3930                addDisappearingView(view);
3931            } else if (detach) {
3932               view.dispatchDetachedFromWindow();
3933            }
3934
3935            if (view.hasTransientState()) {
3936                childHasTransientStateChanged(view, false);
3937            }
3938
3939            onViewRemoved(view);
3940
3941            view.mParent = null;
3942            children[i] = null;
3943        }
3944
3945        if (clearChildFocus) {
3946            clearChildFocus(focused);
3947            if (!rootViewRequestFocus()) {
3948                notifyGlobalFocusCleared(focused);
3949            }
3950        }
3951    }
3952
3953    /**
3954     * Finishes the removal of a detached view. This method will dispatch the detached from
3955     * window event and notify the hierarchy change listener.
3956     * <p>
3957     * This method is intended to be lightweight and makes no assumptions about whether the
3958     * parent or child should be redrawn. Proper use of this method will include also making
3959     * any appropriate {@link #requestLayout()} or {@link #invalidate()} calls.
3960     * For example, callers can {@link #post(Runnable) post} a {@link Runnable}
3961     * which performs a {@link #requestLayout()} on the next frame, after all detach/remove
3962     * calls are finished, causing layout to be run prior to redrawing the view hierarchy.
3963     *
3964     * @param child the child to be definitely removed from the view hierarchy
3965     * @param animate if true and the view has an animation, the view is placed in the
3966     *                disappearing views list, otherwise, it is detached from the window
3967     *
3968     * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
3969     * @see #detachAllViewsFromParent()
3970     * @see #detachViewFromParent(View)
3971     * @see #detachViewFromParent(int)
3972     */
3973    protected void removeDetachedView(View child, boolean animate) {
3974        if (mTransition != null) {
3975            mTransition.removeChild(this, child);
3976        }
3977
3978        if (child == mFocused) {
3979            child.clearFocus();
3980        }
3981
3982        child.clearAccessibilityFocus();
3983
3984        cancelTouchTarget(child);
3985        cancelHoverTarget(child);
3986
3987        if ((animate && child.getAnimation() != null) ||
3988                (mTransitioningViews != null && mTransitioningViews.contains(child))) {
3989            addDisappearingView(child);
3990        } else if (child.mAttachInfo != null) {
3991            child.dispatchDetachedFromWindow();
3992        }
3993
3994        if (child.hasTransientState()) {
3995            childHasTransientStateChanged(child, false);
3996        }
3997
3998        onViewRemoved(child);
3999    }
4000
4001    /**
4002     * Attaches a view to this view group. Attaching a view assigns this group as the parent,
4003     * sets the layout parameters and puts the view in the list of children so that
4004     * it can be retrieved by calling {@link #getChildAt(int)}.
4005     * <p>
4006     * This method is intended to be lightweight and makes no assumptions about whether the
4007     * parent or child should be redrawn. Proper use of this method will include also making
4008     * any appropriate {@link #requestLayout()} or {@link #invalidate()} calls.
4009     * For example, callers can {@link #post(Runnable) post} a {@link Runnable}
4010     * which performs a {@link #requestLayout()} on the next frame, after all detach/attach
4011     * calls are finished, causing layout to be run prior to redrawing the view hierarchy.
4012     * <p>
4013     * This method should be called only for views which were detached from their parent.
4014     *
4015     * @param child the child to attach
4016     * @param index the index at which the child should be attached
4017     * @param params the layout parameters of the child
4018     *
4019     * @see #removeDetachedView(View, boolean)
4020     * @see #detachAllViewsFromParent()
4021     * @see #detachViewFromParent(View)
4022     * @see #detachViewFromParent(int)
4023     */
4024    protected void attachViewToParent(View child, int index, LayoutParams params) {
4025        child.mLayoutParams = params;
4026
4027        if (index < 0) {
4028            index = mChildrenCount;
4029        }
4030
4031        addInArray(child, index);
4032
4033        child.mParent = this;
4034        child.mPrivateFlags = (child.mPrivateFlags & ~PFLAG_DIRTY_MASK
4035                        & ~PFLAG_DRAWING_CACHE_VALID)
4036                | PFLAG_DRAWN | PFLAG_INVALIDATED;
4037        this.mPrivateFlags |= PFLAG_INVALIDATED;
4038
4039        if (child.hasFocus()) {
4040            requestChildFocus(child, child.findFocus());
4041        }
4042    }
4043
4044    /**
4045     * Detaches a view from its parent. Detaching a view should be followed
4046     * either by a call to
4047     * {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
4048     * or a call to {@link #removeDetachedView(View, boolean)}. Detachment should only be
4049     * temporary; reattachment or removal should happen within the same drawing cycle as
4050     * detachment. When a view is detached, its parent is null and cannot be retrieved by a
4051     * call to {@link #getChildAt(int)}.
4052     *
4053     * @param child the child to detach
4054     *
4055     * @see #detachViewFromParent(int)
4056     * @see #detachViewsFromParent(int, int)
4057     * @see #detachAllViewsFromParent()
4058     * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
4059     * @see #removeDetachedView(View, boolean)
4060     */
4061    protected void detachViewFromParent(View child) {
4062        removeFromArray(indexOfChild(child));
4063    }
4064
4065    /**
4066     * Detaches a view from its parent. Detaching a view should be followed
4067     * either by a call to
4068     * {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
4069     * or a call to {@link #removeDetachedView(View, boolean)}. Detachment should only be
4070     * temporary; reattachment or removal should happen within the same drawing cycle as
4071     * detachment. When a view is detached, its parent is null and cannot be retrieved by a
4072     * call to {@link #getChildAt(int)}.
4073     *
4074     * @param index the index of the child to detach
4075     *
4076     * @see #detachViewFromParent(View)
4077     * @see #detachAllViewsFromParent()
4078     * @see #detachViewsFromParent(int, int)
4079     * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
4080     * @see #removeDetachedView(View, boolean)
4081     */
4082    protected void detachViewFromParent(int index) {
4083        removeFromArray(index);
4084    }
4085
4086    /**
4087     * Detaches a range of views from their parents. Detaching a view should be followed
4088     * either by a call to
4089     * {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
4090     * or a call to {@link #removeDetachedView(View, boolean)}. Detachment should only be
4091     * temporary; reattachment or removal should happen within the same drawing cycle as
4092     * detachment. When a view is detached, its parent is null and cannot be retrieved by a
4093     * call to {@link #getChildAt(int)}.
4094     *
4095     * @param start the first index of the childrend range to detach
4096     * @param count the number of children to detach
4097     *
4098     * @see #detachViewFromParent(View)
4099     * @see #detachViewFromParent(int)
4100     * @see #detachAllViewsFromParent()
4101     * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
4102     * @see #removeDetachedView(View, boolean)
4103     */
4104    protected void detachViewsFromParent(int start, int count) {
4105        removeFromArray(start, count);
4106    }
4107
4108    /**
4109     * Detaches all views from the parent. Detaching a view should be followed
4110     * either by a call to
4111     * {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
4112     * or a call to {@link #removeDetachedView(View, boolean)}. Detachment should only be
4113     * temporary; reattachment or removal should happen within the same drawing cycle as
4114     * detachment. When a view is detached, its parent is null and cannot be retrieved by a
4115     * call to {@link #getChildAt(int)}.
4116     *
4117     * @see #detachViewFromParent(View)
4118     * @see #detachViewFromParent(int)
4119     * @see #detachViewsFromParent(int, int)
4120     * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
4121     * @see #removeDetachedView(View, boolean)
4122     */
4123    protected void detachAllViewsFromParent() {
4124        final int count = mChildrenCount;
4125        if (count <= 0) {
4126            return;
4127        }
4128
4129        final View[] children = mChildren;
4130        mChildrenCount = 0;
4131
4132        for (int i = count - 1; i >= 0; i--) {
4133            children[i].mParent = null;
4134            children[i] = null;
4135        }
4136    }
4137
4138    /**
4139     * Don't call or override this method. It is used for the implementation of
4140     * the view hierarchy.
4141     */
4142    public final void invalidateChild(View child, final Rect dirty) {
4143        ViewParent parent = this;
4144
4145        final AttachInfo attachInfo = mAttachInfo;
4146        if (attachInfo != null) {
4147            // If the child is drawing an animation, we want to copy this flag onto
4148            // ourselves and the parent to make sure the invalidate request goes
4149            // through
4150            final boolean drawAnimation = (child.mPrivateFlags & PFLAG_DRAW_ANIMATION)
4151                    == PFLAG_DRAW_ANIMATION;
4152
4153            // Check whether the child that requests the invalidate is fully opaque
4154            // Views being animated or transformed are not considered opaque because we may
4155            // be invalidating their old position and need the parent to paint behind them.
4156            Matrix childMatrix = child.getMatrix();
4157            final boolean isOpaque = child.isOpaque() && !drawAnimation &&
4158                    child.getAnimation() == null && childMatrix.isIdentity();
4159            // Mark the child as dirty, using the appropriate flag
4160            // Make sure we do not set both flags at the same time
4161            int opaqueFlag = isOpaque ? PFLAG_DIRTY_OPAQUE : PFLAG_DIRTY;
4162
4163            if (child.mLayerType != LAYER_TYPE_NONE) {
4164                mPrivateFlags |= PFLAG_INVALIDATED;
4165                mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
4166                child.mLocalDirtyRect.union(dirty);
4167            }
4168
4169            final int[] location = attachInfo.mInvalidateChildLocation;
4170            location[CHILD_LEFT_INDEX] = child.mLeft;
4171            location[CHILD_TOP_INDEX] = child.mTop;
4172            if (!childMatrix.isIdentity() ||
4173                    (mGroupFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) {
4174                RectF boundingRect = attachInfo.mTmpTransformRect;
4175                boundingRect.set(dirty);
4176                Matrix transformMatrix;
4177                if ((mGroupFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) {
4178                    Transformation t = attachInfo.mTmpTransformation;
4179                    boolean transformed = getChildStaticTransformation(child, t);
4180                    if (transformed) {
4181                        transformMatrix = attachInfo.mTmpMatrix;
4182                        transformMatrix.set(t.getMatrix());
4183                        if (!childMatrix.isIdentity()) {
4184                            transformMatrix.preConcat(childMatrix);
4185                        }
4186                    } else {
4187                        transformMatrix = childMatrix;
4188                    }
4189                } else {
4190                    transformMatrix = childMatrix;
4191                }
4192                transformMatrix.mapRect(boundingRect);
4193                dirty.set((int) (boundingRect.left - 0.5f),
4194                        (int) (boundingRect.top - 0.5f),
4195                        (int) (boundingRect.right + 0.5f),
4196                        (int) (boundingRect.bottom + 0.5f));
4197            }
4198
4199            do {
4200                View view = null;
4201                if (parent instanceof View) {
4202                    view = (View) parent;
4203                }
4204
4205                if (drawAnimation) {
4206                    if (view != null) {
4207                        view.mPrivateFlags |= PFLAG_DRAW_ANIMATION;
4208                    } else if (parent instanceof ViewRootImpl) {
4209                        ((ViewRootImpl) parent).mIsAnimating = true;
4210                    }
4211                }
4212
4213                // If the parent is dirty opaque or not dirty, mark it dirty with the opaque
4214                // flag coming from the child that initiated the invalidate
4215                if (view != null) {
4216                    if ((view.mViewFlags & FADING_EDGE_MASK) != 0 &&
4217                            view.getSolidColor() == 0) {
4218                        opaqueFlag = PFLAG_DIRTY;
4219                    }
4220                    if ((view.mPrivateFlags & PFLAG_DIRTY_MASK) != PFLAG_DIRTY) {
4221                        view.mPrivateFlags = (view.mPrivateFlags & ~PFLAG_DIRTY_MASK) | opaqueFlag;
4222                    }
4223                }
4224
4225                parent = parent.invalidateChildInParent(location, dirty);
4226                if (view != null) {
4227                    // Account for transform on current parent
4228                    Matrix m = view.getMatrix();
4229                    if (!m.isIdentity()) {
4230                        RectF boundingRect = attachInfo.mTmpTransformRect;
4231                        boundingRect.set(dirty);
4232                        m.mapRect(boundingRect);
4233                        dirty.set((int) (boundingRect.left - 0.5f),
4234                                (int) (boundingRect.top - 0.5f),
4235                                (int) (boundingRect.right + 0.5f),
4236                                (int) (boundingRect.bottom + 0.5f));
4237                    }
4238                }
4239            } while (parent != null);
4240        }
4241    }
4242
4243    /**
4244     * Don't call or override this method. It is used for the implementation of
4245     * the view hierarchy.
4246     *
4247     * This implementation returns null if this ViewGroup does not have a parent,
4248     * if this ViewGroup is already fully invalidated or if the dirty rectangle
4249     * does not intersect with this ViewGroup's bounds.
4250     */
4251    public ViewParent invalidateChildInParent(final int[] location, final Rect dirty) {
4252        if ((mPrivateFlags & PFLAG_DRAWN) == PFLAG_DRAWN ||
4253                (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID) {
4254            if ((mGroupFlags & (FLAG_OPTIMIZE_INVALIDATE | FLAG_ANIMATION_DONE)) !=
4255                        FLAG_OPTIMIZE_INVALIDATE) {
4256                dirty.offset(location[CHILD_LEFT_INDEX] - mScrollX,
4257                        location[CHILD_TOP_INDEX] - mScrollY);
4258
4259                final int left = mLeft;
4260                final int top = mTop;
4261
4262                if ((mGroupFlags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN) {
4263                    if (!dirty.intersect(0, 0, mRight - left, mBottom - top)) {
4264                        dirty.setEmpty();
4265                    }
4266                }
4267                mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
4268
4269                location[CHILD_LEFT_INDEX] = left;
4270                location[CHILD_TOP_INDEX] = top;
4271
4272                if (mLayerType != LAYER_TYPE_NONE) {
4273                    mPrivateFlags |= PFLAG_INVALIDATED;
4274                    mLocalDirtyRect.union(dirty);
4275                }
4276
4277                return mParent;
4278
4279            } else {
4280                mPrivateFlags &= ~PFLAG_DRAWN & ~PFLAG_DRAWING_CACHE_VALID;
4281
4282                location[CHILD_LEFT_INDEX] = mLeft;
4283                location[CHILD_TOP_INDEX] = mTop;
4284                if ((mGroupFlags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN) {
4285                    dirty.set(0, 0, mRight - mLeft, mBottom - mTop);
4286                } else {
4287                    // in case the dirty rect extends outside the bounds of this container
4288                    dirty.union(0, 0, mRight - mLeft, mBottom - mTop);
4289                }
4290
4291                if (mLayerType != LAYER_TYPE_NONE) {
4292                    mPrivateFlags |= PFLAG_INVALIDATED;
4293                    mLocalDirtyRect.union(dirty);
4294                }
4295
4296                return mParent;
4297            }
4298        }
4299
4300        return null;
4301    }
4302
4303    /**
4304     * Quick invalidation method called by View.invalidateViewProperty. This doesn't set the
4305     * DRAWN flags and doesn't handle the Animation logic that the default invalidation methods
4306     * do; all we want to do here is schedule a traversal with the appropriate dirty rect.
4307     *
4308     * @hide
4309     */
4310    public void invalidateChildFast(View child, final Rect dirty) {
4311        ViewParent parent = this;
4312
4313        final AttachInfo attachInfo = mAttachInfo;
4314        if (attachInfo != null) {
4315            if (child.mLayerType != LAYER_TYPE_NONE) {
4316                child.mLocalDirtyRect.union(dirty);
4317            }
4318
4319            int left = child.mLeft;
4320            int top = child.mTop;
4321            if (!child.getMatrix().isIdentity()) {
4322                child.transformRect(dirty);
4323            }
4324
4325            do {
4326                if (parent instanceof ViewGroup) {
4327                    ViewGroup parentVG = (ViewGroup) parent;
4328                    if (parentVG.mLayerType != LAYER_TYPE_NONE) {
4329                        // Layered parents should be recreated, not just re-issued
4330                        parentVG.invalidate();
4331                        parent = null;
4332                    } else {
4333                        parent = parentVG.invalidateChildInParentFast(left, top, dirty);
4334                        left = parentVG.mLeft;
4335                        top = parentVG.mTop;
4336                    }
4337                } else {
4338                    // Reached the top; this calls into the usual invalidate method in
4339                    // ViewRootImpl, which schedules a traversal
4340                    final int[] location = attachInfo.mInvalidateChildLocation;
4341                    location[0] = left;
4342                    location[1] = top;
4343                    parent = parent.invalidateChildInParent(location, dirty);
4344                }
4345            } while (parent != null);
4346        }
4347    }
4348
4349    /**
4350     * Quick invalidation method that simply transforms the dirty rect into the parent's
4351     * coordinate system, pruning the invalidation if the parent has already been invalidated.
4352     */
4353    private ViewParent invalidateChildInParentFast(int left, int top, final Rect dirty) {
4354        if ((mPrivateFlags & PFLAG_DRAWN) == PFLAG_DRAWN ||
4355                (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID) {
4356            dirty.offset(left - mScrollX, top - mScrollY);
4357
4358            if ((mGroupFlags & FLAG_CLIP_CHILDREN) == 0 ||
4359                    dirty.intersect(0, 0, mRight - mLeft, mBottom - mTop)) {
4360
4361                if (mLayerType != LAYER_TYPE_NONE) {
4362                    mLocalDirtyRect.union(dirty);
4363                }
4364                if (!getMatrix().isIdentity()) {
4365                    transformRect(dirty);
4366                }
4367
4368                return mParent;
4369            }
4370        }
4371
4372        return null;
4373    }
4374
4375    /**
4376     * Offset a rectangle that is in a descendant's coordinate
4377     * space into our coordinate space.
4378     * @param descendant A descendant of this view
4379     * @param rect A rectangle defined in descendant's coordinate space.
4380     */
4381    public final void offsetDescendantRectToMyCoords(View descendant, Rect rect) {
4382        offsetRectBetweenParentAndChild(descendant, rect, true, false);
4383    }
4384
4385    /**
4386     * Offset a rectangle that is in our coordinate space into an ancestor's
4387     * coordinate space.
4388     * @param descendant A descendant of this view
4389     * @param rect A rectangle defined in descendant's coordinate space.
4390     */
4391    public final void offsetRectIntoDescendantCoords(View descendant, Rect rect) {
4392        offsetRectBetweenParentAndChild(descendant, rect, false, false);
4393    }
4394
4395    /**
4396     * Helper method that offsets a rect either from parent to descendant or
4397     * descendant to parent.
4398     */
4399    void offsetRectBetweenParentAndChild(View descendant, Rect rect,
4400            boolean offsetFromChildToParent, boolean clipToBounds) {
4401
4402        // already in the same coord system :)
4403        if (descendant == this) {
4404            return;
4405        }
4406
4407        ViewParent theParent = descendant.mParent;
4408
4409        // search and offset up to the parent
4410        while ((theParent != null)
4411                && (theParent instanceof View)
4412                && (theParent != this)) {
4413
4414            if (offsetFromChildToParent) {
4415                rect.offset(descendant.mLeft - descendant.mScrollX,
4416                        descendant.mTop - descendant.mScrollY);
4417                if (clipToBounds) {
4418                    View p = (View) theParent;
4419                    rect.intersect(0, 0, p.mRight - p.mLeft, p.mBottom - p.mTop);
4420                }
4421            } else {
4422                if (clipToBounds) {
4423                    View p = (View) theParent;
4424                    rect.intersect(0, 0, p.mRight - p.mLeft, p.mBottom - p.mTop);
4425                }
4426                rect.offset(descendant.mScrollX - descendant.mLeft,
4427                        descendant.mScrollY - descendant.mTop);
4428            }
4429
4430            descendant = (View) theParent;
4431            theParent = descendant.mParent;
4432        }
4433
4434        // now that we are up to this view, need to offset one more time
4435        // to get into our coordinate space
4436        if (theParent == this) {
4437            if (offsetFromChildToParent) {
4438                rect.offset(descendant.mLeft - descendant.mScrollX,
4439                        descendant.mTop - descendant.mScrollY);
4440            } else {
4441                rect.offset(descendant.mScrollX - descendant.mLeft,
4442                        descendant.mScrollY - descendant.mTop);
4443            }
4444        } else {
4445            throw new IllegalArgumentException("parameter must be a descendant of this view");
4446        }
4447    }
4448
4449    /**
4450     * Offset the vertical location of all children of this view by the specified number of pixels.
4451     *
4452     * @param offset the number of pixels to offset
4453     *
4454     * @hide
4455     */
4456    public void offsetChildrenTopAndBottom(int offset) {
4457        final int count = mChildrenCount;
4458        final View[] children = mChildren;
4459
4460        for (int i = 0; i < count; i++) {
4461            final View v = children[i];
4462            v.mTop += offset;
4463            v.mBottom += offset;
4464            if (v.mDisplayList != null) {
4465                v.mDisplayList.offsetTopAndBottom(offset);
4466                invalidateViewProperty(false, false);
4467            }
4468        }
4469    }
4470
4471    /**
4472     * {@inheritDoc}
4473     */
4474    public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) {
4475        // It doesn't make a whole lot of sense to call this on a view that isn't attached,
4476        // but for some simple tests it can be useful. If we don't have attach info this
4477        // will allocate memory.
4478        final RectF rect = mAttachInfo != null ? mAttachInfo.mTmpTransformRect : new RectF();
4479        rect.set(r);
4480
4481        if (!child.hasIdentityMatrix()) {
4482           child.getMatrix().mapRect(rect);
4483        }
4484
4485        int dx = child.mLeft - mScrollX;
4486        int dy = child.mTop - mScrollY;
4487
4488        rect.offset(dx, dy);
4489
4490        if (offset != null) {
4491            if (!child.hasIdentityMatrix()) {
4492                float[] position = mAttachInfo != null ? mAttachInfo.mTmpTransformLocation
4493                        : new float[2];
4494                position[0] = offset.x;
4495                position[1] = offset.y;
4496                child.getMatrix().mapPoints(position);
4497                offset.x = (int) (position[0] + 0.5f);
4498                offset.y = (int) (position[1] + 0.5f);
4499            }
4500            offset.x += dx;
4501            offset.y += dy;
4502        }
4503
4504        if (rect.intersect(0, 0, mRight - mLeft, mBottom - mTop)) {
4505            if (mParent == null) return true;
4506            r.set((int) (rect.left + 0.5f), (int) (rect.top + 0.5f),
4507                    (int) (rect.right + 0.5f), (int) (rect.bottom + 0.5f));
4508            return mParent.getChildVisibleRect(this, r, offset);
4509        }
4510
4511        return false;
4512    }
4513
4514    /**
4515     * {@inheritDoc}
4516     */
4517    @Override
4518    public final void layout(int l, int t, int r, int b) {
4519        if (mTransition == null || !mTransition.isChangingLayout()) {
4520            if (mTransition != null) {
4521                mTransition.layoutChange(this);
4522            }
4523            super.layout(l, t, r, b);
4524        } else {
4525            // record the fact that we noop'd it; request layout when transition finishes
4526            mLayoutSuppressed = true;
4527        }
4528    }
4529
4530    /**
4531     * {@inheritDoc}
4532     */
4533    @Override
4534    protected abstract void onLayout(boolean changed,
4535            int l, int t, int r, int b);
4536
4537    /**
4538     * Indicates whether the view group has the ability to animate its children
4539     * after the first layout.
4540     *
4541     * @return true if the children can be animated, false otherwise
4542     */
4543    protected boolean canAnimate() {
4544        return mLayoutAnimationController != null;
4545    }
4546
4547    /**
4548     * Runs the layout animation. Calling this method triggers a relayout of
4549     * this view group.
4550     */
4551    public void startLayoutAnimation() {
4552        if (mLayoutAnimationController != null) {
4553            mGroupFlags |= FLAG_RUN_ANIMATION;
4554            requestLayout();
4555        }
4556    }
4557
4558    /**
4559     * Schedules the layout animation to be played after the next layout pass
4560     * of this view group. This can be used to restart the layout animation
4561     * when the content of the view group changes or when the activity is
4562     * paused and resumed.
4563     */
4564    public void scheduleLayoutAnimation() {
4565        mGroupFlags |= FLAG_RUN_ANIMATION;
4566    }
4567
4568    /**
4569     * Sets the layout animation controller used to animate the group's
4570     * children after the first layout.
4571     *
4572     * @param controller the animation controller
4573     */
4574    public void setLayoutAnimation(LayoutAnimationController controller) {
4575        mLayoutAnimationController = controller;
4576        if (mLayoutAnimationController != null) {
4577            mGroupFlags |= FLAG_RUN_ANIMATION;
4578        }
4579    }
4580
4581    /**
4582     * Returns the layout animation controller used to animate the group's
4583     * children.
4584     *
4585     * @return the current animation controller
4586     */
4587    public LayoutAnimationController getLayoutAnimation() {
4588        return mLayoutAnimationController;
4589    }
4590
4591    /**
4592     * Indicates whether the children's drawing cache is used during a layout
4593     * animation. By default, the drawing cache is enabled but this will prevent
4594     * nested layout animations from working. To nest animations, you must disable
4595     * the cache.
4596     *
4597     * @return true if the animation cache is enabled, false otherwise
4598     *
4599     * @see #setAnimationCacheEnabled(boolean)
4600     * @see View#setDrawingCacheEnabled(boolean)
4601     */
4602    @ViewDebug.ExportedProperty
4603    public boolean isAnimationCacheEnabled() {
4604        return (mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE;
4605    }
4606
4607    /**
4608     * Enables or disables the children's drawing cache during a layout animation.
4609     * By default, the drawing cache is enabled but this will prevent nested
4610     * layout animations from working. To nest animations, you must disable the
4611     * cache.
4612     *
4613     * @param enabled true to enable the animation cache, false otherwise
4614     *
4615     * @see #isAnimationCacheEnabled()
4616     * @see View#setDrawingCacheEnabled(boolean)
4617     */
4618    public void setAnimationCacheEnabled(boolean enabled) {
4619        setBooleanFlag(FLAG_ANIMATION_CACHE, enabled);
4620    }
4621
4622    /**
4623     * Indicates whether this ViewGroup will always try to draw its children using their
4624     * drawing cache. By default this property is enabled.
4625     *
4626     * @return true if the animation cache is enabled, false otherwise
4627     *
4628     * @see #setAlwaysDrawnWithCacheEnabled(boolean)
4629     * @see #setChildrenDrawnWithCacheEnabled(boolean)
4630     * @see View#setDrawingCacheEnabled(boolean)
4631     */
4632    @ViewDebug.ExportedProperty(category = "drawing")
4633    public boolean isAlwaysDrawnWithCacheEnabled() {
4634        return (mGroupFlags & FLAG_ALWAYS_DRAWN_WITH_CACHE) == FLAG_ALWAYS_DRAWN_WITH_CACHE;
4635    }
4636
4637    /**
4638     * Indicates whether this ViewGroup will always try to draw its children using their
4639     * drawing cache. This property can be set to true when the cache rendering is
4640     * slightly different from the children's normal rendering. Renderings can be different,
4641     * for instance, when the cache's quality is set to low.
4642     *
4643     * When this property is disabled, the ViewGroup will use the drawing cache of its
4644     * children only when asked to. It's usually the task of subclasses to tell ViewGroup
4645     * when to start using the drawing cache and when to stop using it.
4646     *
4647     * @param always true to always draw with the drawing cache, false otherwise
4648     *
4649     * @see #isAlwaysDrawnWithCacheEnabled()
4650     * @see #setChildrenDrawnWithCacheEnabled(boolean)
4651     * @see View#setDrawingCacheEnabled(boolean)
4652     * @see View#setDrawingCacheQuality(int)
4653     */
4654    public void setAlwaysDrawnWithCacheEnabled(boolean always) {
4655        setBooleanFlag(FLAG_ALWAYS_DRAWN_WITH_CACHE, always);
4656    }
4657
4658    /**
4659     * Indicates whether the ViewGroup is currently drawing its children using
4660     * their drawing cache.
4661     *
4662     * @return true if children should be drawn with their cache, false otherwise
4663     *
4664     * @see #setAlwaysDrawnWithCacheEnabled(boolean)
4665     * @see #setChildrenDrawnWithCacheEnabled(boolean)
4666     */
4667    @ViewDebug.ExportedProperty(category = "drawing")
4668    protected boolean isChildrenDrawnWithCacheEnabled() {
4669        return (mGroupFlags & FLAG_CHILDREN_DRAWN_WITH_CACHE) == FLAG_CHILDREN_DRAWN_WITH_CACHE;
4670    }
4671
4672    /**
4673     * Tells the ViewGroup to draw its children using their drawing cache. This property
4674     * is ignored when {@link #isAlwaysDrawnWithCacheEnabled()} is true. A child's drawing cache
4675     * will be used only if it has been enabled.
4676     *
4677     * Subclasses should call this method to start and stop using the drawing cache when
4678     * they perform performance sensitive operations, like scrolling or animating.
4679     *
4680     * @param enabled true if children should be drawn with their cache, false otherwise
4681     *
4682     * @see #setAlwaysDrawnWithCacheEnabled(boolean)
4683     * @see #isChildrenDrawnWithCacheEnabled()
4684     */
4685    protected void setChildrenDrawnWithCacheEnabled(boolean enabled) {
4686        setBooleanFlag(FLAG_CHILDREN_DRAWN_WITH_CACHE, enabled);
4687    }
4688
4689    /**
4690     * Indicates whether the ViewGroup is drawing its children in the order defined by
4691     * {@link #getChildDrawingOrder(int, int)}.
4692     *
4693     * @return true if children drawing order is defined by {@link #getChildDrawingOrder(int, int)},
4694     *         false otherwise
4695     *
4696     * @see #setChildrenDrawingOrderEnabled(boolean)
4697     * @see #getChildDrawingOrder(int, int)
4698     */
4699    @ViewDebug.ExportedProperty(category = "drawing")
4700    protected boolean isChildrenDrawingOrderEnabled() {
4701        return (mGroupFlags & FLAG_USE_CHILD_DRAWING_ORDER) == FLAG_USE_CHILD_DRAWING_ORDER;
4702    }
4703
4704    /**
4705     * Tells the ViewGroup whether to draw its children in the order defined by the method
4706     * {@link #getChildDrawingOrder(int, int)}.
4707     *
4708     * @param enabled true if the order of the children when drawing is determined by
4709     *        {@link #getChildDrawingOrder(int, int)}, false otherwise
4710     *
4711     * @see #isChildrenDrawingOrderEnabled()
4712     * @see #getChildDrawingOrder(int, int)
4713     */
4714    protected void setChildrenDrawingOrderEnabled(boolean enabled) {
4715        setBooleanFlag(FLAG_USE_CHILD_DRAWING_ORDER, enabled);
4716    }
4717
4718    private void setBooleanFlag(int flag, boolean value) {
4719        if (value) {
4720            mGroupFlags |= flag;
4721        } else {
4722            mGroupFlags &= ~flag;
4723        }
4724    }
4725
4726    /**
4727     * Returns an integer indicating what types of drawing caches are kept in memory.
4728     *
4729     * @see #setPersistentDrawingCache(int)
4730     * @see #setAnimationCacheEnabled(boolean)
4731     *
4732     * @return one or a combination of {@link #PERSISTENT_NO_CACHE},
4733     *         {@link #PERSISTENT_ANIMATION_CACHE}, {@link #PERSISTENT_SCROLLING_CACHE}
4734     *         and {@link #PERSISTENT_ALL_CACHES}
4735     */
4736    @ViewDebug.ExportedProperty(category = "drawing", mapping = {
4737        @ViewDebug.IntToString(from = PERSISTENT_NO_CACHE,        to = "NONE"),
4738        @ViewDebug.IntToString(from = PERSISTENT_ANIMATION_CACHE, to = "ANIMATION"),
4739        @ViewDebug.IntToString(from = PERSISTENT_SCROLLING_CACHE, to = "SCROLLING"),
4740        @ViewDebug.IntToString(from = PERSISTENT_ALL_CACHES,      to = "ALL")
4741    })
4742    public int getPersistentDrawingCache() {
4743        return mPersistentDrawingCache;
4744    }
4745
4746    /**
4747     * Indicates what types of drawing caches should be kept in memory after
4748     * they have been created.
4749     *
4750     * @see #getPersistentDrawingCache()
4751     * @see #setAnimationCacheEnabled(boolean)
4752     *
4753     * @param drawingCacheToKeep one or a combination of {@link #PERSISTENT_NO_CACHE},
4754     *        {@link #PERSISTENT_ANIMATION_CACHE}, {@link #PERSISTENT_SCROLLING_CACHE}
4755     *        and {@link #PERSISTENT_ALL_CACHES}
4756     */
4757    public void setPersistentDrawingCache(int drawingCacheToKeep) {
4758        mPersistentDrawingCache = drawingCacheToKeep & PERSISTENT_ALL_CACHES;
4759    }
4760
4761    /**
4762     * Returns the basis of alignment during layout operations on this view group:
4763     * either {@link #LAYOUT_MODE_CLIP_BOUNDS} or {@link #LAYOUT_MODE_OPTICAL_BOUNDS}.
4764     *
4765     * @return the layout mode to use during layout operations
4766     *
4767     * @see #setLayoutMode(int)
4768     */
4769    public int getLayoutMode() {
4770        return mLayoutMode;
4771    }
4772
4773    /**
4774     * Sets the basis of alignment during the layout of this view group.
4775     * Valid values are either {@link #LAYOUT_MODE_CLIP_BOUNDS} or
4776     * {@link #LAYOUT_MODE_OPTICAL_BOUNDS}.
4777     * <p>
4778     * The default is {@link #LAYOUT_MODE_CLIP_BOUNDS}.
4779     *
4780     * @param layoutMode the layout mode to use during layout operations
4781     *
4782     * @see #getLayoutMode()
4783     */
4784    public void setLayoutMode(int layoutMode) {
4785        if (mLayoutMode != layoutMode) {
4786            mLayoutMode = layoutMode;
4787            requestLayout();
4788        }
4789    }
4790
4791    /**
4792     * Returns a new set of layout parameters based on the supplied attributes set.
4793     *
4794     * @param attrs the attributes to build the layout parameters from
4795     *
4796     * @return an instance of {@link android.view.ViewGroup.LayoutParams} or one
4797     *         of its descendants
4798     */
4799    public LayoutParams generateLayoutParams(AttributeSet attrs) {
4800        return new LayoutParams(getContext(), attrs);
4801    }
4802
4803    /**
4804     * Returns a safe set of layout parameters based on the supplied layout params.
4805     * When a ViewGroup is passed a View whose layout params do not pass the test of
4806     * {@link #checkLayoutParams(android.view.ViewGroup.LayoutParams)}, this method
4807     * is invoked. This method should return a new set of layout params suitable for
4808     * this ViewGroup, possibly by copying the appropriate attributes from the
4809     * specified set of layout params.
4810     *
4811     * @param p The layout parameters to convert into a suitable set of layout parameters
4812     *          for this ViewGroup.
4813     *
4814     * @return an instance of {@link android.view.ViewGroup.LayoutParams} or one
4815     *         of its descendants
4816     */
4817    protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
4818        return p;
4819    }
4820
4821    /**
4822     * Returns a set of default layout parameters. These parameters are requested
4823     * when the View passed to {@link #addView(View)} has no layout parameters
4824     * already set. If null is returned, an exception is thrown from addView.
4825     *
4826     * @return a set of default layout parameters or null
4827     */
4828    protected LayoutParams generateDefaultLayoutParams() {
4829        return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
4830    }
4831
4832    /**
4833     * {@inheritDoc}
4834     */
4835    @Override
4836    protected void debug(int depth) {
4837        super.debug(depth);
4838        String output;
4839
4840        if (mFocused != null) {
4841            output = debugIndent(depth);
4842            output += "mFocused";
4843            Log.d(VIEW_LOG_TAG, output);
4844        }
4845        if (mChildrenCount != 0) {
4846            output = debugIndent(depth);
4847            output += "{";
4848            Log.d(VIEW_LOG_TAG, output);
4849        }
4850        int count = mChildrenCount;
4851        for (int i = 0; i < count; i++) {
4852            View child = mChildren[i];
4853            child.debug(depth + 1);
4854        }
4855
4856        if (mChildrenCount != 0) {
4857            output = debugIndent(depth);
4858            output += "}";
4859            Log.d(VIEW_LOG_TAG, output);
4860        }
4861    }
4862
4863    /**
4864     * Returns the position in the group of the specified child view.
4865     *
4866     * @param child the view for which to get the position
4867     * @return a positive integer representing the position of the view in the
4868     *         group, or -1 if the view does not exist in the group
4869     */
4870    public int indexOfChild(View child) {
4871        final int count = mChildrenCount;
4872        final View[] children = mChildren;
4873        for (int i = 0; i < count; i++) {
4874            if (children[i] == child) {
4875                return i;
4876            }
4877        }
4878        return -1;
4879    }
4880
4881    /**
4882     * Returns the number of children in the group.
4883     *
4884     * @return a positive integer representing the number of children in
4885     *         the group
4886     */
4887    public int getChildCount() {
4888        return mChildrenCount;
4889    }
4890
4891    /**
4892     * Returns the view at the specified position in the group.
4893     *
4894     * @param index the position at which to get the view from
4895     * @return the view at the specified position or null if the position
4896     *         does not exist within the group
4897     */
4898    public View getChildAt(int index) {
4899        if (index < 0 || index >= mChildrenCount) {
4900            return null;
4901        }
4902        return mChildren[index];
4903    }
4904
4905    /**
4906     * Ask all of the children of this view to measure themselves, taking into
4907     * account both the MeasureSpec requirements for this view and its padding.
4908     * We skip children that are in the GONE state The heavy lifting is done in
4909     * getChildMeasureSpec.
4910     *
4911     * @param widthMeasureSpec The width requirements for this view
4912     * @param heightMeasureSpec The height requirements for this view
4913     */
4914    protected void measureChildren(int widthMeasureSpec, int heightMeasureSpec) {
4915        final int size = mChildrenCount;
4916        final View[] children = mChildren;
4917        for (int i = 0; i < size; ++i) {
4918            final View child = children[i];
4919            if ((child.mViewFlags & VISIBILITY_MASK) != GONE) {
4920                measureChild(child, widthMeasureSpec, heightMeasureSpec);
4921            }
4922        }
4923    }
4924
4925    /**
4926     * Ask one of the children of this view to measure itself, taking into
4927     * account both the MeasureSpec requirements for this view and its padding.
4928     * The heavy lifting is done in getChildMeasureSpec.
4929     *
4930     * @param child The child to measure
4931     * @param parentWidthMeasureSpec The width requirements for this view
4932     * @param parentHeightMeasureSpec The height requirements for this view
4933     */
4934    protected void measureChild(View child, int parentWidthMeasureSpec,
4935            int parentHeightMeasureSpec) {
4936        final LayoutParams lp = child.getLayoutParams();
4937
4938        final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
4939                mPaddingLeft + mPaddingRight, lp.width);
4940        final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
4941                mPaddingTop + mPaddingBottom, lp.height);
4942
4943        child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
4944    }
4945
4946    /**
4947     * Ask one of the children of this view to measure itself, taking into
4948     * account both the MeasureSpec requirements for this view and its padding
4949     * and margins. The child must have MarginLayoutParams The heavy lifting is
4950     * done in getChildMeasureSpec.
4951     *
4952     * @param child The child to measure
4953     * @param parentWidthMeasureSpec The width requirements for this view
4954     * @param widthUsed Extra space that has been used up by the parent
4955     *        horizontally (possibly by other children of the parent)
4956     * @param parentHeightMeasureSpec The height requirements for this view
4957     * @param heightUsed Extra space that has been used up by the parent
4958     *        vertically (possibly by other children of the parent)
4959     */
4960    protected void measureChildWithMargins(View child,
4961            int parentWidthMeasureSpec, int widthUsed,
4962            int parentHeightMeasureSpec, int heightUsed) {
4963        final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
4964
4965        final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
4966                mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin
4967                        + widthUsed, lp.width);
4968        final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
4969                mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin
4970                        + heightUsed, lp.height);
4971
4972        child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
4973    }
4974
4975    /**
4976     * Does the hard part of measureChildren: figuring out the MeasureSpec to
4977     * pass to a particular child. This method figures out the right MeasureSpec
4978     * for one dimension (height or width) of one child view.
4979     *
4980     * The goal is to combine information from our MeasureSpec with the
4981     * LayoutParams of the child to get the best possible results. For example,
4982     * if the this view knows its size (because its MeasureSpec has a mode of
4983     * EXACTLY), and the child has indicated in its LayoutParams that it wants
4984     * to be the same size as the parent, the parent should ask the child to
4985     * layout given an exact size.
4986     *
4987     * @param spec The requirements for this view
4988     * @param padding The padding of this view for the current dimension and
4989     *        margins, if applicable
4990     * @param childDimension How big the child wants to be in the current
4991     *        dimension
4992     * @return a MeasureSpec integer for the child
4993     */
4994    public static int getChildMeasureSpec(int spec, int padding, int childDimension) {
4995        int specMode = MeasureSpec.getMode(spec);
4996        int specSize = MeasureSpec.getSize(spec);
4997
4998        int size = Math.max(0, specSize - padding);
4999
5000        int resultSize = 0;
5001        int resultMode = 0;
5002
5003        switch (specMode) {
5004        // Parent has imposed an exact size on us
5005        case MeasureSpec.EXACTLY:
5006            if (childDimension >= 0) {
5007                resultSize = childDimension;
5008                resultMode = MeasureSpec.EXACTLY;
5009            } else if (childDimension == LayoutParams.MATCH_PARENT) {
5010                // Child wants to be our size. So be it.
5011                resultSize = size;
5012                resultMode = MeasureSpec.EXACTLY;
5013            } else if (childDimension == LayoutParams.WRAP_CONTENT) {
5014                // Child wants to determine its own size. It can't be
5015                // bigger than us.
5016                resultSize = size;
5017                resultMode = MeasureSpec.AT_MOST;
5018            }
5019            break;
5020
5021        // Parent has imposed a maximum size on us
5022        case MeasureSpec.AT_MOST:
5023            if (childDimension >= 0) {
5024                // Child wants a specific size... so be it
5025                resultSize = childDimension;
5026                resultMode = MeasureSpec.EXACTLY;
5027            } else if (childDimension == LayoutParams.MATCH_PARENT) {
5028                // Child wants to be our size, but our size is not fixed.
5029                // Constrain child to not be bigger than us.
5030                resultSize = size;
5031                resultMode = MeasureSpec.AT_MOST;
5032            } else if (childDimension == LayoutParams.WRAP_CONTENT) {
5033                // Child wants to determine its own size. It can't be
5034                // bigger than us.
5035                resultSize = size;
5036                resultMode = MeasureSpec.AT_MOST;
5037            }
5038            break;
5039
5040        // Parent asked to see how big we want to be
5041        case MeasureSpec.UNSPECIFIED:
5042            if (childDimension >= 0) {
5043                // Child wants a specific size... let him have it
5044                resultSize = childDimension;
5045                resultMode = MeasureSpec.EXACTLY;
5046            } else if (childDimension == LayoutParams.MATCH_PARENT) {
5047                // Child wants to be our size... find out how big it should
5048                // be
5049                resultSize = 0;
5050                resultMode = MeasureSpec.UNSPECIFIED;
5051            } else if (childDimension == LayoutParams.WRAP_CONTENT) {
5052                // Child wants to determine its own size.... find out how
5053                // big it should be
5054                resultSize = 0;
5055                resultMode = MeasureSpec.UNSPECIFIED;
5056            }
5057            break;
5058        }
5059        return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
5060    }
5061
5062
5063    /**
5064     * Removes any pending animations for views that have been removed. Call
5065     * this if you don't want animations for exiting views to stack up.
5066     */
5067    public void clearDisappearingChildren() {
5068        if (mDisappearingChildren != null) {
5069            mDisappearingChildren.clear();
5070            invalidate();
5071        }
5072    }
5073
5074    /**
5075     * Add a view which is removed from mChildren but still needs animation
5076     *
5077     * @param v View to add
5078     */
5079    private void addDisappearingView(View v) {
5080        ArrayList<View> disappearingChildren = mDisappearingChildren;
5081
5082        if (disappearingChildren == null) {
5083            disappearingChildren = mDisappearingChildren = new ArrayList<View>();
5084        }
5085
5086        disappearingChildren.add(v);
5087    }
5088
5089    /**
5090     * Cleanup a view when its animation is done. This may mean removing it from
5091     * the list of disappearing views.
5092     *
5093     * @param view The view whose animation has finished
5094     * @param animation The animation, cannot be null
5095     */
5096    void finishAnimatingView(final View view, Animation animation) {
5097        final ArrayList<View> disappearingChildren = mDisappearingChildren;
5098        if (disappearingChildren != null) {
5099            if (disappearingChildren.contains(view)) {
5100                disappearingChildren.remove(view);
5101
5102                if (view.mAttachInfo != null) {
5103                    view.dispatchDetachedFromWindow();
5104                }
5105
5106                view.clearAnimation();
5107                mGroupFlags |= FLAG_INVALIDATE_REQUIRED;
5108            }
5109        }
5110
5111        if (animation != null && !animation.getFillAfter()) {
5112            view.clearAnimation();
5113        }
5114
5115        if ((view.mPrivateFlags & PFLAG_ANIMATION_STARTED) == PFLAG_ANIMATION_STARTED) {
5116            view.onAnimationEnd();
5117            // Should be performed by onAnimationEnd() but this avoid an infinite loop,
5118            // so we'd rather be safe than sorry
5119            view.mPrivateFlags &= ~PFLAG_ANIMATION_STARTED;
5120            // Draw one more frame after the animation is done
5121            mGroupFlags |= FLAG_INVALIDATE_REQUIRED;
5122        }
5123    }
5124
5125    /**
5126     * Utility function called by View during invalidation to determine whether a view that
5127     * is invisible or gone should still be invalidated because it is being transitioned (and
5128     * therefore still needs to be drawn).
5129     */
5130    boolean isViewTransitioning(View view) {
5131        return (mTransitioningViews != null && mTransitioningViews.contains(view));
5132    }
5133
5134    /**
5135     * This method tells the ViewGroup that the given View object, which should have this
5136     * ViewGroup as its parent,
5137     * should be kept around  (re-displayed when the ViewGroup draws its children) even if it
5138     * is removed from its parent. This allows animations, such as those used by
5139     * {@link android.app.Fragment} and {@link android.animation.LayoutTransition} to animate
5140     * the removal of views. A call to this method should always be accompanied by a later call
5141     * to {@link #endViewTransition(View)}, such as after an animation on the View has finished,
5142     * so that the View finally gets removed.
5143     *
5144     * @param view The View object to be kept visible even if it gets removed from its parent.
5145     */
5146    public void startViewTransition(View view) {
5147        if (view.mParent == this) {
5148            if (mTransitioningViews == null) {
5149                mTransitioningViews = new ArrayList<View>();
5150            }
5151            mTransitioningViews.add(view);
5152        }
5153    }
5154
5155    /**
5156     * This method should always be called following an earlier call to
5157     * {@link #startViewTransition(View)}. The given View is finally removed from its parent
5158     * and will no longer be displayed. Note that this method does not perform the functionality
5159     * of removing a view from its parent; it just discontinues the display of a View that
5160     * has previously been removed.
5161     *
5162     * @return view The View object that has been removed but is being kept around in the visible
5163     * hierarchy by an earlier call to {@link #startViewTransition(View)}.
5164     */
5165    public void endViewTransition(View view) {
5166        if (mTransitioningViews != null) {
5167            mTransitioningViews.remove(view);
5168            final ArrayList<View> disappearingChildren = mDisappearingChildren;
5169            if (disappearingChildren != null && disappearingChildren.contains(view)) {
5170                disappearingChildren.remove(view);
5171                if (mVisibilityChangingChildren != null &&
5172                        mVisibilityChangingChildren.contains(view)) {
5173                    mVisibilityChangingChildren.remove(view);
5174                } else {
5175                    if (view.mAttachInfo != null) {
5176                        view.dispatchDetachedFromWindow();
5177                    }
5178                    if (view.mParent != null) {
5179                        view.mParent = null;
5180                    }
5181                }
5182                invalidate();
5183            }
5184        }
5185    }
5186
5187    private LayoutTransition.TransitionListener mLayoutTransitionListener =
5188            new LayoutTransition.TransitionListener() {
5189        @Override
5190        public void startTransition(LayoutTransition transition, ViewGroup container,
5191                View view, int transitionType) {
5192            // We only care about disappearing items, since we need special logic to keep
5193            // those items visible after they've been 'removed'
5194            if (transitionType == LayoutTransition.DISAPPEARING) {
5195                startViewTransition(view);
5196            }
5197        }
5198
5199        @Override
5200        public void endTransition(LayoutTransition transition, ViewGroup container,
5201                View view, int transitionType) {
5202            if (mLayoutSuppressed && !transition.isChangingLayout()) {
5203                requestLayout();
5204                mLayoutSuppressed = false;
5205            }
5206            if (transitionType == LayoutTransition.DISAPPEARING && mTransitioningViews != null) {
5207                endViewTransition(view);
5208            }
5209        }
5210    };
5211
5212    /**
5213     * {@inheritDoc}
5214     */
5215    @Override
5216    public boolean gatherTransparentRegion(Region region) {
5217        // If no transparent regions requested, we are always opaque.
5218        final boolean meOpaque = (mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) == 0;
5219        if (meOpaque && region == null) {
5220            // The caller doesn't care about the region, so stop now.
5221            return true;
5222        }
5223        super.gatherTransparentRegion(region);
5224        final View[] children = mChildren;
5225        final int count = mChildrenCount;
5226        boolean noneOfTheChildrenAreTransparent = true;
5227        for (int i = 0; i < count; i++) {
5228            final View child = children[i];
5229            if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
5230                if (!child.gatherTransparentRegion(region)) {
5231                    noneOfTheChildrenAreTransparent = false;
5232                }
5233            }
5234        }
5235        return meOpaque || noneOfTheChildrenAreTransparent;
5236    }
5237
5238    /**
5239     * {@inheritDoc}
5240     */
5241    public void requestTransparentRegion(View child) {
5242        if (child != null) {
5243            child.mPrivateFlags |= View.PFLAG_REQUEST_TRANSPARENT_REGIONS;
5244            if (mParent != null) {
5245                mParent.requestTransparentRegion(this);
5246            }
5247        }
5248    }
5249
5250
5251    @Override
5252    protected boolean fitSystemWindows(Rect insets) {
5253        boolean done = super.fitSystemWindows(insets);
5254        if (!done) {
5255            final int count = mChildrenCount;
5256            final View[] children = mChildren;
5257            for (int i = 0; i < count; i++) {
5258                done = children[i].fitSystemWindows(insets);
5259                if (done) {
5260                    break;
5261                }
5262            }
5263        }
5264        return done;
5265    }
5266
5267    /**
5268     * Returns the animation listener to which layout animation events are
5269     * sent.
5270     *
5271     * @return an {@link android.view.animation.Animation.AnimationListener}
5272     */
5273    public Animation.AnimationListener getLayoutAnimationListener() {
5274        return mAnimationListener;
5275    }
5276
5277    @Override
5278    protected void drawableStateChanged() {
5279        super.drawableStateChanged();
5280
5281        if ((mGroupFlags & FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE) != 0) {
5282            if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0) {
5283                throw new IllegalStateException("addStateFromChildren cannot be enabled if a"
5284                        + " child has duplicateParentState set to true");
5285            }
5286
5287            final View[] children = mChildren;
5288            final int count = mChildrenCount;
5289
5290            for (int i = 0; i < count; i++) {
5291                final View child = children[i];
5292                if ((child.mViewFlags & DUPLICATE_PARENT_STATE) != 0) {
5293                    child.refreshDrawableState();
5294                }
5295            }
5296        }
5297    }
5298
5299    @Override
5300    public void jumpDrawablesToCurrentState() {
5301        super.jumpDrawablesToCurrentState();
5302        final View[] children = mChildren;
5303        final int count = mChildrenCount;
5304        for (int i = 0; i < count; i++) {
5305            children[i].jumpDrawablesToCurrentState();
5306        }
5307    }
5308
5309    @Override
5310    protected int[] onCreateDrawableState(int extraSpace) {
5311        if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) == 0) {
5312            return super.onCreateDrawableState(extraSpace);
5313        }
5314
5315        int need = 0;
5316        int n = getChildCount();
5317        for (int i = 0; i < n; i++) {
5318            int[] childState = getChildAt(i).getDrawableState();
5319
5320            if (childState != null) {
5321                need += childState.length;
5322            }
5323        }
5324
5325        int[] state = super.onCreateDrawableState(extraSpace + need);
5326
5327        for (int i = 0; i < n; i++) {
5328            int[] childState = getChildAt(i).getDrawableState();
5329
5330            if (childState != null) {
5331                state = mergeDrawableStates(state, childState);
5332            }
5333        }
5334
5335        return state;
5336    }
5337
5338    /**
5339     * Sets whether this ViewGroup's drawable states also include
5340     * its children's drawable states.  This is used, for example, to
5341     * make a group appear to be focused when its child EditText or button
5342     * is focused.
5343     */
5344    public void setAddStatesFromChildren(boolean addsStates) {
5345        if (addsStates) {
5346            mGroupFlags |= FLAG_ADD_STATES_FROM_CHILDREN;
5347        } else {
5348            mGroupFlags &= ~FLAG_ADD_STATES_FROM_CHILDREN;
5349        }
5350
5351        refreshDrawableState();
5352    }
5353
5354    /**
5355     * Returns whether this ViewGroup's drawable states also include
5356     * its children's drawable states.  This is used, for example, to
5357     * make a group appear to be focused when its child EditText or button
5358     * is focused.
5359     */
5360    public boolean addStatesFromChildren() {
5361        return (mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0;
5362    }
5363
5364    /**
5365     * If {@link #addStatesFromChildren} is true, refreshes this group's
5366     * drawable state (to include the states from its children).
5367     */
5368    public void childDrawableStateChanged(View child) {
5369        if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0) {
5370            refreshDrawableState();
5371        }
5372    }
5373
5374    /**
5375     * Specifies the animation listener to which layout animation events must
5376     * be sent. Only
5377     * {@link android.view.animation.Animation.AnimationListener#onAnimationStart(Animation)}
5378     * and
5379     * {@link android.view.animation.Animation.AnimationListener#onAnimationEnd(Animation)}
5380     * are invoked.
5381     *
5382     * @param animationListener the layout animation listener
5383     */
5384    public void setLayoutAnimationListener(Animation.AnimationListener animationListener) {
5385        mAnimationListener = animationListener;
5386    }
5387
5388    /**
5389     * This method is called by LayoutTransition when there are 'changing' animations that need
5390     * to start after the layout/setup phase. The request is forwarded to the ViewAncestor, who
5391     * starts all pending transitions prior to the drawing phase in the current traversal.
5392     *
5393     * @param transition The LayoutTransition to be started on the next traversal.
5394     *
5395     * @hide
5396     */
5397    public void requestTransitionStart(LayoutTransition transition) {
5398        ViewRootImpl viewAncestor = getViewRootImpl();
5399        if (viewAncestor != null) {
5400            viewAncestor.requestTransitionStart(transition);
5401        }
5402    }
5403
5404    /**
5405     * @hide
5406     */
5407    @Override
5408    public void resolveRtlPropertiesIfNeeded() {
5409        super.resolveRtlPropertiesIfNeeded();
5410        int count = getChildCount();
5411        for (int i = 0; i < count; i++) {
5412            final View child = getChildAt(i);
5413            if (child.isLayoutDirectionInherited()) {
5414                child.resolveRtlPropertiesIfNeeded();
5415            }
5416        }
5417    }
5418
5419    /**
5420     * @hide
5421     */
5422    @Override
5423    public boolean resolveLayoutDirection() {
5424        final boolean result = super.resolveLayoutDirection();
5425        if (result) {
5426            int count = getChildCount();
5427            for (int i = 0; i < count; i++) {
5428                final View child = getChildAt(i);
5429                if (child.isLayoutDirectionInherited()) {
5430                    child.resolveLayoutDirection();
5431                }
5432            }
5433        }
5434        return result;
5435    }
5436
5437    /**
5438     * @hide
5439     */
5440    @Override
5441    public boolean resolveTextDirection() {
5442        final boolean result = super.resolveTextDirection();
5443        if (result) {
5444            int count = getChildCount();
5445            for (int i = 0; i < count; i++) {
5446                final View child = getChildAt(i);
5447                if (child.isTextDirectionInherited()) {
5448                    child.resolveTextDirection();
5449                }
5450            }
5451        }
5452        return result;
5453    }
5454
5455    /**
5456     * @hide
5457     */
5458    @Override
5459    public boolean resolveTextAlignment() {
5460        final boolean result = super.resolveTextAlignment();
5461        if (result) {
5462            int count = getChildCount();
5463            for (int i = 0; i < count; i++) {
5464                final View child = getChildAt(i);
5465                if (child.isTextAlignmentInherited()) {
5466                    child.resolveTextAlignment();
5467                }
5468            }
5469        }
5470        return result;
5471    }
5472
5473    /**
5474     * @hide
5475     */
5476    @Override
5477    public void resolvePadding() {
5478        super.resolvePadding();
5479        int count = getChildCount();
5480        for (int i = 0; i < count; i++) {
5481            final View child = getChildAt(i);
5482            if (child.isLayoutDirectionInherited()) {
5483                child.resolvePadding();
5484            }
5485        }
5486    }
5487
5488    /**
5489     * @hide
5490     */
5491    @Override
5492    protected void resolveDrawables() {
5493        super.resolveDrawables();
5494        int count = getChildCount();
5495        for (int i = 0; i < count; i++) {
5496            final View child = getChildAt(i);
5497            if (child.isLayoutDirectionInherited()) {
5498                child.resolveDrawables();
5499            }
5500        }
5501    }
5502
5503    /**
5504     * @hide
5505     */
5506    @Override
5507    public void resolveLayoutParams() {
5508        super.resolveLayoutParams();
5509        int count = getChildCount();
5510        for (int i = 0; i < count; i++) {
5511            final View child = getChildAt(i);
5512            child.resolveLayoutParams();
5513        }
5514    }
5515
5516    /**
5517     * @hide
5518     */
5519    @Override
5520    public void resetResolvedLayoutDirection() {
5521        super.resetResolvedLayoutDirection();
5522
5523        int count = getChildCount();
5524        for (int i = 0; i < count; i++) {
5525            final View child = getChildAt(i);
5526            if (child.isLayoutDirectionInherited()) {
5527                child.resetResolvedLayoutDirection();
5528            }
5529        }
5530    }
5531
5532    /**
5533     * @hide
5534     */
5535    @Override
5536    public void resetResolvedTextDirection() {
5537        super.resetResolvedTextDirection();
5538
5539        int count = getChildCount();
5540        for (int i = 0; i < count; i++) {
5541            final View child = getChildAt(i);
5542            if (child.isTextDirectionInherited()) {
5543                child.resetResolvedTextDirection();
5544            }
5545        }
5546    }
5547
5548    /**
5549     * @hide
5550     */
5551    @Override
5552    public void resetResolvedTextAlignment() {
5553        super.resetResolvedTextAlignment();
5554
5555        int count = getChildCount();
5556        for (int i = 0; i < count; i++) {
5557            final View child = getChildAt(i);
5558            if (child.isTextAlignmentInherited()) {
5559                child.resetResolvedTextAlignment();
5560            }
5561        }
5562    }
5563
5564    /**
5565     * @hide
5566     */
5567    @Override
5568    public void resetResolvedPadding() {
5569        super.resetResolvedPadding();
5570
5571        int count = getChildCount();
5572        for (int i = 0; i < count; i++) {
5573            final View child = getChildAt(i);
5574            if (child.isLayoutDirectionInherited()) {
5575                child.resetResolvedPadding();
5576            }
5577        }
5578    }
5579
5580    /**
5581     * @hide
5582     */
5583    @Override
5584    protected void resetResolvedDrawables() {
5585        super.resetResolvedDrawables();
5586
5587        int count = getChildCount();
5588        for (int i = 0; i < count; i++) {
5589            final View child = getChildAt(i);
5590            if (child.isLayoutDirectionInherited()) {
5591                child.resetResolvedDrawables();
5592            }
5593        }
5594    }
5595
5596    /**
5597     * Return true if the pressed state should be delayed for children or descendants of this
5598     * ViewGroup. Generally, this should be done for containers that can scroll, such as a List.
5599     * This prevents the pressed state from appearing when the user is actually trying to scroll
5600     * the content.
5601     *
5602     * The default implementation returns true for compatibility reasons. Subclasses that do
5603     * not scroll should generally override this method and return false.
5604     */
5605    public boolean shouldDelayChildPressedState() {
5606        return true;
5607    }
5608
5609    /** @hide */
5610    protected void onSetLayoutParams(View child, LayoutParams layoutParams) {
5611    }
5612
5613    /**
5614     * LayoutParams are used by views to tell their parents how they want to be
5615     * laid out. See
5616     * {@link android.R.styleable#ViewGroup_Layout ViewGroup Layout Attributes}
5617     * for a list of all child view attributes that this class supports.
5618     *
5619     * <p>
5620     * The base LayoutParams class just describes how big the view wants to be
5621     * for both width and height. For each dimension, it can specify one of:
5622     * <ul>
5623     * <li>FILL_PARENT (renamed MATCH_PARENT in API Level 8 and higher), which
5624     * means that the view wants to be as big as its parent (minus padding)
5625     * <li> WRAP_CONTENT, which means that the view wants to be just big enough
5626     * to enclose its content (plus padding)
5627     * <li> an exact number
5628     * </ul>
5629     * There are subclasses of LayoutParams for different subclasses of
5630     * ViewGroup. For example, AbsoluteLayout has its own subclass of
5631     * LayoutParams which adds an X and Y value.</p>
5632     *
5633     * <div class="special reference">
5634     * <h3>Developer Guides</h3>
5635     * <p>For more information about creating user interface layouts, read the
5636     * <a href="{@docRoot}guide/topics/ui/declaring-layout.html">XML Layouts</a> developer
5637     * guide.</p></div>
5638     *
5639     * @attr ref android.R.styleable#ViewGroup_Layout_layout_height
5640     * @attr ref android.R.styleable#ViewGroup_Layout_layout_width
5641     */
5642    public static class LayoutParams {
5643        /**
5644         * Special value for the height or width requested by a View.
5645         * FILL_PARENT means that the view wants to be as big as its parent,
5646         * minus the parent's padding, if any. This value is deprecated
5647         * starting in API Level 8 and replaced by {@link #MATCH_PARENT}.
5648         */
5649        @SuppressWarnings({"UnusedDeclaration"})
5650        @Deprecated
5651        public static final int FILL_PARENT = -1;
5652
5653        /**
5654         * Special value for the height or width requested by a View.
5655         * MATCH_PARENT means that the view wants to be as big as its parent,
5656         * minus the parent's padding, if any. Introduced in API Level 8.
5657         */
5658        public static final int MATCH_PARENT = -1;
5659
5660        /**
5661         * Special value for the height or width requested by a View.
5662         * WRAP_CONTENT means that the view wants to be just large enough to fit
5663         * its own internal content, taking its own padding into account.
5664         */
5665        public static final int WRAP_CONTENT = -2;
5666
5667        /**
5668         * Information about how wide the view wants to be. Can be one of the
5669         * constants FILL_PARENT (replaced by MATCH_PARENT ,
5670         * in API Level 8) or WRAP_CONTENT. or an exact size.
5671         */
5672        @ViewDebug.ExportedProperty(category = "layout", mapping = {
5673            @ViewDebug.IntToString(from = MATCH_PARENT, to = "MATCH_PARENT"),
5674            @ViewDebug.IntToString(from = WRAP_CONTENT, to = "WRAP_CONTENT")
5675        })
5676        public int width;
5677
5678        /**
5679         * Information about how tall the view wants to be. Can be one of the
5680         * constants FILL_PARENT (replaced by MATCH_PARENT ,
5681         * in API Level 8) or WRAP_CONTENT. or an exact size.
5682         */
5683        @ViewDebug.ExportedProperty(category = "layout", mapping = {
5684            @ViewDebug.IntToString(from = MATCH_PARENT, to = "MATCH_PARENT"),
5685            @ViewDebug.IntToString(from = WRAP_CONTENT, to = "WRAP_CONTENT")
5686        })
5687        public int height;
5688
5689        /**
5690         * Used to animate layouts.
5691         */
5692        public LayoutAnimationController.AnimationParameters layoutAnimationParameters;
5693
5694        /**
5695         * Creates a new set of layout parameters. The values are extracted from
5696         * the supplied attributes set and context. The XML attributes mapped
5697         * to this set of layout parameters are:
5698         *
5699         * <ul>
5700         *   <li><code>layout_width</code>: the width, either an exact value,
5701         *   {@link #WRAP_CONTENT}, or {@link #FILL_PARENT} (replaced by
5702         *   {@link #MATCH_PARENT} in API Level 8)</li>
5703         *   <li><code>layout_height</code>: the height, either an exact value,
5704         *   {@link #WRAP_CONTENT}, or {@link #FILL_PARENT} (replaced by
5705         *   {@link #MATCH_PARENT} in API Level 8)</li>
5706         * </ul>
5707         *
5708         * @param c the application environment
5709         * @param attrs the set of attributes from which to extract the layout
5710         *              parameters' values
5711         */
5712        public LayoutParams(Context c, AttributeSet attrs) {
5713            TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.ViewGroup_Layout);
5714            setBaseAttributes(a,
5715                    R.styleable.ViewGroup_Layout_layout_width,
5716                    R.styleable.ViewGroup_Layout_layout_height);
5717            a.recycle();
5718        }
5719
5720        /**
5721         * Creates a new set of layout parameters with the specified width
5722         * and height.
5723         *
5724         * @param width the width, 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         * @param height the height, either {@link #WRAP_CONTENT},
5728         *        {@link #FILL_PARENT} (replaced by {@link #MATCH_PARENT} in
5729         *        API Level 8), or a fixed size in pixels
5730         */
5731        public LayoutParams(int width, int height) {
5732            this.width = width;
5733            this.height = height;
5734        }
5735
5736        /**
5737         * Copy constructor. Clones the width and height values of the source.
5738         *
5739         * @param source The layout params to copy from.
5740         */
5741        public LayoutParams(LayoutParams source) {
5742            this.width = source.width;
5743            this.height = source.height;
5744        }
5745
5746        /**
5747         * Used internally by MarginLayoutParams.
5748         * @hide
5749         */
5750        LayoutParams() {
5751        }
5752
5753        /**
5754         * Extracts the layout parameters from the supplied attributes.
5755         *
5756         * @param a the style attributes to extract the parameters from
5757         * @param widthAttr the identifier of the width attribute
5758         * @param heightAttr the identifier of the height attribute
5759         */
5760        protected void setBaseAttributes(TypedArray a, int widthAttr, int heightAttr) {
5761            width = a.getLayoutDimension(widthAttr, "layout_width");
5762            height = a.getLayoutDimension(heightAttr, "layout_height");
5763        }
5764
5765        /**
5766         * Resolve layout parameters depending on the layout direction. Subclasses that care about
5767         * layoutDirection changes should override this method. The default implementation does
5768         * nothing.
5769         *
5770         * @param layoutDirection the direction of the layout
5771         *
5772         * {@link View#LAYOUT_DIRECTION_LTR}
5773         * {@link View#LAYOUT_DIRECTION_RTL}
5774         */
5775        public void resolveLayoutDirection(int layoutDirection) {
5776        }
5777
5778        /**
5779         * Returns a String representation of this set of layout parameters.
5780         *
5781         * @param output the String to prepend to the internal representation
5782         * @return a String with the following format: output +
5783         *         "ViewGroup.LayoutParams={ width=WIDTH, height=HEIGHT }"
5784         *
5785         * @hide
5786         */
5787        public String debug(String output) {
5788            return output + "ViewGroup.LayoutParams={ width="
5789                    + sizeToString(width) + ", height=" + sizeToString(height) + " }";
5790        }
5791
5792        /**
5793         * Use {@code canvas} to draw suitable debugging annotations for these LayoutParameters.
5794         *
5795         * @param view the view that contains these layout parameters
5796         * @param canvas the canvas on which to draw
5797         *
5798         * @hide
5799         */
5800        public void onDebugDraw(View view, Canvas canvas, Paint paint) {
5801        }
5802
5803        /**
5804         * Converts the specified size to a readable String.
5805         *
5806         * @param size the size to convert
5807         * @return a String instance representing the supplied size
5808         *
5809         * @hide
5810         */
5811        protected static String sizeToString(int size) {
5812            if (size == WRAP_CONTENT) {
5813                return "wrap-content";
5814            }
5815            if (size == MATCH_PARENT) {
5816                return "match-parent";
5817            }
5818            return String.valueOf(size);
5819        }
5820    }
5821
5822    /**
5823     * Per-child layout information for layouts that support margins.
5824     * See
5825     * {@link android.R.styleable#ViewGroup_MarginLayout ViewGroup Margin Layout Attributes}
5826     * for a list of all child view attributes that this class supports.
5827     */
5828    public static class MarginLayoutParams extends ViewGroup.LayoutParams {
5829        /**
5830         * The left margin in pixels of the child.
5831         * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
5832         * to this field.
5833         */
5834        @ViewDebug.ExportedProperty(category = "layout")
5835        public int leftMargin;
5836
5837        /**
5838         * The top margin in pixels of the child.
5839         * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
5840         * to this field.
5841         */
5842        @ViewDebug.ExportedProperty(category = "layout")
5843        public int topMargin;
5844
5845        /**
5846         * The right margin in pixels of the child.
5847         * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
5848         * to this field.
5849         */
5850        @ViewDebug.ExportedProperty(category = "layout")
5851        public int rightMargin;
5852
5853        /**
5854         * The bottom margin in pixels of the child.
5855         * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
5856         * to this field.
5857         */
5858        @ViewDebug.ExportedProperty(category = "layout")
5859        public int bottomMargin;
5860
5861        /**
5862         * The start margin in pixels of the child.
5863         * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
5864         * to this field.
5865         */
5866        @ViewDebug.ExportedProperty(category = "layout")
5867        private int startMargin = DEFAULT_RELATIVE;
5868
5869        /**
5870         * The end margin in pixels of the child.
5871         * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
5872         * to this field.
5873         */
5874        @ViewDebug.ExportedProperty(category = "layout")
5875        private int endMargin = DEFAULT_RELATIVE;
5876
5877        /**
5878         * The default start and end margin.
5879         * @hide
5880         */
5881        public static final int DEFAULT_RELATIVE = Integer.MIN_VALUE;
5882
5883        private int initialLeftMargin;
5884        private int initialRightMargin;
5885
5886        private static int LAYOUT_DIRECTION_UNDEFINED = -1;
5887
5888        // Layout direction undefined by default
5889        private int layoutDirection = LAYOUT_DIRECTION_UNDEFINED;
5890
5891        /**
5892         * Creates a new set of layout parameters. The values are extracted from
5893         * the supplied attributes set and context.
5894         *
5895         * @param c the application environment
5896         * @param attrs the set of attributes from which to extract the layout
5897         *              parameters' values
5898         */
5899        public MarginLayoutParams(Context c, AttributeSet attrs) {
5900            super();
5901
5902            TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.ViewGroup_MarginLayout);
5903            setBaseAttributes(a,
5904                    R.styleable.ViewGroup_MarginLayout_layout_width,
5905                    R.styleable.ViewGroup_MarginLayout_layout_height);
5906
5907            int margin = a.getDimensionPixelSize(
5908                    com.android.internal.R.styleable.ViewGroup_MarginLayout_layout_margin, -1);
5909            if (margin >= 0) {
5910                leftMargin = margin;
5911                topMargin = margin;
5912                rightMargin= margin;
5913                bottomMargin = margin;
5914            } else {
5915                leftMargin = a.getDimensionPixelSize(
5916                        R.styleable.ViewGroup_MarginLayout_layout_marginLeft, 0);
5917                topMargin = a.getDimensionPixelSize(
5918                        R.styleable.ViewGroup_MarginLayout_layout_marginTop, 0);
5919                rightMargin = a.getDimensionPixelSize(
5920                        R.styleable.ViewGroup_MarginLayout_layout_marginRight, 0);
5921                bottomMargin = a.getDimensionPixelSize(
5922                        R.styleable.ViewGroup_MarginLayout_layout_marginBottom, 0);
5923                startMargin = a.getDimensionPixelSize(
5924                        R.styleable.ViewGroup_MarginLayout_layout_marginStart, DEFAULT_RELATIVE);
5925                endMargin = a.getDimensionPixelSize(
5926                        R.styleable.ViewGroup_MarginLayout_layout_marginEnd, DEFAULT_RELATIVE);
5927            }
5928
5929            initialLeftMargin = leftMargin;
5930            initialRightMargin = rightMargin;
5931
5932            a.recycle();
5933        }
5934
5935        /**
5936         * {@inheritDoc}
5937         */
5938        public MarginLayoutParams(int width, int height) {
5939            super(width, height);
5940        }
5941
5942        /**
5943         * Copy constructor. Clones the width, height and margin values of the source.
5944         *
5945         * @param source The layout params to copy from.
5946         */
5947        public MarginLayoutParams(MarginLayoutParams source) {
5948            this.width = source.width;
5949            this.height = source.height;
5950
5951            this.leftMargin = source.leftMargin;
5952            this.topMargin = source.topMargin;
5953            this.rightMargin = source.rightMargin;
5954            this.bottomMargin = source.bottomMargin;
5955            this.startMargin = source.startMargin;
5956            this.endMargin = source.endMargin;
5957
5958            this.initialLeftMargin = source.leftMargin;
5959            this.initialRightMargin = source.rightMargin;
5960
5961            setLayoutDirection(source.layoutDirection);
5962        }
5963
5964        /**
5965         * {@inheritDoc}
5966         */
5967        public MarginLayoutParams(LayoutParams source) {
5968            super(source);
5969        }
5970
5971        /**
5972         * Sets the margins, in pixels. A call to {@link android.view.View#requestLayout()} needs
5973         * to be done so that the new margins are taken into account. Left and right margins may be
5974         * overriden by {@link android.view.View#requestLayout()} depending on layout direction.
5975         *
5976         * @param left the left margin size
5977         * @param top the top margin size
5978         * @param right the right margin size
5979         * @param bottom the bottom margin size
5980         *
5981         * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginLeft
5982         * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginTop
5983         * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginRight
5984         * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginBottom
5985         */
5986        public void setMargins(int left, int top, int right, int bottom) {
5987            leftMargin = left;
5988            topMargin = top;
5989            rightMargin = right;
5990            bottomMargin = bottom;
5991            initialLeftMargin = left;
5992            initialRightMargin = right;
5993        }
5994
5995        /**
5996         * Sets the relative margins, in pixels. A call to {@link android.view.View#requestLayout()}
5997         * needs to be done so that the new relative margins are taken into account. Left and right
5998         * margins may be overriden by {@link android.view.View#requestLayout()} depending on layout
5999         * direction.
6000         *
6001         * @param start the start margin size
6002         * @param top the top margin size
6003         * @param end the right margin size
6004         * @param bottom the bottom margin size
6005         *
6006         * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart
6007         * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginTop
6008         * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd
6009         * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginBottom
6010         *
6011         * @hide
6012         */
6013        public void setMarginsRelative(int start, int top, int end, int bottom) {
6014            startMargin = start;
6015            topMargin = top;
6016            endMargin = end;
6017            bottomMargin = bottom;
6018            initialLeftMargin = 0;
6019            initialRightMargin = 0;
6020        }
6021
6022        /**
6023         * Sets the relative start margin.
6024         *
6025         * @param start the start margin size
6026         *
6027         * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart
6028         */
6029        public void setMarginStart(int start) {
6030            startMargin = start;
6031        }
6032
6033        /**
6034         * Returns the start margin in pixels.
6035         *
6036         * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart
6037         *
6038         * @return the start margin in pixels.
6039         */
6040        public int getMarginStart() {
6041            if (startMargin != DEFAULT_RELATIVE) return startMargin;
6042            switch(layoutDirection) {
6043                case View.LAYOUT_DIRECTION_RTL:
6044                    return rightMargin;
6045                case View.LAYOUT_DIRECTION_LTR:
6046                default:
6047                    return leftMargin;
6048            }
6049        }
6050
6051        /**
6052         * Sets the relative end margin.
6053         *
6054         * @param end the end margin size
6055         *
6056         * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd
6057         */
6058        public void setMarginEnd(int end) {
6059            endMargin = end;
6060        }
6061
6062        /**
6063         * Returns the end margin in pixels.
6064         *
6065         * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd
6066         *
6067         * @return the end margin in pixels.
6068         */
6069        public int getMarginEnd() {
6070            if (endMargin != DEFAULT_RELATIVE) return endMargin;
6071            switch(layoutDirection) {
6072                case View.LAYOUT_DIRECTION_RTL:
6073                    return leftMargin;
6074                case View.LAYOUT_DIRECTION_LTR:
6075                default:
6076                    return rightMargin;
6077            }
6078        }
6079
6080        /**
6081         * Check if margins are relative.
6082         *
6083         * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart
6084         * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd
6085         *
6086         * @return true if either marginStart or marginEnd has been set.
6087         */
6088        public boolean isMarginRelative() {
6089            return (startMargin != DEFAULT_RELATIVE) || (endMargin != DEFAULT_RELATIVE);
6090        }
6091
6092        /**
6093         * Set the layout direction
6094         * @param layoutDirection the layout direction.
6095         *        Should be either {@link View#LAYOUT_DIRECTION_LTR}
6096         *                     or {@link View#LAYOUT_DIRECTION_RTL}.
6097         */
6098        public void setLayoutDirection(int layoutDirection) {
6099            if (layoutDirection != View.LAYOUT_DIRECTION_LTR &&
6100                    layoutDirection != View.LAYOUT_DIRECTION_RTL) return;
6101            this.layoutDirection = layoutDirection;
6102        }
6103
6104        /**
6105         * Retuns the layout direction. Can be either {@link View#LAYOUT_DIRECTION_LTR} or
6106         * {@link View#LAYOUT_DIRECTION_RTL}.
6107         *
6108         * @return the layout direction.
6109         */
6110        public int getLayoutDirection() {
6111            return layoutDirection;
6112        }
6113
6114        /**
6115         * This will be called by {@link android.view.View#requestLayout()}. Left and Right margins
6116         * may be overridden depending on layout direction.
6117         */
6118        @Override
6119        public void resolveLayoutDirection(int layoutDirection) {
6120            setLayoutDirection(layoutDirection);
6121
6122            if (!isMarginRelative()) return;
6123
6124            switch(layoutDirection) {
6125                case View.LAYOUT_DIRECTION_RTL:
6126                    leftMargin = (endMargin > DEFAULT_RELATIVE) ? endMargin : initialLeftMargin;
6127                    rightMargin = (startMargin > DEFAULT_RELATIVE) ? startMargin : initialRightMargin;
6128                    break;
6129                case View.LAYOUT_DIRECTION_LTR:
6130                default:
6131                    leftMargin = (startMargin > DEFAULT_RELATIVE) ? startMargin : initialLeftMargin;
6132                    rightMargin = (endMargin > DEFAULT_RELATIVE) ? endMargin : initialRightMargin;
6133                    break;
6134            }
6135        }
6136
6137        /**
6138         * @hide
6139         */
6140        public boolean isLayoutRtl() {
6141            return (layoutDirection == View.LAYOUT_DIRECTION_RTL);
6142        }
6143
6144        /**
6145         * @hide
6146         */
6147        @Override
6148        public void onDebugDraw(View view, Canvas canvas, Paint paint) {
6149            Insets oi = isLayoutModeOptical(view.mParent) ? view.getOpticalInsets() : Insets.NONE;
6150
6151            fillDifference(canvas,
6152                    view.getLeft()   + oi.left,
6153                    view.getTop()    + oi.top,
6154                    view.getRight()  - oi.right,
6155                    view.getBottom() - oi.bottom,
6156                    leftMargin,
6157                    topMargin,
6158                    rightMargin,
6159                    bottomMargin,
6160                    paint);
6161        }
6162    }
6163
6164    /* Describes a touched view and the ids of the pointers that it has captured.
6165     *
6166     * This code assumes that pointer ids are always in the range 0..31 such that
6167     * it can use a bitfield to track which pointer ids are present.
6168     * As it happens, the lower layers of the input dispatch pipeline also use the
6169     * same trick so the assumption should be safe here...
6170     */
6171    private static final class TouchTarget {
6172        private static final int MAX_RECYCLED = 32;
6173        private static final Object sRecycleLock = new Object();
6174        private static TouchTarget sRecycleBin;
6175        private static int sRecycledCount;
6176
6177        public static final int ALL_POINTER_IDS = -1; // all ones
6178
6179        // The touched child view.
6180        public View child;
6181
6182        // The combined bit mask of pointer ids for all pointers captured by the target.
6183        public int pointerIdBits;
6184
6185        // The next target in the target list.
6186        public TouchTarget next;
6187
6188        private TouchTarget() {
6189        }
6190
6191        public static TouchTarget obtain(View child, int pointerIdBits) {
6192            final TouchTarget target;
6193            synchronized (sRecycleLock) {
6194                if (sRecycleBin == null) {
6195                    target = new TouchTarget();
6196                } else {
6197                    target = sRecycleBin;
6198                    sRecycleBin = target.next;
6199                     sRecycledCount--;
6200                    target.next = null;
6201                }
6202            }
6203            target.child = child;
6204            target.pointerIdBits = pointerIdBits;
6205            return target;
6206        }
6207
6208        public void recycle() {
6209            synchronized (sRecycleLock) {
6210                if (sRecycledCount < MAX_RECYCLED) {
6211                    next = sRecycleBin;
6212                    sRecycleBin = this;
6213                    sRecycledCount += 1;
6214                } else {
6215                    next = null;
6216                }
6217                child = null;
6218            }
6219        }
6220    }
6221
6222    /* Describes a hovered view. */
6223    private static final class HoverTarget {
6224        private static final int MAX_RECYCLED = 32;
6225        private static final Object sRecycleLock = new Object();
6226        private static HoverTarget sRecycleBin;
6227        private static int sRecycledCount;
6228
6229        // The hovered child view.
6230        public View child;
6231
6232        // The next target in the target list.
6233        public HoverTarget next;
6234
6235        private HoverTarget() {
6236        }
6237
6238        public static HoverTarget obtain(View child) {
6239            final HoverTarget target;
6240            synchronized (sRecycleLock) {
6241                if (sRecycleBin == null) {
6242                    target = new HoverTarget();
6243                } else {
6244                    target = sRecycleBin;
6245                    sRecycleBin = target.next;
6246                     sRecycledCount--;
6247                    target.next = null;
6248                }
6249            }
6250            target.child = child;
6251            return target;
6252        }
6253
6254        public void recycle() {
6255            synchronized (sRecycleLock) {
6256                if (sRecycledCount < MAX_RECYCLED) {
6257                    next = sRecycleBin;
6258                    sRecycleBin = this;
6259                    sRecycledCount += 1;
6260                } else {
6261                    next = null;
6262                }
6263                child = null;
6264            }
6265        }
6266    }
6267
6268    /**
6269     * Pooled class that orderes the children of a ViewGroup from start
6270     * to end based on how they are laid out and the layout direction.
6271     */
6272    static class ChildListForAccessibility {
6273
6274        private static final int MAX_POOL_SIZE = 32;
6275
6276        private static final SynchronizedPool<ChildListForAccessibility> sPool =
6277                new SynchronizedPool<ChildListForAccessibility>(MAX_POOL_SIZE);
6278
6279        private final ArrayList<View> mChildren = new ArrayList<View>();
6280
6281        private final ArrayList<ViewLocationHolder> mHolders = new ArrayList<ViewLocationHolder>();
6282
6283        public static ChildListForAccessibility obtain(ViewGroup parent, boolean sort) {
6284            ChildListForAccessibility list = sPool.acquire();
6285            if (list == null) {
6286                list = new ChildListForAccessibility();
6287            }
6288            list.init(parent, sort);
6289            return list;
6290        }
6291
6292        public void recycle() {
6293            clear();
6294            sPool.release(this);
6295        }
6296
6297        public int getChildCount() {
6298            return mChildren.size();
6299        }
6300
6301        public View getChildAt(int index) {
6302            return mChildren.get(index);
6303        }
6304
6305        public int getChildIndex(View child) {
6306            return mChildren.indexOf(child);
6307        }
6308
6309        private void init(ViewGroup parent, boolean sort) {
6310            ArrayList<View> children = mChildren;
6311            final int childCount = parent.getChildCount();
6312            for (int i = 0; i < childCount; i++) {
6313                View child = parent.getChildAt(i);
6314                children.add(child);
6315            }
6316            if (sort) {
6317                ArrayList<ViewLocationHolder> holders = mHolders;
6318                for (int i = 0; i < childCount; i++) {
6319                    View child = children.get(i);
6320                    ViewLocationHolder holder = ViewLocationHolder.obtain(parent, child);
6321                    holders.add(holder);
6322                }
6323                Collections.sort(holders);
6324                for (int i = 0; i < childCount; i++) {
6325                    ViewLocationHolder holder = holders.get(i);
6326                    children.set(i, holder.mView);
6327                    holder.recycle();
6328                }
6329                holders.clear();
6330            }
6331        }
6332
6333        private void clear() {
6334            mChildren.clear();
6335        }
6336    }
6337
6338    /**
6339     * Pooled class that holds a View and its location with respect to
6340     * a specified root. This enables sorting of views based on their
6341     * coordinates without recomputing the position relative to the root
6342     * on every comparison.
6343     */
6344    static class ViewLocationHolder implements Comparable<ViewLocationHolder> {
6345
6346        private static final int MAX_POOL_SIZE = 32;
6347
6348        private static final SynchronizedPool<ViewLocationHolder> sPool =
6349                new SynchronizedPool<ViewLocationHolder>(MAX_POOL_SIZE);
6350
6351        private final Rect mLocation = new Rect();
6352
6353        public View mView;
6354
6355        private int mLayoutDirection;
6356
6357        public static ViewLocationHolder obtain(ViewGroup root, View view) {
6358            ViewLocationHolder holder = sPool.acquire();
6359            if (holder == null) {
6360                holder = new ViewLocationHolder();
6361            }
6362            holder.init(root, view);
6363            return holder;
6364        }
6365
6366        public void recycle() {
6367            clear();
6368            sPool.release(this);
6369        }
6370
6371        @Override
6372        public int compareTo(ViewLocationHolder another) {
6373            // This instance is greater than an invalid argument.
6374            if (another == null) {
6375                return 1;
6376            }
6377            if (getClass() != another.getClass()) {
6378                return 1;
6379            }
6380            // First is above second.
6381            if (mLocation.bottom - another.mLocation.top <= 0) {
6382                return -1;
6383            }
6384            // First is below second.
6385            if (mLocation.top - another.mLocation.bottom >= 0) {
6386                return 1;
6387            }
6388            // LTR
6389            if (mLayoutDirection == LAYOUT_DIRECTION_LTR) {
6390                final int leftDifference = mLocation.left - another.mLocation.left;
6391                // First more to the left than second.
6392                if (leftDifference != 0) {
6393                    return leftDifference;
6394                }
6395            } else { // RTL
6396                final int rightDifference = mLocation.right - another.mLocation.right;
6397                // First more to the right than second.
6398                if (rightDifference != 0) {
6399                    return -rightDifference;
6400                }
6401            }
6402            // Break tie by top.
6403            final int topDiference = mLocation.top - another.mLocation.top;
6404            if (topDiference != 0) {
6405                return topDiference;
6406            }
6407            // Break tie by height.
6408            final int heightDiference = mLocation.height() - another.mLocation.height();
6409            if (heightDiference != 0) {
6410                return -heightDiference;
6411            }
6412            // Break tie by width.
6413            final int widthDiference = mLocation.width() - another.mLocation.width();
6414            if (widthDiference != 0) {
6415                return -widthDiference;
6416            }
6417            // Just break the tie somehow. The accessibliity ids are unique
6418            // and stable, hence this is deterministic tie breaking.
6419            return mView.getAccessibilityViewId() - another.mView.getAccessibilityViewId();
6420        }
6421
6422        private void init(ViewGroup root, View view) {
6423            Rect viewLocation = mLocation;
6424            view.getDrawingRect(viewLocation);
6425            root.offsetDescendantRectToMyCoords(view, viewLocation);
6426            mView = view;
6427            mLayoutDirection = root.getLayoutDirection();
6428        }
6429
6430        private void clear() {
6431            mView = null;
6432            mLocation.set(0, 0, 0, 0);
6433        }
6434    }
6435
6436    private static Paint getDebugPaint() {
6437        if (sDebugPaint == null) {
6438            sDebugPaint = new Paint();
6439            sDebugPaint.setAntiAlias(false);
6440        }
6441        return sDebugPaint;
6442    }
6443
6444    private void drawRect(Canvas canvas, Paint paint, int x1, int y1, int x2, int y2) {
6445        if (sDebugLines== null) {
6446            sDebugLines = new float[16];
6447        }
6448
6449        sDebugLines[0] = x1;
6450        sDebugLines[1] = y1;
6451        sDebugLines[2] = x2;
6452        sDebugLines[3] = y1;
6453
6454        sDebugLines[4] = x2;
6455        sDebugLines[5] = y1;
6456        sDebugLines[6] = x2;
6457        sDebugLines[7] = y2;
6458
6459        sDebugLines[8] = x2;
6460        sDebugLines[9] = y2;
6461        sDebugLines[10] = x1;
6462        sDebugLines[11] = y2;
6463
6464        sDebugLines[12] = x1;
6465        sDebugLines[13] = y2;
6466        sDebugLines[14] = x1;
6467        sDebugLines[15] = y1;
6468
6469        canvas.drawLines(sDebugLines, paint);
6470    }
6471}
6472