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