ViewGroup.java revision 2f57ba56b3d4648476f0c00bd74fc4f6aa052810
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.view.animation.AlphaAnimation;
21import com.android.internal.R;
22import com.android.internal.util.Predicate;
23
24import android.content.Context;
25import android.content.res.Configuration;
26import android.content.res.TypedArray;
27import android.graphics.Bitmap;
28import android.graphics.Canvas;
29import android.graphics.Matrix;
30import android.graphics.Paint;
31import android.graphics.PointF;
32import android.graphics.Rect;
33import android.graphics.RectF;
34import android.graphics.Region;
35import android.os.Build;
36import android.os.Parcelable;
37import android.os.SystemClock;
38import android.util.AttributeSet;
39import android.util.Log;
40import android.util.SparseArray;
41import android.view.accessibility.AccessibilityEvent;
42import android.view.animation.Animation;
43import android.view.animation.AnimationUtils;
44import android.view.animation.LayoutAnimationController;
45import android.view.animation.Transformation;
46
47import java.util.ArrayList;
48import java.util.HashSet;
49
50/**
51 * <p>
52 * A <code>ViewGroup</code> is a special view that can contain other views
53 * (called children.) The view group is the base class for layouts and views
54 * containers. This class also defines the
55 * {@link android.view.ViewGroup.LayoutParams} class which serves as the base
56 * class for layouts parameters.
57 * </p>
58 *
59 * <p>
60 * Also see {@link LayoutParams} for layout attributes.
61 * </p>
62 *
63 * @attr ref android.R.styleable#ViewGroup_clipChildren
64 * @attr ref android.R.styleable#ViewGroup_clipToPadding
65 * @attr ref android.R.styleable#ViewGroup_layoutAnimation
66 * @attr ref android.R.styleable#ViewGroup_animationCache
67 * @attr ref android.R.styleable#ViewGroup_persistentDrawingCache
68 * @attr ref android.R.styleable#ViewGroup_alwaysDrawnWithCache
69 * @attr ref android.R.styleable#ViewGroup_addStatesFromChildren
70 * @attr ref android.R.styleable#ViewGroup_descendantFocusability
71 * @attr ref android.R.styleable#ViewGroup_animateLayoutChanges
72 */
73public abstract class ViewGroup extends View implements ViewParent, ViewManager {
74
75    private static final boolean DBG = false;
76
77    /**
78     * Views which have been hidden or removed which need to be animated on
79     * their way out.
80     * This field should be made private, so it is hidden from the SDK.
81     * {@hide}
82     */
83    protected ArrayList<View> mDisappearingChildren;
84
85    /**
86     * Listener used to propagate events indicating when children are added
87     * and/or removed from a view group.
88     * This field should be made private, so it is hidden from the SDK.
89     * {@hide}
90     */
91    protected OnHierarchyChangeListener mOnHierarchyChangeListener;
92
93    // The view contained within this ViewGroup that has or contains focus.
94    private View mFocused;
95
96    /**
97     * A Transformation used when drawing children, to
98     * apply on the child being drawn.
99     */
100    private final Transformation mChildTransformation = new Transformation();
101
102    /**
103     * Used to track the current invalidation region.
104     */
105    private RectF mInvalidateRegion;
106
107    /**
108     * A Transformation used to calculate a correct
109     * invalidation area when the application is autoscaled.
110     */
111    private Transformation mInvalidationTransformation;
112
113    // View currently under an ongoing drag
114    private View mCurrentDragView;
115
116    // Metadata about the ongoing drag
117    private DragEvent mCurrentDrag;
118    private HashSet<View> mDragNotifiedChildren;
119
120    // Does this group have a child that can accept the current drag payload?
121    private boolean mChildAcceptsDrag;
122
123    // Used during drag dispatch
124    private final PointF mLocalPoint = new PointF();
125
126    // Layout animation
127    private LayoutAnimationController mLayoutAnimationController;
128    private Animation.AnimationListener mAnimationListener;
129
130    // First touch target in the linked list of touch targets.
131    private TouchTarget mFirstTouchTarget;
132
133    // Temporary arrays for splitting pointers.
134    private int[] mTmpPointerIndexMap;
135    private int[] mTmpPointerIds;
136    private MotionEvent.PointerCoords[] mTmpPointerCoords;
137
138    // For debugging only.  You can see these in hierarchyviewer.
139    @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"})
140    @ViewDebug.ExportedProperty(category = "events")
141    private long mLastTouchDownTime;
142    @ViewDebug.ExportedProperty(category = "events")
143    private int mLastTouchDownIndex = -1;
144    @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"})
145    @ViewDebug.ExportedProperty(category = "events")
146    private float mLastTouchDownX;
147    @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"})
148    @ViewDebug.ExportedProperty(category = "events")
149    private float mLastTouchDownY;
150
151    /**
152     * Internal flags.
153     *
154     * This field should be made private, so it is hidden from the SDK.
155     * {@hide}
156     */
157    protected int mGroupFlags;
158
159    // When set, ViewGroup invalidates only the child's rectangle
160    // Set by default
161    private static final int FLAG_CLIP_CHILDREN = 0x1;
162
163    // When set, ViewGroup excludes the padding area from the invalidate rectangle
164    // Set by default
165    private static final int FLAG_CLIP_TO_PADDING = 0x2;
166
167    // When set, dispatchDraw() will invoke invalidate(); this is set by drawChild() when
168    // a child needs to be invalidated and FLAG_OPTIMIZE_INVALIDATE is set
169    private static final int FLAG_INVALIDATE_REQUIRED  = 0x4;
170
171    // When set, dispatchDraw() will run the layout animation and unset the flag
172    private static final int FLAG_RUN_ANIMATION = 0x8;
173
174    // When set, there is either no layout animation on the ViewGroup or the layout
175    // animation is over
176    // Set by default
177    private static final int FLAG_ANIMATION_DONE = 0x10;
178
179    // If set, this ViewGroup has padding; if unset there is no padding and we don't need
180    // to clip it, even if FLAG_CLIP_TO_PADDING is set
181    private static final int FLAG_PADDING_NOT_NULL = 0x20;
182
183    // When set, this ViewGroup caches its children in a Bitmap before starting a layout animation
184    // Set by default
185    private static final int FLAG_ANIMATION_CACHE = 0x40;
186
187    // When set, this ViewGroup converts calls to invalidate(Rect) to invalidate() during a
188    // layout animation; this avoid clobbering the hierarchy
189    // Automatically set when the layout animation starts, depending on the animation's
190    // characteristics
191    private static final int FLAG_OPTIMIZE_INVALIDATE = 0x80;
192
193    // When set, the next call to drawChild() will clear mChildTransformation's matrix
194    private static final int FLAG_CLEAR_TRANSFORMATION = 0x100;
195
196    // When set, this ViewGroup invokes mAnimationListener.onAnimationEnd() and removes
197    // the children's Bitmap caches if necessary
198    // This flag is set when the layout animation is over (after FLAG_ANIMATION_DONE is set)
199    private static final int FLAG_NOTIFY_ANIMATION_LISTENER = 0x200;
200
201    /**
202     * When set, the drawing method will call {@link #getChildDrawingOrder(int, int)}
203     * to get the index of the child to draw for that iteration.
204     *
205     * @hide
206     */
207    protected static final int FLAG_USE_CHILD_DRAWING_ORDER = 0x400;
208
209    /**
210     * When set, this ViewGroup supports static transformations on children; this causes
211     * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} to be
212     * invoked when a child is drawn.
213     *
214     * Any subclass overriding
215     * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} should
216     * set this flags in {@link #mGroupFlags}.
217     *
218     * {@hide}
219     */
220    protected static final int FLAG_SUPPORT_STATIC_TRANSFORMATIONS = 0x800;
221
222    // When the previous drawChild() invocation used an alpha value that was lower than
223    // 1.0 and set it in mCachePaint
224    private static final int FLAG_ALPHA_LOWER_THAN_ONE = 0x1000;
225
226    /**
227     * When set, this ViewGroup's drawable states also include those
228     * of its children.
229     */
230    private static final int FLAG_ADD_STATES_FROM_CHILDREN = 0x2000;
231
232    /**
233     * When set, this ViewGroup tries to always draw its children using their drawing cache.
234     */
235    private static final int FLAG_ALWAYS_DRAWN_WITH_CACHE = 0x4000;
236
237    /**
238     * When set, and if FLAG_ALWAYS_DRAWN_WITH_CACHE is not set, this ViewGroup will try to
239     * draw its children with their drawing cache.
240     */
241    private static final int FLAG_CHILDREN_DRAWN_WITH_CACHE = 0x8000;
242
243    /**
244     * When set, this group will go through its list of children to notify them of
245     * any drawable state change.
246     */
247    private static final int FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE = 0x10000;
248
249    private static final int FLAG_MASK_FOCUSABILITY = 0x60000;
250
251    /**
252     * This view will get focus before any of its descendants.
253     */
254    public static final int FOCUS_BEFORE_DESCENDANTS = 0x20000;
255
256    /**
257     * This view will get focus only if none of its descendants want it.
258     */
259    public static final int FOCUS_AFTER_DESCENDANTS = 0x40000;
260
261    /**
262     * This view will block any of its descendants from getting focus, even
263     * if they are focusable.
264     */
265    public static final int FOCUS_BLOCK_DESCENDANTS = 0x60000;
266
267    /**
268     * Used to map between enum in attrubutes and flag values.
269     */
270    private static final int[] DESCENDANT_FOCUSABILITY_FLAGS =
271            {FOCUS_BEFORE_DESCENDANTS, FOCUS_AFTER_DESCENDANTS,
272                    FOCUS_BLOCK_DESCENDANTS};
273
274    /**
275     * When set, this ViewGroup should not intercept touch events.
276     * {@hide}
277     */
278    protected static final int FLAG_DISALLOW_INTERCEPT = 0x80000;
279
280    /**
281     * When set, this ViewGroup will split MotionEvents to multiple child Views when appropriate.
282     */
283    private static final int FLAG_SPLIT_MOTION_EVENTS = 0x200000;
284
285    /**
286     * Indicates which types of drawing caches are to be kept in memory.
287     * This field should be made private, so it is hidden from the SDK.
288     * {@hide}
289     */
290    protected int mPersistentDrawingCache;
291
292    /**
293     * Used to indicate that no drawing cache should be kept in memory.
294     */
295    public static final int PERSISTENT_NO_CACHE = 0x0;
296
297    /**
298     * Used to indicate that the animation drawing cache should be kept in memory.
299     */
300    public static final int PERSISTENT_ANIMATION_CACHE = 0x1;
301
302    /**
303     * Used to indicate that the scrolling drawing cache should be kept in memory.
304     */
305    public static final int PERSISTENT_SCROLLING_CACHE = 0x2;
306
307    /**
308     * Used to indicate that all drawing caches should be kept in memory.
309     */
310    public static final int PERSISTENT_ALL_CACHES = 0x3;
311
312    /**
313     * We clip to padding when FLAG_CLIP_TO_PADDING and FLAG_PADDING_NOT_NULL
314     * are set at the same time.
315     */
316    protected static final int CLIP_TO_PADDING_MASK = FLAG_CLIP_TO_PADDING | FLAG_PADDING_NOT_NULL;
317
318    // Index of the child's left position in the mLocation array
319    private static final int CHILD_LEFT_INDEX = 0;
320    // Index of the child's top position in the mLocation array
321    private static final int CHILD_TOP_INDEX = 1;
322
323    // Child views of this ViewGroup
324    private View[] mChildren;
325    // Number of valid children in the mChildren array, the rest should be null or not
326    // considered as children
327
328    private boolean mLayoutSuppressed = false;
329
330    private int mChildrenCount;
331
332    private static final int ARRAY_INITIAL_CAPACITY = 12;
333    private static final int ARRAY_CAPACITY_INCREMENT = 12;
334
335    // Used to draw cached views
336    private final Paint mCachePaint = new Paint();
337
338    // Used to animate add/remove changes in layout
339    private LayoutTransition mTransition;
340
341    // The set of views that are currently being transitioned. This list is used to track views
342    // being removed that should not actually be removed from the parent yet because they are
343    // being animated.
344    private ArrayList<View> mTransitioningViews;
345
346    // List of children changing visibility. This is used to potentially keep rendering
347    // views during a transition when they otherwise would have become gone/invisible
348    private ArrayList<View> mVisibilityChangingChildren;
349
350    // Indicates whether this container will use its children layers to draw
351    @ViewDebug.ExportedProperty(category = "drawing")
352    private boolean mDrawLayers = true;
353
354    public ViewGroup(Context context) {
355        super(context);
356        initViewGroup();
357    }
358
359    public ViewGroup(Context context, AttributeSet attrs) {
360        super(context, attrs);
361        initViewGroup();
362        initFromAttributes(context, attrs);
363    }
364
365    public ViewGroup(Context context, AttributeSet attrs, int defStyle) {
366        super(context, attrs, defStyle);
367        initViewGroup();
368        initFromAttributes(context, attrs);
369    }
370
371    private void initViewGroup() {
372        // ViewGroup doesn't draw by default
373        setFlags(WILL_NOT_DRAW, DRAW_MASK);
374        mGroupFlags |= FLAG_CLIP_CHILDREN;
375        mGroupFlags |= FLAG_CLIP_TO_PADDING;
376        mGroupFlags |= FLAG_ANIMATION_DONE;
377        mGroupFlags |= FLAG_ANIMATION_CACHE;
378        mGroupFlags |= FLAG_ALWAYS_DRAWN_WITH_CACHE;
379
380        if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB) {
381            mGroupFlags |= FLAG_SPLIT_MOTION_EVENTS;
382        }
383
384        setDescendantFocusability(FOCUS_BEFORE_DESCENDANTS);
385
386        mChildren = new View[ARRAY_INITIAL_CAPACITY];
387        mChildrenCount = 0;
388
389        mCachePaint.setDither(false);
390
391        mPersistentDrawingCache = PERSISTENT_SCROLLING_CACHE;
392    }
393
394    private void initFromAttributes(Context context, AttributeSet attrs) {
395        TypedArray a = context.obtainStyledAttributes(attrs,
396                R.styleable.ViewGroup);
397
398        final int N = a.getIndexCount();
399        for (int i = 0; i < N; i++) {
400            int attr = a.getIndex(i);
401            switch (attr) {
402                case R.styleable.ViewGroup_clipChildren:
403                    setClipChildren(a.getBoolean(attr, true));
404                    break;
405                case R.styleable.ViewGroup_clipToPadding:
406                    setClipToPadding(a.getBoolean(attr, true));
407                    break;
408                case R.styleable.ViewGroup_animationCache:
409                    setAnimationCacheEnabled(a.getBoolean(attr, true));
410                    break;
411                case R.styleable.ViewGroup_persistentDrawingCache:
412                    setPersistentDrawingCache(a.getInt(attr, PERSISTENT_SCROLLING_CACHE));
413                    break;
414                case R.styleable.ViewGroup_addStatesFromChildren:
415                    setAddStatesFromChildren(a.getBoolean(attr, false));
416                    break;
417                case R.styleable.ViewGroup_alwaysDrawnWithCache:
418                    setAlwaysDrawnWithCacheEnabled(a.getBoolean(attr, true));
419                    break;
420                case R.styleable.ViewGroup_layoutAnimation:
421                    int id = a.getResourceId(attr, -1);
422                    if (id > 0) {
423                        setLayoutAnimation(AnimationUtils.loadLayoutAnimation(mContext, id));
424                    }
425                    break;
426                case R.styleable.ViewGroup_descendantFocusability:
427                    setDescendantFocusability(DESCENDANT_FOCUSABILITY_FLAGS[a.getInt(attr, 0)]);
428                    break;
429                case R.styleable.ViewGroup_splitMotionEvents:
430                    setMotionEventSplittingEnabled(a.getBoolean(attr, false));
431                    break;
432                case R.styleable.ViewGroup_animateLayoutChanges:
433                    boolean animateLayoutChanges = a.getBoolean(attr, false);
434                    if (animateLayoutChanges) {
435                        setLayoutTransition(new LayoutTransition());
436                    }
437                    break;
438            }
439        }
440
441        a.recycle();
442    }
443
444    /**
445     * Gets the descendant focusability of this view group.  The descendant
446     * focusability defines the relationship between this view group and its
447     * descendants when looking for a view to take focus in
448     * {@link #requestFocus(int, android.graphics.Rect)}.
449     *
450     * @return one of {@link #FOCUS_BEFORE_DESCENDANTS}, {@link #FOCUS_AFTER_DESCENDANTS},
451     *   {@link #FOCUS_BLOCK_DESCENDANTS}.
452     */
453    @ViewDebug.ExportedProperty(category = "focus", mapping = {
454        @ViewDebug.IntToString(from = FOCUS_BEFORE_DESCENDANTS, to = "FOCUS_BEFORE_DESCENDANTS"),
455        @ViewDebug.IntToString(from = FOCUS_AFTER_DESCENDANTS, to = "FOCUS_AFTER_DESCENDANTS"),
456        @ViewDebug.IntToString(from = FOCUS_BLOCK_DESCENDANTS, to = "FOCUS_BLOCK_DESCENDANTS")
457    })
458    public int getDescendantFocusability() {
459        return mGroupFlags & FLAG_MASK_FOCUSABILITY;
460    }
461
462    /**
463     * Set the descendant focusability of this view group. This defines the relationship
464     * between this view group and its descendants when looking for a view to
465     * take focus in {@link #requestFocus(int, android.graphics.Rect)}.
466     *
467     * @param focusability one of {@link #FOCUS_BEFORE_DESCENDANTS}, {@link #FOCUS_AFTER_DESCENDANTS},
468     *   {@link #FOCUS_BLOCK_DESCENDANTS}.
469     */
470    public void setDescendantFocusability(int focusability) {
471        switch (focusability) {
472            case FOCUS_BEFORE_DESCENDANTS:
473            case FOCUS_AFTER_DESCENDANTS:
474            case FOCUS_BLOCK_DESCENDANTS:
475                break;
476            default:
477                throw new IllegalArgumentException("must be one of FOCUS_BEFORE_DESCENDANTS, "
478                        + "FOCUS_AFTER_DESCENDANTS, FOCUS_BLOCK_DESCENDANTS");
479        }
480        mGroupFlags &= ~FLAG_MASK_FOCUSABILITY;
481        mGroupFlags |= (focusability & FLAG_MASK_FOCUSABILITY);
482    }
483
484    /**
485     * {@inheritDoc}
486     */
487    @Override
488    void handleFocusGainInternal(int direction, Rect previouslyFocusedRect) {
489        if (mFocused != null) {
490            mFocused.unFocus();
491            mFocused = null;
492        }
493        super.handleFocusGainInternal(direction, previouslyFocusedRect);
494    }
495
496    /**
497     * {@inheritDoc}
498     */
499    public void requestChildFocus(View child, View focused) {
500        if (DBG) {
501            System.out.println(this + " requestChildFocus()");
502        }
503        if (getDescendantFocusability() == FOCUS_BLOCK_DESCENDANTS) {
504            return;
505        }
506
507        // Unfocus us, if necessary
508        super.unFocus();
509
510        // We had a previous notion of who had focus. Clear it.
511        if (mFocused != child) {
512            if (mFocused != null) {
513                mFocused.unFocus();
514            }
515
516            mFocused = child;
517        }
518        if (mParent != null) {
519            mParent.requestChildFocus(this, focused);
520        }
521    }
522
523    /**
524     * {@inheritDoc}
525     */
526    public void focusableViewAvailable(View v) {
527        if (mParent != null
528                // shortcut: don't report a new focusable view if we block our descendants from
529                // getting focus
530                && (getDescendantFocusability() != FOCUS_BLOCK_DESCENDANTS)
531                // shortcut: don't report a new focusable view if we already are focused
532                // (and we don't prefer our descendants)
533                //
534                // note: knowing that mFocused is non-null is not a good enough reason
535                // to break the traversal since in that case we'd actually have to find
536                // the focused view and make sure it wasn't FOCUS_AFTER_DESCENDANTS and
537                // an ancestor of v; this will get checked for at ViewRoot
538                && !(isFocused() && getDescendantFocusability() != FOCUS_AFTER_DESCENDANTS)) {
539            mParent.focusableViewAvailable(v);
540        }
541    }
542
543    /**
544     * {@inheritDoc}
545     */
546    public boolean showContextMenuForChild(View originalView) {
547        return mParent != null && mParent.showContextMenuForChild(originalView);
548    }
549
550    /**
551     * {@inheritDoc}
552     */
553    public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback) {
554        return mParent != null ? mParent.startActionModeForChild(originalView, callback) : null;
555    }
556
557    /**
558     * Find the nearest view in the specified direction that wants to take
559     * focus.
560     *
561     * @param focused The view that currently has focus
562     * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and
563     *        FOCUS_RIGHT, or 0 for not applicable.
564     */
565    public View focusSearch(View focused, int direction) {
566        if (isRootNamespace()) {
567            // root namespace means we should consider ourselves the top of the
568            // tree for focus searching; otherwise we could be focus searching
569            // into other tabs.  see LocalActivityManager and TabHost for more info
570            return FocusFinder.getInstance().findNextFocus(this, focused, direction);
571        } else if (mParent != null) {
572            return mParent.focusSearch(focused, direction);
573        }
574        return null;
575    }
576
577    /**
578     * {@inheritDoc}
579     */
580    public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
581        return false;
582    }
583
584    /**
585     * {@inheritDoc}
586     */
587    @Override
588    public boolean dispatchUnhandledMove(View focused, int direction) {
589        return mFocused != null &&
590                mFocused.dispatchUnhandledMove(focused, direction);
591    }
592
593    /**
594     * {@inheritDoc}
595     */
596    public void clearChildFocus(View child) {
597        if (DBG) {
598            System.out.println(this + " clearChildFocus()");
599        }
600
601        mFocused = null;
602        if (mParent != null) {
603            mParent.clearChildFocus(this);
604        }
605    }
606
607    /**
608     * {@inheritDoc}
609     */
610    @Override
611    public void clearFocus() {
612        super.clearFocus();
613
614        // clear any child focus if it exists
615        if (mFocused != null) {
616            mFocused.clearFocus();
617        }
618    }
619
620    /**
621     * {@inheritDoc}
622     */
623    @Override
624    void unFocus() {
625        if (DBG) {
626            System.out.println(this + " unFocus()");
627        }
628
629        super.unFocus();
630        if (mFocused != null) {
631            mFocused.unFocus();
632        }
633        mFocused = null;
634    }
635
636    /**
637     * Returns the focused child of this view, if any. The child may have focus
638     * or contain focus.
639     *
640     * @return the focused child or null.
641     */
642    public View getFocusedChild() {
643        return mFocused;
644    }
645
646    /**
647     * Returns true if this view has or contains focus
648     *
649     * @return true if this view has or contains focus
650     */
651    @Override
652    public boolean hasFocus() {
653        return (mPrivateFlags & FOCUSED) != 0 || mFocused != null;
654    }
655
656    /*
657     * (non-Javadoc)
658     *
659     * @see android.view.View#findFocus()
660     */
661    @Override
662    public View findFocus() {
663        if (DBG) {
664            System.out.println("Find focus in " + this + ": flags="
665                    + isFocused() + ", child=" + mFocused);
666        }
667
668        if (isFocused()) {
669            return this;
670        }
671
672        if (mFocused != null) {
673            return mFocused.findFocus();
674        }
675        return null;
676    }
677
678    /**
679     * {@inheritDoc}
680     */
681    @Override
682    public boolean hasFocusable() {
683        if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) {
684            return false;
685        }
686
687        if (isFocusable()) {
688            return true;
689        }
690
691        final int descendantFocusability = getDescendantFocusability();
692        if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS) {
693            final int count = mChildrenCount;
694            final View[] children = mChildren;
695
696            for (int i = 0; i < count; i++) {
697                final View child = children[i];
698                if (child.hasFocusable()) {
699                    return true;
700                }
701            }
702        }
703
704        return false;
705    }
706
707    /**
708     * {@inheritDoc}
709     */
710    @Override
711    public void addFocusables(ArrayList<View> views, int direction) {
712        addFocusables(views, direction, FOCUSABLES_TOUCH_MODE);
713    }
714
715    /**
716     * {@inheritDoc}
717     */
718    @Override
719    public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
720        final int focusableCount = views.size();
721
722        final int descendantFocusability = getDescendantFocusability();
723
724        if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS) {
725            final int count = mChildrenCount;
726            final View[] children = mChildren;
727
728            for (int i = 0; i < count; i++) {
729                final View child = children[i];
730                if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
731                    child.addFocusables(views, direction, focusableMode);
732                }
733            }
734        }
735
736        // we add ourselves (if focusable) in all cases except for when we are
737        // FOCUS_AFTER_DESCENDANTS and there are some descendants focusable.  this is
738        // to avoid the focus search finding layouts when a more precise search
739        // among the focusable children would be more interesting.
740        if (
741            descendantFocusability != FOCUS_AFTER_DESCENDANTS ||
742                // No focusable descendants
743                (focusableCount == views.size())) {
744            super.addFocusables(views, direction, focusableMode);
745        }
746    }
747
748    /**
749     * {@inheritDoc}
750     */
751    @Override
752    public void dispatchWindowFocusChanged(boolean hasFocus) {
753        super.dispatchWindowFocusChanged(hasFocus);
754        final int count = mChildrenCount;
755        final View[] children = mChildren;
756        for (int i = 0; i < count; i++) {
757            children[i].dispatchWindowFocusChanged(hasFocus);
758        }
759    }
760
761    /**
762     * {@inheritDoc}
763     */
764    @Override
765    public void addTouchables(ArrayList<View> views) {
766        super.addTouchables(views);
767
768        final int count = mChildrenCount;
769        final View[] children = mChildren;
770
771        for (int i = 0; i < count; i++) {
772            final View child = children[i];
773            if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
774                child.addTouchables(views);
775            }
776        }
777    }
778
779    /**
780     * {@inheritDoc}
781     */
782    @Override
783    public void dispatchDisplayHint(int hint) {
784        super.dispatchDisplayHint(hint);
785        final int count = mChildrenCount;
786        final View[] children = mChildren;
787        for (int i = 0; i < count; i++) {
788            children[i].dispatchDisplayHint(hint);
789        }
790    }
791
792    /**
793     * @hide
794     * @param child
795     * @param visibility
796     */
797    void onChildVisibilityChanged(View child, int visibility) {
798        if (mTransition != null) {
799            if (visibility == VISIBLE) {
800                mTransition.showChild(this, child);
801            } else {
802                mTransition.hideChild(this, child);
803            }
804            if (visibility != VISIBLE) {
805                // Only track this on disappearing views - appearing views are already visible
806                // and don't need special handling during drawChild()
807                if (mVisibilityChangingChildren == null) {
808                    mVisibilityChangingChildren = new ArrayList<View>();
809                }
810                mVisibilityChangingChildren.add(child);
811                if (mTransitioningViews != null && mTransitioningViews.contains(child)) {
812                    addDisappearingView(child);
813                }
814            }
815        }
816
817        // in all cases, for drags
818        if (mCurrentDrag != null) {
819            if (visibility == VISIBLE) {
820                notifyChildOfDrag(child);
821            }
822        }
823    }
824
825    /**
826     * {@inheritDoc}
827     */
828    @Override
829    protected void dispatchVisibilityChanged(View changedView, int visibility) {
830        super.dispatchVisibilityChanged(changedView, visibility);
831        final int count = mChildrenCount;
832        final View[] children = mChildren;
833        for (int i = 0; i < count; i++) {
834            children[i].dispatchVisibilityChanged(changedView, visibility);
835        }
836    }
837
838    /**
839     * {@inheritDoc}
840     */
841    @Override
842    public void dispatchWindowVisibilityChanged(int visibility) {
843        super.dispatchWindowVisibilityChanged(visibility);
844        final int count = mChildrenCount;
845        final View[] children = mChildren;
846        for (int i = 0; i < count; i++) {
847            children[i].dispatchWindowVisibilityChanged(visibility);
848        }
849    }
850
851    /**
852     * {@inheritDoc}
853     */
854    @Override
855    public void dispatchConfigurationChanged(Configuration newConfig) {
856        super.dispatchConfigurationChanged(newConfig);
857        final int count = mChildrenCount;
858        final View[] children = mChildren;
859        for (int i = 0; i < count; i++) {
860            children[i].dispatchConfigurationChanged(newConfig);
861        }
862    }
863
864    /**
865     * {@inheritDoc}
866     */
867    public void recomputeViewAttributes(View child) {
868        if (mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) {
869            ViewParent parent = mParent;
870            if (parent != null) parent.recomputeViewAttributes(this);
871        }
872    }
873
874    @Override
875    void dispatchCollectViewAttributes(int visibility) {
876        visibility |= mViewFlags&VISIBILITY_MASK;
877        super.dispatchCollectViewAttributes(visibility);
878        final int count = mChildrenCount;
879        final View[] children = mChildren;
880        for (int i = 0; i < count; i++) {
881            children[i].dispatchCollectViewAttributes(visibility);
882        }
883    }
884
885    /**
886     * {@inheritDoc}
887     */
888    public void bringChildToFront(View child) {
889        int index = indexOfChild(child);
890        if (index >= 0) {
891            removeFromArray(index);
892            addInArray(child, mChildrenCount);
893            child.mParent = this;
894        }
895    }
896
897    /**
898     * {@inheritDoc}
899     *
900     * !!! TODO: write real docs
901     */
902    @Override
903    public boolean dispatchDragEvent(DragEvent event) {
904        boolean retval = false;
905        final float tx = event.mX;
906        final float ty = event.mY;
907
908        ViewRoot root = getViewRoot();
909
910        // Dispatch down the view hierarchy
911        switch (event.mAction) {
912        case DragEvent.ACTION_DRAG_STARTED: {
913            // clear state to recalculate which views we drag over
914            mCurrentDragView = null;
915
916            // Set up our tracking of drag-started notifications
917            mCurrentDrag = DragEvent.obtain(event);
918            if (mDragNotifiedChildren == null) {
919                mDragNotifiedChildren = new HashSet<View>();
920            } else {
921                mDragNotifiedChildren.clear();
922            }
923
924            // Now dispatch down to our children, caching the responses
925            mChildAcceptsDrag = false;
926            final int count = mChildrenCount;
927            final View[] children = mChildren;
928            for (int i = 0; i < count; i++) {
929                final View child = children[i];
930                if (child.getVisibility() == VISIBLE) {
931                    final boolean handled = notifyChildOfDrag(children[i]);
932                    if (handled) {
933                        mChildAcceptsDrag = true;
934                    }
935                }
936            }
937
938            // Return HANDLED if one of our children can accept the drag
939            if (mChildAcceptsDrag) {
940                retval = true;
941            }
942        } break;
943
944        case DragEvent.ACTION_DRAG_ENDED: {
945            // Release the bookkeeping now that the drag lifecycle has ended
946            if (mDragNotifiedChildren != null) {
947                for (View child : mDragNotifiedChildren) {
948                    // If a child was notified about an ongoing drag, it's told that it's over
949                    child.dispatchDragEvent(event);
950                }
951
952                mDragNotifiedChildren.clear();
953                mCurrentDrag.recycle();
954                mCurrentDrag = null;
955            }
956
957            // We consider drag-ended to have been handled if one of our children
958            // had offered to handle the drag.
959            if (mChildAcceptsDrag) {
960                retval = true;
961            }
962        } break;
963
964        case DragEvent.ACTION_DRAG_LOCATION: {
965            // Find the [possibly new] drag target
966            final View target = findFrontmostDroppableChildAt(event.mX, event.mY, mLocalPoint);
967
968            // If we've changed apparent drag target, tell the view root which view
969            // we're over now [for purposes of the eventual drag-recipient-changed
970            // notifications to the framework] and tell the new target that the drag
971            // has entered its bounds.  The root will see setDragFocus() calls all
972            // the way down to the final leaf view that is handling the LOCATION event
973            // before reporting the new potential recipient to the framework.
974            if (mCurrentDragView != target) {
975                root.setDragFocus(target);
976
977                final int action = event.mAction;
978                // If we've dragged off of a child view, send it the EXITED message
979                if (mCurrentDragView != null) {
980                    event.mAction = DragEvent.ACTION_DRAG_EXITED;
981                    mCurrentDragView.dispatchDragEvent(event);
982                }
983                mCurrentDragView = target;
984
985                // If we've dragged over a new child view, send it the ENTERED message
986                if (target != null) {
987                    event.mAction = DragEvent.ACTION_DRAG_ENTERED;
988                    target.dispatchDragEvent(event);
989                }
990                event.mAction = action;  // restore the event's original state
991            }
992
993            // Dispatch the actual drag location notice, localized into its coordinates
994            if (target != null) {
995                event.mX = mLocalPoint.x;
996                event.mY = mLocalPoint.y;
997
998                retval = target.dispatchDragEvent(event);
999
1000                event.mX = tx;
1001                event.mY = ty;
1002            }
1003        } break;
1004
1005        /* Entered / exited dispatch
1006         *
1007         * DRAG_ENTERED is not dispatched downwards from ViewGroup.  The reason for this is
1008         * that we're about to get the corresponding LOCATION event, which we will use to
1009         * determine which of our children is the new target; at that point we will
1010         * push a DRAG_ENTERED down to the new target child [which may itself be a ViewGroup].
1011         *
1012         * DRAG_EXITED *is* dispatched all the way down immediately: once we know the
1013         * drag has left this ViewGroup, we know by definition that every contained subview
1014         * is also no longer under the drag point.
1015         */
1016
1017        case DragEvent.ACTION_DRAG_EXITED: {
1018            if (mCurrentDragView != null) {
1019                mCurrentDragView.dispatchDragEvent(event);
1020                mCurrentDragView = null;
1021            }
1022        } break;
1023
1024        case DragEvent.ACTION_DROP: {
1025            if (ViewDebug.DEBUG_DRAG) Log.d(View.VIEW_LOG_TAG, "Drop event: " + event);
1026            View target = findFrontmostDroppableChildAt(event.mX, event.mY, mLocalPoint);
1027            if (target != null) {
1028                if (ViewDebug.DEBUG_DRAG) Log.d(View.VIEW_LOG_TAG, "   dispatch drop to " + target);
1029                event.mX = mLocalPoint.x;
1030                event.mY = mLocalPoint.y;
1031                retval = target.dispatchDragEvent(event);
1032                event.mX = tx;
1033                event.mY = ty;
1034            } else {
1035                if (ViewDebug.DEBUG_DRAG) {
1036                    Log.d(View.VIEW_LOG_TAG, "   not dropped on an accepting view");
1037                }
1038            }
1039        } break;
1040        }
1041
1042        // If none of our children could handle the event, try here
1043        if (!retval) {
1044            // Call up to the View implementation that dispatches to installed listeners
1045            retval = super.dispatchDragEvent(event);
1046        }
1047        return retval;
1048    }
1049
1050    // Find the frontmost child view that lies under the given point, and calculate
1051    // the position within its own local coordinate system.
1052    View findFrontmostDroppableChildAt(float x, float y, PointF outLocalPoint) {
1053        final int count = mChildrenCount;
1054        final View[] children = mChildren;
1055        for (int i = count - 1; i >= 0; i--) {
1056            final View child = children[i];
1057            if (!child.mCanAcceptDrop) {
1058                continue;
1059            }
1060
1061            if (isTransformedTouchPointInView(x, y, child, outLocalPoint)) {
1062                return child;
1063            }
1064        }
1065        return null;
1066    }
1067
1068    boolean notifyChildOfDrag(View child) {
1069        if (ViewDebug.DEBUG_DRAG) {
1070            Log.d(View.VIEW_LOG_TAG, "Sending drag-started to view: " + child);
1071        }
1072
1073        if (! mDragNotifiedChildren.contains(child)) {
1074            mDragNotifiedChildren.add(child);
1075            child.mCanAcceptDrop = child.dispatchDragEvent(mCurrentDrag);
1076        }
1077        return child.mCanAcceptDrop;
1078    }
1079
1080    @Override
1081    public void dispatchSystemUiVisibilityChanged(int visible) {
1082        super.dispatchSystemUiVisibilityChanged(visible);
1083
1084        final int count = mChildrenCount;
1085        final View[] children = mChildren;
1086        for (int i=0; i <count; i++) {
1087            final View child = children[i];
1088            child.dispatchSystemUiVisibilityChanged(visible);
1089        }
1090    }
1091
1092    /**
1093     * {@inheritDoc}
1094     */
1095    @Override
1096    public boolean dispatchKeyEventPreIme(KeyEvent event) {
1097        if ((mPrivateFlags & (FOCUSED | HAS_BOUNDS)) == (FOCUSED | HAS_BOUNDS)) {
1098            return super.dispatchKeyEventPreIme(event);
1099        } else if (mFocused != null && (mFocused.mPrivateFlags & HAS_BOUNDS) == HAS_BOUNDS) {
1100            return mFocused.dispatchKeyEventPreIme(event);
1101        }
1102        return false;
1103    }
1104
1105    /**
1106     * {@inheritDoc}
1107     */
1108    @Override
1109    public boolean dispatchKeyEvent(KeyEvent event) {
1110        if ((mPrivateFlags & (FOCUSED | HAS_BOUNDS)) == (FOCUSED | HAS_BOUNDS)) {
1111            return super.dispatchKeyEvent(event);
1112        } else if (mFocused != null && (mFocused.mPrivateFlags & HAS_BOUNDS) == HAS_BOUNDS) {
1113            return mFocused.dispatchKeyEvent(event);
1114        }
1115        return false;
1116    }
1117
1118    /**
1119     * {@inheritDoc}
1120     */
1121    @Override
1122    public boolean dispatchKeyShortcutEvent(KeyEvent event) {
1123        if ((mPrivateFlags & (FOCUSED | HAS_BOUNDS)) == (FOCUSED | HAS_BOUNDS)) {
1124            return super.dispatchKeyShortcutEvent(event);
1125        } else if (mFocused != null && (mFocused.mPrivateFlags & HAS_BOUNDS) == HAS_BOUNDS) {
1126            return mFocused.dispatchKeyShortcutEvent(event);
1127        }
1128        return false;
1129    }
1130
1131    /**
1132     * {@inheritDoc}
1133     */
1134    @Override
1135    public boolean dispatchTrackballEvent(MotionEvent event) {
1136        if ((mPrivateFlags & (FOCUSED | HAS_BOUNDS)) == (FOCUSED | HAS_BOUNDS)) {
1137            return super.dispatchTrackballEvent(event);
1138        } else if (mFocused != null && (mFocused.mPrivateFlags & HAS_BOUNDS) == HAS_BOUNDS) {
1139            return mFocused.dispatchTrackballEvent(event);
1140        }
1141        return false;
1142    }
1143
1144    /**
1145     * {@inheritDoc}
1146     */
1147    @Override
1148    public boolean dispatchTouchEvent(MotionEvent ev) {
1149        if (!onFilterTouchEventForSecurity(ev)) {
1150            return false;
1151        }
1152
1153        final int action = ev.getAction();
1154        final int actionMasked = action & MotionEvent.ACTION_MASK;
1155
1156        // Handle an initial down.
1157        if (actionMasked == MotionEvent.ACTION_DOWN) {
1158            // Throw away all previous state when starting a new touch gesture.
1159            // The framework may have dropped the up or cancel event for the previous gesture
1160            // due to an app switch, ANR, or some other state change.
1161            cancelAndClearTouchTargets(ev);
1162            resetTouchState();
1163        }
1164
1165        // Check for interception.
1166        final boolean intercepted;
1167        if (actionMasked == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null) {
1168            final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
1169            if (!disallowIntercept) {
1170                intercepted = onInterceptTouchEvent(ev);
1171                ev.setAction(action); // restore action in case onInterceptTouchEvent() changed it
1172            } else {
1173                intercepted = false;
1174            }
1175        } else {
1176            intercepted = true;
1177        }
1178
1179        // Check for cancelation.
1180        final boolean canceled = resetCancelNextUpFlag(this)
1181                || actionMasked == MotionEvent.ACTION_CANCEL;
1182
1183        // Update list of touch targets for pointer down, if needed.
1184        final boolean split = (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) != 0;
1185        TouchTarget newTouchTarget = null;
1186        boolean alreadyDispatchedToNewTouchTarget = false;
1187        if (!canceled && !intercepted) {
1188            if (actionMasked == MotionEvent.ACTION_DOWN
1189                    || (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN)) {
1190                final int actionIndex = ev.getActionIndex(); // always 0 for down
1191                final int idBitsToAssign = split ? 1 << ev.getPointerId(actionIndex)
1192                        : TouchTarget.ALL_POINTER_IDS;
1193
1194                // Clean up earlier touch targets for this pointer id in case they
1195                // have become out of sync.
1196                removePointersFromTouchTargets(idBitsToAssign);
1197
1198                final int childrenCount = mChildrenCount;
1199                if (childrenCount != 0) {
1200                    // Find a child that can receive the event.  Scan children from front to back.
1201                    final View[] children = mChildren;
1202                    final float x = ev.getX(actionIndex);
1203                    final float y = ev.getY(actionIndex);
1204
1205                    for (int i = childrenCount - 1; i >= 0; i--) {
1206                        final View child = children[i];
1207                        if ((child.mViewFlags & VISIBILITY_MASK) != VISIBLE
1208                                && child.getAnimation() == null) {
1209                            // Skip invisible child unless it is animating.
1210                            continue;
1211                        }
1212
1213                        if (!isTransformedTouchPointInView(x, y, child, null)) {
1214                            // New pointer is out of child's bounds.
1215                            continue;
1216                        }
1217
1218                        newTouchTarget = getTouchTarget(child);
1219                        if (newTouchTarget != null) {
1220                            // Child is already receiving touch within its bounds.
1221                            // Give it the new pointer in addition to the ones it is handling.
1222                            newTouchTarget.pointerIdBits |= idBitsToAssign;
1223                            break;
1224                        }
1225
1226                        resetCancelNextUpFlag(child);
1227                        if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
1228                            // Child wants to receive touch within its bounds.
1229                            mLastTouchDownTime = ev.getDownTime();
1230                            mLastTouchDownIndex = i;
1231                            mLastTouchDownX = ev.getX();
1232                            mLastTouchDownY = ev.getY();
1233                            newTouchTarget = addTouchTarget(child, idBitsToAssign);
1234                            alreadyDispatchedToNewTouchTarget = true;
1235                            break;
1236                        }
1237                    }
1238                }
1239
1240                if (newTouchTarget == null && mFirstTouchTarget != null) {
1241                    // Did not find a child to receive the event.
1242                    // Assign the pointer to the least recently added target.
1243                    newTouchTarget = mFirstTouchTarget;
1244                    while (newTouchTarget.next != null) {
1245                        newTouchTarget = newTouchTarget.next;
1246                    }
1247                    newTouchTarget.pointerIdBits |= idBitsToAssign;
1248                }
1249            }
1250        }
1251
1252        // Dispatch to touch targets.
1253        boolean handled = false;
1254        if (mFirstTouchTarget == null) {
1255            // No touch targets so treat this as an ordinary view.
1256            handled = dispatchTransformedTouchEvent(ev, canceled, null,
1257                    TouchTarget.ALL_POINTER_IDS);
1258        } else {
1259            // Dispatch to touch targets, excluding the new touch target if we already
1260            // dispatched to it.  Cancel touch targets if necessary.
1261            TouchTarget predecessor = null;
1262            TouchTarget target = mFirstTouchTarget;
1263            while (target != null) {
1264                final TouchTarget next = target.next;
1265                if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) {
1266                    handled = true;
1267                } else {
1268                    final boolean cancelChild = resetCancelNextUpFlag(target.child) || intercepted;
1269                    if (dispatchTransformedTouchEvent(ev, cancelChild,
1270                            target.child, target.pointerIdBits)) {
1271                        handled = true;
1272                    }
1273                    if (cancelChild) {
1274                        if (predecessor == null) {
1275                            mFirstTouchTarget = next;
1276                        } else {
1277                            predecessor.next = next;
1278                        }
1279                        target.recycle();
1280                        target = next;
1281                        continue;
1282                    }
1283                }
1284                predecessor = target;
1285                target = next;
1286            }
1287        }
1288
1289        // Update list of touch targets for pointer up or cancel, if needed.
1290        if (canceled || actionMasked == MotionEvent.ACTION_UP) {
1291            resetTouchState();
1292        } else if (split && actionMasked == MotionEvent.ACTION_POINTER_UP) {
1293            final int actionIndex = ev.getActionIndex();
1294            final int idBitsToRemove = 1 << ev.getPointerId(actionIndex);
1295            removePointersFromTouchTargets(idBitsToRemove);
1296        }
1297
1298        return handled;
1299    }
1300
1301    /**
1302     * Resets all touch state in preparation for a new cycle.
1303     */
1304    private void resetTouchState() {
1305        clearTouchTargets();
1306        resetCancelNextUpFlag(this);
1307        mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
1308    }
1309
1310    /**
1311     * Resets the cancel next up flag.
1312     * Returns true if the flag was previously set.
1313     */
1314    private boolean resetCancelNextUpFlag(View view) {
1315        if ((view.mPrivateFlags & CANCEL_NEXT_UP_EVENT) != 0) {
1316            view.mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT;
1317            return true;
1318        }
1319        return false;
1320    }
1321
1322    /**
1323     * Clears all touch targets.
1324     */
1325    private void clearTouchTargets() {
1326        TouchTarget target = mFirstTouchTarget;
1327        if (target != null) {
1328            do {
1329                TouchTarget next = target.next;
1330                target.recycle();
1331                target = next;
1332            } while (target != null);
1333            mFirstTouchTarget = null;
1334        }
1335    }
1336
1337    /**
1338     * Cancels and clears all touch targets.
1339     */
1340    private void cancelAndClearTouchTargets(MotionEvent event) {
1341        if (mFirstTouchTarget != null) {
1342            boolean syntheticEvent = false;
1343            if (event == null) {
1344                final long now = SystemClock.uptimeMillis();
1345                event = MotionEvent.obtain(now, now,
1346                        MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
1347                syntheticEvent = true;
1348            }
1349
1350            for (TouchTarget target = mFirstTouchTarget; target != null; target = target.next) {
1351                resetCancelNextUpFlag(target.child);
1352                dispatchTransformedTouchEvent(event, true, target.child, target.pointerIdBits);
1353            }
1354            clearTouchTargets();
1355
1356            if (syntheticEvent) {
1357                event.recycle();
1358            }
1359        }
1360    }
1361
1362    /**
1363     * Gets the touch target for specified child view.
1364     * Returns null if not found.
1365     */
1366    private TouchTarget getTouchTarget(View child) {
1367        for (TouchTarget target = mFirstTouchTarget; target != null; target = target.next) {
1368            if (target.child == child) {
1369                return target;
1370            }
1371        }
1372        return null;
1373    }
1374
1375    /**
1376     * Adds a touch target for specified child to the beginning of the list.
1377     * Assumes the target child is not already present.
1378     */
1379    private TouchTarget addTouchTarget(View child, int pointerIdBits) {
1380        TouchTarget target = TouchTarget.obtain(child, pointerIdBits);
1381        target.next = mFirstTouchTarget;
1382        mFirstTouchTarget = target;
1383        return target;
1384    }
1385
1386    /**
1387     * Removes the pointer ids from consideration.
1388     */
1389    private void removePointersFromTouchTargets(int pointerIdBits) {
1390        TouchTarget predecessor = null;
1391        TouchTarget target = mFirstTouchTarget;
1392        while (target != null) {
1393            final TouchTarget next = target.next;
1394            if ((target.pointerIdBits & pointerIdBits) != 0) {
1395                target.pointerIdBits &= ~pointerIdBits;
1396                if (target.pointerIdBits == 0) {
1397                    if (predecessor == null) {
1398                        mFirstTouchTarget = next;
1399                    } else {
1400                        predecessor.next = next;
1401                    }
1402                    target.recycle();
1403                    target = next;
1404                    continue;
1405                }
1406            }
1407            predecessor = target;
1408            target = next;
1409        }
1410    }
1411
1412    /**
1413     * Returns true if a child view contains the specified point when transformed
1414     * into its coordinate space.
1415     * Child must not be null.
1416     * @hide
1417     */
1418    protected boolean isTransformedTouchPointInView(float x, float y, View child,
1419            PointF outLocalPoint) {
1420        float localX = x + mScrollX - child.mLeft;
1421        float localY = y + mScrollY - child.mTop;
1422        if (! child.hasIdentityMatrix() && mAttachInfo != null) {
1423            final float[] localXY = mAttachInfo.mTmpTransformLocation;
1424            localXY[0] = localX;
1425            localXY[1] = localY;
1426            child.getInverseMatrix().mapPoints(localXY);
1427            localX = localXY[0];
1428            localY = localXY[1];
1429        }
1430        final boolean isInView = child.pointInView(localX, localY);
1431        if (isInView && outLocalPoint != null) {
1432            outLocalPoint.set(localX, localY);
1433        }
1434        return isInView;
1435    }
1436
1437    /**
1438     * Transforms a motion event into the coordinate space of a particular child view,
1439     * filters out irrelevant pointer ids, and overrides its action if necessary.
1440     * If child is null, assumes the MotionEvent will be sent to this ViewGroup instead.
1441     */
1442    private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,
1443            View child, int desiredPointerIdBits) {
1444        final boolean handled;
1445
1446        // Canceling motions is a special case.  We don't need to perform any transformations
1447        // or filtering.  The important part is the action, not the contents.
1448        final int oldAction = event.getAction();
1449        if (cancel || oldAction == MotionEvent.ACTION_CANCEL) {
1450            event.setAction(MotionEvent.ACTION_CANCEL);
1451            if (child == null) {
1452                handled = super.dispatchTouchEvent(event);
1453            } else {
1454                handled = child.dispatchTouchEvent(event);
1455            }
1456            event.setAction(oldAction);
1457            return handled;
1458        }
1459
1460        // Calculate the number of pointers to deliver.
1461        final int oldPointerCount = event.getPointerCount();
1462        int newPointerCount = 0;
1463        if (desiredPointerIdBits == TouchTarget.ALL_POINTER_IDS) {
1464            newPointerCount = oldPointerCount;
1465        } else {
1466            for (int i = 0; i < oldPointerCount; i++) {
1467                final int pointerId = event.getPointerId(i);
1468                final int pointerIdBit = 1 << pointerId;
1469                if ((pointerIdBit & desiredPointerIdBits) != 0) {
1470                    newPointerCount += 1;
1471                }
1472            }
1473        }
1474
1475        // If for some reason we ended up in an inconsistent state where it looks like we
1476        // might produce a motion event with no pointers in it, then drop the event.
1477        if (newPointerCount == 0) {
1478            return false;
1479        }
1480
1481        // If the number of pointers is the same and we don't need to perform any fancy
1482        // irreversible transformations, then we can reuse the motion event for this
1483        // dispatch as long as we are careful to revert any changes we make.
1484        final boolean reuse = newPointerCount == oldPointerCount
1485                && (child == null || child.hasIdentityMatrix());
1486        if (reuse) {
1487            if (child == null) {
1488                handled = super.dispatchTouchEvent(event);
1489            } else {
1490                final float offsetX = mScrollX - child.mLeft;
1491                final float offsetY = mScrollY - child.mTop;
1492                event.offsetLocation(offsetX, offsetY);
1493
1494                handled = child.dispatchTouchEvent(event);
1495
1496                event.offsetLocation(-offsetX, -offsetY);
1497            }
1498            return handled;
1499        }
1500
1501        // Make a copy of the event.
1502        // If the number of pointers is different, then we need to filter out irrelevant pointers
1503        // as we make a copy of the motion event.
1504        MotionEvent transformedEvent;
1505        if (newPointerCount == oldPointerCount) {
1506            transformedEvent = MotionEvent.obtain(event);
1507        } else {
1508            growTmpPointerArrays(newPointerCount);
1509            final int[] newPointerIndexMap = mTmpPointerIndexMap;
1510            final int[] newPointerIds = mTmpPointerIds;
1511            final MotionEvent.PointerCoords[] newPointerCoords = mTmpPointerCoords;
1512
1513            int newPointerIndex = 0;
1514            int oldPointerIndex = 0;
1515            while (newPointerIndex < newPointerCount) {
1516                final int pointerId = event.getPointerId(oldPointerIndex);
1517                final int pointerIdBits = 1 << pointerId;
1518                if ((pointerIdBits & desiredPointerIdBits) != 0) {
1519                    newPointerIndexMap[newPointerIndex] = oldPointerIndex;
1520                    newPointerIds[newPointerIndex] = pointerId;
1521                    if (newPointerCoords[newPointerIndex] == null) {
1522                        newPointerCoords[newPointerIndex] = new MotionEvent.PointerCoords();
1523                    }
1524
1525                    newPointerIndex += 1;
1526                }
1527                oldPointerIndex += 1;
1528            }
1529
1530            final int newAction;
1531            if (cancel) {
1532                newAction = MotionEvent.ACTION_CANCEL;
1533            } else {
1534                final int oldMaskedAction = oldAction & MotionEvent.ACTION_MASK;
1535                if (oldMaskedAction == MotionEvent.ACTION_POINTER_DOWN
1536                        || oldMaskedAction == MotionEvent.ACTION_POINTER_UP) {
1537                    final int changedPointerId = event.getPointerId(
1538                            (oldAction & MotionEvent.ACTION_POINTER_INDEX_MASK)
1539                                    >> MotionEvent.ACTION_POINTER_INDEX_SHIFT);
1540                    final int changedPointerIdBits = 1 << changedPointerId;
1541                    if ((changedPointerIdBits & desiredPointerIdBits) != 0) {
1542                        if (newPointerCount == 1) {
1543                            // The first/last pointer went down/up.
1544                            newAction = oldMaskedAction == MotionEvent.ACTION_POINTER_DOWN
1545                                    ? MotionEvent.ACTION_DOWN : MotionEvent.ACTION_UP;
1546                        } else {
1547                            // A secondary pointer went down/up.
1548                            int newChangedPointerIndex = 0;
1549                            while (newPointerIds[newChangedPointerIndex] != changedPointerId) {
1550                                newChangedPointerIndex += 1;
1551                            }
1552                            newAction = oldMaskedAction | (newChangedPointerIndex
1553                                    << MotionEvent.ACTION_POINTER_INDEX_SHIFT);
1554                        }
1555                    } else {
1556                        // An unrelated pointer changed.
1557                        newAction = MotionEvent.ACTION_MOVE;
1558                    }
1559                } else {
1560                    // Simple up/down/cancel/move motion action.
1561                    newAction = oldMaskedAction;
1562                }
1563            }
1564
1565            transformedEvent = null;
1566            final int historySize = event.getHistorySize();
1567            for (int historyIndex = 0; historyIndex <= historySize; historyIndex++) {
1568                for (newPointerIndex = 0; newPointerIndex < newPointerCount; newPointerIndex++) {
1569                    final MotionEvent.PointerCoords c = newPointerCoords[newPointerIndex];
1570                    oldPointerIndex = newPointerIndexMap[newPointerIndex];
1571                    if (historyIndex != historySize) {
1572                        event.getHistoricalPointerCoords(oldPointerIndex, historyIndex, c);
1573                    } else {
1574                        event.getPointerCoords(oldPointerIndex, c);
1575                    }
1576                }
1577
1578                final long eventTime;
1579                if (historyIndex != historySize) {
1580                    eventTime = event.getHistoricalEventTime(historyIndex);
1581                } else {
1582                    eventTime = event.getEventTime();
1583                }
1584
1585                if (transformedEvent == null) {
1586                    transformedEvent = MotionEvent.obtain(
1587                            event.getDownTime(), eventTime, newAction,
1588                            newPointerCount, newPointerIds, newPointerCoords,
1589                            event.getMetaState(), event.getXPrecision(), event.getYPrecision(),
1590                            event.getDeviceId(), event.getEdgeFlags(), event.getSource(),
1591                            event.getFlags());
1592                } else {
1593                    transformedEvent.addBatch(eventTime, newPointerCoords, 0);
1594                }
1595            }
1596        }
1597
1598        // Perform any necessary transformations and dispatch.
1599        if (child == null) {
1600            handled = super.dispatchTouchEvent(transformedEvent);
1601        } else {
1602            final float offsetX = mScrollX - child.mLeft;
1603            final float offsetY = mScrollY - child.mTop;
1604            transformedEvent.offsetLocation(offsetX, offsetY);
1605            if (! child.hasIdentityMatrix()) {
1606                transformedEvent.transform(child.getInverseMatrix());
1607            }
1608
1609            handled = child.dispatchTouchEvent(transformedEvent);
1610        }
1611
1612        // Done.
1613        transformedEvent.recycle();
1614        return handled;
1615    }
1616
1617    /**
1618     * Enlarge the temporary pointer arrays for splitting pointers.
1619     * May discard contents (but keeps PointerCoords objects to avoid reallocating them).
1620     */
1621    private void growTmpPointerArrays(int desiredCapacity) {
1622        final MotionEvent.PointerCoords[] oldTmpPointerCoords = mTmpPointerCoords;
1623        int capacity;
1624        if (oldTmpPointerCoords != null) {
1625            capacity = oldTmpPointerCoords.length;
1626            if (desiredCapacity <= capacity) {
1627                return;
1628            }
1629        } else {
1630            capacity = 4;
1631        }
1632
1633        while (capacity < desiredCapacity) {
1634            capacity *= 2;
1635        }
1636
1637        mTmpPointerIndexMap = new int[capacity];
1638        mTmpPointerIds = new int[capacity];
1639        mTmpPointerCoords = new MotionEvent.PointerCoords[capacity];
1640
1641        if (oldTmpPointerCoords != null) {
1642            System.arraycopy(oldTmpPointerCoords, 0, mTmpPointerCoords, 0,
1643                    oldTmpPointerCoords.length);
1644        }
1645    }
1646
1647    /**
1648     * Enable or disable the splitting of MotionEvents to multiple children during touch event
1649     * dispatch. This behavior is enabled by default for applications that target an
1650     * SDK version of {@link Build.VERSION_CODES#HONEYCOMB} or newer.
1651     *
1652     * <p>When this option is enabled MotionEvents may be split and dispatched to different child
1653     * views depending on where each pointer initially went down. This allows for user interactions
1654     * such as scrolling two panes of content independently, chording of buttons, and performing
1655     * independent gestures on different pieces of content.
1656     *
1657     * @param split <code>true</code> to allow MotionEvents to be split and dispatched to multiple
1658     *              child views. <code>false</code> to only allow one child view to be the target of
1659     *              any MotionEvent received by this ViewGroup.
1660     */
1661    public void setMotionEventSplittingEnabled(boolean split) {
1662        // TODO Applications really shouldn't change this setting mid-touch event,
1663        // but perhaps this should handle that case and send ACTION_CANCELs to any child views
1664        // with gestures in progress when this is changed.
1665        if (split) {
1666            mGroupFlags |= FLAG_SPLIT_MOTION_EVENTS;
1667        } else {
1668            mGroupFlags &= ~FLAG_SPLIT_MOTION_EVENTS;
1669        }
1670    }
1671
1672    /**
1673     * Returns true if MotionEvents dispatched to this ViewGroup can be split to multiple children.
1674     * @return true if MotionEvents dispatched to this ViewGroup can be split to multiple children.
1675     */
1676    public boolean isMotionEventSplittingEnabled() {
1677        return (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) == FLAG_SPLIT_MOTION_EVENTS;
1678    }
1679
1680    /**
1681     * {@inheritDoc}
1682     */
1683    public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
1684
1685        if (disallowIntercept == ((mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0)) {
1686            // We're already in this state, assume our ancestors are too
1687            return;
1688        }
1689
1690        if (disallowIntercept) {
1691            mGroupFlags |= FLAG_DISALLOW_INTERCEPT;
1692        } else {
1693            mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
1694        }
1695
1696        // Pass it up to our parent
1697        if (mParent != null) {
1698            mParent.requestDisallowInterceptTouchEvent(disallowIntercept);
1699        }
1700    }
1701
1702    /**
1703     * Implement this method to intercept all touch screen motion events.  This
1704     * allows you to watch events as they are dispatched to your children, and
1705     * take ownership of the current gesture at any point.
1706     *
1707     * <p>Using this function takes some care, as it has a fairly complicated
1708     * interaction with {@link View#onTouchEvent(MotionEvent)
1709     * View.onTouchEvent(MotionEvent)}, and using it requires implementing
1710     * that method as well as this one in the correct way.  Events will be
1711     * received in the following order:
1712     *
1713     * <ol>
1714     * <li> You will receive the down event here.
1715     * <li> The down event will be handled either by a child of this view
1716     * group, or given to your own onTouchEvent() method to handle; this means
1717     * you should implement onTouchEvent() to return true, so you will
1718     * continue to see the rest of the gesture (instead of looking for
1719     * a parent view to handle it).  Also, by returning true from
1720     * onTouchEvent(), you will not receive any following
1721     * events in onInterceptTouchEvent() and all touch processing must
1722     * happen in onTouchEvent() like normal.
1723     * <li> For as long as you return false from this function, each following
1724     * event (up to and including the final up) will be delivered first here
1725     * and then to the target's onTouchEvent().
1726     * <li> If you return true from here, you will not receive any
1727     * following events: the target view will receive the same event but
1728     * with the action {@link MotionEvent#ACTION_CANCEL}, and all further
1729     * events will be delivered to your onTouchEvent() method and no longer
1730     * appear here.
1731     * </ol>
1732     *
1733     * @param ev The motion event being dispatched down the hierarchy.
1734     * @return Return true to steal motion events from the children and have
1735     * them dispatched to this ViewGroup through onTouchEvent().
1736     * The current target will receive an ACTION_CANCEL event, and no further
1737     * messages will be delivered here.
1738     */
1739    public boolean onInterceptTouchEvent(MotionEvent ev) {
1740        return false;
1741    }
1742
1743    /**
1744     * {@inheritDoc}
1745     *
1746     * Looks for a view to give focus to respecting the setting specified by
1747     * {@link #getDescendantFocusability()}.
1748     *
1749     * Uses {@link #onRequestFocusInDescendants(int, android.graphics.Rect)} to
1750     * find focus within the children of this group when appropriate.
1751     *
1752     * @see #FOCUS_BEFORE_DESCENDANTS
1753     * @see #FOCUS_AFTER_DESCENDANTS
1754     * @see #FOCUS_BLOCK_DESCENDANTS
1755     * @see #onRequestFocusInDescendants
1756     */
1757    @Override
1758    public boolean requestFocus(int direction, Rect previouslyFocusedRect) {
1759        if (DBG) {
1760            System.out.println(this + " ViewGroup.requestFocus direction="
1761                    + direction);
1762        }
1763        int descendantFocusability = getDescendantFocusability();
1764
1765        switch (descendantFocusability) {
1766            case FOCUS_BLOCK_DESCENDANTS:
1767                return super.requestFocus(direction, previouslyFocusedRect);
1768            case FOCUS_BEFORE_DESCENDANTS: {
1769                final boolean took = super.requestFocus(direction, previouslyFocusedRect);
1770                return took ? took : onRequestFocusInDescendants(direction, previouslyFocusedRect);
1771            }
1772            case FOCUS_AFTER_DESCENDANTS: {
1773                final boolean took = onRequestFocusInDescendants(direction, previouslyFocusedRect);
1774                return took ? took : super.requestFocus(direction, previouslyFocusedRect);
1775            }
1776            default:
1777                throw new IllegalStateException("descendant focusability must be "
1778                        + "one of FOCUS_BEFORE_DESCENDANTS, FOCUS_AFTER_DESCENDANTS, FOCUS_BLOCK_DESCENDANTS "
1779                        + "but is " + descendantFocusability);
1780        }
1781    }
1782
1783    /**
1784     * Look for a descendant to call {@link View#requestFocus} on.
1785     * Called by {@link ViewGroup#requestFocus(int, android.graphics.Rect)}
1786     * when it wants to request focus within its children.  Override this to
1787     * customize how your {@link ViewGroup} requests focus within its children.
1788     * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT
1789     * @param previouslyFocusedRect The rectangle (in this View's coordinate system)
1790     *        to give a finer grained hint about where focus is coming from.  May be null
1791     *        if there is no hint.
1792     * @return Whether focus was taken.
1793     */
1794    @SuppressWarnings({"ConstantConditions"})
1795    protected boolean onRequestFocusInDescendants(int direction,
1796            Rect previouslyFocusedRect) {
1797        int index;
1798        int increment;
1799        int end;
1800        int count = mChildrenCount;
1801        if ((direction & FOCUS_FORWARD) != 0) {
1802            index = 0;
1803            increment = 1;
1804            end = count;
1805        } else {
1806            index = count - 1;
1807            increment = -1;
1808            end = -1;
1809        }
1810        final View[] children = mChildren;
1811        for (int i = index; i != end; i += increment) {
1812            View child = children[i];
1813            if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
1814                if (child.requestFocus(direction, previouslyFocusedRect)) {
1815                    return true;
1816                }
1817            }
1818        }
1819        return false;
1820    }
1821
1822    /**
1823     * {@inheritDoc}
1824     *
1825     * @hide
1826     */
1827    @Override
1828    public void dispatchStartTemporaryDetach() {
1829        super.dispatchStartTemporaryDetach();
1830        final int count = mChildrenCount;
1831        final View[] children = mChildren;
1832        for (int i = 0; i < count; i++) {
1833            children[i].dispatchStartTemporaryDetach();
1834        }
1835    }
1836
1837    /**
1838     * {@inheritDoc}
1839     *
1840     * @hide
1841     */
1842    @Override
1843    public void dispatchFinishTemporaryDetach() {
1844        super.dispatchFinishTemporaryDetach();
1845        final int count = mChildrenCount;
1846        final View[] children = mChildren;
1847        for (int i = 0; i < count; i++) {
1848            children[i].dispatchFinishTemporaryDetach();
1849        }
1850    }
1851
1852    /**
1853     * {@inheritDoc}
1854     */
1855    @Override
1856    void dispatchAttachedToWindow(AttachInfo info, int visibility) {
1857        super.dispatchAttachedToWindow(info, visibility);
1858        visibility |= mViewFlags & VISIBILITY_MASK;
1859        final int count = mChildrenCount;
1860        final View[] children = mChildren;
1861        for (int i = 0; i < count; i++) {
1862            children[i].dispatchAttachedToWindow(info, visibility);
1863        }
1864    }
1865
1866    @Override
1867    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
1868        boolean populated = false;
1869        for (int i = 0, count = getChildCount(); i < count; i++) {
1870            populated |= getChildAt(i).dispatchPopulateAccessibilityEvent(event);
1871        }
1872        return populated;
1873    }
1874
1875    /**
1876     * {@inheritDoc}
1877     */
1878    @Override
1879    void dispatchDetachedFromWindow() {
1880        // If we still have a touch target, we are still in the process of
1881        // dispatching motion events to a child; we need to get rid of that
1882        // child to avoid dispatching events to it after the window is torn
1883        // down. To make sure we keep the child in a consistent state, we
1884        // first send it an ACTION_CANCEL motion event.
1885        cancelAndClearTouchTargets(null);
1886
1887        // In case view is detached while transition is running
1888        mLayoutSuppressed = false;
1889
1890        // Tear down our drag tracking
1891        mDragNotifiedChildren = null;
1892        if (mCurrentDrag != null) {
1893            mCurrentDrag.recycle();
1894            mCurrentDrag = null;
1895        }
1896
1897        final int count = mChildrenCount;
1898        final View[] children = mChildren;
1899        for (int i = 0; i < count; i++) {
1900            children[i].dispatchDetachedFromWindow();
1901        }
1902        super.dispatchDetachedFromWindow();
1903    }
1904
1905    /**
1906     * {@inheritDoc}
1907     */
1908    @Override
1909    public void setPadding(int left, int top, int right, int bottom) {
1910        super.setPadding(left, top, right, bottom);
1911
1912        if ((mPaddingLeft | mPaddingTop | mPaddingRight | mPaddingRight) != 0) {
1913            mGroupFlags |= FLAG_PADDING_NOT_NULL;
1914        } else {
1915            mGroupFlags &= ~FLAG_PADDING_NOT_NULL;
1916        }
1917    }
1918
1919    /**
1920     * {@inheritDoc}
1921     */
1922    @Override
1923    protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {
1924        super.dispatchSaveInstanceState(container);
1925        final int count = mChildrenCount;
1926        final View[] children = mChildren;
1927        for (int i = 0; i < count; i++) {
1928            View c = children[i];
1929            if ((c.mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED) {
1930                c.dispatchSaveInstanceState(container);
1931            }
1932        }
1933    }
1934
1935    /**
1936     * Perform dispatching of a {@link #saveHierarchyState freeze()} to only this view,
1937     * not to its children.  For use when overriding
1938     * {@link #dispatchSaveInstanceState dispatchFreeze()} to allow subclasses to freeze
1939     * their own state but not the state of their children.
1940     *
1941     * @param container the container
1942     */
1943    protected void dispatchFreezeSelfOnly(SparseArray<Parcelable> container) {
1944        super.dispatchSaveInstanceState(container);
1945    }
1946
1947    /**
1948     * {@inheritDoc}
1949     */
1950    @Override
1951    protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {
1952        super.dispatchRestoreInstanceState(container);
1953        final int count = mChildrenCount;
1954        final View[] children = mChildren;
1955        for (int i = 0; i < count; i++) {
1956            View c = children[i];
1957            if ((c.mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED) {
1958                c.dispatchRestoreInstanceState(container);
1959            }
1960        }
1961    }
1962
1963    /**
1964     * Perform dispatching of a {@link #restoreHierarchyState thaw()} to only this view,
1965     * not to its children.  For use when overriding
1966     * {@link #dispatchRestoreInstanceState dispatchThaw()} to allow subclasses to thaw
1967     * their own state but not the state of their children.
1968     *
1969     * @param container the container
1970     */
1971    protected void dispatchThawSelfOnly(SparseArray<Parcelable> container) {
1972        super.dispatchRestoreInstanceState(container);
1973    }
1974
1975    /**
1976     * Enables or disables the drawing cache for each child of this view group.
1977     *
1978     * @param enabled true to enable the cache, false to dispose of it
1979     */
1980    protected void setChildrenDrawingCacheEnabled(boolean enabled) {
1981        if (enabled || (mPersistentDrawingCache & PERSISTENT_ALL_CACHES) != PERSISTENT_ALL_CACHES) {
1982            final View[] children = mChildren;
1983            final int count = mChildrenCount;
1984            for (int i = 0; i < count; i++) {
1985                children[i].setDrawingCacheEnabled(enabled);
1986            }
1987        }
1988    }
1989
1990    @Override
1991    protected void onAnimationStart() {
1992        super.onAnimationStart();
1993
1994        // When this ViewGroup's animation starts, build the cache for the children
1995        if ((mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE) {
1996            final int count = mChildrenCount;
1997            final View[] children = mChildren;
1998            final boolean buildCache = !isHardwareAccelerated();
1999
2000            for (int i = 0; i < count; i++) {
2001                final View child = children[i];
2002                if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
2003                    child.setDrawingCacheEnabled(true);
2004                    if (buildCache) {
2005                        child.buildDrawingCache(true);
2006                    }
2007                }
2008            }
2009
2010            mGroupFlags |= FLAG_CHILDREN_DRAWN_WITH_CACHE;
2011        }
2012    }
2013
2014    @Override
2015    protected void onAnimationEnd() {
2016        super.onAnimationEnd();
2017
2018        // When this ViewGroup's animation ends, destroy the cache of the children
2019        if ((mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE) {
2020            mGroupFlags &= ~FLAG_CHILDREN_DRAWN_WITH_CACHE;
2021
2022            if ((mPersistentDrawingCache & PERSISTENT_ANIMATION_CACHE) == 0) {
2023                setChildrenDrawingCacheEnabled(false);
2024            }
2025        }
2026    }
2027
2028    @Override
2029    Bitmap createSnapshot(Bitmap.Config quality, int backgroundColor, boolean skipChildren) {
2030        int count = mChildrenCount;
2031        int[] visibilities = null;
2032
2033        if (skipChildren) {
2034            visibilities = new int[count];
2035            for (int i = 0; i < count; i++) {
2036                View child = getChildAt(i);
2037                visibilities[i] = child.getVisibility();
2038                if (visibilities[i] == View.VISIBLE) {
2039                    child.setVisibility(INVISIBLE);
2040                }
2041            }
2042        }
2043
2044        Bitmap b = super.createSnapshot(quality, backgroundColor, skipChildren);
2045
2046        if (skipChildren) {
2047            for (int i = 0; i < count; i++) {
2048                getChildAt(i).setVisibility(visibilities[i]);
2049            }
2050        }
2051
2052        return b;
2053    }
2054
2055    /**
2056     * {@inheritDoc}
2057     */
2058    @Override
2059    protected void dispatchDraw(Canvas canvas) {
2060        final int count = mChildrenCount;
2061        final View[] children = mChildren;
2062        int flags = mGroupFlags;
2063
2064        if ((flags & FLAG_RUN_ANIMATION) != 0 && canAnimate()) {
2065            final boolean cache = (mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE;
2066
2067            final boolean buildCache = !isHardwareAccelerated();
2068            for (int i = 0; i < count; i++) {
2069                final View child = children[i];
2070                if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
2071                    final LayoutParams params = child.getLayoutParams();
2072                    attachLayoutAnimationParameters(child, params, i, count);
2073                    bindLayoutAnimation(child);
2074                    if (cache) {
2075                        child.setDrawingCacheEnabled(true);
2076                        if (buildCache) {
2077                            child.buildDrawingCache(true);
2078                        }
2079                    }
2080                }
2081            }
2082
2083            final LayoutAnimationController controller = mLayoutAnimationController;
2084            if (controller.willOverlap()) {
2085                mGroupFlags |= FLAG_OPTIMIZE_INVALIDATE;
2086            }
2087
2088            controller.start();
2089
2090            mGroupFlags &= ~FLAG_RUN_ANIMATION;
2091            mGroupFlags &= ~FLAG_ANIMATION_DONE;
2092
2093            if (cache) {
2094                mGroupFlags |= FLAG_CHILDREN_DRAWN_WITH_CACHE;
2095            }
2096
2097            if (mAnimationListener != null) {
2098                mAnimationListener.onAnimationStart(controller.getAnimation());
2099            }
2100        }
2101
2102        int saveCount = 0;
2103        final boolean clipToPadding = (flags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK;
2104        if (clipToPadding) {
2105            saveCount = canvas.save();
2106            canvas.clipRect(mScrollX + mPaddingLeft, mScrollY + mPaddingTop,
2107                    mScrollX + mRight - mLeft - mPaddingRight,
2108                    mScrollY + mBottom - mTop - mPaddingBottom);
2109
2110        }
2111
2112        // We will draw our child's animation, let's reset the flag
2113        mPrivateFlags &= ~DRAW_ANIMATION;
2114        mGroupFlags &= ~FLAG_INVALIDATE_REQUIRED;
2115
2116        boolean more = false;
2117        final long drawingTime = getDrawingTime();
2118
2119        if ((flags & FLAG_USE_CHILD_DRAWING_ORDER) == 0) {
2120            for (int i = 0; i < count; i++) {
2121                final View child = children[i];
2122                if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
2123                    more |= drawChild(canvas, child, drawingTime);
2124                }
2125            }
2126        } else {
2127            for (int i = 0; i < count; i++) {
2128                final View child = children[getChildDrawingOrder(count, i)];
2129                if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
2130                    more |= drawChild(canvas, child, drawingTime);
2131                }
2132            }
2133        }
2134
2135        // Draw any disappearing views that have animations
2136        if (mDisappearingChildren != null) {
2137            final ArrayList<View> disappearingChildren = mDisappearingChildren;
2138            final int disappearingCount = disappearingChildren.size() - 1;
2139            // Go backwards -- we may delete as animations finish
2140            for (int i = disappearingCount; i >= 0; i--) {
2141                final View child = disappearingChildren.get(i);
2142                more |= drawChild(canvas, child, drawingTime);
2143            }
2144        }
2145
2146        if (clipToPadding) {
2147            canvas.restoreToCount(saveCount);
2148        }
2149
2150        // mGroupFlags might have been updated by drawChild()
2151        flags = mGroupFlags;
2152
2153        if ((flags & FLAG_INVALIDATE_REQUIRED) == FLAG_INVALIDATE_REQUIRED) {
2154            invalidate(true);
2155        }
2156
2157        if ((flags & FLAG_ANIMATION_DONE) == 0 && (flags & FLAG_NOTIFY_ANIMATION_LISTENER) == 0 &&
2158                mLayoutAnimationController.isDone() && !more) {
2159            // We want to erase the drawing cache and notify the listener after the
2160            // next frame is drawn because one extra invalidate() is caused by
2161            // drawChild() after the animation is over
2162            mGroupFlags |= FLAG_NOTIFY_ANIMATION_LISTENER;
2163            final Runnable end = new Runnable() {
2164               public void run() {
2165                   notifyAnimationListener();
2166               }
2167            };
2168            post(end);
2169        }
2170    }
2171
2172    /**
2173     * Returns the index of the child to draw for this iteration. Override this
2174     * if you want to change the drawing order of children. By default, it
2175     * returns i.
2176     * <p>
2177     * NOTE: In order for this method to be called, you must enable child ordering
2178     * first by calling {@link #setChildrenDrawingOrderEnabled(boolean)}.
2179     *
2180     * @param i The current iteration.
2181     * @return The index of the child to draw this iteration.
2182     *
2183     * @see #setChildrenDrawingOrderEnabled(boolean)
2184     * @see #isChildrenDrawingOrderEnabled()
2185     */
2186    protected int getChildDrawingOrder(int childCount, int i) {
2187        return i;
2188    }
2189
2190    private void notifyAnimationListener() {
2191        mGroupFlags &= ~FLAG_NOTIFY_ANIMATION_LISTENER;
2192        mGroupFlags |= FLAG_ANIMATION_DONE;
2193
2194        if (mAnimationListener != null) {
2195           final Runnable end = new Runnable() {
2196               public void run() {
2197                   mAnimationListener.onAnimationEnd(mLayoutAnimationController.getAnimation());
2198               }
2199           };
2200           post(end);
2201        }
2202
2203        if ((mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE) {
2204            mGroupFlags &= ~FLAG_CHILDREN_DRAWN_WITH_CACHE;
2205            if ((mPersistentDrawingCache & PERSISTENT_ANIMATION_CACHE) == 0) {
2206                setChildrenDrawingCacheEnabled(false);
2207            }
2208        }
2209
2210        invalidate(true);
2211    }
2212
2213    /**
2214     * This method is used to cause children of this ViewGroup to restore or recreate their
2215     * display lists. It is called by getDisplayList() when the parent ViewGroup does not need
2216     * to recreate its own display list, which would happen if it went through the normal
2217     * draw/dispatchDraw mechanisms.
2218     *
2219     * @hide
2220     */
2221    @Override
2222    protected void dispatchGetDisplayList() {
2223        final int count = mChildrenCount;
2224        final View[] children = mChildren;
2225        for (int i = 0; i < count; i++) {
2226            final View child = children[i];
2227            if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
2228                child.mRecreateDisplayList = (child.mPrivateFlags & INVALIDATED) == INVALIDATED;
2229                child.mPrivateFlags &= ~INVALIDATED;
2230                child.getDisplayList();
2231                child.mRecreateDisplayList = false;
2232            }
2233        }
2234    }
2235
2236    /**
2237     * Draw one child of this View Group. This method is responsible for getting
2238     * the canvas in the right state. This includes clipping, translating so
2239     * that the child's scrolled origin is at 0, 0, and applying any animation
2240     * transformations.
2241     *
2242     * @param canvas The canvas on which to draw the child
2243     * @param child Who to draw
2244     * @param drawingTime The time at which draw is occuring
2245     * @return True if an invalidate() was issued
2246     */
2247    protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
2248        boolean more = false;
2249
2250        final int cl = child.mLeft;
2251        final int ct = child.mTop;
2252        final int cr = child.mRight;
2253        final int cb = child.mBottom;
2254
2255        final boolean childHasIdentityMatrix = child.hasIdentityMatrix();
2256
2257        final int flags = mGroupFlags;
2258
2259        if ((flags & FLAG_CLEAR_TRANSFORMATION) == FLAG_CLEAR_TRANSFORMATION) {
2260            mChildTransformation.clear();
2261            mGroupFlags &= ~FLAG_CLEAR_TRANSFORMATION;
2262        }
2263
2264        Transformation transformToApply = null;
2265        Transformation invalidationTransform;
2266        final Animation a = child.getAnimation();
2267        boolean concatMatrix = false;
2268
2269        boolean scalingRequired = false;
2270        boolean caching;
2271        int layerType = mDrawLayers ? child.getLayerType() : LAYER_TYPE_NONE;
2272
2273        final boolean hardwareAccelerated = canvas.isHardwareAccelerated();
2274        if ((flags & FLAG_CHILDREN_DRAWN_WITH_CACHE) == FLAG_CHILDREN_DRAWN_WITH_CACHE ||
2275                (flags & FLAG_ALWAYS_DRAWN_WITH_CACHE) == FLAG_ALWAYS_DRAWN_WITH_CACHE) {
2276            caching = true;
2277            if (mAttachInfo != null) scalingRequired = mAttachInfo.mScalingRequired;
2278        } else {
2279            caching = (layerType != LAYER_TYPE_NONE) || hardwareAccelerated;
2280        }
2281
2282        if (a != null) {
2283            final boolean initialized = a.isInitialized();
2284            if (!initialized) {
2285                a.initialize(cr - cl, cb - ct, getWidth(), getHeight());
2286                a.initializeInvalidateRegion(0, 0, cr - cl, cb - ct);
2287                child.onAnimationStart();
2288            }
2289
2290            more = a.getTransformation(drawingTime, mChildTransformation,
2291                    scalingRequired ? mAttachInfo.mApplicationScale : 1f);
2292            if (scalingRequired && mAttachInfo.mApplicationScale != 1f) {
2293                if (mInvalidationTransformation == null) {
2294                    mInvalidationTransformation = new Transformation();
2295                }
2296                invalidationTransform = mInvalidationTransformation;
2297                a.getTransformation(drawingTime, invalidationTransform, 1f);
2298            } else {
2299                invalidationTransform = mChildTransformation;
2300            }
2301            transformToApply = mChildTransformation;
2302
2303            concatMatrix = a.willChangeTransformationMatrix();
2304
2305            if (more) {
2306                if (!a.willChangeBounds()) {
2307                    if ((flags & (FLAG_OPTIMIZE_INVALIDATE | FLAG_ANIMATION_DONE)) ==
2308                            FLAG_OPTIMIZE_INVALIDATE) {
2309                        mGroupFlags |= FLAG_INVALIDATE_REQUIRED;
2310                    } else if ((flags & FLAG_INVALIDATE_REQUIRED) == 0) {
2311                        // The child need to draw an animation, potentially offscreen, so
2312                        // make sure we do not cancel invalidate requests
2313                        mPrivateFlags |= DRAW_ANIMATION;
2314                        invalidate(cl, ct, cr, cb);
2315                    }
2316                } else {
2317                    if (mInvalidateRegion == null) {
2318                        mInvalidateRegion = new RectF();
2319                    }
2320                    final RectF region = mInvalidateRegion;
2321                    a.getInvalidateRegion(0, 0, cr - cl, cb - ct, region, invalidationTransform);
2322
2323                    // The child need to draw an animation, potentially offscreen, so
2324                    // make sure we do not cancel invalidate requests
2325                    mPrivateFlags |= DRAW_ANIMATION;
2326
2327                    final int left = cl + (int) region.left;
2328                    final int top = ct + (int) region.top;
2329                    invalidate(left, top, left + (int) region.width(), top + (int) region.height());
2330                }
2331            }
2332        } else if ((flags & FLAG_SUPPORT_STATIC_TRANSFORMATIONS) ==
2333                FLAG_SUPPORT_STATIC_TRANSFORMATIONS) {
2334            final boolean hasTransform = getChildStaticTransformation(child, mChildTransformation);
2335            if (hasTransform) {
2336                final int transformType = mChildTransformation.getTransformationType();
2337                transformToApply = transformType != Transformation.TYPE_IDENTITY ?
2338                        mChildTransformation : null;
2339                concatMatrix = (transformType & Transformation.TYPE_MATRIX) != 0;
2340            }
2341        }
2342
2343        concatMatrix |= !childHasIdentityMatrix;
2344
2345        // Sets the flag as early as possible to allow draw() implementations
2346        // to call invalidate() successfully when doing animations
2347        child.mPrivateFlags |= DRAWN;
2348
2349        if (!concatMatrix && canvas.quickReject(cl, ct, cr, cb, Canvas.EdgeType.BW) &&
2350                (child.mPrivateFlags & DRAW_ANIMATION) == 0) {
2351            return more;
2352        }
2353
2354        float alpha = child.getAlpha();
2355        // Bail out early if the view does not need to be drawn
2356        if (alpha <= ViewConfiguration.ALPHA_THRESHOLD && (child.mPrivateFlags & ALPHA_SET) == 0 &&
2357                !(child instanceof SurfaceView)) {
2358            return more;
2359        }
2360
2361        if (hardwareAccelerated) {
2362            // Clear INVALIDATED flag to allow invalidation to occur during rendering, but
2363            // retain the flag's value temporarily in the mRecreateDisplayList flag
2364            child.mRecreateDisplayList = (child.mPrivateFlags & INVALIDATED) == INVALIDATED;
2365            child.mPrivateFlags &= ~INVALIDATED;
2366        }
2367
2368        child.computeScroll();
2369
2370        final int sx = child.mScrollX;
2371        final int sy = child.mScrollY;
2372
2373        DisplayList displayList = null;
2374        Bitmap cache = null;
2375        boolean hasDisplayList = false;
2376        if (caching) {
2377            if (!hardwareAccelerated) {
2378                if (layerType != LAYER_TYPE_NONE) {
2379                    layerType = LAYER_TYPE_SOFTWARE;
2380                    child.buildDrawingCache(true);
2381                }
2382                cache = child.getDrawingCache(true);
2383            } else {
2384                if (layerType == LAYER_TYPE_SOFTWARE) {
2385                    child.buildDrawingCache(true);
2386                    cache = child.getDrawingCache(true);
2387                } else if (layerType == LAYER_TYPE_NONE) {
2388                    // Delay getting the display list until animation-driven alpha values are
2389                    // set up and possibly passed on to the view
2390                    hasDisplayList = child.canHaveDisplayList();
2391                }
2392            }
2393        }
2394
2395        final boolean hasNoCache = cache == null || hasDisplayList;
2396
2397        final int restoreTo = canvas.save();
2398        if (cache == null && !hasDisplayList) {
2399            canvas.translate(cl - sx, ct - sy);
2400        } else {
2401            canvas.translate(cl, ct);
2402            if (scalingRequired) {
2403                // mAttachInfo cannot be null, otherwise scalingRequired == false
2404                final float scale = 1.0f / mAttachInfo.mApplicationScale;
2405                canvas.scale(scale, scale);
2406            }
2407        }
2408
2409        if (transformToApply != null || alpha < 1.0f || !child.hasIdentityMatrix()) {
2410            if (transformToApply != null || !childHasIdentityMatrix) {
2411                int transX = 0;
2412                int transY = 0;
2413
2414                if (cache == null && !hasDisplayList) {
2415                    transX = -sx;
2416                    transY = -sy;
2417                }
2418
2419                if (transformToApply != null) {
2420                    if (concatMatrix) {
2421                        // Undo the scroll translation, apply the transformation matrix,
2422                        // then redo the scroll translate to get the correct result.
2423                        canvas.translate(-transX, -transY);
2424                        canvas.concat(transformToApply.getMatrix());
2425                        canvas.translate(transX, transY);
2426                        mGroupFlags |= FLAG_CLEAR_TRANSFORMATION;
2427                    }
2428
2429                    float transformAlpha = transformToApply.getAlpha();
2430                    if (transformAlpha < 1.0f) {
2431                        alpha *= transformToApply.getAlpha();
2432                        mGroupFlags |= FLAG_CLEAR_TRANSFORMATION;
2433                    }
2434                }
2435
2436                if (!childHasIdentityMatrix) {
2437                    canvas.translate(-transX, -transY);
2438                    canvas.concat(child.getMatrix());
2439                    canvas.translate(transX, transY);
2440                }
2441            }
2442
2443            if (alpha < 1.0f) {
2444                mGroupFlags |= FLAG_CLEAR_TRANSFORMATION;
2445                if (hasNoCache) {
2446                    final int multipliedAlpha = (int) (255 * alpha);
2447                    if (!child.onSetAlpha(multipliedAlpha)) {
2448                        int layerFlags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG;
2449                        if ((flags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN ||
2450                                layerType != LAYER_TYPE_NONE) {
2451                            layerFlags |= Canvas.CLIP_TO_LAYER_SAVE_FLAG;
2452                        }
2453                        if (layerType == LAYER_TYPE_NONE) {
2454                            canvas.saveLayerAlpha(sx, sy, sx + cr - cl, sy + cb - ct,
2455                                    multipliedAlpha, layerFlags);
2456                        }
2457                    } else {
2458                        // Alpha is handled by the child directly, clobber the layer's alpha
2459                        child.mPrivateFlags |= ALPHA_SET;
2460                    }
2461                }
2462            }
2463        } else if ((child.mPrivateFlags & ALPHA_SET) == ALPHA_SET) {
2464            child.onSetAlpha(255);
2465            child.mPrivateFlags &= ~ALPHA_SET;
2466        }
2467
2468        if ((flags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN) {
2469            if (cache == null && !hasDisplayList) {
2470                canvas.clipRect(sx, sy, sx + (cr - cl), sy + (cb - ct));
2471            } else {
2472                if (!scalingRequired || cache == null) {
2473                    canvas.clipRect(0, 0, cr - cl, cb - ct);
2474                } else {
2475                    canvas.clipRect(0, 0, cache.getWidth(), cache.getHeight());
2476                }
2477            }
2478        }
2479
2480        if (hasDisplayList) {
2481            displayList = child.getDisplayList();
2482        }
2483
2484        if (hasNoCache) {
2485            boolean layerRendered = false;
2486            if (layerType == LAYER_TYPE_HARDWARE) {
2487                final HardwareLayer layer = child.getHardwareLayer();
2488                if (layer != null && layer.isValid()) {
2489                    child.mLayerPaint.setAlpha((int) (alpha * 255));
2490                    ((HardwareCanvas) canvas).drawHardwareLayer(layer, 0, 0, child.mLayerPaint);
2491                    layerRendered = true;
2492                } else {
2493                    canvas.saveLayer(sx, sy, sx + cr - cl, sy + cb - ct, child.mLayerPaint,
2494                            Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG);
2495                }
2496            }
2497
2498            if (!layerRendered) {
2499                if (!hasDisplayList) {
2500                    // Fast path for layouts with no backgrounds
2501                    if ((child.mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
2502                        if (ViewDebug.TRACE_HIERARCHY) {
2503                            ViewDebug.trace(this, ViewDebug.HierarchyTraceType.DRAW);
2504                        }
2505                        child.mPrivateFlags &= ~DIRTY_MASK;
2506                        child.dispatchDraw(canvas);
2507                    } else {
2508                        child.draw(canvas);
2509                    }
2510                } else {
2511                    child.mPrivateFlags &= ~DIRTY_MASK;
2512                    ((HardwareCanvas) canvas).drawDisplayList(displayList);
2513                }
2514            }
2515        } else if (cache != null) {
2516            child.mPrivateFlags &= ~DIRTY_MASK;
2517            Paint cachePaint;
2518
2519            if (layerType == LAYER_TYPE_NONE) {
2520                cachePaint = mCachePaint;
2521                if (alpha < 1.0f) {
2522                    cachePaint.setAlpha((int) (alpha * 255));
2523                    mGroupFlags |= FLAG_ALPHA_LOWER_THAN_ONE;
2524                } else if  ((flags & FLAG_ALPHA_LOWER_THAN_ONE) == FLAG_ALPHA_LOWER_THAN_ONE) {
2525                    cachePaint.setAlpha(255);
2526                    mGroupFlags &= ~FLAG_ALPHA_LOWER_THAN_ONE;
2527                }
2528            } else {
2529                cachePaint = child.mLayerPaint;
2530                cachePaint.setAlpha((int) (alpha * 255));
2531            }
2532            canvas.drawBitmap(cache, 0.0f, 0.0f, cachePaint);
2533        }
2534
2535        canvas.restoreToCount(restoreTo);
2536
2537        if (a != null && !more) {
2538            if (!hardwareAccelerated && !a.getFillAfter()) {
2539                child.onSetAlpha(255);
2540            }
2541            finishAnimatingView(child, a);
2542        }
2543
2544        if (more && hardwareAccelerated) {
2545            // invalidation is the trigger to recreate display lists, so if we're using
2546            // display lists to render, force an invalidate to allow the animation to
2547            // continue drawing another frame
2548            invalidate(true);
2549            if (a instanceof AlphaAnimation) {
2550                // alpha animations should cause the child to recreate its display list
2551                child.invalidate(true);
2552            }
2553        }
2554
2555        child.mRecreateDisplayList = false;
2556
2557        return more;
2558    }
2559
2560    /**
2561     *
2562     * @param enabled True if children should be drawn with layers, false otherwise.
2563     *
2564     * @hide
2565     */
2566    public void setChildrenLayersEnabled(boolean enabled) {
2567        if (enabled != mDrawLayers) {
2568            mDrawLayers = enabled;
2569            invalidate(true);
2570
2571            // We need to invalidate any child with a layer. For instance,
2572            // if a child is backed by a hardware layer and we disable layers
2573            // the child is marked as not dirty (flags cleared the last time
2574            // the child was drawn inside its layer.) However, that child might
2575            // never have created its own display list or have an obsolete
2576            // display list. By invalidating the child we ensure the display
2577            // list is in sync with the content of the hardware layer.
2578            for (int i = 0; i < mChildrenCount; i++) {
2579                View child = mChildren[i];
2580                if (child.mLayerType != LAYER_TYPE_NONE) {
2581                    child.invalidate(true);
2582                }
2583            }
2584        }
2585    }
2586
2587    /**
2588     * By default, children are clipped to their bounds before drawing. This
2589     * allows view groups to override this behavior for animations, etc.
2590     *
2591     * @param clipChildren true to clip children to their bounds,
2592     *        false otherwise
2593     * @attr ref android.R.styleable#ViewGroup_clipChildren
2594     */
2595    public void setClipChildren(boolean clipChildren) {
2596        setBooleanFlag(FLAG_CLIP_CHILDREN, clipChildren);
2597    }
2598
2599    /**
2600     * By default, children are clipped to the padding of the ViewGroup. This
2601     * allows view groups to override this behavior
2602     *
2603     * @param clipToPadding true to clip children to the padding of the
2604     *        group, false otherwise
2605     * @attr ref android.R.styleable#ViewGroup_clipToPadding
2606     */
2607    public void setClipToPadding(boolean clipToPadding) {
2608        setBooleanFlag(FLAG_CLIP_TO_PADDING, clipToPadding);
2609    }
2610
2611    /**
2612     * {@inheritDoc}
2613     */
2614    @Override
2615    public void dispatchSetSelected(boolean selected) {
2616        final View[] children = mChildren;
2617        final int count = mChildrenCount;
2618        for (int i = 0; i < count; i++) {
2619            children[i].setSelected(selected);
2620        }
2621    }
2622
2623    /**
2624     * {@inheritDoc}
2625     */
2626    @Override
2627    public void dispatchSetActivated(boolean activated) {
2628        final View[] children = mChildren;
2629        final int count = mChildrenCount;
2630        for (int i = 0; i < count; i++) {
2631            children[i].setActivated(activated);
2632        }
2633    }
2634
2635    @Override
2636    protected void dispatchSetPressed(boolean pressed) {
2637        final View[] children = mChildren;
2638        final int count = mChildrenCount;
2639        for (int i = 0; i < count; i++) {
2640            children[i].setPressed(pressed);
2641        }
2642    }
2643
2644    /**
2645     * When this property is set to true, this ViewGroup supports static transformations on
2646     * children; this causes
2647     * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} to be
2648     * invoked when a child is drawn.
2649     *
2650     * Any subclass overriding
2651     * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} should
2652     * set this property to true.
2653     *
2654     * @param enabled True to enable static transformations on children, false otherwise.
2655     *
2656     * @see #FLAG_SUPPORT_STATIC_TRANSFORMATIONS
2657     */
2658    protected void setStaticTransformationsEnabled(boolean enabled) {
2659        setBooleanFlag(FLAG_SUPPORT_STATIC_TRANSFORMATIONS, enabled);
2660    }
2661
2662    /**
2663     * {@inheritDoc}
2664     *
2665     * @see #setStaticTransformationsEnabled(boolean)
2666     */
2667    protected boolean getChildStaticTransformation(View child, Transformation t) {
2668        return false;
2669    }
2670
2671    /**
2672     * {@hide}
2673     */
2674    @Override
2675    protected View findViewTraversal(int id) {
2676        if (id == mID) {
2677            return this;
2678        }
2679
2680        final View[] where = mChildren;
2681        final int len = mChildrenCount;
2682
2683        for (int i = 0; i < len; i++) {
2684            View v = where[i];
2685
2686            if ((v.mPrivateFlags & IS_ROOT_NAMESPACE) == 0) {
2687                v = v.findViewById(id);
2688
2689                if (v != null) {
2690                    return v;
2691                }
2692            }
2693        }
2694
2695        return null;
2696    }
2697
2698    /**
2699     * {@hide}
2700     */
2701    @Override
2702    protected View findViewWithTagTraversal(Object tag) {
2703        if (tag != null && tag.equals(mTag)) {
2704            return this;
2705        }
2706
2707        final View[] where = mChildren;
2708        final int len = mChildrenCount;
2709
2710        for (int i = 0; i < len; i++) {
2711            View v = where[i];
2712
2713            if ((v.mPrivateFlags & IS_ROOT_NAMESPACE) == 0) {
2714                v = v.findViewWithTag(tag);
2715
2716                if (v != null) {
2717                    return v;
2718                }
2719            }
2720        }
2721
2722        return null;
2723    }
2724
2725    /**
2726     * {@hide}
2727     */
2728    @Override
2729    protected View findViewByPredicateTraversal(Predicate<View> predicate) {
2730        if (predicate.apply(this)) {
2731            return this;
2732        }
2733
2734        final View[] where = mChildren;
2735        final int len = mChildrenCount;
2736
2737        for (int i = 0; i < len; i++) {
2738            View v = where[i];
2739
2740            if ((v.mPrivateFlags & IS_ROOT_NAMESPACE) == 0) {
2741                v = v.findViewByPredicate(predicate);
2742
2743                if (v != null) {
2744                    return v;
2745                }
2746            }
2747        }
2748
2749        return null;
2750    }
2751
2752    /**
2753     * Adds a child view. If no layout parameters are already set on the child, the
2754     * default parameters for this ViewGroup are set on the child.
2755     *
2756     * @param child the child view to add
2757     *
2758     * @see #generateDefaultLayoutParams()
2759     */
2760    public void addView(View child) {
2761        addView(child, -1);
2762    }
2763
2764    /**
2765     * Adds a child view. If no layout parameters are already set on the child, the
2766     * default parameters for this ViewGroup are set on the child.
2767     *
2768     * @param child the child view to add
2769     * @param index the position at which to add the child
2770     *
2771     * @see #generateDefaultLayoutParams()
2772     */
2773    public void addView(View child, int index) {
2774        LayoutParams params = child.getLayoutParams();
2775        if (params == null) {
2776            params = generateDefaultLayoutParams();
2777            if (params == null) {
2778                throw new IllegalArgumentException("generateDefaultLayoutParams() cannot return null");
2779            }
2780        }
2781        addView(child, index, params);
2782    }
2783
2784    /**
2785     * Adds a child view with this ViewGroup's default layout parameters and the
2786     * specified width and height.
2787     *
2788     * @param child the child view to add
2789     */
2790    public void addView(View child, int width, int height) {
2791        final LayoutParams params = generateDefaultLayoutParams();
2792        params.width = width;
2793        params.height = height;
2794        addView(child, -1, params);
2795    }
2796
2797    /**
2798     * Adds a child view with the specified layout parameters.
2799     *
2800     * @param child the child view to add
2801     * @param params the layout parameters to set on the child
2802     */
2803    public void addView(View child, LayoutParams params) {
2804        addView(child, -1, params);
2805    }
2806
2807    /**
2808     * Adds a child view with the specified layout parameters.
2809     *
2810     * @param child the child view to add
2811     * @param index the position at which to add the child
2812     * @param params the layout parameters to set on the child
2813     */
2814    public void addView(View child, int index, LayoutParams params) {
2815        if (DBG) {
2816            System.out.println(this + " addView");
2817        }
2818
2819        // addViewInner() will call child.requestLayout() when setting the new LayoutParams
2820        // therefore, we call requestLayout() on ourselves before, so that the child's request
2821        // will be blocked at our level
2822        requestLayout();
2823        invalidate(true);
2824        addViewInner(child, index, params, false);
2825    }
2826
2827    /**
2828     * {@inheritDoc}
2829     */
2830    public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
2831        if (!checkLayoutParams(params)) {
2832            throw new IllegalArgumentException("Invalid LayoutParams supplied to " + this);
2833        }
2834        if (view.mParent != this) {
2835            throw new IllegalArgumentException("Given view not a child of " + this);
2836        }
2837        view.setLayoutParams(params);
2838    }
2839
2840    /**
2841     * {@inheritDoc}
2842     */
2843    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
2844        return  p != null;
2845    }
2846
2847    /**
2848     * Interface definition for a callback to be invoked when the hierarchy
2849     * within this view changed. The hierarchy changes whenever a child is added
2850     * to or removed from this view.
2851     */
2852    public interface OnHierarchyChangeListener {
2853        /**
2854         * Called when a new child is added to a parent view.
2855         *
2856         * @param parent the view in which a child was added
2857         * @param child the new child view added in the hierarchy
2858         */
2859        void onChildViewAdded(View parent, View child);
2860
2861        /**
2862         * Called when a child is removed from a parent view.
2863         *
2864         * @param parent the view from which the child was removed
2865         * @param child the child removed from the hierarchy
2866         */
2867        void onChildViewRemoved(View parent, View child);
2868    }
2869
2870    /**
2871     * Register a callback to be invoked when a child is added to or removed
2872     * from this view.
2873     *
2874     * @param listener the callback to invoke on hierarchy change
2875     */
2876    public void setOnHierarchyChangeListener(OnHierarchyChangeListener listener) {
2877        mOnHierarchyChangeListener = listener;
2878    }
2879
2880    /**
2881     * Adds a view during layout. This is useful if in your onLayout() method,
2882     * you need to add more views (as does the list view for example).
2883     *
2884     * If index is negative, it means put it at the end of the list.
2885     *
2886     * @param child the view to add to the group
2887     * @param index the index at which the child must be added
2888     * @param params the layout parameters to associate with the child
2889     * @return true if the child was added, false otherwise
2890     */
2891    protected boolean addViewInLayout(View child, int index, LayoutParams params) {
2892        return addViewInLayout(child, index, params, false);
2893    }
2894
2895    /**
2896     * Adds a view during layout. This is useful if in your onLayout() method,
2897     * you need to add more views (as does the list view for example).
2898     *
2899     * If index is negative, it means put it at the end of the list.
2900     *
2901     * @param child the view to add to the group
2902     * @param index the index at which the child must be added
2903     * @param params the layout parameters to associate with the child
2904     * @param preventRequestLayout if true, calling this method will not trigger a
2905     *        layout request on child
2906     * @return true if the child was added, false otherwise
2907     */
2908    protected boolean addViewInLayout(View child, int index, LayoutParams params,
2909            boolean preventRequestLayout) {
2910        child.mParent = null;
2911        addViewInner(child, index, params, preventRequestLayout);
2912        child.mPrivateFlags = (child.mPrivateFlags & ~DIRTY_MASK) | DRAWN;
2913        return true;
2914    }
2915
2916    /**
2917     * Prevents the specified child to be laid out during the next layout pass.
2918     *
2919     * @param child the child on which to perform the cleanup
2920     */
2921    protected void cleanupLayoutState(View child) {
2922        child.mPrivateFlags &= ~View.FORCE_LAYOUT;
2923    }
2924
2925    private void addViewInner(View child, int index, LayoutParams params,
2926            boolean preventRequestLayout) {
2927
2928        if (child.getParent() != null) {
2929            throw new IllegalStateException("The specified child already has a parent. " +
2930                    "You must call removeView() on the child's parent first.");
2931        }
2932
2933        if (mTransition != null) {
2934            mTransition.addChild(this, child);
2935        }
2936
2937        if (!checkLayoutParams(params)) {
2938            params = generateLayoutParams(params);
2939        }
2940
2941        if (preventRequestLayout) {
2942            child.mLayoutParams = params;
2943        } else {
2944            child.setLayoutParams(params);
2945        }
2946
2947        if (index < 0) {
2948            index = mChildrenCount;
2949        }
2950
2951        addInArray(child, index);
2952
2953        // tell our children
2954        if (preventRequestLayout) {
2955            child.assignParent(this);
2956        } else {
2957            child.mParent = this;
2958        }
2959
2960        if (child.hasFocus()) {
2961            requestChildFocus(child, child.findFocus());
2962        }
2963
2964        AttachInfo ai = mAttachInfo;
2965        if (ai != null) {
2966            boolean lastKeepOn = ai.mKeepScreenOn;
2967            ai.mKeepScreenOn = false;
2968            child.dispatchAttachedToWindow(mAttachInfo, (mViewFlags&VISIBILITY_MASK));
2969            if (ai.mKeepScreenOn) {
2970                needGlobalAttributesUpdate(true);
2971            }
2972            ai.mKeepScreenOn = lastKeepOn;
2973        }
2974
2975        if (mOnHierarchyChangeListener != null) {
2976            mOnHierarchyChangeListener.onChildViewAdded(this, child);
2977        }
2978
2979        if ((child.mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE) {
2980            mGroupFlags |= FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE;
2981        }
2982    }
2983
2984    private void addInArray(View child, int index) {
2985        View[] children = mChildren;
2986        final int count = mChildrenCount;
2987        final int size = children.length;
2988        if (index == count) {
2989            if (size == count) {
2990                mChildren = new View[size + ARRAY_CAPACITY_INCREMENT];
2991                System.arraycopy(children, 0, mChildren, 0, size);
2992                children = mChildren;
2993            }
2994            children[mChildrenCount++] = child;
2995        } else if (index < count) {
2996            if (size == count) {
2997                mChildren = new View[size + ARRAY_CAPACITY_INCREMENT];
2998                System.arraycopy(children, 0, mChildren, 0, index);
2999                System.arraycopy(children, index, mChildren, index + 1, count - index);
3000                children = mChildren;
3001            } else {
3002                System.arraycopy(children, index, children, index + 1, count - index);
3003            }
3004            children[index] = child;
3005            mChildrenCount++;
3006            if (mLastTouchDownIndex >= index) {
3007                mLastTouchDownIndex++;
3008            }
3009        } else {
3010            throw new IndexOutOfBoundsException("index=" + index + " count=" + count);
3011        }
3012    }
3013
3014    // This method also sets the child's mParent to null
3015    private void removeFromArray(int index) {
3016        final View[] children = mChildren;
3017        if (!(mTransitioningViews != null && mTransitioningViews.contains(children[index]))) {
3018            children[index].mParent = null;
3019        }
3020        final int count = mChildrenCount;
3021        if (index == count - 1) {
3022            children[--mChildrenCount] = null;
3023        } else if (index >= 0 && index < count) {
3024            System.arraycopy(children, index + 1, children, index, count - index - 1);
3025            children[--mChildrenCount] = null;
3026        } else {
3027            throw new IndexOutOfBoundsException();
3028        }
3029        if (mLastTouchDownIndex == index) {
3030            mLastTouchDownTime = 0;
3031            mLastTouchDownIndex = -1;
3032        } else if (mLastTouchDownIndex > index) {
3033            mLastTouchDownIndex--;
3034        }
3035    }
3036
3037    // This method also sets the children's mParent to null
3038    private void removeFromArray(int start, int count) {
3039        final View[] children = mChildren;
3040        final int childrenCount = mChildrenCount;
3041
3042        start = Math.max(0, start);
3043        final int end = Math.min(childrenCount, start + count);
3044
3045        if (start == end) {
3046            return;
3047        }
3048
3049        if (end == childrenCount) {
3050            for (int i = start; i < end; i++) {
3051                children[i].mParent = null;
3052                children[i] = null;
3053            }
3054        } else {
3055            for (int i = start; i < end; i++) {
3056                children[i].mParent = null;
3057            }
3058
3059            // Since we're looping above, we might as well do the copy, but is arraycopy()
3060            // faster than the extra 2 bounds checks we would do in the loop?
3061            System.arraycopy(children, end, children, start, childrenCount - end);
3062
3063            for (int i = childrenCount - (end - start); i < childrenCount; i++) {
3064                children[i] = null;
3065            }
3066        }
3067
3068        mChildrenCount -= (end - start);
3069    }
3070
3071    private void bindLayoutAnimation(View child) {
3072        Animation a = mLayoutAnimationController.getAnimationForView(child);
3073        child.setAnimation(a);
3074    }
3075
3076    /**
3077     * Subclasses should override this method to set layout animation
3078     * parameters on the supplied child.
3079     *
3080     * @param child the child to associate with animation parameters
3081     * @param params the child's layout parameters which hold the animation
3082     *        parameters
3083     * @param index the index of the child in the view group
3084     * @param count the number of children in the view group
3085     */
3086    protected void attachLayoutAnimationParameters(View child,
3087            LayoutParams params, int index, int count) {
3088        LayoutAnimationController.AnimationParameters animationParams =
3089                    params.layoutAnimationParameters;
3090        if (animationParams == null) {
3091            animationParams = new LayoutAnimationController.AnimationParameters();
3092            params.layoutAnimationParameters = animationParams;
3093        }
3094
3095        animationParams.count = count;
3096        animationParams.index = index;
3097    }
3098
3099    /**
3100     * {@inheritDoc}
3101     */
3102    public void removeView(View view) {
3103        removeViewInternal(view);
3104        requestLayout();
3105        invalidate(true);
3106    }
3107
3108    /**
3109     * Removes a view during layout. This is useful if in your onLayout() method,
3110     * you need to remove more views.
3111     *
3112     * @param view the view to remove from the group
3113     */
3114    public void removeViewInLayout(View view) {
3115        removeViewInternal(view);
3116    }
3117
3118    /**
3119     * Removes a range of views during layout. This is useful if in your onLayout() method,
3120     * you need to remove more views.
3121     *
3122     * @param start the index of the first view to remove from the group
3123     * @param count the number of views to remove from the group
3124     */
3125    public void removeViewsInLayout(int start, int count) {
3126        removeViewsInternal(start, count);
3127    }
3128
3129    /**
3130     * Removes the view at the specified position in the group.
3131     *
3132     * @param index the position in the group of the view to remove
3133     */
3134    public void removeViewAt(int index) {
3135        removeViewInternal(index, getChildAt(index));
3136        requestLayout();
3137        invalidate(true);
3138    }
3139
3140    /**
3141     * Removes the specified range of views from the group.
3142     *
3143     * @param start the first position in the group of the range of views to remove
3144     * @param count the number of views to remove
3145     */
3146    public void removeViews(int start, int count) {
3147        removeViewsInternal(start, count);
3148        requestLayout();
3149        invalidate(true);
3150    }
3151
3152    private void removeViewInternal(View view) {
3153        final int index = indexOfChild(view);
3154        if (index >= 0) {
3155            removeViewInternal(index, view);
3156        }
3157    }
3158
3159    private void removeViewInternal(int index, View view) {
3160
3161        if (mTransition != null) {
3162            mTransition.removeChild(this, view);
3163        }
3164
3165        boolean clearChildFocus = false;
3166        if (view == mFocused) {
3167            view.clearFocusForRemoval();
3168            clearChildFocus = true;
3169        }
3170
3171        if (view.getAnimation() != null ||
3172                (mTransitioningViews != null && mTransitioningViews.contains(view))) {
3173            addDisappearingView(view);
3174        } else if (view.mAttachInfo != null) {
3175           view.dispatchDetachedFromWindow();
3176        }
3177
3178        if (mOnHierarchyChangeListener != null) {
3179            mOnHierarchyChangeListener.onChildViewRemoved(this, view);
3180        }
3181
3182        needGlobalAttributesUpdate(false);
3183
3184        removeFromArray(index);
3185
3186        if (clearChildFocus) {
3187            clearChildFocus(view);
3188        }
3189    }
3190
3191    /**
3192     * Sets the LayoutTransition object for this ViewGroup. If the LayoutTransition object is
3193     * not null, changes in layout which occur because of children being added to or removed from
3194     * the ViewGroup will be animated according to the animations defined in that LayoutTransition
3195     * object. By default, the transition object is null (so layout changes are not animated).
3196     *
3197     * @param transition The LayoutTransition object that will animated changes in layout. A value
3198     * of <code>null</code> means no transition will run on layout changes.
3199     * @attr ref android.R.styleable#ViewGroup_animateLayoutChanges
3200     */
3201    public void setLayoutTransition(LayoutTransition transition) {
3202        if (mTransition != null) {
3203            mTransition.removeTransitionListener(mLayoutTransitionListener);
3204        }
3205        mTransition = transition;
3206        if (mTransition != null) {
3207            mTransition.addTransitionListener(mLayoutTransitionListener);
3208        }
3209    }
3210
3211    /**
3212     * Gets the LayoutTransition object for this ViewGroup. If the LayoutTransition object is
3213     * not null, changes in layout which occur because of children being added to or removed from
3214     * the ViewGroup will be animated according to the animations defined in that LayoutTransition
3215     * object. By default, the transition object is null (so layout changes are not animated).
3216     *
3217     * @return LayoutTranstion The LayoutTransition object that will animated changes in layout.
3218     * A value of <code>null</code> means no transition will run on layout changes.
3219     */
3220    public LayoutTransition getLayoutTransition() {
3221        return mTransition;
3222    }
3223
3224    private void removeViewsInternal(int start, int count) {
3225        final OnHierarchyChangeListener onHierarchyChangeListener = mOnHierarchyChangeListener;
3226        final boolean notifyListener = onHierarchyChangeListener != null;
3227        final View focused = mFocused;
3228        final boolean detach = mAttachInfo != null;
3229        View clearChildFocus = null;
3230
3231        final View[] children = mChildren;
3232        final int end = start + count;
3233
3234        for (int i = start; i < end; i++) {
3235            final View view = children[i];
3236
3237            if (mTransition != null) {
3238                mTransition.removeChild(this, view);
3239            }
3240
3241            if (view == focused) {
3242                view.clearFocusForRemoval();
3243                clearChildFocus = view;
3244            }
3245
3246            if (view.getAnimation() != null ||
3247                (mTransitioningViews != null && mTransitioningViews.contains(view))) {
3248                addDisappearingView(view);
3249            } else if (detach) {
3250               view.dispatchDetachedFromWindow();
3251            }
3252
3253            needGlobalAttributesUpdate(false);
3254
3255            if (notifyListener) {
3256                onHierarchyChangeListener.onChildViewRemoved(this, view);
3257            }
3258        }
3259
3260        removeFromArray(start, count);
3261
3262        if (clearChildFocus != null) {
3263            clearChildFocus(clearChildFocus);
3264        }
3265    }
3266
3267    /**
3268     * Call this method to remove all child views from the
3269     * ViewGroup.
3270     */
3271    public void removeAllViews() {
3272        removeAllViewsInLayout();
3273        requestLayout();
3274        invalidate(true);
3275    }
3276
3277    /**
3278     * Called by a ViewGroup subclass to remove child views from itself,
3279     * when it must first know its size on screen before it can calculate how many
3280     * child views it will render. An example is a Gallery or a ListView, which
3281     * may "have" 50 children, but actually only render the number of children
3282     * that can currently fit inside the object on screen. Do not call
3283     * this method unless you are extending ViewGroup and understand the
3284     * view measuring and layout pipeline.
3285     */
3286    public void removeAllViewsInLayout() {
3287        final int count = mChildrenCount;
3288        if (count <= 0) {
3289            return;
3290        }
3291
3292        final View[] children = mChildren;
3293        mChildrenCount = 0;
3294
3295        final OnHierarchyChangeListener listener = mOnHierarchyChangeListener;
3296        final boolean notify = listener != null;
3297        final View focused = mFocused;
3298        final boolean detach = mAttachInfo != null;
3299        View clearChildFocus = null;
3300
3301        needGlobalAttributesUpdate(false);
3302
3303        for (int i = count - 1; i >= 0; i--) {
3304            final View view = children[i];
3305
3306            if (mTransition != null) {
3307                mTransition.removeChild(this, view);
3308            }
3309
3310            if (view == focused) {
3311                view.clearFocusForRemoval();
3312                clearChildFocus = view;
3313            }
3314
3315            if (view.getAnimation() != null ||
3316                    (mTransitioningViews != null && mTransitioningViews.contains(view))) {
3317                addDisappearingView(view);
3318            } else if (detach) {
3319               view.dispatchDetachedFromWindow();
3320            }
3321
3322            if (notify) {
3323                listener.onChildViewRemoved(this, view);
3324            }
3325
3326            view.mParent = null;
3327            children[i] = null;
3328        }
3329
3330        if (clearChildFocus != null) {
3331            clearChildFocus(clearChildFocus);
3332        }
3333    }
3334
3335    /**
3336     * Finishes the removal of a detached view. This method will dispatch the detached from
3337     * window event and notify the hierarchy change listener.
3338     *
3339     * @param child the child to be definitely removed from the view hierarchy
3340     * @param animate if true and the view has an animation, the view is placed in the
3341     *                disappearing views list, otherwise, it is detached from the window
3342     *
3343     * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
3344     * @see #detachAllViewsFromParent()
3345     * @see #detachViewFromParent(View)
3346     * @see #detachViewFromParent(int)
3347     */
3348    protected void removeDetachedView(View child, boolean animate) {
3349        if (mTransition != null) {
3350            mTransition.removeChild(this, child);
3351        }
3352
3353        if (child == mFocused) {
3354            child.clearFocus();
3355        }
3356
3357        if ((animate && child.getAnimation() != null) ||
3358                (mTransitioningViews != null && mTransitioningViews.contains(child))) {
3359            addDisappearingView(child);
3360        } else if (child.mAttachInfo != null) {
3361            child.dispatchDetachedFromWindow();
3362        }
3363
3364        if (mOnHierarchyChangeListener != null) {
3365            mOnHierarchyChangeListener.onChildViewRemoved(this, child);
3366        }
3367    }
3368
3369    /**
3370     * Attaches a view to this view group. Attaching a view assigns this group as the parent,
3371     * sets the layout parameters and puts the view in the list of children so it can be retrieved
3372     * by calling {@link #getChildAt(int)}.
3373     *
3374     * This method should be called only for view which were detached from their parent.
3375     *
3376     * @param child the child to attach
3377     * @param index the index at which the child should be attached
3378     * @param params the layout parameters of the child
3379     *
3380     * @see #removeDetachedView(View, boolean)
3381     * @see #detachAllViewsFromParent()
3382     * @see #detachViewFromParent(View)
3383     * @see #detachViewFromParent(int)
3384     */
3385    protected void attachViewToParent(View child, int index, LayoutParams params) {
3386        child.mLayoutParams = params;
3387
3388        if (index < 0) {
3389            index = mChildrenCount;
3390        }
3391
3392        addInArray(child, index);
3393
3394        child.mParent = this;
3395        child.mPrivateFlags = (child.mPrivateFlags & ~DIRTY_MASK & ~DRAWING_CACHE_VALID) |
3396                DRAWN | INVALIDATED;
3397        this.mPrivateFlags |= INVALIDATED;
3398
3399        if (child.hasFocus()) {
3400            requestChildFocus(child, child.findFocus());
3401        }
3402    }
3403
3404    /**
3405     * Detaches a view from its parent. Detaching a view should be temporary and followed
3406     * either by a call to {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
3407     * or a call to {@link #removeDetachedView(View, boolean)}. When a view is detached,
3408     * its parent is null and cannot be retrieved by a call to {@link #getChildAt(int)}.
3409     *
3410     * @param child the child to detach
3411     *
3412     * @see #detachViewFromParent(int)
3413     * @see #detachViewsFromParent(int, int)
3414     * @see #detachAllViewsFromParent()
3415     * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
3416     * @see #removeDetachedView(View, boolean)
3417     */
3418    protected void detachViewFromParent(View child) {
3419        removeFromArray(indexOfChild(child));
3420    }
3421
3422    /**
3423     * Detaches a view from its parent. Detaching a view should be temporary and followed
3424     * either by a call to {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
3425     * or a call to {@link #removeDetachedView(View, boolean)}. When a view is detached,
3426     * its parent is null and cannot be retrieved by a call to {@link #getChildAt(int)}.
3427     *
3428     * @param index the index of the child to detach
3429     *
3430     * @see #detachViewFromParent(View)
3431     * @see #detachAllViewsFromParent()
3432     * @see #detachViewsFromParent(int, int)
3433     * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
3434     * @see #removeDetachedView(View, boolean)
3435     */
3436    protected void detachViewFromParent(int index) {
3437        removeFromArray(index);
3438    }
3439
3440    /**
3441     * Detaches a range of view from their parent. Detaching a view should be temporary and followed
3442     * either by a call to {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
3443     * or a call to {@link #removeDetachedView(View, boolean)}. When a view is detached, its
3444     * parent is null and cannot be retrieved by a call to {@link #getChildAt(int)}.
3445     *
3446     * @param start the first index of the childrend range to detach
3447     * @param count the number of children to detach
3448     *
3449     * @see #detachViewFromParent(View)
3450     * @see #detachViewFromParent(int)
3451     * @see #detachAllViewsFromParent()
3452     * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
3453     * @see #removeDetachedView(View, boolean)
3454     */
3455    protected void detachViewsFromParent(int start, int count) {
3456        removeFromArray(start, count);
3457    }
3458
3459    /**
3460     * Detaches all views from the parent. Detaching a view should be temporary and followed
3461     * either by a call to {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
3462     * or a call to {@link #removeDetachedView(View, boolean)}. When a view is detached,
3463     * its parent is null and cannot be retrieved by a call to {@link #getChildAt(int)}.
3464     *
3465     * @see #detachViewFromParent(View)
3466     * @see #detachViewFromParent(int)
3467     * @see #detachViewsFromParent(int, int)
3468     * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
3469     * @see #removeDetachedView(View, boolean)
3470     */
3471    protected void detachAllViewsFromParent() {
3472        final int count = mChildrenCount;
3473        if (count <= 0) {
3474            return;
3475        }
3476
3477        final View[] children = mChildren;
3478        mChildrenCount = 0;
3479
3480        for (int i = count - 1; i >= 0; i--) {
3481            children[i].mParent = null;
3482            children[i] = null;
3483        }
3484    }
3485
3486    /**
3487     * Don't call or override this method. It is used for the implementation of
3488     * the view hierarchy.
3489     */
3490    public final void invalidateChild(View child, final Rect dirty) {
3491        if (ViewDebug.TRACE_HIERARCHY) {
3492            ViewDebug.trace(this, ViewDebug.HierarchyTraceType.INVALIDATE_CHILD);
3493        }
3494
3495        ViewParent parent = this;
3496
3497        final AttachInfo attachInfo = mAttachInfo;
3498        if (attachInfo != null) {
3499            // If the child is drawing an animation, we want to copy this flag onto
3500            // ourselves and the parent to make sure the invalidate request goes
3501            // through
3502            final boolean drawAnimation = (child.mPrivateFlags & DRAW_ANIMATION) == DRAW_ANIMATION;
3503
3504            if (dirty == null) {
3505                if (child.mLayerType != LAYER_TYPE_NONE) {
3506                    mPrivateFlags |= INVALIDATED;
3507                    mPrivateFlags &= ~DRAWING_CACHE_VALID;
3508                    child.mLocalDirtyRect.setEmpty();
3509                }
3510                do {
3511                    View view = null;
3512                    if (parent instanceof View) {
3513                        view = (View) parent;
3514                        if (view.mLayerType != LAYER_TYPE_NONE) {
3515                            view.mLocalDirtyRect.setEmpty();
3516                            if (view.getParent() instanceof View) {
3517                                final View grandParent = (View) view.getParent();
3518                                grandParent.mPrivateFlags |= INVALIDATED;
3519                                grandParent.mPrivateFlags &= ~DRAWING_CACHE_VALID;
3520                            }
3521                        }
3522                        if ((view.mPrivateFlags & DIRTY_MASK) != 0) {
3523                            // already marked dirty - we're done
3524                            break;
3525                        }
3526                    }
3527
3528                    if (drawAnimation) {
3529                        if (view != null) {
3530                            view.mPrivateFlags |= DRAW_ANIMATION;
3531                        } else if (parent instanceof ViewRoot) {
3532                            ((ViewRoot) parent).mIsAnimating = true;
3533                        }
3534                    }
3535
3536                    if (parent instanceof ViewRoot) {
3537                        ((ViewRoot) parent).invalidate();
3538                        parent = null;
3539                    } else if (view != null) {
3540                        if ((view.mPrivateFlags & DRAWN) == DRAWN ||
3541                                (view.mPrivateFlags & DRAWING_CACHE_VALID) == DRAWING_CACHE_VALID) {
3542                            view.mPrivateFlags &= ~DRAWING_CACHE_VALID;
3543                            view.mPrivateFlags |= DIRTY;
3544                            parent = view.mParent;
3545                        } else {
3546                            parent = null;
3547                        }
3548                    }
3549                } while (parent != null);
3550            } else {
3551                // Check whether the child that requests the invalidate is fully opaque
3552                final boolean isOpaque = child.isOpaque() && !drawAnimation &&
3553                        child.getAnimation() == null;
3554                // Mark the child as dirty, using the appropriate flag
3555                // Make sure we do not set both flags at the same time
3556                int opaqueFlag = isOpaque ? DIRTY_OPAQUE : DIRTY;
3557
3558                if (child.mLayerType != LAYER_TYPE_NONE) {
3559                    mPrivateFlags |= INVALIDATED;
3560                    mPrivateFlags &= ~DRAWING_CACHE_VALID;
3561                    child.mLocalDirtyRect.union(dirty);
3562                }
3563
3564                final int[] location = attachInfo.mInvalidateChildLocation;
3565                location[CHILD_LEFT_INDEX] = child.mLeft;
3566                location[CHILD_TOP_INDEX] = child.mTop;
3567                Matrix childMatrix = child.getMatrix();
3568                if (!childMatrix.isIdentity()) {
3569                    RectF boundingRect = attachInfo.mTmpTransformRect;
3570                    boundingRect.set(dirty);
3571                    childMatrix.mapRect(boundingRect);
3572                    dirty.set((int) boundingRect.left, (int) boundingRect.top,
3573                            (int) (boundingRect.right + 0.5f),
3574                            (int) (boundingRect.bottom + 0.5f));
3575                }
3576
3577                do {
3578                    View view = null;
3579                    if (parent instanceof View) {
3580                        view = (View) parent;
3581                        if (view.mLayerType != LAYER_TYPE_NONE &&
3582                                view.getParent() instanceof View) {
3583                            final View grandParent = (View) view.getParent();
3584                            grandParent.mPrivateFlags |= INVALIDATED;
3585                            grandParent.mPrivateFlags &= ~DRAWING_CACHE_VALID;
3586                        }
3587                    }
3588
3589                    if (drawAnimation) {
3590                        if (view != null) {
3591                            view.mPrivateFlags |= DRAW_ANIMATION;
3592                        } else if (parent instanceof ViewRoot) {
3593                            ((ViewRoot) parent).mIsAnimating = true;
3594                        }
3595                    }
3596
3597                    // If the parent is dirty opaque or not dirty, mark it dirty with the opaque
3598                    // flag coming from the child that initiated the invalidate
3599                    if (view != null) {
3600                        if ((view.mViewFlags & FADING_EDGE_MASK) != 0 &&
3601                                view.getSolidColor() == 0 && !view.isOpaque()) {
3602                            opaqueFlag = DIRTY;
3603                        }
3604                        if ((view.mPrivateFlags & DIRTY_MASK) != DIRTY) {
3605                            view.mPrivateFlags = (view.mPrivateFlags & ~DIRTY_MASK) | opaqueFlag;
3606                        }
3607                    }
3608
3609                    parent = parent.invalidateChildInParent(location, dirty);
3610                    if (view != null) {
3611                        // Account for transform on current parent
3612                        Matrix m = view.getMatrix();
3613                        if (!m.isIdentity()) {
3614                            RectF boundingRect = attachInfo.mTmpTransformRect;
3615                            boundingRect.set(dirty);
3616                            m.mapRect(boundingRect);
3617                            dirty.set((int) boundingRect.left, (int) boundingRect.top,
3618                                    (int) (boundingRect.right + 0.5f),
3619                                    (int) (boundingRect.bottom + 0.5f));
3620                        }
3621                    }
3622                } while (parent != null);
3623            }
3624        }
3625    }
3626
3627    /**
3628     * Don't call or override this method. It is used for the implementation of
3629     * the view hierarchy.
3630     *
3631     * This implementation returns null if this ViewGroup does not have a parent,
3632     * if this ViewGroup is already fully invalidated or if the dirty rectangle
3633     * does not intersect with this ViewGroup's bounds.
3634     */
3635    public ViewParent invalidateChildInParent(final int[] location, final Rect dirty) {
3636        if (ViewDebug.TRACE_HIERARCHY) {
3637            ViewDebug.trace(this, ViewDebug.HierarchyTraceType.INVALIDATE_CHILD_IN_PARENT);
3638        }
3639
3640        if ((mPrivateFlags & DRAWN) == DRAWN ||
3641                (mPrivateFlags & DRAWING_CACHE_VALID) == DRAWING_CACHE_VALID) {
3642            if ((mGroupFlags & (FLAG_OPTIMIZE_INVALIDATE | FLAG_ANIMATION_DONE)) !=
3643                        FLAG_OPTIMIZE_INVALIDATE) {
3644                dirty.offset(location[CHILD_LEFT_INDEX] - mScrollX,
3645                        location[CHILD_TOP_INDEX] - mScrollY);
3646
3647                final int left = mLeft;
3648                final int top = mTop;
3649
3650                if (dirty.intersect(0, 0, mRight - left, mBottom - top) ||
3651                        (mPrivateFlags & DRAW_ANIMATION) == DRAW_ANIMATION) {
3652                    mPrivateFlags &= ~DRAWING_CACHE_VALID;
3653
3654                    location[CHILD_LEFT_INDEX] = left;
3655                    location[CHILD_TOP_INDEX] = top;
3656
3657                    if (mLayerType != LAYER_TYPE_NONE) {
3658                        mLocalDirtyRect.union(dirty);
3659                    }
3660
3661                    return mParent;
3662                }
3663            } else {
3664                mPrivateFlags &= ~DRAWN & ~DRAWING_CACHE_VALID;
3665
3666                location[CHILD_LEFT_INDEX] = mLeft;
3667                location[CHILD_TOP_INDEX] = mTop;
3668
3669                dirty.set(0, 0, mRight - mLeft, mBottom - mTop);
3670
3671                if (mLayerType != LAYER_TYPE_NONE) {
3672                    mLocalDirtyRect.union(dirty);
3673                }
3674
3675                return mParent;
3676            }
3677        }
3678
3679        return null;
3680    }
3681
3682    /**
3683     * Offset a rectangle that is in a descendant's coordinate
3684     * space into our coordinate space.
3685     * @param descendant A descendant of this view
3686     * @param rect A rectangle defined in descendant's coordinate space.
3687     */
3688    public final void offsetDescendantRectToMyCoords(View descendant, Rect rect) {
3689        offsetRectBetweenParentAndChild(descendant, rect, true, false);
3690    }
3691
3692    /**
3693     * Offset a rectangle that is in our coordinate space into an ancestor's
3694     * coordinate space.
3695     * @param descendant A descendant of this view
3696     * @param rect A rectangle defined in descendant's coordinate space.
3697     */
3698    public final void offsetRectIntoDescendantCoords(View descendant, Rect rect) {
3699        offsetRectBetweenParentAndChild(descendant, rect, false, false);
3700    }
3701
3702    /**
3703     * Helper method that offsets a rect either from parent to descendant or
3704     * descendant to parent.
3705     */
3706    void offsetRectBetweenParentAndChild(View descendant, Rect rect,
3707            boolean offsetFromChildToParent, boolean clipToBounds) {
3708
3709        // already in the same coord system :)
3710        if (descendant == this) {
3711            return;
3712        }
3713
3714        ViewParent theParent = descendant.mParent;
3715
3716        // search and offset up to the parent
3717        while ((theParent != null)
3718                && (theParent instanceof View)
3719                && (theParent != this)) {
3720
3721            if (offsetFromChildToParent) {
3722                rect.offset(descendant.mLeft - descendant.mScrollX,
3723                        descendant.mTop - descendant.mScrollY);
3724                if (clipToBounds) {
3725                    View p = (View) theParent;
3726                    rect.intersect(0, 0, p.mRight - p.mLeft, p.mBottom - p.mTop);
3727                }
3728            } else {
3729                if (clipToBounds) {
3730                    View p = (View) theParent;
3731                    rect.intersect(0, 0, p.mRight - p.mLeft, p.mBottom - p.mTop);
3732                }
3733                rect.offset(descendant.mScrollX - descendant.mLeft,
3734                        descendant.mScrollY - descendant.mTop);
3735            }
3736
3737            descendant = (View) theParent;
3738            theParent = descendant.mParent;
3739        }
3740
3741        // now that we are up to this view, need to offset one more time
3742        // to get into our coordinate space
3743        if (theParent == this) {
3744            if (offsetFromChildToParent) {
3745                rect.offset(descendant.mLeft - descendant.mScrollX,
3746                        descendant.mTop - descendant.mScrollY);
3747            } else {
3748                rect.offset(descendant.mScrollX - descendant.mLeft,
3749                        descendant.mScrollY - descendant.mTop);
3750            }
3751        } else {
3752            throw new IllegalArgumentException("parameter must be a descendant of this view");
3753        }
3754    }
3755
3756    /**
3757     * Offset the vertical location of all children of this view by the specified number of pixels.
3758     *
3759     * @param offset the number of pixels to offset
3760     *
3761     * @hide
3762     */
3763    public void offsetChildrenTopAndBottom(int offset) {
3764        final int count = mChildrenCount;
3765        final View[] children = mChildren;
3766
3767        for (int i = 0; i < count; i++) {
3768            final View v = children[i];
3769            v.mTop += offset;
3770            v.mBottom += offset;
3771        }
3772    }
3773
3774    /**
3775     * {@inheritDoc}
3776     */
3777    public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) {
3778        int dx = child.mLeft - mScrollX;
3779        int dy = child.mTop - mScrollY;
3780        if (offset != null) {
3781            offset.x += dx;
3782            offset.y += dy;
3783        }
3784        r.offset(dx, dy);
3785        return r.intersect(0, 0, mRight - mLeft, mBottom - mTop) &&
3786               (mParent == null || mParent.getChildVisibleRect(this, r, offset));
3787    }
3788
3789    /**
3790     * {@inheritDoc}
3791     */
3792    @Override
3793    public final void layout(int l, int t, int r, int b) {
3794        if (mTransition == null || !mTransition.isChangingLayout()) {
3795            super.layout(l, t, r, b);
3796        } else {
3797            // record the fact that we noop'd it; request layout when transition finishes
3798            mLayoutSuppressed = true;
3799        }
3800    }
3801
3802    /**
3803     * {@inheritDoc}
3804     */
3805    @Override
3806    protected abstract void onLayout(boolean changed,
3807            int l, int t, int r, int b);
3808
3809    /**
3810     * Indicates whether the view group has the ability to animate its children
3811     * after the first layout.
3812     *
3813     * @return true if the children can be animated, false otherwise
3814     */
3815    protected boolean canAnimate() {
3816        return mLayoutAnimationController != null;
3817    }
3818
3819    /**
3820     * Runs the layout animation. Calling this method triggers a relayout of
3821     * this view group.
3822     */
3823    public void startLayoutAnimation() {
3824        if (mLayoutAnimationController != null) {
3825            mGroupFlags |= FLAG_RUN_ANIMATION;
3826            requestLayout();
3827        }
3828    }
3829
3830    /**
3831     * Schedules the layout animation to be played after the next layout pass
3832     * of this view group. This can be used to restart the layout animation
3833     * when the content of the view group changes or when the activity is
3834     * paused and resumed.
3835     */
3836    public void scheduleLayoutAnimation() {
3837        mGroupFlags |= FLAG_RUN_ANIMATION;
3838    }
3839
3840    /**
3841     * Sets the layout animation controller used to animate the group's
3842     * children after the first layout.
3843     *
3844     * @param controller the animation controller
3845     */
3846    public void setLayoutAnimation(LayoutAnimationController controller) {
3847        mLayoutAnimationController = controller;
3848        if (mLayoutAnimationController != null) {
3849            mGroupFlags |= FLAG_RUN_ANIMATION;
3850        }
3851    }
3852
3853    /**
3854     * Returns the layout animation controller used to animate the group's
3855     * children.
3856     *
3857     * @return the current animation controller
3858     */
3859    public LayoutAnimationController getLayoutAnimation() {
3860        return mLayoutAnimationController;
3861    }
3862
3863    /**
3864     * Indicates whether the children's drawing cache is used during a layout
3865     * animation. By default, the drawing cache is enabled but this will prevent
3866     * nested layout animations from working. To nest animations, you must disable
3867     * the cache.
3868     *
3869     * @return true if the animation cache is enabled, false otherwise
3870     *
3871     * @see #setAnimationCacheEnabled(boolean)
3872     * @see View#setDrawingCacheEnabled(boolean)
3873     */
3874    @ViewDebug.ExportedProperty
3875    public boolean isAnimationCacheEnabled() {
3876        return (mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE;
3877    }
3878
3879    /**
3880     * Enables or disables the children's drawing cache during a layout animation.
3881     * By default, the drawing cache is enabled but this will prevent nested
3882     * layout animations from working. To nest animations, you must disable the
3883     * cache.
3884     *
3885     * @param enabled true to enable the animation cache, false otherwise
3886     *
3887     * @see #isAnimationCacheEnabled()
3888     * @see View#setDrawingCacheEnabled(boolean)
3889     */
3890    public void setAnimationCacheEnabled(boolean enabled) {
3891        setBooleanFlag(FLAG_ANIMATION_CACHE, enabled);
3892    }
3893
3894    /**
3895     * Indicates whether this ViewGroup will always try to draw its children using their
3896     * drawing cache. By default this property is enabled.
3897     *
3898     * @return true if the animation cache is enabled, false otherwise
3899     *
3900     * @see #setAlwaysDrawnWithCacheEnabled(boolean)
3901     * @see #setChildrenDrawnWithCacheEnabled(boolean)
3902     * @see View#setDrawingCacheEnabled(boolean)
3903     */
3904    @ViewDebug.ExportedProperty(category = "drawing")
3905    public boolean isAlwaysDrawnWithCacheEnabled() {
3906        return (mGroupFlags & FLAG_ALWAYS_DRAWN_WITH_CACHE) == FLAG_ALWAYS_DRAWN_WITH_CACHE;
3907    }
3908
3909    /**
3910     * Indicates whether this ViewGroup will always try to draw its children using their
3911     * drawing cache. This property can be set to true when the cache rendering is
3912     * slightly different from the children's normal rendering. Renderings can be different,
3913     * for instance, when the cache's quality is set to low.
3914     *
3915     * When this property is disabled, the ViewGroup will use the drawing cache of its
3916     * children only when asked to. It's usually the task of subclasses to tell ViewGroup
3917     * when to start using the drawing cache and when to stop using it.
3918     *
3919     * @param always true to always draw with the drawing cache, false otherwise
3920     *
3921     * @see #isAlwaysDrawnWithCacheEnabled()
3922     * @see #setChildrenDrawnWithCacheEnabled(boolean)
3923     * @see View#setDrawingCacheEnabled(boolean)
3924     * @see View#setDrawingCacheQuality(int)
3925     */
3926    public void setAlwaysDrawnWithCacheEnabled(boolean always) {
3927        setBooleanFlag(FLAG_ALWAYS_DRAWN_WITH_CACHE, always);
3928    }
3929
3930    /**
3931     * Indicates whether the ViewGroup is currently drawing its children using
3932     * their drawing cache.
3933     *
3934     * @return true if children should be drawn with their cache, false otherwise
3935     *
3936     * @see #setAlwaysDrawnWithCacheEnabled(boolean)
3937     * @see #setChildrenDrawnWithCacheEnabled(boolean)
3938     */
3939    @ViewDebug.ExportedProperty(category = "drawing")
3940    protected boolean isChildrenDrawnWithCacheEnabled() {
3941        return (mGroupFlags & FLAG_CHILDREN_DRAWN_WITH_CACHE) == FLAG_CHILDREN_DRAWN_WITH_CACHE;
3942    }
3943
3944    /**
3945     * Tells the ViewGroup to draw its children using their drawing cache. This property
3946     * is ignored when {@link #isAlwaysDrawnWithCacheEnabled()} is true. A child's drawing cache
3947     * will be used only if it has been enabled.
3948     *
3949     * Subclasses should call this method to start and stop using the drawing cache when
3950     * they perform performance sensitive operations, like scrolling or animating.
3951     *
3952     * @param enabled true if children should be drawn with their cache, false otherwise
3953     *
3954     * @see #setAlwaysDrawnWithCacheEnabled(boolean)
3955     * @see #isChildrenDrawnWithCacheEnabled()
3956     */
3957    protected void setChildrenDrawnWithCacheEnabled(boolean enabled) {
3958        setBooleanFlag(FLAG_CHILDREN_DRAWN_WITH_CACHE, enabled);
3959    }
3960
3961    /**
3962     * Indicates whether the ViewGroup is drawing its children in the order defined by
3963     * {@link #getChildDrawingOrder(int, int)}.
3964     *
3965     * @return true if children drawing order is defined by {@link #getChildDrawingOrder(int, int)},
3966     *         false otherwise
3967     *
3968     * @see #setChildrenDrawingOrderEnabled(boolean)
3969     * @see #getChildDrawingOrder(int, int)
3970     */
3971    @ViewDebug.ExportedProperty(category = "drawing")
3972    protected boolean isChildrenDrawingOrderEnabled() {
3973        return (mGroupFlags & FLAG_USE_CHILD_DRAWING_ORDER) == FLAG_USE_CHILD_DRAWING_ORDER;
3974    }
3975
3976    /**
3977     * Tells the ViewGroup whether to draw its children in the order defined by the method
3978     * {@link #getChildDrawingOrder(int, int)}.
3979     *
3980     * @param enabled true if the order of the children when drawing is determined by
3981     *        {@link #getChildDrawingOrder(int, int)}, false otherwise
3982     *
3983     * @see #isChildrenDrawingOrderEnabled()
3984     * @see #getChildDrawingOrder(int, int)
3985     */
3986    protected void setChildrenDrawingOrderEnabled(boolean enabled) {
3987        setBooleanFlag(FLAG_USE_CHILD_DRAWING_ORDER, enabled);
3988    }
3989
3990    private void setBooleanFlag(int flag, boolean value) {
3991        if (value) {
3992            mGroupFlags |= flag;
3993        } else {
3994            mGroupFlags &= ~flag;
3995        }
3996    }
3997
3998    /**
3999     * Returns an integer indicating what types of drawing caches are kept in memory.
4000     *
4001     * @see #setPersistentDrawingCache(int)
4002     * @see #setAnimationCacheEnabled(boolean)
4003     *
4004     * @return one or a combination of {@link #PERSISTENT_NO_CACHE},
4005     *         {@link #PERSISTENT_ANIMATION_CACHE}, {@link #PERSISTENT_SCROLLING_CACHE}
4006     *         and {@link #PERSISTENT_ALL_CACHES}
4007     */
4008    @ViewDebug.ExportedProperty(category = "drawing", mapping = {
4009        @ViewDebug.IntToString(from = PERSISTENT_NO_CACHE,        to = "NONE"),
4010        @ViewDebug.IntToString(from = PERSISTENT_ANIMATION_CACHE, to = "ANIMATION"),
4011        @ViewDebug.IntToString(from = PERSISTENT_SCROLLING_CACHE, to = "SCROLLING"),
4012        @ViewDebug.IntToString(from = PERSISTENT_ALL_CACHES,      to = "ALL")
4013    })
4014    public int getPersistentDrawingCache() {
4015        return mPersistentDrawingCache;
4016    }
4017
4018    /**
4019     * Indicates what types of drawing caches should be kept in memory after
4020     * they have been created.
4021     *
4022     * @see #getPersistentDrawingCache()
4023     * @see #setAnimationCacheEnabled(boolean)
4024     *
4025     * @param drawingCacheToKeep one or a combination of {@link #PERSISTENT_NO_CACHE},
4026     *        {@link #PERSISTENT_ANIMATION_CACHE}, {@link #PERSISTENT_SCROLLING_CACHE}
4027     *        and {@link #PERSISTENT_ALL_CACHES}
4028     */
4029    public void setPersistentDrawingCache(int drawingCacheToKeep) {
4030        mPersistentDrawingCache = drawingCacheToKeep & PERSISTENT_ALL_CACHES;
4031    }
4032
4033    /**
4034     * Returns a new set of layout parameters based on the supplied attributes set.
4035     *
4036     * @param attrs the attributes to build the layout parameters from
4037     *
4038     * @return an instance of {@link android.view.ViewGroup.LayoutParams} or one
4039     *         of its descendants
4040     */
4041    public LayoutParams generateLayoutParams(AttributeSet attrs) {
4042        return new LayoutParams(getContext(), attrs);
4043    }
4044
4045    /**
4046     * Returns a safe set of layout parameters based on the supplied layout params.
4047     * When a ViewGroup is passed a View whose layout params do not pass the test of
4048     * {@link #checkLayoutParams(android.view.ViewGroup.LayoutParams)}, this method
4049     * is invoked. This method should return a new set of layout params suitable for
4050     * this ViewGroup, possibly by copying the appropriate attributes from the
4051     * specified set of layout params.
4052     *
4053     * @param p The layout parameters to convert into a suitable set of layout parameters
4054     *          for this ViewGroup.
4055     *
4056     * @return an instance of {@link android.view.ViewGroup.LayoutParams} or one
4057     *         of its descendants
4058     */
4059    protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
4060        return p;
4061    }
4062
4063    /**
4064     * Returns a set of default layout parameters. These parameters are requested
4065     * when the View passed to {@link #addView(View)} has no layout parameters
4066     * already set. If null is returned, an exception is thrown from addView.
4067     *
4068     * @return a set of default layout parameters or null
4069     */
4070    protected LayoutParams generateDefaultLayoutParams() {
4071        return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
4072    }
4073
4074    /**
4075     * @hide
4076     */
4077    @Override
4078    protected boolean dispatchConsistencyCheck(int consistency) {
4079        boolean result = super.dispatchConsistencyCheck(consistency);
4080
4081        final int count = mChildrenCount;
4082        final View[] children = mChildren;
4083        for (int i = 0; i < count; i++) {
4084            if (!children[i].dispatchConsistencyCheck(consistency)) result = false;
4085        }
4086
4087        return result;
4088    }
4089
4090    /**
4091     * @hide
4092     */
4093    @Override
4094    protected boolean onConsistencyCheck(int consistency) {
4095        boolean result = super.onConsistencyCheck(consistency);
4096
4097        final boolean checkLayout = (consistency & ViewDebug.CONSISTENCY_LAYOUT) != 0;
4098        final boolean checkDrawing = (consistency & ViewDebug.CONSISTENCY_DRAWING) != 0;
4099
4100        if (checkLayout) {
4101            final int count = mChildrenCount;
4102            final View[] children = mChildren;
4103            for (int i = 0; i < count; i++) {
4104                if (children[i].getParent() != this) {
4105                    result = false;
4106                    android.util.Log.d(ViewDebug.CONSISTENCY_LOG_TAG,
4107                            "View " + children[i] + " has no parent/a parent that is not " + this);
4108                }
4109            }
4110        }
4111
4112        if (checkDrawing) {
4113            // If this group is dirty, check that the parent is dirty as well
4114            if ((mPrivateFlags & DIRTY_MASK) != 0) {
4115                final ViewParent parent = getParent();
4116                if (parent != null && !(parent instanceof ViewRoot)) {
4117                    if ((((View) parent).mPrivateFlags & DIRTY_MASK) == 0) {
4118                        result = false;
4119                        android.util.Log.d(ViewDebug.CONSISTENCY_LOG_TAG,
4120                                "ViewGroup " + this + " is dirty but its parent is not: " + this);
4121                    }
4122                }
4123            }
4124        }
4125
4126        return result;
4127    }
4128
4129    /**
4130     * {@inheritDoc}
4131     */
4132    @Override
4133    protected void debug(int depth) {
4134        super.debug(depth);
4135        String output;
4136
4137        if (mFocused != null) {
4138            output = debugIndent(depth);
4139            output += "mFocused";
4140            Log.d(VIEW_LOG_TAG, output);
4141        }
4142        if (mChildrenCount != 0) {
4143            output = debugIndent(depth);
4144            output += "{";
4145            Log.d(VIEW_LOG_TAG, output);
4146        }
4147        int count = mChildrenCount;
4148        for (int i = 0; i < count; i++) {
4149            View child = mChildren[i];
4150            child.debug(depth + 1);
4151        }
4152
4153        if (mChildrenCount != 0) {
4154            output = debugIndent(depth);
4155            output += "}";
4156            Log.d(VIEW_LOG_TAG, output);
4157        }
4158    }
4159
4160    /**
4161     * Returns the position in the group of the specified child view.
4162     *
4163     * @param child the view for which to get the position
4164     * @return a positive integer representing the position of the view in the
4165     *         group, or -1 if the view does not exist in the group
4166     */
4167    public int indexOfChild(View child) {
4168        final int count = mChildrenCount;
4169        final View[] children = mChildren;
4170        for (int i = 0; i < count; i++) {
4171            if (children[i] == child) {
4172                return i;
4173            }
4174        }
4175        return -1;
4176    }
4177
4178    /**
4179     * Returns the number of children in the group.
4180     *
4181     * @return a positive integer representing the number of children in
4182     *         the group
4183     */
4184    public int getChildCount() {
4185        return mChildrenCount;
4186    }
4187
4188    /**
4189     * Returns the view at the specified position in the group.
4190     *
4191     * @param index the position at which to get the view from
4192     * @return the view at the specified position or null if the position
4193     *         does not exist within the group
4194     */
4195    public View getChildAt(int index) {
4196        try {
4197            return mChildren[index];
4198        } catch (IndexOutOfBoundsException ex) {
4199            return null;
4200        }
4201    }
4202
4203    /**
4204     * Ask all of the children of this view to measure themselves, taking into
4205     * account both the MeasureSpec requirements for this view and its padding.
4206     * We skip children that are in the GONE state The heavy lifting is done in
4207     * getChildMeasureSpec.
4208     *
4209     * @param widthMeasureSpec The width requirements for this view
4210     * @param heightMeasureSpec The height requirements for this view
4211     */
4212    protected void measureChildren(int widthMeasureSpec, int heightMeasureSpec) {
4213        final int size = mChildrenCount;
4214        final View[] children = mChildren;
4215        for (int i = 0; i < size; ++i) {
4216            final View child = children[i];
4217            if ((child.mViewFlags & VISIBILITY_MASK) != GONE) {
4218                measureChild(child, widthMeasureSpec, heightMeasureSpec);
4219            }
4220        }
4221    }
4222
4223    /**
4224     * Ask one of the children of this view to measure itself, taking into
4225     * account both the MeasureSpec requirements for this view and its padding.
4226     * The heavy lifting is done in getChildMeasureSpec.
4227     *
4228     * @param child The child to measure
4229     * @param parentWidthMeasureSpec The width requirements for this view
4230     * @param parentHeightMeasureSpec The height requirements for this view
4231     */
4232    protected void measureChild(View child, int parentWidthMeasureSpec,
4233            int parentHeightMeasureSpec) {
4234        final LayoutParams lp = child.getLayoutParams();
4235
4236        final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
4237                mPaddingLeft + mPaddingRight, lp.width);
4238        final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
4239                mPaddingTop + mPaddingBottom, lp.height);
4240
4241        child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
4242    }
4243
4244    /**
4245     * Ask one of the children of this view to measure itself, taking into
4246     * account both the MeasureSpec requirements for this view and its padding
4247     * and margins. The child must have MarginLayoutParams The heavy lifting is
4248     * done in getChildMeasureSpec.
4249     *
4250     * @param child The child to measure
4251     * @param parentWidthMeasureSpec The width requirements for this view
4252     * @param widthUsed Extra space that has been used up by the parent
4253     *        horizontally (possibly by other children of the parent)
4254     * @param parentHeightMeasureSpec The height requirements for this view
4255     * @param heightUsed Extra space that has been used up by the parent
4256     *        vertically (possibly by other children of the parent)
4257     */
4258    protected void measureChildWithMargins(View child,
4259            int parentWidthMeasureSpec, int widthUsed,
4260            int parentHeightMeasureSpec, int heightUsed) {
4261        final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
4262
4263        final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
4264                mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin
4265                        + widthUsed, lp.width);
4266        final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
4267                mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin
4268                        + heightUsed, lp.height);
4269
4270        child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
4271    }
4272
4273    /**
4274     * Does the hard part of measureChildren: figuring out the MeasureSpec to
4275     * pass to a particular child. This method figures out the right MeasureSpec
4276     * for one dimension (height or width) of one child view.
4277     *
4278     * The goal is to combine information from our MeasureSpec with the
4279     * LayoutParams of the child to get the best possible results. For example,
4280     * if the this view knows its size (because its MeasureSpec has a mode of
4281     * EXACTLY), and the child has indicated in its LayoutParams that it wants
4282     * to be the same size as the parent, the parent should ask the child to
4283     * layout given an exact size.
4284     *
4285     * @param spec The requirements for this view
4286     * @param padding The padding of this view for the current dimension and
4287     *        margins, if applicable
4288     * @param childDimension How big the child wants to be in the current
4289     *        dimension
4290     * @return a MeasureSpec integer for the child
4291     */
4292    public static int getChildMeasureSpec(int spec, int padding, int childDimension) {
4293        int specMode = MeasureSpec.getMode(spec);
4294        int specSize = MeasureSpec.getSize(spec);
4295
4296        int size = Math.max(0, specSize - padding);
4297
4298        int resultSize = 0;
4299        int resultMode = 0;
4300
4301        switch (specMode) {
4302        // Parent has imposed an exact size on us
4303        case MeasureSpec.EXACTLY:
4304            if (childDimension >= 0) {
4305                resultSize = childDimension;
4306                resultMode = MeasureSpec.EXACTLY;
4307            } else if (childDimension == LayoutParams.MATCH_PARENT) {
4308                // Child wants to be our size. So be it.
4309                resultSize = size;
4310                resultMode = MeasureSpec.EXACTLY;
4311            } else if (childDimension == LayoutParams.WRAP_CONTENT) {
4312                // Child wants to determine its own size. It can't be
4313                // bigger than us.
4314                resultSize = size;
4315                resultMode = MeasureSpec.AT_MOST;
4316            }
4317            break;
4318
4319        // Parent has imposed a maximum size on us
4320        case MeasureSpec.AT_MOST:
4321            if (childDimension >= 0) {
4322                // Child wants a specific size... so be it
4323                resultSize = childDimension;
4324                resultMode = MeasureSpec.EXACTLY;
4325            } else if (childDimension == LayoutParams.MATCH_PARENT) {
4326                // Child wants to be our size, but our size is not fixed.
4327                // Constrain child to not be bigger than us.
4328                resultSize = size;
4329                resultMode = MeasureSpec.AT_MOST;
4330            } else if (childDimension == LayoutParams.WRAP_CONTENT) {
4331                // Child wants to determine its own size. It can't be
4332                // bigger than us.
4333                resultSize = size;
4334                resultMode = MeasureSpec.AT_MOST;
4335            }
4336            break;
4337
4338        // Parent asked to see how big we want to be
4339        case MeasureSpec.UNSPECIFIED:
4340            if (childDimension >= 0) {
4341                // Child wants a specific size... let him have it
4342                resultSize = childDimension;
4343                resultMode = MeasureSpec.EXACTLY;
4344            } else if (childDimension == LayoutParams.MATCH_PARENT) {
4345                // Child wants to be our size... find out how big it should
4346                // be
4347                resultSize = 0;
4348                resultMode = MeasureSpec.UNSPECIFIED;
4349            } else if (childDimension == LayoutParams.WRAP_CONTENT) {
4350                // Child wants to determine its own size.... find out how
4351                // big it should be
4352                resultSize = 0;
4353                resultMode = MeasureSpec.UNSPECIFIED;
4354            }
4355            break;
4356        }
4357        return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
4358    }
4359
4360
4361    /**
4362     * Removes any pending animations for views that have been removed. Call
4363     * this if you don't want animations for exiting views to stack up.
4364     */
4365    public void clearDisappearingChildren() {
4366        if (mDisappearingChildren != null) {
4367            mDisappearingChildren.clear();
4368        }
4369    }
4370
4371    /**
4372     * Add a view which is removed from mChildren but still needs animation
4373     *
4374     * @param v View to add
4375     */
4376    private void addDisappearingView(View v) {
4377        ArrayList<View> disappearingChildren = mDisappearingChildren;
4378
4379        if (disappearingChildren == null) {
4380            disappearingChildren = mDisappearingChildren = new ArrayList<View>();
4381        }
4382
4383        disappearingChildren.add(v);
4384    }
4385
4386    /**
4387     * Cleanup a view when its animation is done. This may mean removing it from
4388     * the list of disappearing views.
4389     *
4390     * @param view The view whose animation has finished
4391     * @param animation The animation, cannot be null
4392     */
4393    private void finishAnimatingView(final View view, Animation animation) {
4394        final ArrayList<View> disappearingChildren = mDisappearingChildren;
4395        if (disappearingChildren != null) {
4396            if (disappearingChildren.contains(view)) {
4397                disappearingChildren.remove(view);
4398
4399                if (view.mAttachInfo != null) {
4400                    view.dispatchDetachedFromWindow();
4401                }
4402
4403                view.clearAnimation();
4404                mGroupFlags |= FLAG_INVALIDATE_REQUIRED;
4405            }
4406        }
4407
4408        if (animation != null && !animation.getFillAfter()) {
4409            view.clearAnimation();
4410        }
4411
4412        if ((view.mPrivateFlags & ANIMATION_STARTED) == ANIMATION_STARTED) {
4413            view.onAnimationEnd();
4414            // Should be performed by onAnimationEnd() but this avoid an infinite loop,
4415            // so we'd rather be safe than sorry
4416            view.mPrivateFlags &= ~ANIMATION_STARTED;
4417            // Draw one more frame after the animation is done
4418            mGroupFlags |= FLAG_INVALIDATE_REQUIRED;
4419        }
4420    }
4421
4422    /**
4423     * This method tells the ViewGroup that the given View object, which should have this
4424     * ViewGroup as its parent,
4425     * should be kept around  (re-displayed when the ViewGroup draws its children) even if it
4426     * is removed from its parent. This allows animations, such as those used by
4427     * {@link android.app.Fragment} and {@link android.animation.LayoutTransition} to animate
4428     * the removal of views. A call to this method should always be accompanied by a later call
4429     * to {@link #endViewTransition(View)}, such as after an animation on the View has finished,
4430     * so that the View finally gets removed.
4431     *
4432     * @param view The View object to be kept visible even if it gets removed from its parent.
4433     */
4434    public void startViewTransition(View view) {
4435        if (view.mParent == this) {
4436            if (mTransitioningViews == null) {
4437                mTransitioningViews = new ArrayList<View>();
4438            }
4439            mTransitioningViews.add(view);
4440        }
4441    }
4442
4443    /**
4444     * This method should always be called following an earlier call to
4445     * {@link #startViewTransition(View)}. The given View is finally removed from its parent
4446     * and will no longer be displayed. Note that this method does not perform the functionality
4447     * of removing a view from its parent; it just discontinues the display of a View that
4448     * has previously been removed.
4449     *
4450     * @return view The View object that has been removed but is being kept around in the visible
4451     * hierarchy by an earlier call to {@link #startViewTransition(View)}.
4452     */
4453    public void endViewTransition(View view) {
4454        if (mTransitioningViews != null) {
4455            mTransitioningViews.remove(view);
4456            final ArrayList<View> disappearingChildren = mDisappearingChildren;
4457            if (disappearingChildren != null && disappearingChildren.contains(view)) {
4458                disappearingChildren.remove(view);
4459                if (mVisibilityChangingChildren != null &&
4460                        mVisibilityChangingChildren.contains(view)) {
4461                    mVisibilityChangingChildren.remove(view);
4462                } else {
4463                    if (view.mAttachInfo != null) {
4464                        view.dispatchDetachedFromWindow();
4465                    }
4466                    if (view.mParent != null) {
4467                        view.mParent = null;
4468                    }
4469                }
4470                mGroupFlags |= FLAG_INVALIDATE_REQUIRED;
4471            }
4472        }
4473    }
4474
4475    private LayoutTransition.TransitionListener mLayoutTransitionListener =
4476            new LayoutTransition.TransitionListener() {
4477        @Override
4478        public void startTransition(LayoutTransition transition, ViewGroup container,
4479                View view, int transitionType) {
4480            // We only care about disappearing items, since we need special logic to keep
4481            // those items visible after they've been 'removed'
4482            if (transitionType == LayoutTransition.DISAPPEARING) {
4483                startViewTransition(view);
4484            }
4485        }
4486
4487        @Override
4488        public void endTransition(LayoutTransition transition, ViewGroup container,
4489                View view, int transitionType) {
4490            if (mLayoutSuppressed && !transition.isChangingLayout()) {
4491                requestLayout();
4492                mLayoutSuppressed = false;
4493            }
4494            if (transitionType == LayoutTransition.DISAPPEARING && mTransitioningViews != null) {
4495                endViewTransition(view);
4496            }
4497        }
4498    };
4499
4500    /**
4501     * {@inheritDoc}
4502     */
4503    @Override
4504    public boolean gatherTransparentRegion(Region region) {
4505        // If no transparent regions requested, we are always opaque.
4506        final boolean meOpaque = (mPrivateFlags & View.REQUEST_TRANSPARENT_REGIONS) == 0;
4507        if (meOpaque && region == null) {
4508            // The caller doesn't care about the region, so stop now.
4509            return true;
4510        }
4511        super.gatherTransparentRegion(region);
4512        final View[] children = mChildren;
4513        final int count = mChildrenCount;
4514        boolean noneOfTheChildrenAreTransparent = true;
4515        for (int i = 0; i < count; i++) {
4516            final View child = children[i];
4517            if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
4518                if (!child.gatherTransparentRegion(region)) {
4519                    noneOfTheChildrenAreTransparent = false;
4520                }
4521            }
4522        }
4523        return meOpaque || noneOfTheChildrenAreTransparent;
4524    }
4525
4526    /**
4527     * {@inheritDoc}
4528     */
4529    public void requestTransparentRegion(View child) {
4530        if (child != null) {
4531            child.mPrivateFlags |= View.REQUEST_TRANSPARENT_REGIONS;
4532            if (mParent != null) {
4533                mParent.requestTransparentRegion(this);
4534            }
4535        }
4536    }
4537
4538
4539    @Override
4540    protected boolean fitSystemWindows(Rect insets) {
4541        boolean done = super.fitSystemWindows(insets);
4542        if (!done) {
4543            final int count = mChildrenCount;
4544            final View[] children = mChildren;
4545            for (int i = 0; i < count; i++) {
4546                done = children[i].fitSystemWindows(insets);
4547                if (done) {
4548                    break;
4549                }
4550            }
4551        }
4552        return done;
4553    }
4554
4555    /**
4556     * Returns the animation listener to which layout animation events are
4557     * sent.
4558     *
4559     * @return an {@link android.view.animation.Animation.AnimationListener}
4560     */
4561    public Animation.AnimationListener getLayoutAnimationListener() {
4562        return mAnimationListener;
4563    }
4564
4565    @Override
4566    protected void drawableStateChanged() {
4567        super.drawableStateChanged();
4568
4569        if ((mGroupFlags & FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE) != 0) {
4570            if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0) {
4571                throw new IllegalStateException("addStateFromChildren cannot be enabled if a"
4572                        + " child has duplicateParentState set to true");
4573            }
4574
4575            final View[] children = mChildren;
4576            final int count = mChildrenCount;
4577
4578            for (int i = 0; i < count; i++) {
4579                final View child = children[i];
4580                if ((child.mViewFlags & DUPLICATE_PARENT_STATE) != 0) {
4581                    child.refreshDrawableState();
4582                }
4583            }
4584        }
4585    }
4586
4587    @Override
4588    public void jumpDrawablesToCurrentState() {
4589        super.jumpDrawablesToCurrentState();
4590        final View[] children = mChildren;
4591        final int count = mChildrenCount;
4592        for (int i = 0; i < count; i++) {
4593            children[i].jumpDrawablesToCurrentState();
4594        }
4595    }
4596
4597    @Override
4598    protected int[] onCreateDrawableState(int extraSpace) {
4599        if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) == 0) {
4600            return super.onCreateDrawableState(extraSpace);
4601        }
4602
4603        int need = 0;
4604        int n = getChildCount();
4605        for (int i = 0; i < n; i++) {
4606            int[] childState = getChildAt(i).getDrawableState();
4607
4608            if (childState != null) {
4609                need += childState.length;
4610            }
4611        }
4612
4613        int[] state = super.onCreateDrawableState(extraSpace + need);
4614
4615        for (int i = 0; i < n; i++) {
4616            int[] childState = getChildAt(i).getDrawableState();
4617
4618            if (childState != null) {
4619                state = mergeDrawableStates(state, childState);
4620            }
4621        }
4622
4623        return state;
4624    }
4625
4626    /**
4627     * Sets whether this ViewGroup's drawable states also include
4628     * its children's drawable states.  This is used, for example, to
4629     * make a group appear to be focused when its child EditText or button
4630     * is focused.
4631     */
4632    public void setAddStatesFromChildren(boolean addsStates) {
4633        if (addsStates) {
4634            mGroupFlags |= FLAG_ADD_STATES_FROM_CHILDREN;
4635        } else {
4636            mGroupFlags &= ~FLAG_ADD_STATES_FROM_CHILDREN;
4637        }
4638
4639        refreshDrawableState();
4640    }
4641
4642    /**
4643     * Returns whether this ViewGroup's drawable states also include
4644     * its children's drawable states.  This is used, for example, to
4645     * make a group appear to be focused when its child EditText or button
4646     * is focused.
4647     */
4648    public boolean addStatesFromChildren() {
4649        return (mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0;
4650    }
4651
4652    /**
4653     * If {link #addStatesFromChildren} is true, refreshes this group's
4654     * drawable state (to include the states from its children).
4655     */
4656    public void childDrawableStateChanged(View child) {
4657        if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0) {
4658            refreshDrawableState();
4659        }
4660    }
4661
4662    /**
4663     * Specifies the animation listener to which layout animation events must
4664     * be sent. Only
4665     * {@link android.view.animation.Animation.AnimationListener#onAnimationStart(Animation)}
4666     * and
4667     * {@link android.view.animation.Animation.AnimationListener#onAnimationEnd(Animation)}
4668     * are invoked.
4669     *
4670     * @param animationListener the layout animation listener
4671     */
4672    public void setLayoutAnimationListener(Animation.AnimationListener animationListener) {
4673        mAnimationListener = animationListener;
4674    }
4675
4676    /**
4677     * LayoutParams are used by views to tell their parents how they want to be
4678     * laid out. See
4679     * {@link android.R.styleable#ViewGroup_Layout ViewGroup Layout Attributes}
4680     * for a list of all child view attributes that this class supports.
4681     *
4682     * <p>
4683     * The base LayoutParams class just describes how big the view wants to be
4684     * for both width and height. For each dimension, it can specify one of:
4685     * <ul>
4686     * <li>FILL_PARENT (renamed MATCH_PARENT in API Level 8 and higher), which
4687     * means that the view wants to be as big as its parent (minus padding)
4688     * <li> WRAP_CONTENT, which means that the view wants to be just big enough
4689     * to enclose its content (plus padding)
4690     * <li> an exact number
4691     * </ul>
4692     * There are subclasses of LayoutParams for different subclasses of
4693     * ViewGroup. For example, AbsoluteLayout has its own subclass of
4694     * LayoutParams which adds an X and Y value.
4695     *
4696     * @attr ref android.R.styleable#ViewGroup_Layout_layout_height
4697     * @attr ref android.R.styleable#ViewGroup_Layout_layout_width
4698     */
4699    public static class LayoutParams {
4700        /**
4701         * Special value for the height or width requested by a View.
4702         * FILL_PARENT means that the view wants to be as big as its parent,
4703         * minus the parent's padding, if any. This value is deprecated
4704         * starting in API Level 8 and replaced by {@link #MATCH_PARENT}.
4705         */
4706        @SuppressWarnings({"UnusedDeclaration"})
4707        @Deprecated
4708        public static final int FILL_PARENT = -1;
4709
4710        /**
4711         * Special value for the height or width requested by a View.
4712         * MATCH_PARENT means that the view wants to be as big as its parent,
4713         * minus the parent's padding, if any. Introduced in API Level 8.
4714         */
4715        public static final int MATCH_PARENT = -1;
4716
4717        /**
4718         * Special value for the height or width requested by a View.
4719         * WRAP_CONTENT means that the view wants to be just large enough to fit
4720         * its own internal content, taking its own padding into account.
4721         */
4722        public static final int WRAP_CONTENT = -2;
4723
4724        /**
4725         * Information about how wide the view wants to be. Can be one of the
4726         * constants FILL_PARENT (replaced by MATCH_PARENT ,
4727         * in API Level 8) or WRAP_CONTENT. or an exact size.
4728         */
4729        @ViewDebug.ExportedProperty(category = "layout", mapping = {
4730            @ViewDebug.IntToString(from = MATCH_PARENT, to = "MATCH_PARENT"),
4731            @ViewDebug.IntToString(from = WRAP_CONTENT, to = "WRAP_CONTENT")
4732        })
4733        public int width;
4734
4735        /**
4736         * Information about how tall the view wants to be. Can be one of the
4737         * constants FILL_PARENT (replaced by MATCH_PARENT ,
4738         * in API Level 8) or WRAP_CONTENT. or an exact size.
4739         */
4740        @ViewDebug.ExportedProperty(category = "layout", mapping = {
4741            @ViewDebug.IntToString(from = MATCH_PARENT, to = "MATCH_PARENT"),
4742            @ViewDebug.IntToString(from = WRAP_CONTENT, to = "WRAP_CONTENT")
4743        })
4744        public int height;
4745
4746        /**
4747         * Used to animate layouts.
4748         */
4749        public LayoutAnimationController.AnimationParameters layoutAnimationParameters;
4750
4751        /**
4752         * Creates a new set of layout parameters. The values are extracted from
4753         * the supplied attributes set and context. The XML attributes mapped
4754         * to this set of layout parameters are:
4755         *
4756         * <ul>
4757         *   <li><code>layout_width</code>: the width, either an exact value,
4758         *   {@link #WRAP_CONTENT}, or {@link #FILL_PARENT} (replaced by
4759         *   {@link #MATCH_PARENT} in API Level 8)</li>
4760         *   <li><code>layout_height</code>: the height, either an exact value,
4761         *   {@link #WRAP_CONTENT}, or {@link #FILL_PARENT} (replaced by
4762         *   {@link #MATCH_PARENT} in API Level 8)</li>
4763         * </ul>
4764         *
4765         * @param c the application environment
4766         * @param attrs the set of attributes from which to extract the layout
4767         *              parameters' values
4768         */
4769        public LayoutParams(Context c, AttributeSet attrs) {
4770            TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.ViewGroup_Layout);
4771            setBaseAttributes(a,
4772                    R.styleable.ViewGroup_Layout_layout_width,
4773                    R.styleable.ViewGroup_Layout_layout_height);
4774            a.recycle();
4775        }
4776
4777        /**
4778         * Creates a new set of layout parameters with the specified width
4779         * and height.
4780         *
4781         * @param width the width, either {@link #WRAP_CONTENT},
4782         *        {@link #FILL_PARENT} (replaced by {@link #MATCH_PARENT} in
4783         *        API Level 8), or a fixed size in pixels
4784         * @param height the height, either {@link #WRAP_CONTENT},
4785         *        {@link #FILL_PARENT} (replaced by {@link #MATCH_PARENT} in
4786         *        API Level 8), or a fixed size in pixels
4787         */
4788        public LayoutParams(int width, int height) {
4789            this.width = width;
4790            this.height = height;
4791        }
4792
4793        /**
4794         * Copy constructor. Clones the width and height values of the source.
4795         *
4796         * @param source The layout params to copy from.
4797         */
4798        public LayoutParams(LayoutParams source) {
4799            this.width = source.width;
4800            this.height = source.height;
4801        }
4802
4803        /**
4804         * Used internally by MarginLayoutParams.
4805         * @hide
4806         */
4807        LayoutParams() {
4808        }
4809
4810        /**
4811         * Extracts the layout parameters from the supplied attributes.
4812         *
4813         * @param a the style attributes to extract the parameters from
4814         * @param widthAttr the identifier of the width attribute
4815         * @param heightAttr the identifier of the height attribute
4816         */
4817        protected void setBaseAttributes(TypedArray a, int widthAttr, int heightAttr) {
4818            width = a.getLayoutDimension(widthAttr, "layout_width");
4819            height = a.getLayoutDimension(heightAttr, "layout_height");
4820        }
4821
4822        /**
4823         * Returns a String representation of this set of layout parameters.
4824         *
4825         * @param output the String to prepend to the internal representation
4826         * @return a String with the following format: output +
4827         *         "ViewGroup.LayoutParams={ width=WIDTH, height=HEIGHT }"
4828         *
4829         * @hide
4830         */
4831        public String debug(String output) {
4832            return output + "ViewGroup.LayoutParams={ width="
4833                    + sizeToString(width) + ", height=" + sizeToString(height) + " }";
4834        }
4835
4836        /**
4837         * Converts the specified size to a readable String.
4838         *
4839         * @param size the size to convert
4840         * @return a String instance representing the supplied size
4841         *
4842         * @hide
4843         */
4844        protected static String sizeToString(int size) {
4845            if (size == WRAP_CONTENT) {
4846                return "wrap-content";
4847            }
4848            if (size == MATCH_PARENT) {
4849                return "match-parent";
4850            }
4851            return String.valueOf(size);
4852        }
4853    }
4854
4855    /**
4856     * Per-child layout information for layouts that support margins.
4857     * See
4858     * {@link android.R.styleable#ViewGroup_MarginLayout ViewGroup Margin Layout Attributes}
4859     * for a list of all child view attributes that this class supports.
4860     */
4861    public static class MarginLayoutParams extends ViewGroup.LayoutParams {
4862        /**
4863         * The left margin in pixels of the child.
4864         */
4865        @ViewDebug.ExportedProperty(category = "layout")
4866        public int leftMargin;
4867
4868        /**
4869         * The top margin in pixels of the child.
4870         */
4871        @ViewDebug.ExportedProperty(category = "layout")
4872        public int topMargin;
4873
4874        /**
4875         * The right margin in pixels of the child.
4876         */
4877        @ViewDebug.ExportedProperty(category = "layout")
4878        public int rightMargin;
4879
4880        /**
4881         * The bottom margin in pixels of the child.
4882         */
4883        @ViewDebug.ExportedProperty(category = "layout")
4884        public int bottomMargin;
4885
4886        /**
4887         * Creates a new set of layout parameters. The values are extracted from
4888         * the supplied attributes set and context.
4889         *
4890         * @param c the application environment
4891         * @param attrs the set of attributes from which to extract the layout
4892         *              parameters' values
4893         */
4894        public MarginLayoutParams(Context c, AttributeSet attrs) {
4895            super();
4896
4897            TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.ViewGroup_MarginLayout);
4898            setBaseAttributes(a,
4899                    R.styleable.ViewGroup_MarginLayout_layout_width,
4900                    R.styleable.ViewGroup_MarginLayout_layout_height);
4901
4902            int margin = a.getDimensionPixelSize(
4903                    com.android.internal.R.styleable.ViewGroup_MarginLayout_layout_margin, -1);
4904            if (margin >= 0) {
4905                leftMargin = margin;
4906                topMargin = margin;
4907                rightMargin= margin;
4908                bottomMargin = margin;
4909            } else {
4910                leftMargin = a.getDimensionPixelSize(
4911                        R.styleable.ViewGroup_MarginLayout_layout_marginLeft, 0);
4912                topMargin = a.getDimensionPixelSize(
4913                        R.styleable.ViewGroup_MarginLayout_layout_marginTop, 0);
4914                rightMargin = a.getDimensionPixelSize(
4915                        R.styleable.ViewGroup_MarginLayout_layout_marginRight, 0);
4916                bottomMargin = a.getDimensionPixelSize(
4917                        R.styleable.ViewGroup_MarginLayout_layout_marginBottom, 0);
4918            }
4919
4920            a.recycle();
4921        }
4922
4923        /**
4924         * {@inheritDoc}
4925         */
4926        public MarginLayoutParams(int width, int height) {
4927            super(width, height);
4928        }
4929
4930        /**
4931         * Copy constructor. Clones the width, height and margin values of the source.
4932         *
4933         * @param source The layout params to copy from.
4934         */
4935        public MarginLayoutParams(MarginLayoutParams source) {
4936            this.width = source.width;
4937            this.height = source.height;
4938
4939            this.leftMargin = source.leftMargin;
4940            this.topMargin = source.topMargin;
4941            this.rightMargin = source.rightMargin;
4942            this.bottomMargin = source.bottomMargin;
4943        }
4944
4945        /**
4946         * {@inheritDoc}
4947         */
4948        public MarginLayoutParams(LayoutParams source) {
4949            super(source);
4950        }
4951
4952        /**
4953         * Sets the margins, in pixels.
4954         *
4955         * @param left the left margin size
4956         * @param top the top margin size
4957         * @param right the right margin size
4958         * @param bottom the bottom margin size
4959         *
4960         * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginLeft
4961         * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginTop
4962         * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginRight
4963         * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginBottom
4964         */
4965        public void setMargins(int left, int top, int right, int bottom) {
4966            leftMargin = left;
4967            topMargin = top;
4968            rightMargin = right;
4969            bottomMargin = bottom;
4970        }
4971    }
4972
4973    /* Describes a touched view and the ids of the pointers that it has captured.
4974     *
4975     * This code assumes that pointer ids are always in the range 0..31 such that
4976     * it can use a bitfield to track which pointer ids are present.
4977     * As it happens, the lower layers of the input dispatch pipeline also use the
4978     * same trick so the assumption should be safe here...
4979     */
4980    private static final class TouchTarget {
4981        private static final int MAX_RECYCLED = 32;
4982        private static final Object sRecycleLock = new Object();
4983        private static TouchTarget sRecycleBin;
4984        private static int sRecycledCount;
4985
4986        public static final int ALL_POINTER_IDS = -1; // all ones
4987
4988        // The touched child view.
4989        public View child;
4990
4991        // The combined bit mask of pointer ids for all pointers captured by the target.
4992        public int pointerIdBits;
4993
4994        // The next target in the target list.
4995        public TouchTarget next;
4996
4997        private TouchTarget() {
4998        }
4999
5000        public static TouchTarget obtain(View child, int pointerIdBits) {
5001            final TouchTarget target;
5002            synchronized (sRecycleLock) {
5003                if (sRecycleBin == null) {
5004                    target = new TouchTarget();
5005                } else {
5006                    target = sRecycleBin;
5007                    sRecycleBin = target.next;
5008                     sRecycledCount--;
5009                    target.next = null;
5010                }
5011            }
5012            target.child = child;
5013            target.pointerIdBits = pointerIdBits;
5014            return target;
5015        }
5016
5017        public void recycle() {
5018            synchronized (sRecycleLock) {
5019                if (sRecycledCount < MAX_RECYCLED) {
5020                    next = sRecycleBin;
5021                    sRecycleBin = this;
5022                    sRecycledCount += 1;
5023                } else {
5024                    next = null;
5025                }
5026                child = null;
5027            }
5028        }
5029    }
5030}
5031