ViewGroup.java revision 44fbc03f651ce79b0726a6bb585567918a88e29c
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 dispatchGenericMotionEvent(MotionEvent event) {
1149        if ((mPrivateFlags & (FOCUSED | HAS_BOUNDS)) == (FOCUSED | HAS_BOUNDS)) {
1150            return super.dispatchGenericMotionEvent(event);
1151        } else if (mFocused != null && (mFocused.mPrivateFlags & HAS_BOUNDS) == HAS_BOUNDS) {
1152            return mFocused.dispatchGenericMotionEvent(event);
1153        }
1154        return false;
1155    }
1156
1157    /**
1158     * {@inheritDoc}
1159     */
1160    @Override
1161    public boolean dispatchTouchEvent(MotionEvent ev) {
1162        if (!onFilterTouchEventForSecurity(ev)) {
1163            return false;
1164        }
1165
1166        final int action = ev.getAction();
1167        final int actionMasked = action & MotionEvent.ACTION_MASK;
1168
1169        // Handle an initial down.
1170        if (actionMasked == MotionEvent.ACTION_DOWN) {
1171            // Throw away all previous state when starting a new touch gesture.
1172            // The framework may have dropped the up or cancel event for the previous gesture
1173            // due to an app switch, ANR, or some other state change.
1174            cancelAndClearTouchTargets(ev);
1175            resetTouchState();
1176        }
1177
1178        // Check for interception.
1179        final boolean intercepted;
1180        if (actionMasked == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null) {
1181            final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
1182            if (!disallowIntercept) {
1183                intercepted = onInterceptTouchEvent(ev);
1184                ev.setAction(action); // restore action in case onInterceptTouchEvent() changed it
1185            } else {
1186                intercepted = false;
1187            }
1188        } else {
1189            intercepted = true;
1190        }
1191
1192        // Check for cancelation.
1193        final boolean canceled = resetCancelNextUpFlag(this)
1194                || actionMasked == MotionEvent.ACTION_CANCEL;
1195
1196        // Update list of touch targets for pointer down, if needed.
1197        final boolean split = (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) != 0;
1198        TouchTarget newTouchTarget = null;
1199        boolean alreadyDispatchedToNewTouchTarget = false;
1200        if (!canceled && !intercepted) {
1201            if (actionMasked == MotionEvent.ACTION_DOWN
1202                    || (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN)) {
1203                final int actionIndex = ev.getActionIndex(); // always 0 for down
1204                final int idBitsToAssign = split ? 1 << ev.getPointerId(actionIndex)
1205                        : TouchTarget.ALL_POINTER_IDS;
1206
1207                // Clean up earlier touch targets for this pointer id in case they
1208                // have become out of sync.
1209                removePointersFromTouchTargets(idBitsToAssign);
1210
1211                final int childrenCount = mChildrenCount;
1212                if (childrenCount != 0) {
1213                    // Find a child that can receive the event.  Scan children from front to back.
1214                    final View[] children = mChildren;
1215                    final float x = ev.getX(actionIndex);
1216                    final float y = ev.getY(actionIndex);
1217
1218                    for (int i = childrenCount - 1; i >= 0; i--) {
1219                        final View child = children[i];
1220                        if ((child.mViewFlags & VISIBILITY_MASK) != VISIBLE
1221                                && child.getAnimation() == null) {
1222                            // Skip invisible child unless it is animating.
1223                            continue;
1224                        }
1225
1226                        if (!isTransformedTouchPointInView(x, y, child, null)) {
1227                            // New pointer is out of child's bounds.
1228                            continue;
1229                        }
1230
1231                        newTouchTarget = getTouchTarget(child);
1232                        if (newTouchTarget != null) {
1233                            // Child is already receiving touch within its bounds.
1234                            // Give it the new pointer in addition to the ones it is handling.
1235                            newTouchTarget.pointerIdBits |= idBitsToAssign;
1236                            break;
1237                        }
1238
1239                        resetCancelNextUpFlag(child);
1240                        if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
1241                            // Child wants to receive touch within its bounds.
1242                            mLastTouchDownTime = ev.getDownTime();
1243                            mLastTouchDownIndex = i;
1244                            mLastTouchDownX = ev.getX();
1245                            mLastTouchDownY = ev.getY();
1246                            newTouchTarget = addTouchTarget(child, idBitsToAssign);
1247                            alreadyDispatchedToNewTouchTarget = true;
1248                            break;
1249                        }
1250                    }
1251                }
1252
1253                if (newTouchTarget == null && mFirstTouchTarget != null) {
1254                    // Did not find a child to receive the event.
1255                    // Assign the pointer to the least recently added target.
1256                    newTouchTarget = mFirstTouchTarget;
1257                    while (newTouchTarget.next != null) {
1258                        newTouchTarget = newTouchTarget.next;
1259                    }
1260                    newTouchTarget.pointerIdBits |= idBitsToAssign;
1261                }
1262            }
1263        }
1264
1265        // Dispatch to touch targets.
1266        boolean handled = false;
1267        if (mFirstTouchTarget == null) {
1268            // No touch targets so treat this as an ordinary view.
1269            handled = dispatchTransformedTouchEvent(ev, canceled, null,
1270                    TouchTarget.ALL_POINTER_IDS);
1271        } else {
1272            // Dispatch to touch targets, excluding the new touch target if we already
1273            // dispatched to it.  Cancel touch targets if necessary.
1274            TouchTarget predecessor = null;
1275            TouchTarget target = mFirstTouchTarget;
1276            while (target != null) {
1277                final TouchTarget next = target.next;
1278                if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) {
1279                    handled = true;
1280                } else {
1281                    final boolean cancelChild = resetCancelNextUpFlag(target.child) || intercepted;
1282                    if (dispatchTransformedTouchEvent(ev, cancelChild,
1283                            target.child, target.pointerIdBits)) {
1284                        handled = true;
1285                    }
1286                    if (cancelChild) {
1287                        if (predecessor == null) {
1288                            mFirstTouchTarget = next;
1289                        } else {
1290                            predecessor.next = next;
1291                        }
1292                        target.recycle();
1293                        target = next;
1294                        continue;
1295                    }
1296                }
1297                predecessor = target;
1298                target = next;
1299            }
1300        }
1301
1302        // Update list of touch targets for pointer up or cancel, if needed.
1303        if (canceled || actionMasked == MotionEvent.ACTION_UP) {
1304            resetTouchState();
1305        } else if (split && actionMasked == MotionEvent.ACTION_POINTER_UP) {
1306            final int actionIndex = ev.getActionIndex();
1307            final int idBitsToRemove = 1 << ev.getPointerId(actionIndex);
1308            removePointersFromTouchTargets(idBitsToRemove);
1309        }
1310
1311        return handled;
1312    }
1313
1314    /**
1315     * Resets all touch state in preparation for a new cycle.
1316     */
1317    private void resetTouchState() {
1318        clearTouchTargets();
1319        resetCancelNextUpFlag(this);
1320        mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
1321    }
1322
1323    /**
1324     * Resets the cancel next up flag.
1325     * Returns true if the flag was previously set.
1326     */
1327    private boolean resetCancelNextUpFlag(View view) {
1328        if ((view.mPrivateFlags & CANCEL_NEXT_UP_EVENT) != 0) {
1329            view.mPrivateFlags &= ~CANCEL_NEXT_UP_EVENT;
1330            return true;
1331        }
1332        return false;
1333    }
1334
1335    /**
1336     * Clears all touch targets.
1337     */
1338    private void clearTouchTargets() {
1339        TouchTarget target = mFirstTouchTarget;
1340        if (target != null) {
1341            do {
1342                TouchTarget next = target.next;
1343                target.recycle();
1344                target = next;
1345            } while (target != null);
1346            mFirstTouchTarget = null;
1347        }
1348    }
1349
1350    /**
1351     * Cancels and clears all touch targets.
1352     */
1353    private void cancelAndClearTouchTargets(MotionEvent event) {
1354        if (mFirstTouchTarget != null) {
1355            boolean syntheticEvent = false;
1356            if (event == null) {
1357                final long now = SystemClock.uptimeMillis();
1358                event = MotionEvent.obtain(now, now,
1359                        MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
1360                syntheticEvent = true;
1361            }
1362
1363            for (TouchTarget target = mFirstTouchTarget; target != null; target = target.next) {
1364                resetCancelNextUpFlag(target.child);
1365                dispatchTransformedTouchEvent(event, true, target.child, target.pointerIdBits);
1366            }
1367            clearTouchTargets();
1368
1369            if (syntheticEvent) {
1370                event.recycle();
1371            }
1372        }
1373    }
1374
1375    /**
1376     * Gets the touch target for specified child view.
1377     * Returns null if not found.
1378     */
1379    private TouchTarget getTouchTarget(View child) {
1380        for (TouchTarget target = mFirstTouchTarget; target != null; target = target.next) {
1381            if (target.child == child) {
1382                return target;
1383            }
1384        }
1385        return null;
1386    }
1387
1388    /**
1389     * Adds a touch target for specified child to the beginning of the list.
1390     * Assumes the target child is not already present.
1391     */
1392    private TouchTarget addTouchTarget(View child, int pointerIdBits) {
1393        TouchTarget target = TouchTarget.obtain(child, pointerIdBits);
1394        target.next = mFirstTouchTarget;
1395        mFirstTouchTarget = target;
1396        return target;
1397    }
1398
1399    /**
1400     * Removes the pointer ids from consideration.
1401     */
1402    private void removePointersFromTouchTargets(int pointerIdBits) {
1403        TouchTarget predecessor = null;
1404        TouchTarget target = mFirstTouchTarget;
1405        while (target != null) {
1406            final TouchTarget next = target.next;
1407            if ((target.pointerIdBits & pointerIdBits) != 0) {
1408                target.pointerIdBits &= ~pointerIdBits;
1409                if (target.pointerIdBits == 0) {
1410                    if (predecessor == null) {
1411                        mFirstTouchTarget = next;
1412                    } else {
1413                        predecessor.next = next;
1414                    }
1415                    target.recycle();
1416                    target = next;
1417                    continue;
1418                }
1419            }
1420            predecessor = target;
1421            target = next;
1422        }
1423    }
1424
1425    /**
1426     * Returns true if a child view contains the specified point when transformed
1427     * into its coordinate space.
1428     * Child must not be null.
1429     * @hide
1430     */
1431    protected boolean isTransformedTouchPointInView(float x, float y, View child,
1432            PointF outLocalPoint) {
1433        float localX = x + mScrollX - child.mLeft;
1434        float localY = y + mScrollY - child.mTop;
1435        if (! child.hasIdentityMatrix() && mAttachInfo != null) {
1436            final float[] localXY = mAttachInfo.mTmpTransformLocation;
1437            localXY[0] = localX;
1438            localXY[1] = localY;
1439            child.getInverseMatrix().mapPoints(localXY);
1440            localX = localXY[0];
1441            localY = localXY[1];
1442        }
1443        final boolean isInView = child.pointInView(localX, localY);
1444        if (isInView && outLocalPoint != null) {
1445            outLocalPoint.set(localX, localY);
1446        }
1447        return isInView;
1448    }
1449
1450    /**
1451     * Transforms a motion event into the coordinate space of a particular child view,
1452     * filters out irrelevant pointer ids, and overrides its action if necessary.
1453     * If child is null, assumes the MotionEvent will be sent to this ViewGroup instead.
1454     */
1455    private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,
1456            View child, int desiredPointerIdBits) {
1457        final boolean handled;
1458
1459        // Canceling motions is a special case.  We don't need to perform any transformations
1460        // or filtering.  The important part is the action, not the contents.
1461        final int oldAction = event.getAction();
1462        if (cancel || oldAction == MotionEvent.ACTION_CANCEL) {
1463            event.setAction(MotionEvent.ACTION_CANCEL);
1464            if (child == null) {
1465                handled = super.dispatchTouchEvent(event);
1466            } else {
1467                handled = child.dispatchTouchEvent(event);
1468            }
1469            event.setAction(oldAction);
1470            return handled;
1471        }
1472
1473        // Calculate the number of pointers to deliver.
1474        final int oldPointerCount = event.getPointerCount();
1475        int newPointerCount = 0;
1476        if (desiredPointerIdBits == TouchTarget.ALL_POINTER_IDS) {
1477            newPointerCount = oldPointerCount;
1478        } else {
1479            for (int i = 0; i < oldPointerCount; i++) {
1480                final int pointerId = event.getPointerId(i);
1481                final int pointerIdBit = 1 << pointerId;
1482                if ((pointerIdBit & desiredPointerIdBits) != 0) {
1483                    newPointerCount += 1;
1484                }
1485            }
1486        }
1487
1488        // If for some reason we ended up in an inconsistent state where it looks like we
1489        // might produce a motion event with no pointers in it, then drop the event.
1490        if (newPointerCount == 0) {
1491            return false;
1492        }
1493
1494        // If the number of pointers is the same and we don't need to perform any fancy
1495        // irreversible transformations, then we can reuse the motion event for this
1496        // dispatch as long as we are careful to revert any changes we make.
1497        final boolean reuse = newPointerCount == oldPointerCount
1498                && (child == null || child.hasIdentityMatrix());
1499        if (reuse) {
1500            if (child == null) {
1501                handled = super.dispatchTouchEvent(event);
1502            } else {
1503                final float offsetX = mScrollX - child.mLeft;
1504                final float offsetY = mScrollY - child.mTop;
1505                event.offsetLocation(offsetX, offsetY);
1506
1507                handled = child.dispatchTouchEvent(event);
1508
1509                event.offsetLocation(-offsetX, -offsetY);
1510            }
1511            return handled;
1512        }
1513
1514        // Make a copy of the event.
1515        // If the number of pointers is different, then we need to filter out irrelevant pointers
1516        // as we make a copy of the motion event.
1517        MotionEvent transformedEvent;
1518        if (newPointerCount == oldPointerCount) {
1519            transformedEvent = MotionEvent.obtain(event);
1520        } else {
1521            growTmpPointerArrays(newPointerCount);
1522            final int[] newPointerIndexMap = mTmpPointerIndexMap;
1523            final int[] newPointerIds = mTmpPointerIds;
1524            final MotionEvent.PointerCoords[] newPointerCoords = mTmpPointerCoords;
1525
1526            int newPointerIndex = 0;
1527            int oldPointerIndex = 0;
1528            while (newPointerIndex < newPointerCount) {
1529                final int pointerId = event.getPointerId(oldPointerIndex);
1530                final int pointerIdBits = 1 << pointerId;
1531                if ((pointerIdBits & desiredPointerIdBits) != 0) {
1532                    newPointerIndexMap[newPointerIndex] = oldPointerIndex;
1533                    newPointerIds[newPointerIndex] = pointerId;
1534                    if (newPointerCoords[newPointerIndex] == null) {
1535                        newPointerCoords[newPointerIndex] = new MotionEvent.PointerCoords();
1536                    }
1537
1538                    newPointerIndex += 1;
1539                }
1540                oldPointerIndex += 1;
1541            }
1542
1543            final int newAction;
1544            if (cancel) {
1545                newAction = MotionEvent.ACTION_CANCEL;
1546            } else {
1547                final int oldMaskedAction = oldAction & MotionEvent.ACTION_MASK;
1548                if (oldMaskedAction == MotionEvent.ACTION_POINTER_DOWN
1549                        || oldMaskedAction == MotionEvent.ACTION_POINTER_UP) {
1550                    final int changedPointerId = event.getPointerId(
1551                            (oldAction & MotionEvent.ACTION_POINTER_INDEX_MASK)
1552                                    >> MotionEvent.ACTION_POINTER_INDEX_SHIFT);
1553                    final int changedPointerIdBits = 1 << changedPointerId;
1554                    if ((changedPointerIdBits & desiredPointerIdBits) != 0) {
1555                        if (newPointerCount == 1) {
1556                            // The first/last pointer went down/up.
1557                            newAction = oldMaskedAction == MotionEvent.ACTION_POINTER_DOWN
1558                                    ? MotionEvent.ACTION_DOWN : MotionEvent.ACTION_UP;
1559                        } else {
1560                            // A secondary pointer went down/up.
1561                            int newChangedPointerIndex = 0;
1562                            while (newPointerIds[newChangedPointerIndex] != changedPointerId) {
1563                                newChangedPointerIndex += 1;
1564                            }
1565                            newAction = oldMaskedAction | (newChangedPointerIndex
1566                                    << MotionEvent.ACTION_POINTER_INDEX_SHIFT);
1567                        }
1568                    } else {
1569                        // An unrelated pointer changed.
1570                        newAction = MotionEvent.ACTION_MOVE;
1571                    }
1572                } else {
1573                    // Simple up/down/cancel/move motion action.
1574                    newAction = oldMaskedAction;
1575                }
1576            }
1577
1578            transformedEvent = null;
1579            final int historySize = event.getHistorySize();
1580            for (int historyIndex = 0; historyIndex <= historySize; historyIndex++) {
1581                for (newPointerIndex = 0; newPointerIndex < newPointerCount; newPointerIndex++) {
1582                    final MotionEvent.PointerCoords c = newPointerCoords[newPointerIndex];
1583                    oldPointerIndex = newPointerIndexMap[newPointerIndex];
1584                    if (historyIndex != historySize) {
1585                        event.getHistoricalPointerCoords(oldPointerIndex, historyIndex, c);
1586                    } else {
1587                        event.getPointerCoords(oldPointerIndex, c);
1588                    }
1589                }
1590
1591                final long eventTime;
1592                if (historyIndex != historySize) {
1593                    eventTime = event.getHistoricalEventTime(historyIndex);
1594                } else {
1595                    eventTime = event.getEventTime();
1596                }
1597
1598                if (transformedEvent == null) {
1599                    transformedEvent = MotionEvent.obtain(
1600                            event.getDownTime(), eventTime, newAction,
1601                            newPointerCount, newPointerIds, newPointerCoords,
1602                            event.getMetaState(), event.getXPrecision(), event.getYPrecision(),
1603                            event.getDeviceId(), event.getEdgeFlags(), event.getSource(),
1604                            event.getFlags());
1605                } else {
1606                    transformedEvent.addBatch(eventTime, newPointerCoords, 0);
1607                }
1608            }
1609        }
1610
1611        // Perform any necessary transformations and dispatch.
1612        if (child == null) {
1613            handled = super.dispatchTouchEvent(transformedEvent);
1614        } else {
1615            final float offsetX = mScrollX - child.mLeft;
1616            final float offsetY = mScrollY - child.mTop;
1617            transformedEvent.offsetLocation(offsetX, offsetY);
1618            if (! child.hasIdentityMatrix()) {
1619                transformedEvent.transform(child.getInverseMatrix());
1620            }
1621
1622            handled = child.dispatchTouchEvent(transformedEvent);
1623        }
1624
1625        // Done.
1626        transformedEvent.recycle();
1627        return handled;
1628    }
1629
1630    /**
1631     * Enlarge the temporary pointer arrays for splitting pointers.
1632     * May discard contents (but keeps PointerCoords objects to avoid reallocating them).
1633     */
1634    private void growTmpPointerArrays(int desiredCapacity) {
1635        final MotionEvent.PointerCoords[] oldTmpPointerCoords = mTmpPointerCoords;
1636        int capacity;
1637        if (oldTmpPointerCoords != null) {
1638            capacity = oldTmpPointerCoords.length;
1639            if (desiredCapacity <= capacity) {
1640                return;
1641            }
1642        } else {
1643            capacity = 4;
1644        }
1645
1646        while (capacity < desiredCapacity) {
1647            capacity *= 2;
1648        }
1649
1650        mTmpPointerIndexMap = new int[capacity];
1651        mTmpPointerIds = new int[capacity];
1652        mTmpPointerCoords = new MotionEvent.PointerCoords[capacity];
1653
1654        if (oldTmpPointerCoords != null) {
1655            System.arraycopy(oldTmpPointerCoords, 0, mTmpPointerCoords, 0,
1656                    oldTmpPointerCoords.length);
1657        }
1658    }
1659
1660    /**
1661     * Enable or disable the splitting of MotionEvents to multiple children during touch event
1662     * dispatch. This behavior is enabled by default for applications that target an
1663     * SDK version of {@link Build.VERSION_CODES#HONEYCOMB} or newer.
1664     *
1665     * <p>When this option is enabled MotionEvents may be split and dispatched to different child
1666     * views depending on where each pointer initially went down. This allows for user interactions
1667     * such as scrolling two panes of content independently, chording of buttons, and performing
1668     * independent gestures on different pieces of content.
1669     *
1670     * @param split <code>true</code> to allow MotionEvents to be split and dispatched to multiple
1671     *              child views. <code>false</code> to only allow one child view to be the target of
1672     *              any MotionEvent received by this ViewGroup.
1673     */
1674    public void setMotionEventSplittingEnabled(boolean split) {
1675        // TODO Applications really shouldn't change this setting mid-touch event,
1676        // but perhaps this should handle that case and send ACTION_CANCELs to any child views
1677        // with gestures in progress when this is changed.
1678        if (split) {
1679            mGroupFlags |= FLAG_SPLIT_MOTION_EVENTS;
1680        } else {
1681            mGroupFlags &= ~FLAG_SPLIT_MOTION_EVENTS;
1682        }
1683    }
1684
1685    /**
1686     * Returns true if MotionEvents dispatched to this ViewGroup can be split to multiple children.
1687     * @return true if MotionEvents dispatched to this ViewGroup can be split to multiple children.
1688     */
1689    public boolean isMotionEventSplittingEnabled() {
1690        return (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) == FLAG_SPLIT_MOTION_EVENTS;
1691    }
1692
1693    /**
1694     * {@inheritDoc}
1695     */
1696    public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
1697
1698        if (disallowIntercept == ((mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0)) {
1699            // We're already in this state, assume our ancestors are too
1700            return;
1701        }
1702
1703        if (disallowIntercept) {
1704            mGroupFlags |= FLAG_DISALLOW_INTERCEPT;
1705        } else {
1706            mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
1707        }
1708
1709        // Pass it up to our parent
1710        if (mParent != null) {
1711            mParent.requestDisallowInterceptTouchEvent(disallowIntercept);
1712        }
1713    }
1714
1715    /**
1716     * Implement this method to intercept all touch screen motion events.  This
1717     * allows you to watch events as they are dispatched to your children, and
1718     * take ownership of the current gesture at any point.
1719     *
1720     * <p>Using this function takes some care, as it has a fairly complicated
1721     * interaction with {@link View#onTouchEvent(MotionEvent)
1722     * View.onTouchEvent(MotionEvent)}, and using it requires implementing
1723     * that method as well as this one in the correct way.  Events will be
1724     * received in the following order:
1725     *
1726     * <ol>
1727     * <li> You will receive the down event here.
1728     * <li> The down event will be handled either by a child of this view
1729     * group, or given to your own onTouchEvent() method to handle; this means
1730     * you should implement onTouchEvent() to return true, so you will
1731     * continue to see the rest of the gesture (instead of looking for
1732     * a parent view to handle it).  Also, by returning true from
1733     * onTouchEvent(), you will not receive any following
1734     * events in onInterceptTouchEvent() and all touch processing must
1735     * happen in onTouchEvent() like normal.
1736     * <li> For as long as you return false from this function, each following
1737     * event (up to and including the final up) will be delivered first here
1738     * and then to the target's onTouchEvent().
1739     * <li> If you return true from here, you will not receive any
1740     * following events: the target view will receive the same event but
1741     * with the action {@link MotionEvent#ACTION_CANCEL}, and all further
1742     * events will be delivered to your onTouchEvent() method and no longer
1743     * appear here.
1744     * </ol>
1745     *
1746     * @param ev The motion event being dispatched down the hierarchy.
1747     * @return Return true to steal motion events from the children and have
1748     * them dispatched to this ViewGroup through onTouchEvent().
1749     * The current target will receive an ACTION_CANCEL event, and no further
1750     * messages will be delivered here.
1751     */
1752    public boolean onInterceptTouchEvent(MotionEvent ev) {
1753        return false;
1754    }
1755
1756    /**
1757     * {@inheritDoc}
1758     *
1759     * Looks for a view to give focus to respecting the setting specified by
1760     * {@link #getDescendantFocusability()}.
1761     *
1762     * Uses {@link #onRequestFocusInDescendants(int, android.graphics.Rect)} to
1763     * find focus within the children of this group when appropriate.
1764     *
1765     * @see #FOCUS_BEFORE_DESCENDANTS
1766     * @see #FOCUS_AFTER_DESCENDANTS
1767     * @see #FOCUS_BLOCK_DESCENDANTS
1768     * @see #onRequestFocusInDescendants
1769     */
1770    @Override
1771    public boolean requestFocus(int direction, Rect previouslyFocusedRect) {
1772        if (DBG) {
1773            System.out.println(this + " ViewGroup.requestFocus direction="
1774                    + direction);
1775        }
1776        int descendantFocusability = getDescendantFocusability();
1777
1778        switch (descendantFocusability) {
1779            case FOCUS_BLOCK_DESCENDANTS:
1780                return super.requestFocus(direction, previouslyFocusedRect);
1781            case FOCUS_BEFORE_DESCENDANTS: {
1782                final boolean took = super.requestFocus(direction, previouslyFocusedRect);
1783                return took ? took : onRequestFocusInDescendants(direction, previouslyFocusedRect);
1784            }
1785            case FOCUS_AFTER_DESCENDANTS: {
1786                final boolean took = onRequestFocusInDescendants(direction, previouslyFocusedRect);
1787                return took ? took : super.requestFocus(direction, previouslyFocusedRect);
1788            }
1789            default:
1790                throw new IllegalStateException("descendant focusability must be "
1791                        + "one of FOCUS_BEFORE_DESCENDANTS, FOCUS_AFTER_DESCENDANTS, FOCUS_BLOCK_DESCENDANTS "
1792                        + "but is " + descendantFocusability);
1793        }
1794    }
1795
1796    /**
1797     * Look for a descendant to call {@link View#requestFocus} on.
1798     * Called by {@link ViewGroup#requestFocus(int, android.graphics.Rect)}
1799     * when it wants to request focus within its children.  Override this to
1800     * customize how your {@link ViewGroup} requests focus within its children.
1801     * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT
1802     * @param previouslyFocusedRect The rectangle (in this View's coordinate system)
1803     *        to give a finer grained hint about where focus is coming from.  May be null
1804     *        if there is no hint.
1805     * @return Whether focus was taken.
1806     */
1807    @SuppressWarnings({"ConstantConditions"})
1808    protected boolean onRequestFocusInDescendants(int direction,
1809            Rect previouslyFocusedRect) {
1810        int index;
1811        int increment;
1812        int end;
1813        int count = mChildrenCount;
1814        if ((direction & FOCUS_FORWARD) != 0) {
1815            index = 0;
1816            increment = 1;
1817            end = count;
1818        } else {
1819            index = count - 1;
1820            increment = -1;
1821            end = -1;
1822        }
1823        final View[] children = mChildren;
1824        for (int i = index; i != end; i += increment) {
1825            View child = children[i];
1826            if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
1827                if (child.requestFocus(direction, previouslyFocusedRect)) {
1828                    return true;
1829                }
1830            }
1831        }
1832        return false;
1833    }
1834
1835    /**
1836     * {@inheritDoc}
1837     *
1838     * @hide
1839     */
1840    @Override
1841    public void dispatchStartTemporaryDetach() {
1842        super.dispatchStartTemporaryDetach();
1843        final int count = mChildrenCount;
1844        final View[] children = mChildren;
1845        for (int i = 0; i < count; i++) {
1846            children[i].dispatchStartTemporaryDetach();
1847        }
1848    }
1849
1850    /**
1851     * {@inheritDoc}
1852     *
1853     * @hide
1854     */
1855    @Override
1856    public void dispatchFinishTemporaryDetach() {
1857        super.dispatchFinishTemporaryDetach();
1858        final int count = mChildrenCount;
1859        final View[] children = mChildren;
1860        for (int i = 0; i < count; i++) {
1861            children[i].dispatchFinishTemporaryDetach();
1862        }
1863    }
1864
1865    /**
1866     * {@inheritDoc}
1867     */
1868    @Override
1869    void dispatchAttachedToWindow(AttachInfo info, int visibility) {
1870        super.dispatchAttachedToWindow(info, visibility);
1871        visibility |= mViewFlags & VISIBILITY_MASK;
1872        final int count = mChildrenCount;
1873        final View[] children = mChildren;
1874        for (int i = 0; i < count; i++) {
1875            children[i].dispatchAttachedToWindow(info, visibility);
1876        }
1877    }
1878
1879    @Override
1880    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
1881        boolean populated = false;
1882        for (int i = 0, count = getChildCount(); i < count; i++) {
1883            populated |= getChildAt(i).dispatchPopulateAccessibilityEvent(event);
1884        }
1885        return populated;
1886    }
1887
1888    /**
1889     * {@inheritDoc}
1890     */
1891    @Override
1892    void dispatchDetachedFromWindow() {
1893        // If we still have a touch target, we are still in the process of
1894        // dispatching motion events to a child; we need to get rid of that
1895        // child to avoid dispatching events to it after the window is torn
1896        // down. To make sure we keep the child in a consistent state, we
1897        // first send it an ACTION_CANCEL motion event.
1898        cancelAndClearTouchTargets(null);
1899
1900        // In case view is detached while transition is running
1901        mLayoutSuppressed = false;
1902
1903        // Tear down our drag tracking
1904        mDragNotifiedChildren = null;
1905        if (mCurrentDrag != null) {
1906            mCurrentDrag.recycle();
1907            mCurrentDrag = null;
1908        }
1909
1910        final int count = mChildrenCount;
1911        final View[] children = mChildren;
1912        for (int i = 0; i < count; i++) {
1913            children[i].dispatchDetachedFromWindow();
1914        }
1915        super.dispatchDetachedFromWindow();
1916    }
1917
1918    /**
1919     * {@inheritDoc}
1920     */
1921    @Override
1922    public void setPadding(int left, int top, int right, int bottom) {
1923        super.setPadding(left, top, right, bottom);
1924
1925        if ((mPaddingLeft | mPaddingTop | mPaddingRight | mPaddingRight) != 0) {
1926            mGroupFlags |= FLAG_PADDING_NOT_NULL;
1927        } else {
1928            mGroupFlags &= ~FLAG_PADDING_NOT_NULL;
1929        }
1930    }
1931
1932    /**
1933     * {@inheritDoc}
1934     */
1935    @Override
1936    protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {
1937        super.dispatchSaveInstanceState(container);
1938        final int count = mChildrenCount;
1939        final View[] children = mChildren;
1940        for (int i = 0; i < count; i++) {
1941            View c = children[i];
1942            if ((c.mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED) {
1943                c.dispatchSaveInstanceState(container);
1944            }
1945        }
1946    }
1947
1948    /**
1949     * Perform dispatching of a {@link #saveHierarchyState freeze()} to only this view,
1950     * not to its children.  For use when overriding
1951     * {@link #dispatchSaveInstanceState dispatchFreeze()} to allow subclasses to freeze
1952     * their own state but not the state of their children.
1953     *
1954     * @param container the container
1955     */
1956    protected void dispatchFreezeSelfOnly(SparseArray<Parcelable> container) {
1957        super.dispatchSaveInstanceState(container);
1958    }
1959
1960    /**
1961     * {@inheritDoc}
1962     */
1963    @Override
1964    protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {
1965        super.dispatchRestoreInstanceState(container);
1966        final int count = mChildrenCount;
1967        final View[] children = mChildren;
1968        for (int i = 0; i < count; i++) {
1969            View c = children[i];
1970            if ((c.mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED) {
1971                c.dispatchRestoreInstanceState(container);
1972            }
1973        }
1974    }
1975
1976    /**
1977     * Perform dispatching of a {@link #restoreHierarchyState thaw()} to only this view,
1978     * not to its children.  For use when overriding
1979     * {@link #dispatchRestoreInstanceState dispatchThaw()} to allow subclasses to thaw
1980     * their own state but not the state of their children.
1981     *
1982     * @param container the container
1983     */
1984    protected void dispatchThawSelfOnly(SparseArray<Parcelable> container) {
1985        super.dispatchRestoreInstanceState(container);
1986    }
1987
1988    /**
1989     * Enables or disables the drawing cache for each child of this view group.
1990     *
1991     * @param enabled true to enable the cache, false to dispose of it
1992     */
1993    protected void setChildrenDrawingCacheEnabled(boolean enabled) {
1994        if (enabled || (mPersistentDrawingCache & PERSISTENT_ALL_CACHES) != PERSISTENT_ALL_CACHES) {
1995            final View[] children = mChildren;
1996            final int count = mChildrenCount;
1997            for (int i = 0; i < count; i++) {
1998                children[i].setDrawingCacheEnabled(enabled);
1999            }
2000        }
2001    }
2002
2003    @Override
2004    protected void onAnimationStart() {
2005        super.onAnimationStart();
2006
2007        // When this ViewGroup's animation starts, build the cache for the children
2008        if ((mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE) {
2009            final int count = mChildrenCount;
2010            final View[] children = mChildren;
2011            final boolean buildCache = !isHardwareAccelerated();
2012
2013            for (int i = 0; i < count; i++) {
2014                final View child = children[i];
2015                if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
2016                    child.setDrawingCacheEnabled(true);
2017                    if (buildCache) {
2018                        child.buildDrawingCache(true);
2019                    }
2020                }
2021            }
2022
2023            mGroupFlags |= FLAG_CHILDREN_DRAWN_WITH_CACHE;
2024        }
2025    }
2026
2027    @Override
2028    protected void onAnimationEnd() {
2029        super.onAnimationEnd();
2030
2031        // When this ViewGroup's animation ends, destroy the cache of the children
2032        if ((mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE) {
2033            mGroupFlags &= ~FLAG_CHILDREN_DRAWN_WITH_CACHE;
2034
2035            if ((mPersistentDrawingCache & PERSISTENT_ANIMATION_CACHE) == 0) {
2036                setChildrenDrawingCacheEnabled(false);
2037            }
2038        }
2039    }
2040
2041    @Override
2042    Bitmap createSnapshot(Bitmap.Config quality, int backgroundColor, boolean skipChildren) {
2043        int count = mChildrenCount;
2044        int[] visibilities = null;
2045
2046        if (skipChildren) {
2047            visibilities = new int[count];
2048            for (int i = 0; i < count; i++) {
2049                View child = getChildAt(i);
2050                visibilities[i] = child.getVisibility();
2051                if (visibilities[i] == View.VISIBLE) {
2052                    child.setVisibility(INVISIBLE);
2053                }
2054            }
2055        }
2056
2057        Bitmap b = super.createSnapshot(quality, backgroundColor, skipChildren);
2058
2059        if (skipChildren) {
2060            for (int i = 0; i < count; i++) {
2061                getChildAt(i).setVisibility(visibilities[i]);
2062            }
2063        }
2064
2065        return b;
2066    }
2067
2068    /**
2069     * {@inheritDoc}
2070     */
2071    @Override
2072    protected void dispatchDraw(Canvas canvas) {
2073        final int count = mChildrenCount;
2074        final View[] children = mChildren;
2075        int flags = mGroupFlags;
2076
2077        if ((flags & FLAG_RUN_ANIMATION) != 0 && canAnimate()) {
2078            final boolean cache = (mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE;
2079
2080            final boolean buildCache = !isHardwareAccelerated();
2081            for (int i = 0; i < count; i++) {
2082                final View child = children[i];
2083                if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
2084                    final LayoutParams params = child.getLayoutParams();
2085                    attachLayoutAnimationParameters(child, params, i, count);
2086                    bindLayoutAnimation(child);
2087                    if (cache) {
2088                        child.setDrawingCacheEnabled(true);
2089                        if (buildCache) {
2090                            child.buildDrawingCache(true);
2091                        }
2092                    }
2093                }
2094            }
2095
2096            final LayoutAnimationController controller = mLayoutAnimationController;
2097            if (controller.willOverlap()) {
2098                mGroupFlags |= FLAG_OPTIMIZE_INVALIDATE;
2099            }
2100
2101            controller.start();
2102
2103            mGroupFlags &= ~FLAG_RUN_ANIMATION;
2104            mGroupFlags &= ~FLAG_ANIMATION_DONE;
2105
2106            if (cache) {
2107                mGroupFlags |= FLAG_CHILDREN_DRAWN_WITH_CACHE;
2108            }
2109
2110            if (mAnimationListener != null) {
2111                mAnimationListener.onAnimationStart(controller.getAnimation());
2112            }
2113        }
2114
2115        int saveCount = 0;
2116        final boolean clipToPadding = (flags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK;
2117        if (clipToPadding) {
2118            saveCount = canvas.save();
2119            canvas.clipRect(mScrollX + mPaddingLeft, mScrollY + mPaddingTop,
2120                    mScrollX + mRight - mLeft - mPaddingRight,
2121                    mScrollY + mBottom - mTop - mPaddingBottom);
2122
2123        }
2124
2125        // We will draw our child's animation, let's reset the flag
2126        mPrivateFlags &= ~DRAW_ANIMATION;
2127        mGroupFlags &= ~FLAG_INVALIDATE_REQUIRED;
2128
2129        boolean more = false;
2130        final long drawingTime = getDrawingTime();
2131
2132        if ((flags & FLAG_USE_CHILD_DRAWING_ORDER) == 0) {
2133            for (int i = 0; i < count; i++) {
2134                final View child = children[i];
2135                if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
2136                    more |= drawChild(canvas, child, drawingTime);
2137                }
2138            }
2139        } else {
2140            for (int i = 0; i < count; i++) {
2141                final View child = children[getChildDrawingOrder(count, i)];
2142                if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
2143                    more |= drawChild(canvas, child, drawingTime);
2144                }
2145            }
2146        }
2147
2148        // Draw any disappearing views that have animations
2149        if (mDisappearingChildren != null) {
2150            final ArrayList<View> disappearingChildren = mDisappearingChildren;
2151            final int disappearingCount = disappearingChildren.size() - 1;
2152            // Go backwards -- we may delete as animations finish
2153            for (int i = disappearingCount; i >= 0; i--) {
2154                final View child = disappearingChildren.get(i);
2155                more |= drawChild(canvas, child, drawingTime);
2156            }
2157        }
2158
2159        if (clipToPadding) {
2160            canvas.restoreToCount(saveCount);
2161        }
2162
2163        // mGroupFlags might have been updated by drawChild()
2164        flags = mGroupFlags;
2165
2166        if ((flags & FLAG_INVALIDATE_REQUIRED) == FLAG_INVALIDATE_REQUIRED) {
2167            invalidate(true);
2168        }
2169
2170        if ((flags & FLAG_ANIMATION_DONE) == 0 && (flags & FLAG_NOTIFY_ANIMATION_LISTENER) == 0 &&
2171                mLayoutAnimationController.isDone() && !more) {
2172            // We want to erase the drawing cache and notify the listener after the
2173            // next frame is drawn because one extra invalidate() is caused by
2174            // drawChild() after the animation is over
2175            mGroupFlags |= FLAG_NOTIFY_ANIMATION_LISTENER;
2176            final Runnable end = new Runnable() {
2177               public void run() {
2178                   notifyAnimationListener();
2179               }
2180            };
2181            post(end);
2182        }
2183    }
2184
2185    /**
2186     * Returns the index of the child to draw for this iteration. Override this
2187     * if you want to change the drawing order of children. By default, it
2188     * returns i.
2189     * <p>
2190     * NOTE: In order for this method to be called, you must enable child ordering
2191     * first by calling {@link #setChildrenDrawingOrderEnabled(boolean)}.
2192     *
2193     * @param i The current iteration.
2194     * @return The index of the child to draw this iteration.
2195     *
2196     * @see #setChildrenDrawingOrderEnabled(boolean)
2197     * @see #isChildrenDrawingOrderEnabled()
2198     */
2199    protected int getChildDrawingOrder(int childCount, int i) {
2200        return i;
2201    }
2202
2203    private void notifyAnimationListener() {
2204        mGroupFlags &= ~FLAG_NOTIFY_ANIMATION_LISTENER;
2205        mGroupFlags |= FLAG_ANIMATION_DONE;
2206
2207        if (mAnimationListener != null) {
2208           final Runnable end = new Runnable() {
2209               public void run() {
2210                   mAnimationListener.onAnimationEnd(mLayoutAnimationController.getAnimation());
2211               }
2212           };
2213           post(end);
2214        }
2215
2216        if ((mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE) {
2217            mGroupFlags &= ~FLAG_CHILDREN_DRAWN_WITH_CACHE;
2218            if ((mPersistentDrawingCache & PERSISTENT_ANIMATION_CACHE) == 0) {
2219                setChildrenDrawingCacheEnabled(false);
2220            }
2221        }
2222
2223        invalidate(true);
2224    }
2225
2226    /**
2227     * This method is used to cause children of this ViewGroup to restore or recreate their
2228     * display lists. It is called by getDisplayList() when the parent ViewGroup does not need
2229     * to recreate its own display list, which would happen if it went through the normal
2230     * draw/dispatchDraw mechanisms.
2231     *
2232     * @hide
2233     */
2234    @Override
2235    protected void dispatchGetDisplayList() {
2236        final int count = mChildrenCount;
2237        final View[] children = mChildren;
2238        for (int i = 0; i < count; i++) {
2239            final View child = children[i];
2240            child.mRecreateDisplayList = (child.mPrivateFlags & INVALIDATED) == INVALIDATED;
2241            child.mPrivateFlags &= ~INVALIDATED;
2242            child.getDisplayList();
2243            child.mRecreateDisplayList = false;
2244        }
2245    }
2246
2247    /**
2248     * Draw one child of this View Group. This method is responsible for getting
2249     * the canvas in the right state. This includes clipping, translating so
2250     * that the child's scrolled origin is at 0, 0, and applying any animation
2251     * transformations.
2252     *
2253     * @param canvas The canvas on which to draw the child
2254     * @param child Who to draw
2255     * @param drawingTime The time at which draw is occuring
2256     * @return True if an invalidate() was issued
2257     */
2258    protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
2259        boolean more = false;
2260
2261        final int cl = child.mLeft;
2262        final int ct = child.mTop;
2263        final int cr = child.mRight;
2264        final int cb = child.mBottom;
2265
2266        final boolean childHasIdentityMatrix = child.hasIdentityMatrix();
2267
2268        final int flags = mGroupFlags;
2269
2270        if ((flags & FLAG_CLEAR_TRANSFORMATION) == FLAG_CLEAR_TRANSFORMATION) {
2271            mChildTransformation.clear();
2272            mGroupFlags &= ~FLAG_CLEAR_TRANSFORMATION;
2273        }
2274
2275        Transformation transformToApply = null;
2276        Transformation invalidationTransform;
2277        final Animation a = child.getAnimation();
2278        boolean concatMatrix = false;
2279
2280        boolean scalingRequired = false;
2281        boolean caching;
2282        int layerType = mDrawLayers ? child.getLayerType() : LAYER_TYPE_NONE;
2283
2284        final boolean hardwareAccelerated = canvas.isHardwareAccelerated();
2285        if ((flags & FLAG_CHILDREN_DRAWN_WITH_CACHE) == FLAG_CHILDREN_DRAWN_WITH_CACHE ||
2286                (flags & FLAG_ALWAYS_DRAWN_WITH_CACHE) == FLAG_ALWAYS_DRAWN_WITH_CACHE) {
2287            caching = true;
2288            if (mAttachInfo != null) scalingRequired = mAttachInfo.mScalingRequired;
2289        } else {
2290            caching = (layerType != LAYER_TYPE_NONE) || hardwareAccelerated;
2291        }
2292
2293        if (a != null) {
2294            final boolean initialized = a.isInitialized();
2295            if (!initialized) {
2296                a.initialize(cr - cl, cb - ct, getWidth(), getHeight());
2297                a.initializeInvalidateRegion(0, 0, cr - cl, cb - ct);
2298                child.onAnimationStart();
2299            }
2300
2301            more = a.getTransformation(drawingTime, mChildTransformation,
2302                    scalingRequired ? mAttachInfo.mApplicationScale : 1f);
2303            if (scalingRequired && mAttachInfo.mApplicationScale != 1f) {
2304                if (mInvalidationTransformation == null) {
2305                    mInvalidationTransformation = new Transformation();
2306                }
2307                invalidationTransform = mInvalidationTransformation;
2308                a.getTransformation(drawingTime, invalidationTransform, 1f);
2309            } else {
2310                invalidationTransform = mChildTransformation;
2311            }
2312            transformToApply = mChildTransformation;
2313
2314            concatMatrix = a.willChangeTransformationMatrix();
2315
2316            if (more) {
2317                if (!a.willChangeBounds()) {
2318                    if ((flags & (FLAG_OPTIMIZE_INVALIDATE | FLAG_ANIMATION_DONE)) ==
2319                            FLAG_OPTIMIZE_INVALIDATE) {
2320                        mGroupFlags |= FLAG_INVALIDATE_REQUIRED;
2321                    } else if ((flags & FLAG_INVALIDATE_REQUIRED) == 0) {
2322                        // The child need to draw an animation, potentially offscreen, so
2323                        // make sure we do not cancel invalidate requests
2324                        mPrivateFlags |= DRAW_ANIMATION;
2325                        invalidate(cl, ct, cr, cb);
2326                    }
2327                } else {
2328                    if (mInvalidateRegion == null) {
2329                        mInvalidateRegion = new RectF();
2330                    }
2331                    final RectF region = mInvalidateRegion;
2332                    a.getInvalidateRegion(0, 0, cr - cl, cb - ct, region, invalidationTransform);
2333
2334                    // The child need to draw an animation, potentially offscreen, so
2335                    // make sure we do not cancel invalidate requests
2336                    mPrivateFlags |= DRAW_ANIMATION;
2337
2338                    final int left = cl + (int) region.left;
2339                    final int top = ct + (int) region.top;
2340                    invalidate(left, top, left + (int) region.width(), top + (int) region.height());
2341                }
2342            }
2343        } else if ((flags & FLAG_SUPPORT_STATIC_TRANSFORMATIONS) ==
2344                FLAG_SUPPORT_STATIC_TRANSFORMATIONS) {
2345            final boolean hasTransform = getChildStaticTransformation(child, mChildTransformation);
2346            if (hasTransform) {
2347                final int transformType = mChildTransformation.getTransformationType();
2348                transformToApply = transformType != Transformation.TYPE_IDENTITY ?
2349                        mChildTransformation : null;
2350                concatMatrix = (transformType & Transformation.TYPE_MATRIX) != 0;
2351            }
2352        }
2353
2354        concatMatrix |= !childHasIdentityMatrix;
2355
2356        // Sets the flag as early as possible to allow draw() implementations
2357        // to call invalidate() successfully when doing animations
2358        child.mPrivateFlags |= DRAWN;
2359
2360        if (!concatMatrix && canvas.quickReject(cl, ct, cr, cb, Canvas.EdgeType.BW) &&
2361                (child.mPrivateFlags & DRAW_ANIMATION) == 0) {
2362            return more;
2363        }
2364
2365        float alpha = child.getAlpha();
2366        // Bail out early if the view does not need to be drawn
2367        if (alpha <= ViewConfiguration.ALPHA_THRESHOLD && (child.mPrivateFlags & ALPHA_SET) == 0 &&
2368                !(child instanceof SurfaceView)) {
2369            return more;
2370        }
2371
2372        if (hardwareAccelerated) {
2373            // Clear INVALIDATED flag to allow invalidation to occur during rendering, but
2374            // retain the flag's value temporarily in the mRecreateDisplayList flag
2375            child.mRecreateDisplayList = (child.mPrivateFlags & INVALIDATED) == INVALIDATED;
2376            child.mPrivateFlags &= ~INVALIDATED;
2377        }
2378
2379        child.computeScroll();
2380
2381        final int sx = child.mScrollX;
2382        final int sy = child.mScrollY;
2383
2384        DisplayList displayList = null;
2385        Bitmap cache = null;
2386        boolean hasDisplayList = false;
2387        if (caching) {
2388            if (!hardwareAccelerated) {
2389                if (layerType != LAYER_TYPE_NONE) {
2390                    layerType = LAYER_TYPE_SOFTWARE;
2391                    child.buildDrawingCache(true);
2392                }
2393                cache = child.getDrawingCache(true);
2394            } else {
2395                if (layerType == LAYER_TYPE_SOFTWARE) {
2396                    child.buildDrawingCache(true);
2397                    cache = child.getDrawingCache(true);
2398                } else if (layerType == LAYER_TYPE_NONE) {
2399                    // Delay getting the display list until animation-driven alpha values are
2400                    // set up and possibly passed on to the view
2401                    hasDisplayList = child.canHaveDisplayList();
2402                }
2403            }
2404        }
2405
2406        final boolean hasNoCache = cache == null || hasDisplayList;
2407
2408        final int restoreTo = canvas.save();
2409        if (cache == null && !hasDisplayList) {
2410            canvas.translate(cl - sx, ct - sy);
2411        } else {
2412            canvas.translate(cl, ct);
2413            if (scalingRequired) {
2414                // mAttachInfo cannot be null, otherwise scalingRequired == false
2415                final float scale = 1.0f / mAttachInfo.mApplicationScale;
2416                canvas.scale(scale, scale);
2417            }
2418        }
2419
2420        if (transformToApply != null || alpha < 1.0f || !child.hasIdentityMatrix()) {
2421            if (transformToApply != null || !childHasIdentityMatrix) {
2422                int transX = 0;
2423                int transY = 0;
2424
2425                if (cache == null && !hasDisplayList) {
2426                    transX = -sx;
2427                    transY = -sy;
2428                }
2429
2430                if (transformToApply != null) {
2431                    if (concatMatrix) {
2432                        // Undo the scroll translation, apply the transformation matrix,
2433                        // then redo the scroll translate to get the correct result.
2434                        canvas.translate(-transX, -transY);
2435                        canvas.concat(transformToApply.getMatrix());
2436                        canvas.translate(transX, transY);
2437                        mGroupFlags |= FLAG_CLEAR_TRANSFORMATION;
2438                    }
2439
2440                    float transformAlpha = transformToApply.getAlpha();
2441                    if (transformAlpha < 1.0f) {
2442                        alpha *= transformToApply.getAlpha();
2443                        mGroupFlags |= FLAG_CLEAR_TRANSFORMATION;
2444                    }
2445                }
2446
2447                if (!childHasIdentityMatrix) {
2448                    canvas.translate(-transX, -transY);
2449                    canvas.concat(child.getMatrix());
2450                    canvas.translate(transX, transY);
2451                }
2452            }
2453
2454            if (alpha < 1.0f) {
2455                mGroupFlags |= FLAG_CLEAR_TRANSFORMATION;
2456                if (hasNoCache) {
2457                    final int multipliedAlpha = (int) (255 * alpha);
2458                    if (!child.onSetAlpha(multipliedAlpha)) {
2459                        int layerFlags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG;
2460                        if ((flags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN ||
2461                                layerType != LAYER_TYPE_NONE) {
2462                            layerFlags |= Canvas.CLIP_TO_LAYER_SAVE_FLAG;
2463                        }
2464                        if (layerType == LAYER_TYPE_NONE) {
2465                            canvas.saveLayerAlpha(sx, sy, sx + cr - cl, sy + cb - ct,
2466                                    multipliedAlpha, layerFlags);
2467                        }
2468                    } else {
2469                        // Alpha is handled by the child directly, clobber the layer's alpha
2470                        child.mPrivateFlags |= ALPHA_SET;
2471                    }
2472                }
2473            }
2474        } else if ((child.mPrivateFlags & ALPHA_SET) == ALPHA_SET) {
2475            child.onSetAlpha(255);
2476            child.mPrivateFlags &= ~ALPHA_SET;
2477        }
2478
2479        if ((flags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN) {
2480            if (cache == null && !hasDisplayList) {
2481                canvas.clipRect(sx, sy, sx + (cr - cl), sy + (cb - ct));
2482            } else {
2483                if (!scalingRequired || cache == null) {
2484                    canvas.clipRect(0, 0, cr - cl, cb - ct);
2485                } else {
2486                    canvas.clipRect(0, 0, cache.getWidth(), cache.getHeight());
2487                }
2488            }
2489        }
2490
2491        if (hasDisplayList) {
2492            displayList = child.getDisplayList();
2493        }
2494
2495        if (hasNoCache) {
2496            boolean layerRendered = false;
2497            if (layerType == LAYER_TYPE_HARDWARE) {
2498                final HardwareLayer layer = child.getHardwareLayer();
2499                if (layer != null && layer.isValid()) {
2500                    child.mLayerPaint.setAlpha((int) (alpha * 255));
2501                    ((HardwareCanvas) canvas).drawHardwareLayer(layer, 0, 0, child.mLayerPaint);
2502                    layerRendered = true;
2503                } else {
2504                    canvas.saveLayer(sx, sy, sx + cr - cl, sy + cb - ct, child.mLayerPaint,
2505                            Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG);
2506                }
2507            }
2508
2509            if (!layerRendered) {
2510                if (!hasDisplayList) {
2511                    // Fast path for layouts with no backgrounds
2512                    if ((child.mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
2513                        if (ViewDebug.TRACE_HIERARCHY) {
2514                            ViewDebug.trace(this, ViewDebug.HierarchyTraceType.DRAW);
2515                        }
2516                        child.mPrivateFlags &= ~DIRTY_MASK;
2517                        child.dispatchDraw(canvas);
2518                    } else {
2519                        child.draw(canvas);
2520                    }
2521                } else {
2522                    child.mPrivateFlags &= ~DIRTY_MASK;
2523                    ((HardwareCanvas) canvas).drawDisplayList(displayList);
2524                }
2525            }
2526        } else if (cache != null) {
2527            child.mPrivateFlags &= ~DIRTY_MASK;
2528            Paint cachePaint;
2529
2530            if (layerType == LAYER_TYPE_NONE) {
2531                cachePaint = mCachePaint;
2532                if (alpha < 1.0f) {
2533                    cachePaint.setAlpha((int) (alpha * 255));
2534                    mGroupFlags |= FLAG_ALPHA_LOWER_THAN_ONE;
2535                } else if  ((flags & FLAG_ALPHA_LOWER_THAN_ONE) == FLAG_ALPHA_LOWER_THAN_ONE) {
2536                    cachePaint.setAlpha(255);
2537                    mGroupFlags &= ~FLAG_ALPHA_LOWER_THAN_ONE;
2538                }
2539            } else {
2540                cachePaint = child.mLayerPaint;
2541                cachePaint.setAlpha((int) (alpha * 255));
2542            }
2543            canvas.drawBitmap(cache, 0.0f, 0.0f, cachePaint);
2544        }
2545
2546        canvas.restoreToCount(restoreTo);
2547
2548        if (a != null && !more) {
2549            if (!hardwareAccelerated && !a.getFillAfter()) {
2550                child.onSetAlpha(255);
2551            }
2552            finishAnimatingView(child, a);
2553        }
2554
2555        if (more && hardwareAccelerated) {
2556            // invalidation is the trigger to recreate display lists, so if we're using
2557            // display lists to render, force an invalidate to allow the animation to
2558            // continue drawing another frame
2559            invalidate(true);
2560            if (a instanceof AlphaAnimation) {
2561                // alpha animations should cause the child to recreate its display list
2562                child.invalidate(true);
2563            }
2564        }
2565
2566        child.mRecreateDisplayList = false;
2567
2568        return more;
2569    }
2570
2571    /**
2572     *
2573     * @param enabled True if children should be drawn with layers, false otherwise.
2574     *
2575     * @hide
2576     */
2577    public void setChildrenLayersEnabled(boolean enabled) {
2578        mDrawLayers = enabled;
2579        invalidate(true);
2580    }
2581
2582    /**
2583     * By default, children are clipped to their bounds before drawing. This
2584     * allows view groups to override this behavior for animations, etc.
2585     *
2586     * @param clipChildren true to clip children to their bounds,
2587     *        false otherwise
2588     * @attr ref android.R.styleable#ViewGroup_clipChildren
2589     */
2590    public void setClipChildren(boolean clipChildren) {
2591        setBooleanFlag(FLAG_CLIP_CHILDREN, clipChildren);
2592    }
2593
2594    /**
2595     * By default, children are clipped to the padding of the ViewGroup. This
2596     * allows view groups to override this behavior
2597     *
2598     * @param clipToPadding true to clip children to the padding of the
2599     *        group, false otherwise
2600     * @attr ref android.R.styleable#ViewGroup_clipToPadding
2601     */
2602    public void setClipToPadding(boolean clipToPadding) {
2603        setBooleanFlag(FLAG_CLIP_TO_PADDING, clipToPadding);
2604    }
2605
2606    /**
2607     * {@inheritDoc}
2608     */
2609    @Override
2610    public void dispatchSetSelected(boolean selected) {
2611        final View[] children = mChildren;
2612        final int count = mChildrenCount;
2613        for (int i = 0; i < count; i++) {
2614            children[i].setSelected(selected);
2615        }
2616    }
2617
2618    /**
2619     * {@inheritDoc}
2620     */
2621    @Override
2622    public void dispatchSetActivated(boolean activated) {
2623        final View[] children = mChildren;
2624        final int count = mChildrenCount;
2625        for (int i = 0; i < count; i++) {
2626            children[i].setActivated(activated);
2627        }
2628    }
2629
2630    @Override
2631    protected void dispatchSetPressed(boolean pressed) {
2632        final View[] children = mChildren;
2633        final int count = mChildrenCount;
2634        for (int i = 0; i < count; i++) {
2635            children[i].setPressed(pressed);
2636        }
2637    }
2638
2639    /**
2640     * When this property is set to true, this ViewGroup supports static transformations on
2641     * children; this causes
2642     * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} to be
2643     * invoked when a child is drawn.
2644     *
2645     * Any subclass overriding
2646     * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} should
2647     * set this property to true.
2648     *
2649     * @param enabled True to enable static transformations on children, false otherwise.
2650     *
2651     * @see #FLAG_SUPPORT_STATIC_TRANSFORMATIONS
2652     */
2653    protected void setStaticTransformationsEnabled(boolean enabled) {
2654        setBooleanFlag(FLAG_SUPPORT_STATIC_TRANSFORMATIONS, enabled);
2655    }
2656
2657    /**
2658     * {@inheritDoc}
2659     *
2660     * @see #setStaticTransformationsEnabled(boolean)
2661     */
2662    protected boolean getChildStaticTransformation(View child, Transformation t) {
2663        return false;
2664    }
2665
2666    /**
2667     * {@hide}
2668     */
2669    @Override
2670    protected View findViewTraversal(int id) {
2671        if (id == mID) {
2672            return this;
2673        }
2674
2675        final View[] where = mChildren;
2676        final int len = mChildrenCount;
2677
2678        for (int i = 0; i < len; i++) {
2679            View v = where[i];
2680
2681            if ((v.mPrivateFlags & IS_ROOT_NAMESPACE) == 0) {
2682                v = v.findViewById(id);
2683
2684                if (v != null) {
2685                    return v;
2686                }
2687            }
2688        }
2689
2690        return null;
2691    }
2692
2693    /**
2694     * {@hide}
2695     */
2696    @Override
2697    protected View findViewWithTagTraversal(Object tag) {
2698        if (tag != null && tag.equals(mTag)) {
2699            return this;
2700        }
2701
2702        final View[] where = mChildren;
2703        final int len = mChildrenCount;
2704
2705        for (int i = 0; i < len; i++) {
2706            View v = where[i];
2707
2708            if ((v.mPrivateFlags & IS_ROOT_NAMESPACE) == 0) {
2709                v = v.findViewWithTag(tag);
2710
2711                if (v != null) {
2712                    return v;
2713                }
2714            }
2715        }
2716
2717        return null;
2718    }
2719
2720    /**
2721     * {@hide}
2722     */
2723    @Override
2724    protected View findViewByPredicateTraversal(Predicate<View> predicate) {
2725        if (predicate.apply(this)) {
2726            return this;
2727        }
2728
2729        final View[] where = mChildren;
2730        final int len = mChildrenCount;
2731
2732        for (int i = 0; i < len; i++) {
2733            View v = where[i];
2734
2735            if ((v.mPrivateFlags & IS_ROOT_NAMESPACE) == 0) {
2736                v = v.findViewByPredicate(predicate);
2737
2738                if (v != null) {
2739                    return v;
2740                }
2741            }
2742        }
2743
2744        return null;
2745    }
2746
2747    /**
2748     * Adds a child view. If no layout parameters are already set on the child, the
2749     * default parameters for this ViewGroup are set on the child.
2750     *
2751     * @param child the child view to add
2752     *
2753     * @see #generateDefaultLayoutParams()
2754     */
2755    public void addView(View child) {
2756        addView(child, -1);
2757    }
2758
2759    /**
2760     * Adds a child view. If no layout parameters are already set on the child, the
2761     * default parameters for this ViewGroup are set on the child.
2762     *
2763     * @param child the child view to add
2764     * @param index the position at which to add the child
2765     *
2766     * @see #generateDefaultLayoutParams()
2767     */
2768    public void addView(View child, int index) {
2769        LayoutParams params = child.getLayoutParams();
2770        if (params == null) {
2771            params = generateDefaultLayoutParams();
2772            if (params == null) {
2773                throw new IllegalArgumentException("generateDefaultLayoutParams() cannot return null");
2774            }
2775        }
2776        addView(child, index, params);
2777    }
2778
2779    /**
2780     * Adds a child view with this ViewGroup's default layout parameters and the
2781     * specified width and height.
2782     *
2783     * @param child the child view to add
2784     */
2785    public void addView(View child, int width, int height) {
2786        final LayoutParams params = generateDefaultLayoutParams();
2787        params.width = width;
2788        params.height = height;
2789        addView(child, -1, params);
2790    }
2791
2792    /**
2793     * Adds a child view with the specified layout parameters.
2794     *
2795     * @param child the child view to add
2796     * @param params the layout parameters to set on the child
2797     */
2798    public void addView(View child, LayoutParams params) {
2799        addView(child, -1, params);
2800    }
2801
2802    /**
2803     * Adds a child view with the specified layout parameters.
2804     *
2805     * @param child the child view to add
2806     * @param index the position at which to add the child
2807     * @param params the layout parameters to set on the child
2808     */
2809    public void addView(View child, int index, LayoutParams params) {
2810        if (DBG) {
2811            System.out.println(this + " addView");
2812        }
2813
2814        // addViewInner() will call child.requestLayout() when setting the new LayoutParams
2815        // therefore, we call requestLayout() on ourselves before, so that the child's request
2816        // will be blocked at our level
2817        requestLayout();
2818        invalidate(true);
2819        addViewInner(child, index, params, false);
2820    }
2821
2822    /**
2823     * {@inheritDoc}
2824     */
2825    public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
2826        if (!checkLayoutParams(params)) {
2827            throw new IllegalArgumentException("Invalid LayoutParams supplied to " + this);
2828        }
2829        if (view.mParent != this) {
2830            throw new IllegalArgumentException("Given view not a child of " + this);
2831        }
2832        view.setLayoutParams(params);
2833    }
2834
2835    /**
2836     * {@inheritDoc}
2837     */
2838    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
2839        return  p != null;
2840    }
2841
2842    /**
2843     * Interface definition for a callback to be invoked when the hierarchy
2844     * within this view changed. The hierarchy changes whenever a child is added
2845     * to or removed from this view.
2846     */
2847    public interface OnHierarchyChangeListener {
2848        /**
2849         * Called when a new child is added to a parent view.
2850         *
2851         * @param parent the view in which a child was added
2852         * @param child the new child view added in the hierarchy
2853         */
2854        void onChildViewAdded(View parent, View child);
2855
2856        /**
2857         * Called when a child is removed from a parent view.
2858         *
2859         * @param parent the view from which the child was removed
2860         * @param child the child removed from the hierarchy
2861         */
2862        void onChildViewRemoved(View parent, View child);
2863    }
2864
2865    /**
2866     * Register a callback to be invoked when a child is added to or removed
2867     * from this view.
2868     *
2869     * @param listener the callback to invoke on hierarchy change
2870     */
2871    public void setOnHierarchyChangeListener(OnHierarchyChangeListener listener) {
2872        mOnHierarchyChangeListener = listener;
2873    }
2874
2875    /**
2876     * Adds a view during layout. This is useful if in your onLayout() method,
2877     * you need to add more views (as does the list view for example).
2878     *
2879     * If index is negative, it means put it at the end of the list.
2880     *
2881     * @param child the view to add to the group
2882     * @param index the index at which the child must be added
2883     * @param params the layout parameters to associate with the child
2884     * @return true if the child was added, false otherwise
2885     */
2886    protected boolean addViewInLayout(View child, int index, LayoutParams params) {
2887        return addViewInLayout(child, index, params, false);
2888    }
2889
2890    /**
2891     * Adds a view during layout. This is useful if in your onLayout() method,
2892     * you need to add more views (as does the list view for example).
2893     *
2894     * If index is negative, it means put it at the end of the list.
2895     *
2896     * @param child the view to add to the group
2897     * @param index the index at which the child must be added
2898     * @param params the layout parameters to associate with the child
2899     * @param preventRequestLayout if true, calling this method will not trigger a
2900     *        layout request on child
2901     * @return true if the child was added, false otherwise
2902     */
2903    protected boolean addViewInLayout(View child, int index, LayoutParams params,
2904            boolean preventRequestLayout) {
2905        child.mParent = null;
2906        addViewInner(child, index, params, preventRequestLayout);
2907        child.mPrivateFlags = (child.mPrivateFlags & ~DIRTY_MASK) | DRAWN;
2908        return true;
2909    }
2910
2911    /**
2912     * Prevents the specified child to be laid out during the next layout pass.
2913     *
2914     * @param child the child on which to perform the cleanup
2915     */
2916    protected void cleanupLayoutState(View child) {
2917        child.mPrivateFlags &= ~View.FORCE_LAYOUT;
2918    }
2919
2920    private void addViewInner(View child, int index, LayoutParams params,
2921            boolean preventRequestLayout) {
2922
2923        if (child.getParent() != null) {
2924            throw new IllegalStateException("The specified child already has a parent. " +
2925                    "You must call removeView() on the child's parent first.");
2926        }
2927
2928        if (mTransition != null) {
2929            mTransition.addChild(this, child);
2930        }
2931
2932        if (!checkLayoutParams(params)) {
2933            params = generateLayoutParams(params);
2934        }
2935
2936        if (preventRequestLayout) {
2937            child.mLayoutParams = params;
2938        } else {
2939            child.setLayoutParams(params);
2940        }
2941
2942        if (index < 0) {
2943            index = mChildrenCount;
2944        }
2945
2946        addInArray(child, index);
2947
2948        // tell our children
2949        if (preventRequestLayout) {
2950            child.assignParent(this);
2951        } else {
2952            child.mParent = this;
2953        }
2954
2955        if (child.hasFocus()) {
2956            requestChildFocus(child, child.findFocus());
2957        }
2958
2959        AttachInfo ai = mAttachInfo;
2960        if (ai != null) {
2961            boolean lastKeepOn = ai.mKeepScreenOn;
2962            ai.mKeepScreenOn = false;
2963            child.dispatchAttachedToWindow(mAttachInfo, (mViewFlags&VISIBILITY_MASK));
2964            if (ai.mKeepScreenOn) {
2965                needGlobalAttributesUpdate(true);
2966            }
2967            ai.mKeepScreenOn = lastKeepOn;
2968        }
2969
2970        if (mOnHierarchyChangeListener != null) {
2971            mOnHierarchyChangeListener.onChildViewAdded(this, child);
2972        }
2973
2974        if ((child.mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE) {
2975            mGroupFlags |= FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE;
2976        }
2977    }
2978
2979    private void addInArray(View child, int index) {
2980        View[] children = mChildren;
2981        final int count = mChildrenCount;
2982        final int size = children.length;
2983        if (index == count) {
2984            if (size == count) {
2985                mChildren = new View[size + ARRAY_CAPACITY_INCREMENT];
2986                System.arraycopy(children, 0, mChildren, 0, size);
2987                children = mChildren;
2988            }
2989            children[mChildrenCount++] = child;
2990        } else if (index < count) {
2991            if (size == count) {
2992                mChildren = new View[size + ARRAY_CAPACITY_INCREMENT];
2993                System.arraycopy(children, 0, mChildren, 0, index);
2994                System.arraycopy(children, index, mChildren, index + 1, count - index);
2995                children = mChildren;
2996            } else {
2997                System.arraycopy(children, index, children, index + 1, count - index);
2998            }
2999            children[index] = child;
3000            mChildrenCount++;
3001            if (mLastTouchDownIndex >= index) {
3002                mLastTouchDownIndex++;
3003            }
3004        } else {
3005            throw new IndexOutOfBoundsException("index=" + index + " count=" + count);
3006        }
3007    }
3008
3009    // This method also sets the child's mParent to null
3010    private void removeFromArray(int index) {
3011        final View[] children = mChildren;
3012        if (!(mTransitioningViews != null && mTransitioningViews.contains(children[index]))) {
3013            children[index].mParent = null;
3014        }
3015        final int count = mChildrenCount;
3016        if (index == count - 1) {
3017            children[--mChildrenCount] = null;
3018        } else if (index >= 0 && index < count) {
3019            System.arraycopy(children, index + 1, children, index, count - index - 1);
3020            children[--mChildrenCount] = null;
3021        } else {
3022            throw new IndexOutOfBoundsException();
3023        }
3024        if (mLastTouchDownIndex == index) {
3025            mLastTouchDownTime = 0;
3026            mLastTouchDownIndex = -1;
3027        } else if (mLastTouchDownIndex > index) {
3028            mLastTouchDownIndex--;
3029        }
3030    }
3031
3032    // This method also sets the children's mParent to null
3033    private void removeFromArray(int start, int count) {
3034        final View[] children = mChildren;
3035        final int childrenCount = mChildrenCount;
3036
3037        start = Math.max(0, start);
3038        final int end = Math.min(childrenCount, start + count);
3039
3040        if (start == end) {
3041            return;
3042        }
3043
3044        if (end == childrenCount) {
3045            for (int i = start; i < end; i++) {
3046                children[i].mParent = null;
3047                children[i] = null;
3048            }
3049        } else {
3050            for (int i = start; i < end; i++) {
3051                children[i].mParent = null;
3052            }
3053
3054            // Since we're looping above, we might as well do the copy, but is arraycopy()
3055            // faster than the extra 2 bounds checks we would do in the loop?
3056            System.arraycopy(children, end, children, start, childrenCount - end);
3057
3058            for (int i = childrenCount - (end - start); i < childrenCount; i++) {
3059                children[i] = null;
3060            }
3061        }
3062
3063        mChildrenCount -= (end - start);
3064    }
3065
3066    private void bindLayoutAnimation(View child) {
3067        Animation a = mLayoutAnimationController.getAnimationForView(child);
3068        child.setAnimation(a);
3069    }
3070
3071    /**
3072     * Subclasses should override this method to set layout animation
3073     * parameters on the supplied child.
3074     *
3075     * @param child the child to associate with animation parameters
3076     * @param params the child's layout parameters which hold the animation
3077     *        parameters
3078     * @param index the index of the child in the view group
3079     * @param count the number of children in the view group
3080     */
3081    protected void attachLayoutAnimationParameters(View child,
3082            LayoutParams params, int index, int count) {
3083        LayoutAnimationController.AnimationParameters animationParams =
3084                    params.layoutAnimationParameters;
3085        if (animationParams == null) {
3086            animationParams = new LayoutAnimationController.AnimationParameters();
3087            params.layoutAnimationParameters = animationParams;
3088        }
3089
3090        animationParams.count = count;
3091        animationParams.index = index;
3092    }
3093
3094    /**
3095     * {@inheritDoc}
3096     */
3097    public void removeView(View view) {
3098        removeViewInternal(view);
3099        requestLayout();
3100        invalidate(true);
3101    }
3102
3103    /**
3104     * Removes a view during layout. This is useful if in your onLayout() method,
3105     * you need to remove more views.
3106     *
3107     * @param view the view to remove from the group
3108     */
3109    public void removeViewInLayout(View view) {
3110        removeViewInternal(view);
3111    }
3112
3113    /**
3114     * Removes a range of views during layout. This is useful if in your onLayout() method,
3115     * you need to remove more views.
3116     *
3117     * @param start the index of the first view to remove from the group
3118     * @param count the number of views to remove from the group
3119     */
3120    public void removeViewsInLayout(int start, int count) {
3121        removeViewsInternal(start, count);
3122    }
3123
3124    /**
3125     * Removes the view at the specified position in the group.
3126     *
3127     * @param index the position in the group of the view to remove
3128     */
3129    public void removeViewAt(int index) {
3130        removeViewInternal(index, getChildAt(index));
3131        requestLayout();
3132        invalidate(true);
3133    }
3134
3135    /**
3136     * Removes the specified range of views from the group.
3137     *
3138     * @param start the first position in the group of the range of views to remove
3139     * @param count the number of views to remove
3140     */
3141    public void removeViews(int start, int count) {
3142        removeViewsInternal(start, count);
3143        requestLayout();
3144        invalidate(true);
3145    }
3146
3147    private void removeViewInternal(View view) {
3148        final int index = indexOfChild(view);
3149        if (index >= 0) {
3150            removeViewInternal(index, view);
3151        }
3152    }
3153
3154    private void removeViewInternal(int index, View view) {
3155
3156        if (mTransition != null) {
3157            mTransition.removeChild(this, view);
3158        }
3159
3160        boolean clearChildFocus = false;
3161        if (view == mFocused) {
3162            view.clearFocusForRemoval();
3163            clearChildFocus = true;
3164        }
3165
3166        if (view.getAnimation() != null ||
3167                (mTransitioningViews != null && mTransitioningViews.contains(view))) {
3168            addDisappearingView(view);
3169        } else if (view.mAttachInfo != null) {
3170           view.dispatchDetachedFromWindow();
3171        }
3172
3173        if (mOnHierarchyChangeListener != null) {
3174            mOnHierarchyChangeListener.onChildViewRemoved(this, view);
3175        }
3176
3177        needGlobalAttributesUpdate(false);
3178
3179        removeFromArray(index);
3180
3181        if (clearChildFocus) {
3182            clearChildFocus(view);
3183        }
3184    }
3185
3186    /**
3187     * Sets the LayoutTransition object for this ViewGroup. If the LayoutTransition object is
3188     * not null, changes in layout which occur because of children being added to or removed from
3189     * the ViewGroup will be animated according to the animations defined in that LayoutTransition
3190     * object. By default, the transition object is null (so layout changes are not animated).
3191     *
3192     * @param transition The LayoutTransition object that will animated changes in layout. A value
3193     * of <code>null</code> means no transition will run on layout changes.
3194     * @attr ref android.R.styleable#ViewGroup_animateLayoutChanges
3195     */
3196    public void setLayoutTransition(LayoutTransition transition) {
3197        if (mTransition != null) {
3198            mTransition.removeTransitionListener(mLayoutTransitionListener);
3199        }
3200        mTransition = transition;
3201        if (mTransition != null) {
3202            mTransition.addTransitionListener(mLayoutTransitionListener);
3203        }
3204    }
3205
3206    /**
3207     * Gets the LayoutTransition object for this ViewGroup. If the LayoutTransition object is
3208     * not null, changes in layout which occur because of children being added to or removed from
3209     * the ViewGroup will be animated according to the animations defined in that LayoutTransition
3210     * object. By default, the transition object is null (so layout changes are not animated).
3211     *
3212     * @return LayoutTranstion The LayoutTransition object that will animated changes in layout.
3213     * A value of <code>null</code> means no transition will run on layout changes.
3214     */
3215    public LayoutTransition getLayoutTransition() {
3216        return mTransition;
3217    }
3218
3219    private void removeViewsInternal(int start, int count) {
3220        final OnHierarchyChangeListener onHierarchyChangeListener = mOnHierarchyChangeListener;
3221        final boolean notifyListener = onHierarchyChangeListener != null;
3222        final View focused = mFocused;
3223        final boolean detach = mAttachInfo != null;
3224        View clearChildFocus = null;
3225
3226        final View[] children = mChildren;
3227        final int end = start + count;
3228
3229        for (int i = start; i < end; i++) {
3230            final View view = children[i];
3231
3232            if (mTransition != null) {
3233                mTransition.removeChild(this, view);
3234            }
3235
3236            if (view == focused) {
3237                view.clearFocusForRemoval();
3238                clearChildFocus = view;
3239            }
3240
3241            if (view.getAnimation() != null ||
3242                (mTransitioningViews != null && mTransitioningViews.contains(view))) {
3243                addDisappearingView(view);
3244            } else if (detach) {
3245               view.dispatchDetachedFromWindow();
3246            }
3247
3248            needGlobalAttributesUpdate(false);
3249
3250            if (notifyListener) {
3251                onHierarchyChangeListener.onChildViewRemoved(this, view);
3252            }
3253        }
3254
3255        removeFromArray(start, count);
3256
3257        if (clearChildFocus != null) {
3258            clearChildFocus(clearChildFocus);
3259        }
3260    }
3261
3262    /**
3263     * Call this method to remove all child views from the
3264     * ViewGroup.
3265     */
3266    public void removeAllViews() {
3267        removeAllViewsInLayout();
3268        requestLayout();
3269        invalidate(true);
3270    }
3271
3272    /**
3273     * Called by a ViewGroup subclass to remove child views from itself,
3274     * when it must first know its size on screen before it can calculate how many
3275     * child views it will render. An example is a Gallery or a ListView, which
3276     * may "have" 50 children, but actually only render the number of children
3277     * that can currently fit inside the object on screen. Do not call
3278     * this method unless you are extending ViewGroup and understand the
3279     * view measuring and layout pipeline.
3280     */
3281    public void removeAllViewsInLayout() {
3282        final int count = mChildrenCount;
3283        if (count <= 0) {
3284            return;
3285        }
3286
3287        final View[] children = mChildren;
3288        mChildrenCount = 0;
3289
3290        final OnHierarchyChangeListener listener = mOnHierarchyChangeListener;
3291        final boolean notify = listener != null;
3292        final View focused = mFocused;
3293        final boolean detach = mAttachInfo != null;
3294        View clearChildFocus = null;
3295
3296        needGlobalAttributesUpdate(false);
3297
3298        for (int i = count - 1; i >= 0; i--) {
3299            final View view = children[i];
3300
3301            if (mTransition != null) {
3302                mTransition.removeChild(this, view);
3303            }
3304
3305            if (view == focused) {
3306                view.clearFocusForRemoval();
3307                clearChildFocus = view;
3308            }
3309
3310            if (view.getAnimation() != null ||
3311                    (mTransitioningViews != null && mTransitioningViews.contains(view))) {
3312                addDisappearingView(view);
3313            } else if (detach) {
3314               view.dispatchDetachedFromWindow();
3315            }
3316
3317            if (notify) {
3318                listener.onChildViewRemoved(this, view);
3319            }
3320
3321            view.mParent = null;
3322            children[i] = null;
3323        }
3324
3325        if (clearChildFocus != null) {
3326            clearChildFocus(clearChildFocus);
3327        }
3328    }
3329
3330    /**
3331     * Finishes the removal of a detached view. This method will dispatch the detached from
3332     * window event and notify the hierarchy change listener.
3333     *
3334     * @param child the child to be definitely removed from the view hierarchy
3335     * @param animate if true and the view has an animation, the view is placed in the
3336     *                disappearing views list, otherwise, it is detached from the window
3337     *
3338     * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
3339     * @see #detachAllViewsFromParent()
3340     * @see #detachViewFromParent(View)
3341     * @see #detachViewFromParent(int)
3342     */
3343    protected void removeDetachedView(View child, boolean animate) {
3344        if (mTransition != null) {
3345            mTransition.removeChild(this, child);
3346        }
3347
3348        if (child == mFocused) {
3349            child.clearFocus();
3350        }
3351
3352        if ((animate && child.getAnimation() != null) ||
3353                (mTransitioningViews != null && mTransitioningViews.contains(child))) {
3354            addDisappearingView(child);
3355        } else if (child.mAttachInfo != null) {
3356            child.dispatchDetachedFromWindow();
3357        }
3358
3359        if (mOnHierarchyChangeListener != null) {
3360            mOnHierarchyChangeListener.onChildViewRemoved(this, child);
3361        }
3362    }
3363
3364    /**
3365     * Attaches a view to this view group. Attaching a view assigns this group as the parent,
3366     * sets the layout parameters and puts the view in the list of children so it can be retrieved
3367     * by calling {@link #getChildAt(int)}.
3368     *
3369     * This method should be called only for view which were detached from their parent.
3370     *
3371     * @param child the child to attach
3372     * @param index the index at which the child should be attached
3373     * @param params the layout parameters of the child
3374     *
3375     * @see #removeDetachedView(View, boolean)
3376     * @see #detachAllViewsFromParent()
3377     * @see #detachViewFromParent(View)
3378     * @see #detachViewFromParent(int)
3379     */
3380    protected void attachViewToParent(View child, int index, LayoutParams params) {
3381        child.mLayoutParams = params;
3382
3383        if (index < 0) {
3384            index = mChildrenCount;
3385        }
3386
3387        addInArray(child, index);
3388
3389        child.mParent = this;
3390        child.mPrivateFlags = (child.mPrivateFlags & ~DIRTY_MASK & ~DRAWING_CACHE_VALID) |
3391                DRAWN | INVALIDATED;
3392        this.mPrivateFlags |= INVALIDATED;
3393
3394        if (child.hasFocus()) {
3395            requestChildFocus(child, child.findFocus());
3396        }
3397    }
3398
3399    /**
3400     * Detaches a view from its parent. Detaching a view should be temporary and followed
3401     * either by a call to {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
3402     * or a call to {@link #removeDetachedView(View, boolean)}. When a view is detached,
3403     * its parent is null and cannot be retrieved by a call to {@link #getChildAt(int)}.
3404     *
3405     * @param child the child to detach
3406     *
3407     * @see #detachViewFromParent(int)
3408     * @see #detachViewsFromParent(int, int)
3409     * @see #detachAllViewsFromParent()
3410     * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
3411     * @see #removeDetachedView(View, boolean)
3412     */
3413    protected void detachViewFromParent(View child) {
3414        removeFromArray(indexOfChild(child));
3415    }
3416
3417    /**
3418     * Detaches a view from its parent. Detaching a view should be temporary and followed
3419     * either by a call to {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
3420     * or a call to {@link #removeDetachedView(View, boolean)}. When a view is detached,
3421     * its parent is null and cannot be retrieved by a call to {@link #getChildAt(int)}.
3422     *
3423     * @param index the index of the child to detach
3424     *
3425     * @see #detachViewFromParent(View)
3426     * @see #detachAllViewsFromParent()
3427     * @see #detachViewsFromParent(int, int)
3428     * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
3429     * @see #removeDetachedView(View, boolean)
3430     */
3431    protected void detachViewFromParent(int index) {
3432        removeFromArray(index);
3433    }
3434
3435    /**
3436     * Detaches a range of view from their parent. Detaching a view should be temporary and followed
3437     * either by a call to {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
3438     * or a call to {@link #removeDetachedView(View, boolean)}. When a view is detached, its
3439     * parent is null and cannot be retrieved by a call to {@link #getChildAt(int)}.
3440     *
3441     * @param start the first index of the childrend range to detach
3442     * @param count the number of children to detach
3443     *
3444     * @see #detachViewFromParent(View)
3445     * @see #detachViewFromParent(int)
3446     * @see #detachAllViewsFromParent()
3447     * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
3448     * @see #removeDetachedView(View, boolean)
3449     */
3450    protected void detachViewsFromParent(int start, int count) {
3451        removeFromArray(start, count);
3452    }
3453
3454    /**
3455     * Detaches all views from the parent. Detaching a view should be temporary and followed
3456     * either by a call to {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
3457     * or a call to {@link #removeDetachedView(View, boolean)}. When a view is detached,
3458     * its parent is null and cannot be retrieved by a call to {@link #getChildAt(int)}.
3459     *
3460     * @see #detachViewFromParent(View)
3461     * @see #detachViewFromParent(int)
3462     * @see #detachViewsFromParent(int, int)
3463     * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
3464     * @see #removeDetachedView(View, boolean)
3465     */
3466    protected void detachAllViewsFromParent() {
3467        final int count = mChildrenCount;
3468        if (count <= 0) {
3469            return;
3470        }
3471
3472        final View[] children = mChildren;
3473        mChildrenCount = 0;
3474
3475        for (int i = count - 1; i >= 0; i--) {
3476            children[i].mParent = null;
3477            children[i] = null;
3478        }
3479    }
3480
3481    /**
3482     * Don't call or override this method. It is used for the implementation of
3483     * the view hierarchy.
3484     */
3485    public final void invalidateChild(View child, final Rect dirty) {
3486        if (ViewDebug.TRACE_HIERARCHY) {
3487            ViewDebug.trace(this, ViewDebug.HierarchyTraceType.INVALIDATE_CHILD);
3488        }
3489
3490        ViewParent parent = this;
3491
3492        final AttachInfo attachInfo = mAttachInfo;
3493        if (attachInfo != null) {
3494            // If the child is drawing an animation, we want to copy this flag onto
3495            // ourselves and the parent to make sure the invalidate request goes
3496            // through
3497            final boolean drawAnimation = (child.mPrivateFlags & DRAW_ANIMATION) == DRAW_ANIMATION;
3498
3499            if (dirty == null) {
3500                if (child.mLayerType != LAYER_TYPE_NONE) {
3501                    mPrivateFlags |= INVALIDATED;
3502                    mPrivateFlags &= ~DRAWING_CACHE_VALID;
3503                    child.mLocalDirtyRect.setEmpty();
3504                }
3505                do {
3506                    View view = null;
3507                    if (parent instanceof View) {
3508                        view = (View) parent;
3509                        if (view.mLayerType != LAYER_TYPE_NONE) {
3510                            view.mLocalDirtyRect.setEmpty();
3511                            if (view.getParent() instanceof View) {
3512                                final View grandParent = (View) view.getParent();
3513                                grandParent.mPrivateFlags |= INVALIDATED;
3514                                grandParent.mPrivateFlags &= ~DRAWING_CACHE_VALID;
3515                            }
3516                        }
3517                        if ((view.mPrivateFlags & DIRTY_MASK) != 0) {
3518                            // already marked dirty - we're done
3519                            break;
3520                        }
3521                    }
3522
3523                    if (drawAnimation) {
3524                        if (view != null) {
3525                            view.mPrivateFlags |= DRAW_ANIMATION;
3526                        } else if (parent instanceof ViewRoot) {
3527                            ((ViewRoot) parent).mIsAnimating = true;
3528                        }
3529                    }
3530
3531                    if (parent instanceof ViewRoot) {
3532                        ((ViewRoot) parent).invalidate();
3533                        parent = null;
3534                    } else if (view != null) {
3535                        if ((view.mPrivateFlags & DRAWN) == DRAWN ||
3536                                (view.mPrivateFlags & DRAWING_CACHE_VALID) == DRAWING_CACHE_VALID) {
3537                            view.mPrivateFlags &= ~DRAWING_CACHE_VALID;
3538                            view.mPrivateFlags |= DIRTY;
3539                            parent = view.mParent;
3540                        } else {
3541                            parent = null;
3542                        }
3543                    }
3544                } while (parent != null);
3545            } else {
3546                // Check whether the child that requests the invalidate is fully opaque
3547                final boolean isOpaque = child.isOpaque() && !drawAnimation &&
3548                        child.getAnimation() == null;
3549                // Mark the child as dirty, using the appropriate flag
3550                // Make sure we do not set both flags at the same time
3551                int opaqueFlag = isOpaque ? DIRTY_OPAQUE : DIRTY;
3552
3553                if (child.mLayerType != LAYER_TYPE_NONE) {
3554                    mPrivateFlags |= INVALIDATED;
3555                    mPrivateFlags &= ~DRAWING_CACHE_VALID;
3556                    child.mLocalDirtyRect.union(dirty);
3557                }
3558
3559                final int[] location = attachInfo.mInvalidateChildLocation;
3560                location[CHILD_LEFT_INDEX] = child.mLeft;
3561                location[CHILD_TOP_INDEX] = child.mTop;
3562                Matrix childMatrix = child.getMatrix();
3563                if (!childMatrix.isIdentity()) {
3564                    RectF boundingRect = attachInfo.mTmpTransformRect;
3565                    boundingRect.set(dirty);
3566                    childMatrix.mapRect(boundingRect);
3567                    dirty.set((int) boundingRect.left, (int) boundingRect.top,
3568                            (int) (boundingRect.right + 0.5f),
3569                            (int) (boundingRect.bottom + 0.5f));
3570                }
3571
3572                do {
3573                    View view = null;
3574                    if (parent instanceof View) {
3575                        view = (View) parent;
3576                        if (view.mLayerType != LAYER_TYPE_NONE &&
3577                                view.getParent() instanceof View) {
3578                            final View grandParent = (View) view.getParent();
3579                            grandParent.mPrivateFlags |= INVALIDATED;
3580                            grandParent.mPrivateFlags &= ~DRAWING_CACHE_VALID;
3581                        }
3582                    }
3583
3584                    if (drawAnimation) {
3585                        if (view != null) {
3586                            view.mPrivateFlags |= DRAW_ANIMATION;
3587                        } else if (parent instanceof ViewRoot) {
3588                            ((ViewRoot) parent).mIsAnimating = true;
3589                        }
3590                    }
3591
3592                    // If the parent is dirty opaque or not dirty, mark it dirty with the opaque
3593                    // flag coming from the child that initiated the invalidate
3594                    if (view != null) {
3595                        if ((view.mViewFlags & FADING_EDGE_MASK) != 0 &&
3596                                view.getSolidColor() == 0 && !view.isOpaque()) {
3597                            opaqueFlag = DIRTY;
3598                        }
3599                        if ((view.mPrivateFlags & DIRTY_MASK) != DIRTY) {
3600                            view.mPrivateFlags = (view.mPrivateFlags & ~DIRTY_MASK) | opaqueFlag;
3601                        }
3602                    }
3603
3604                    parent = parent.invalidateChildInParent(location, dirty);
3605                    if (view != null) {
3606                        // Account for transform on current parent
3607                        Matrix m = view.getMatrix();
3608                        if (!m.isIdentity()) {
3609                            RectF boundingRect = attachInfo.mTmpTransformRect;
3610                            boundingRect.set(dirty);
3611                            m.mapRect(boundingRect);
3612                            dirty.set((int) boundingRect.left, (int) boundingRect.top,
3613                                    (int) (boundingRect.right + 0.5f),
3614                                    (int) (boundingRect.bottom + 0.5f));
3615                        }
3616                    }
3617                } while (parent != null);
3618            }
3619        }
3620    }
3621
3622    /**
3623     * Don't call or override this method. It is used for the implementation of
3624     * the view hierarchy.
3625     *
3626     * This implementation returns null if this ViewGroup does not have a parent,
3627     * if this ViewGroup is already fully invalidated or if the dirty rectangle
3628     * does not intersect with this ViewGroup's bounds.
3629     */
3630    public ViewParent invalidateChildInParent(final int[] location, final Rect dirty) {
3631        if (ViewDebug.TRACE_HIERARCHY) {
3632            ViewDebug.trace(this, ViewDebug.HierarchyTraceType.INVALIDATE_CHILD_IN_PARENT);
3633        }
3634
3635        if ((mPrivateFlags & DRAWN) == DRAWN ||
3636                (mPrivateFlags & DRAWING_CACHE_VALID) == DRAWING_CACHE_VALID) {
3637            if ((mGroupFlags & (FLAG_OPTIMIZE_INVALIDATE | FLAG_ANIMATION_DONE)) !=
3638                        FLAG_OPTIMIZE_INVALIDATE) {
3639                dirty.offset(location[CHILD_LEFT_INDEX] - mScrollX,
3640                        location[CHILD_TOP_INDEX] - mScrollY);
3641
3642                final int left = mLeft;
3643                final int top = mTop;
3644
3645                if (dirty.intersect(0, 0, mRight - left, mBottom - top) ||
3646                        (mPrivateFlags & DRAW_ANIMATION) == DRAW_ANIMATION) {
3647                    mPrivateFlags &= ~DRAWING_CACHE_VALID;
3648
3649                    location[CHILD_LEFT_INDEX] = left;
3650                    location[CHILD_TOP_INDEX] = top;
3651
3652                    if (mLayerType != LAYER_TYPE_NONE) {
3653                        mLocalDirtyRect.union(dirty);
3654                    }
3655
3656                    return mParent;
3657                }
3658            } else {
3659                mPrivateFlags &= ~DRAWN & ~DRAWING_CACHE_VALID;
3660
3661                location[CHILD_LEFT_INDEX] = mLeft;
3662                location[CHILD_TOP_INDEX] = mTop;
3663
3664                dirty.set(0, 0, mRight - mLeft, mBottom - mTop);
3665
3666                if (mLayerType != LAYER_TYPE_NONE) {
3667                    mLocalDirtyRect.union(dirty);
3668                }
3669
3670                return mParent;
3671            }
3672        }
3673
3674        return null;
3675    }
3676
3677    /**
3678     * Offset a rectangle that is in a descendant's coordinate
3679     * space into our coordinate space.
3680     * @param descendant A descendant of this view
3681     * @param rect A rectangle defined in descendant's coordinate space.
3682     */
3683    public final void offsetDescendantRectToMyCoords(View descendant, Rect rect) {
3684        offsetRectBetweenParentAndChild(descendant, rect, true, false);
3685    }
3686
3687    /**
3688     * Offset a rectangle that is in our coordinate space into an ancestor's
3689     * coordinate space.
3690     * @param descendant A descendant of this view
3691     * @param rect A rectangle defined in descendant's coordinate space.
3692     */
3693    public final void offsetRectIntoDescendantCoords(View descendant, Rect rect) {
3694        offsetRectBetweenParentAndChild(descendant, rect, false, false);
3695    }
3696
3697    /**
3698     * Helper method that offsets a rect either from parent to descendant or
3699     * descendant to parent.
3700     */
3701    void offsetRectBetweenParentAndChild(View descendant, Rect rect,
3702            boolean offsetFromChildToParent, boolean clipToBounds) {
3703
3704        // already in the same coord system :)
3705        if (descendant == this) {
3706            return;
3707        }
3708
3709        ViewParent theParent = descendant.mParent;
3710
3711        // search and offset up to the parent
3712        while ((theParent != null)
3713                && (theParent instanceof View)
3714                && (theParent != this)) {
3715
3716            if (offsetFromChildToParent) {
3717                rect.offset(descendant.mLeft - descendant.mScrollX,
3718                        descendant.mTop - descendant.mScrollY);
3719                if (clipToBounds) {
3720                    View p = (View) theParent;
3721                    rect.intersect(0, 0, p.mRight - p.mLeft, p.mBottom - p.mTop);
3722                }
3723            } else {
3724                if (clipToBounds) {
3725                    View p = (View) theParent;
3726                    rect.intersect(0, 0, p.mRight - p.mLeft, p.mBottom - p.mTop);
3727                }
3728                rect.offset(descendant.mScrollX - descendant.mLeft,
3729                        descendant.mScrollY - descendant.mTop);
3730            }
3731
3732            descendant = (View) theParent;
3733            theParent = descendant.mParent;
3734        }
3735
3736        // now that we are up to this view, need to offset one more time
3737        // to get into our coordinate space
3738        if (theParent == this) {
3739            if (offsetFromChildToParent) {
3740                rect.offset(descendant.mLeft - descendant.mScrollX,
3741                        descendant.mTop - descendant.mScrollY);
3742            } else {
3743                rect.offset(descendant.mScrollX - descendant.mLeft,
3744                        descendant.mScrollY - descendant.mTop);
3745            }
3746        } else {
3747            throw new IllegalArgumentException("parameter must be a descendant of this view");
3748        }
3749    }
3750
3751    /**
3752     * Offset the vertical location of all children of this view by the specified number of pixels.
3753     *
3754     * @param offset the number of pixels to offset
3755     *
3756     * @hide
3757     */
3758    public void offsetChildrenTopAndBottom(int offset) {
3759        final int count = mChildrenCount;
3760        final View[] children = mChildren;
3761
3762        for (int i = 0; i < count; i++) {
3763            final View v = children[i];
3764            v.mTop += offset;
3765            v.mBottom += offset;
3766        }
3767    }
3768
3769    /**
3770     * {@inheritDoc}
3771     */
3772    public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) {
3773        int dx = child.mLeft - mScrollX;
3774        int dy = child.mTop - mScrollY;
3775        if (offset != null) {
3776            offset.x += dx;
3777            offset.y += dy;
3778        }
3779        r.offset(dx, dy);
3780        return r.intersect(0, 0, mRight - mLeft, mBottom - mTop) &&
3781               (mParent == null || mParent.getChildVisibleRect(this, r, offset));
3782    }
3783
3784    /**
3785     * {@inheritDoc}
3786     */
3787    @Override
3788    public final void layout(int l, int t, int r, int b) {
3789        if (mTransition == null || !mTransition.isChangingLayout()) {
3790            super.layout(l, t, r, b);
3791        } else {
3792            // record the fact that we noop'd it; request layout when transition finishes
3793            mLayoutSuppressed = true;
3794        }
3795    }
3796
3797    /**
3798     * {@inheritDoc}
3799     */
3800    @Override
3801    protected abstract void onLayout(boolean changed,
3802            int l, int t, int r, int b);
3803
3804    /**
3805     * Indicates whether the view group has the ability to animate its children
3806     * after the first layout.
3807     *
3808     * @return true if the children can be animated, false otherwise
3809     */
3810    protected boolean canAnimate() {
3811        return mLayoutAnimationController != null;
3812    }
3813
3814    /**
3815     * Runs the layout animation. Calling this method triggers a relayout of
3816     * this view group.
3817     */
3818    public void startLayoutAnimation() {
3819        if (mLayoutAnimationController != null) {
3820            mGroupFlags |= FLAG_RUN_ANIMATION;
3821            requestLayout();
3822        }
3823    }
3824
3825    /**
3826     * Schedules the layout animation to be played after the next layout pass
3827     * of this view group. This can be used to restart the layout animation
3828     * when the content of the view group changes or when the activity is
3829     * paused and resumed.
3830     */
3831    public void scheduleLayoutAnimation() {
3832        mGroupFlags |= FLAG_RUN_ANIMATION;
3833    }
3834
3835    /**
3836     * Sets the layout animation controller used to animate the group's
3837     * children after the first layout.
3838     *
3839     * @param controller the animation controller
3840     */
3841    public void setLayoutAnimation(LayoutAnimationController controller) {
3842        mLayoutAnimationController = controller;
3843        if (mLayoutAnimationController != null) {
3844            mGroupFlags |= FLAG_RUN_ANIMATION;
3845        }
3846    }
3847
3848    /**
3849     * Returns the layout animation controller used to animate the group's
3850     * children.
3851     *
3852     * @return the current animation controller
3853     */
3854    public LayoutAnimationController getLayoutAnimation() {
3855        return mLayoutAnimationController;
3856    }
3857
3858    /**
3859     * Indicates whether the children's drawing cache is used during a layout
3860     * animation. By default, the drawing cache is enabled but this will prevent
3861     * nested layout animations from working. To nest animations, you must disable
3862     * the cache.
3863     *
3864     * @return true if the animation cache is enabled, false otherwise
3865     *
3866     * @see #setAnimationCacheEnabled(boolean)
3867     * @see View#setDrawingCacheEnabled(boolean)
3868     */
3869    @ViewDebug.ExportedProperty
3870    public boolean isAnimationCacheEnabled() {
3871        return (mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE;
3872    }
3873
3874    /**
3875     * Enables or disables the children's drawing cache during a layout animation.
3876     * By default, the drawing cache is enabled but this will prevent nested
3877     * layout animations from working. To nest animations, you must disable the
3878     * cache.
3879     *
3880     * @param enabled true to enable the animation cache, false otherwise
3881     *
3882     * @see #isAnimationCacheEnabled()
3883     * @see View#setDrawingCacheEnabled(boolean)
3884     */
3885    public void setAnimationCacheEnabled(boolean enabled) {
3886        setBooleanFlag(FLAG_ANIMATION_CACHE, enabled);
3887    }
3888
3889    /**
3890     * Indicates whether this ViewGroup will always try to draw its children using their
3891     * drawing cache. By default this property is enabled.
3892     *
3893     * @return true if the animation cache is enabled, false otherwise
3894     *
3895     * @see #setAlwaysDrawnWithCacheEnabled(boolean)
3896     * @see #setChildrenDrawnWithCacheEnabled(boolean)
3897     * @see View#setDrawingCacheEnabled(boolean)
3898     */
3899    @ViewDebug.ExportedProperty(category = "drawing")
3900    public boolean isAlwaysDrawnWithCacheEnabled() {
3901        return (mGroupFlags & FLAG_ALWAYS_DRAWN_WITH_CACHE) == FLAG_ALWAYS_DRAWN_WITH_CACHE;
3902    }
3903
3904    /**
3905     * Indicates whether this ViewGroup will always try to draw its children using their
3906     * drawing cache. This property can be set to true when the cache rendering is
3907     * slightly different from the children's normal rendering. Renderings can be different,
3908     * for instance, when the cache's quality is set to low.
3909     *
3910     * When this property is disabled, the ViewGroup will use the drawing cache of its
3911     * children only when asked to. It's usually the task of subclasses to tell ViewGroup
3912     * when to start using the drawing cache and when to stop using it.
3913     *
3914     * @param always true to always draw with the drawing cache, false otherwise
3915     *
3916     * @see #isAlwaysDrawnWithCacheEnabled()
3917     * @see #setChildrenDrawnWithCacheEnabled(boolean)
3918     * @see View#setDrawingCacheEnabled(boolean)
3919     * @see View#setDrawingCacheQuality(int)
3920     */
3921    public void setAlwaysDrawnWithCacheEnabled(boolean always) {
3922        setBooleanFlag(FLAG_ALWAYS_DRAWN_WITH_CACHE, always);
3923    }
3924
3925    /**
3926     * Indicates whether the ViewGroup is currently drawing its children using
3927     * their drawing cache.
3928     *
3929     * @return true if children should be drawn with their cache, false otherwise
3930     *
3931     * @see #setAlwaysDrawnWithCacheEnabled(boolean)
3932     * @see #setChildrenDrawnWithCacheEnabled(boolean)
3933     */
3934    @ViewDebug.ExportedProperty(category = "drawing")
3935    protected boolean isChildrenDrawnWithCacheEnabled() {
3936        return (mGroupFlags & FLAG_CHILDREN_DRAWN_WITH_CACHE) == FLAG_CHILDREN_DRAWN_WITH_CACHE;
3937    }
3938
3939    /**
3940     * Tells the ViewGroup to draw its children using their drawing cache. This property
3941     * is ignored when {@link #isAlwaysDrawnWithCacheEnabled()} is true. A child's drawing cache
3942     * will be used only if it has been enabled.
3943     *
3944     * Subclasses should call this method to start and stop using the drawing cache when
3945     * they perform performance sensitive operations, like scrolling or animating.
3946     *
3947     * @param enabled true if children should be drawn with their cache, false otherwise
3948     *
3949     * @see #setAlwaysDrawnWithCacheEnabled(boolean)
3950     * @see #isChildrenDrawnWithCacheEnabled()
3951     */
3952    protected void setChildrenDrawnWithCacheEnabled(boolean enabled) {
3953        setBooleanFlag(FLAG_CHILDREN_DRAWN_WITH_CACHE, enabled);
3954    }
3955
3956    /**
3957     * Indicates whether the ViewGroup is drawing its children in the order defined by
3958     * {@link #getChildDrawingOrder(int, int)}.
3959     *
3960     * @return true if children drawing order is defined by {@link #getChildDrawingOrder(int, int)},
3961     *         false otherwise
3962     *
3963     * @see #setChildrenDrawingOrderEnabled(boolean)
3964     * @see #getChildDrawingOrder(int, int)
3965     */
3966    @ViewDebug.ExportedProperty(category = "drawing")
3967    protected boolean isChildrenDrawingOrderEnabled() {
3968        return (mGroupFlags & FLAG_USE_CHILD_DRAWING_ORDER) == FLAG_USE_CHILD_DRAWING_ORDER;
3969    }
3970
3971    /**
3972     * Tells the ViewGroup whether to draw its children in the order defined by the method
3973     * {@link #getChildDrawingOrder(int, int)}.
3974     *
3975     * @param enabled true if the order of the children when drawing is determined by
3976     *        {@link #getChildDrawingOrder(int, int)}, false otherwise
3977     *
3978     * @see #isChildrenDrawingOrderEnabled()
3979     * @see #getChildDrawingOrder(int, int)
3980     */
3981    protected void setChildrenDrawingOrderEnabled(boolean enabled) {
3982        setBooleanFlag(FLAG_USE_CHILD_DRAWING_ORDER, enabled);
3983    }
3984
3985    private void setBooleanFlag(int flag, boolean value) {
3986        if (value) {
3987            mGroupFlags |= flag;
3988        } else {
3989            mGroupFlags &= ~flag;
3990        }
3991    }
3992
3993    /**
3994     * Returns an integer indicating what types of drawing caches are kept in memory.
3995     *
3996     * @see #setPersistentDrawingCache(int)
3997     * @see #setAnimationCacheEnabled(boolean)
3998     *
3999     * @return one or a combination of {@link #PERSISTENT_NO_CACHE},
4000     *         {@link #PERSISTENT_ANIMATION_CACHE}, {@link #PERSISTENT_SCROLLING_CACHE}
4001     *         and {@link #PERSISTENT_ALL_CACHES}
4002     */
4003    @ViewDebug.ExportedProperty(category = "drawing", mapping = {
4004        @ViewDebug.IntToString(from = PERSISTENT_NO_CACHE,        to = "NONE"),
4005        @ViewDebug.IntToString(from = PERSISTENT_ANIMATION_CACHE, to = "ANIMATION"),
4006        @ViewDebug.IntToString(from = PERSISTENT_SCROLLING_CACHE, to = "SCROLLING"),
4007        @ViewDebug.IntToString(from = PERSISTENT_ALL_CACHES,      to = "ALL")
4008    })
4009    public int getPersistentDrawingCache() {
4010        return mPersistentDrawingCache;
4011    }
4012
4013    /**
4014     * Indicates what types of drawing caches should be kept in memory after
4015     * they have been created.
4016     *
4017     * @see #getPersistentDrawingCache()
4018     * @see #setAnimationCacheEnabled(boolean)
4019     *
4020     * @param drawingCacheToKeep one or a combination of {@link #PERSISTENT_NO_CACHE},
4021     *        {@link #PERSISTENT_ANIMATION_CACHE}, {@link #PERSISTENT_SCROLLING_CACHE}
4022     *        and {@link #PERSISTENT_ALL_CACHES}
4023     */
4024    public void setPersistentDrawingCache(int drawingCacheToKeep) {
4025        mPersistentDrawingCache = drawingCacheToKeep & PERSISTENT_ALL_CACHES;
4026    }
4027
4028    /**
4029     * Returns a new set of layout parameters based on the supplied attributes set.
4030     *
4031     * @param attrs the attributes to build the layout parameters from
4032     *
4033     * @return an instance of {@link android.view.ViewGroup.LayoutParams} or one
4034     *         of its descendants
4035     */
4036    public LayoutParams generateLayoutParams(AttributeSet attrs) {
4037        return new LayoutParams(getContext(), attrs);
4038    }
4039
4040    /**
4041     * Returns a safe set of layout parameters based on the supplied layout params.
4042     * When a ViewGroup is passed a View whose layout params do not pass the test of
4043     * {@link #checkLayoutParams(android.view.ViewGroup.LayoutParams)}, this method
4044     * is invoked. This method should return a new set of layout params suitable for
4045     * this ViewGroup, possibly by copying the appropriate attributes from the
4046     * specified set of layout params.
4047     *
4048     * @param p The layout parameters to convert into a suitable set of layout parameters
4049     *          for this ViewGroup.
4050     *
4051     * @return an instance of {@link android.view.ViewGroup.LayoutParams} or one
4052     *         of its descendants
4053     */
4054    protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
4055        return p;
4056    }
4057
4058    /**
4059     * Returns a set of default layout parameters. These parameters are requested
4060     * when the View passed to {@link #addView(View)} has no layout parameters
4061     * already set. If null is returned, an exception is thrown from addView.
4062     *
4063     * @return a set of default layout parameters or null
4064     */
4065    protected LayoutParams generateDefaultLayoutParams() {
4066        return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
4067    }
4068
4069    /**
4070     * @hide
4071     */
4072    @Override
4073    protected boolean dispatchConsistencyCheck(int consistency) {
4074        boolean result = super.dispatchConsistencyCheck(consistency);
4075
4076        final int count = mChildrenCount;
4077        final View[] children = mChildren;
4078        for (int i = 0; i < count; i++) {
4079            if (!children[i].dispatchConsistencyCheck(consistency)) result = false;
4080        }
4081
4082        return result;
4083    }
4084
4085    /**
4086     * @hide
4087     */
4088    @Override
4089    protected boolean onConsistencyCheck(int consistency) {
4090        boolean result = super.onConsistencyCheck(consistency);
4091
4092        final boolean checkLayout = (consistency & ViewDebug.CONSISTENCY_LAYOUT) != 0;
4093        final boolean checkDrawing = (consistency & ViewDebug.CONSISTENCY_DRAWING) != 0;
4094
4095        if (checkLayout) {
4096            final int count = mChildrenCount;
4097            final View[] children = mChildren;
4098            for (int i = 0; i < count; i++) {
4099                if (children[i].getParent() != this) {
4100                    result = false;
4101                    android.util.Log.d(ViewDebug.CONSISTENCY_LOG_TAG,
4102                            "View " + children[i] + " has no parent/a parent that is not " + this);
4103                }
4104            }
4105        }
4106
4107        if (checkDrawing) {
4108            // If this group is dirty, check that the parent is dirty as well
4109            if ((mPrivateFlags & DIRTY_MASK) != 0) {
4110                final ViewParent parent = getParent();
4111                if (parent != null && !(parent instanceof ViewRoot)) {
4112                    if ((((View) parent).mPrivateFlags & DIRTY_MASK) == 0) {
4113                        result = false;
4114                        android.util.Log.d(ViewDebug.CONSISTENCY_LOG_TAG,
4115                                "ViewGroup " + this + " is dirty but its parent is not: " + this);
4116                    }
4117                }
4118            }
4119        }
4120
4121        return result;
4122    }
4123
4124    /**
4125     * {@inheritDoc}
4126     */
4127    @Override
4128    protected void debug(int depth) {
4129        super.debug(depth);
4130        String output;
4131
4132        if (mFocused != null) {
4133            output = debugIndent(depth);
4134            output += "mFocused";
4135            Log.d(VIEW_LOG_TAG, output);
4136        }
4137        if (mChildrenCount != 0) {
4138            output = debugIndent(depth);
4139            output += "{";
4140            Log.d(VIEW_LOG_TAG, output);
4141        }
4142        int count = mChildrenCount;
4143        for (int i = 0; i < count; i++) {
4144            View child = mChildren[i];
4145            child.debug(depth + 1);
4146        }
4147
4148        if (mChildrenCount != 0) {
4149            output = debugIndent(depth);
4150            output += "}";
4151            Log.d(VIEW_LOG_TAG, output);
4152        }
4153    }
4154
4155    /**
4156     * Returns the position in the group of the specified child view.
4157     *
4158     * @param child the view for which to get the position
4159     * @return a positive integer representing the position of the view in the
4160     *         group, or -1 if the view does not exist in the group
4161     */
4162    public int indexOfChild(View child) {
4163        final int count = mChildrenCount;
4164        final View[] children = mChildren;
4165        for (int i = 0; i < count; i++) {
4166            if (children[i] == child) {
4167                return i;
4168            }
4169        }
4170        return -1;
4171    }
4172
4173    /**
4174     * Returns the number of children in the group.
4175     *
4176     * @return a positive integer representing the number of children in
4177     *         the group
4178     */
4179    public int getChildCount() {
4180        return mChildrenCount;
4181    }
4182
4183    /**
4184     * Returns the view at the specified position in the group.
4185     *
4186     * @param index the position at which to get the view from
4187     * @return the view at the specified position or null if the position
4188     *         does not exist within the group
4189     */
4190    public View getChildAt(int index) {
4191        try {
4192            return mChildren[index];
4193        } catch (IndexOutOfBoundsException ex) {
4194            return null;
4195        }
4196    }
4197
4198    /**
4199     * Ask all of the children of this view to measure themselves, taking into
4200     * account both the MeasureSpec requirements for this view and its padding.
4201     * We skip children that are in the GONE state The heavy lifting is done in
4202     * getChildMeasureSpec.
4203     *
4204     * @param widthMeasureSpec The width requirements for this view
4205     * @param heightMeasureSpec The height requirements for this view
4206     */
4207    protected void measureChildren(int widthMeasureSpec, int heightMeasureSpec) {
4208        final int size = mChildrenCount;
4209        final View[] children = mChildren;
4210        for (int i = 0; i < size; ++i) {
4211            final View child = children[i];
4212            if ((child.mViewFlags & VISIBILITY_MASK) != GONE) {
4213                measureChild(child, widthMeasureSpec, heightMeasureSpec);
4214            }
4215        }
4216    }
4217
4218    /**
4219     * Ask one of the children of this view to measure itself, taking into
4220     * account both the MeasureSpec requirements for this view and its padding.
4221     * The heavy lifting is done in getChildMeasureSpec.
4222     *
4223     * @param child The child to measure
4224     * @param parentWidthMeasureSpec The width requirements for this view
4225     * @param parentHeightMeasureSpec The height requirements for this view
4226     */
4227    protected void measureChild(View child, int parentWidthMeasureSpec,
4228            int parentHeightMeasureSpec) {
4229        final LayoutParams lp = child.getLayoutParams();
4230
4231        final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
4232                mPaddingLeft + mPaddingRight, lp.width);
4233        final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
4234                mPaddingTop + mPaddingBottom, lp.height);
4235
4236        child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
4237    }
4238
4239    /**
4240     * Ask one of the children of this view to measure itself, taking into
4241     * account both the MeasureSpec requirements for this view and its padding
4242     * and margins. The child must have MarginLayoutParams The heavy lifting is
4243     * done in getChildMeasureSpec.
4244     *
4245     * @param child The child to measure
4246     * @param parentWidthMeasureSpec The width requirements for this view
4247     * @param widthUsed Extra space that has been used up by the parent
4248     *        horizontally (possibly by other children of the parent)
4249     * @param parentHeightMeasureSpec The height requirements for this view
4250     * @param heightUsed Extra space that has been used up by the parent
4251     *        vertically (possibly by other children of the parent)
4252     */
4253    protected void measureChildWithMargins(View child,
4254            int parentWidthMeasureSpec, int widthUsed,
4255            int parentHeightMeasureSpec, int heightUsed) {
4256        final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
4257
4258        final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
4259                mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin
4260                        + widthUsed, lp.width);
4261        final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
4262                mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin
4263                        + heightUsed, lp.height);
4264
4265        child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
4266    }
4267
4268    /**
4269     * Does the hard part of measureChildren: figuring out the MeasureSpec to
4270     * pass to a particular child. This method figures out the right MeasureSpec
4271     * for one dimension (height or width) of one child view.
4272     *
4273     * The goal is to combine information from our MeasureSpec with the
4274     * LayoutParams of the child to get the best possible results. For example,
4275     * if the this view knows its size (because its MeasureSpec has a mode of
4276     * EXACTLY), and the child has indicated in its LayoutParams that it wants
4277     * to be the same size as the parent, the parent should ask the child to
4278     * layout given an exact size.
4279     *
4280     * @param spec The requirements for this view
4281     * @param padding The padding of this view for the current dimension and
4282     *        margins, if applicable
4283     * @param childDimension How big the child wants to be in the current
4284     *        dimension
4285     * @return a MeasureSpec integer for the child
4286     */
4287    public static int getChildMeasureSpec(int spec, int padding, int childDimension) {
4288        int specMode = MeasureSpec.getMode(spec);
4289        int specSize = MeasureSpec.getSize(spec);
4290
4291        int size = Math.max(0, specSize - padding);
4292
4293        int resultSize = 0;
4294        int resultMode = 0;
4295
4296        switch (specMode) {
4297        // Parent has imposed an exact size on us
4298        case MeasureSpec.EXACTLY:
4299            if (childDimension >= 0) {
4300                resultSize = childDimension;
4301                resultMode = MeasureSpec.EXACTLY;
4302            } else if (childDimension == LayoutParams.MATCH_PARENT) {
4303                // Child wants to be our size. So be it.
4304                resultSize = size;
4305                resultMode = MeasureSpec.EXACTLY;
4306            } else if (childDimension == LayoutParams.WRAP_CONTENT) {
4307                // Child wants to determine its own size. It can't be
4308                // bigger than us.
4309                resultSize = size;
4310                resultMode = MeasureSpec.AT_MOST;
4311            }
4312            break;
4313
4314        // Parent has imposed a maximum size on us
4315        case MeasureSpec.AT_MOST:
4316            if (childDimension >= 0) {
4317                // Child wants a specific size... so be it
4318                resultSize = childDimension;
4319                resultMode = MeasureSpec.EXACTLY;
4320            } else if (childDimension == LayoutParams.MATCH_PARENT) {
4321                // Child wants to be our size, but our size is not fixed.
4322                // Constrain child to not be bigger than us.
4323                resultSize = size;
4324                resultMode = MeasureSpec.AT_MOST;
4325            } else if (childDimension == LayoutParams.WRAP_CONTENT) {
4326                // Child wants to determine its own size. It can't be
4327                // bigger than us.
4328                resultSize = size;
4329                resultMode = MeasureSpec.AT_MOST;
4330            }
4331            break;
4332
4333        // Parent asked to see how big we want to be
4334        case MeasureSpec.UNSPECIFIED:
4335            if (childDimension >= 0) {
4336                // Child wants a specific size... let him have it
4337                resultSize = childDimension;
4338                resultMode = MeasureSpec.EXACTLY;
4339            } else if (childDimension == LayoutParams.MATCH_PARENT) {
4340                // Child wants to be our size... find out how big it should
4341                // be
4342                resultSize = 0;
4343                resultMode = MeasureSpec.UNSPECIFIED;
4344            } else if (childDimension == LayoutParams.WRAP_CONTENT) {
4345                // Child wants to determine its own size.... find out how
4346                // big it should be
4347                resultSize = 0;
4348                resultMode = MeasureSpec.UNSPECIFIED;
4349            }
4350            break;
4351        }
4352        return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
4353    }
4354
4355
4356    /**
4357     * Removes any pending animations for views that have been removed. Call
4358     * this if you don't want animations for exiting views to stack up.
4359     */
4360    public void clearDisappearingChildren() {
4361        if (mDisappearingChildren != null) {
4362            mDisappearingChildren.clear();
4363        }
4364    }
4365
4366    /**
4367     * Add a view which is removed from mChildren but still needs animation
4368     *
4369     * @param v View to add
4370     */
4371    private void addDisappearingView(View v) {
4372        ArrayList<View> disappearingChildren = mDisappearingChildren;
4373
4374        if (disappearingChildren == null) {
4375            disappearingChildren = mDisappearingChildren = new ArrayList<View>();
4376        }
4377
4378        disappearingChildren.add(v);
4379    }
4380
4381    /**
4382     * Cleanup a view when its animation is done. This may mean removing it from
4383     * the list of disappearing views.
4384     *
4385     * @param view The view whose animation has finished
4386     * @param animation The animation, cannot be null
4387     */
4388    private void finishAnimatingView(final View view, Animation animation) {
4389        final ArrayList<View> disappearingChildren = mDisappearingChildren;
4390        if (disappearingChildren != null) {
4391            if (disappearingChildren.contains(view)) {
4392                disappearingChildren.remove(view);
4393
4394                if (view.mAttachInfo != null) {
4395                    view.dispatchDetachedFromWindow();
4396                }
4397
4398                view.clearAnimation();
4399                mGroupFlags |= FLAG_INVALIDATE_REQUIRED;
4400            }
4401        }
4402
4403        if (animation != null && !animation.getFillAfter()) {
4404            view.clearAnimation();
4405        }
4406
4407        if ((view.mPrivateFlags & ANIMATION_STARTED) == ANIMATION_STARTED) {
4408            view.onAnimationEnd();
4409            // Should be performed by onAnimationEnd() but this avoid an infinite loop,
4410            // so we'd rather be safe than sorry
4411            view.mPrivateFlags &= ~ANIMATION_STARTED;
4412            // Draw one more frame after the animation is done
4413            mGroupFlags |= FLAG_INVALIDATE_REQUIRED;
4414        }
4415    }
4416
4417    /**
4418     * This method tells the ViewGroup that the given View object, which should have this
4419     * ViewGroup as its parent,
4420     * should be kept around  (re-displayed when the ViewGroup draws its children) even if it
4421     * is removed from its parent. This allows animations, such as those used by
4422     * {@link android.app.Fragment} and {@link android.animation.LayoutTransition} to animate
4423     * the removal of views. A call to this method should always be accompanied by a later call
4424     * to {@link #endViewTransition(View)}, such as after an animation on the View has finished,
4425     * so that the View finally gets removed.
4426     *
4427     * @param view The View object to be kept visible even if it gets removed from its parent.
4428     */
4429    public void startViewTransition(View view) {
4430        if (view.mParent == this) {
4431            if (mTransitioningViews == null) {
4432                mTransitioningViews = new ArrayList<View>();
4433            }
4434            mTransitioningViews.add(view);
4435        }
4436    }
4437
4438    /**
4439     * This method should always be called following an earlier call to
4440     * {@link #startViewTransition(View)}. The given View is finally removed from its parent
4441     * and will no longer be displayed. Note that this method does not perform the functionality
4442     * of removing a view from its parent; it just discontinues the display of a View that
4443     * has previously been removed.
4444     *
4445     * @return view The View object that has been removed but is being kept around in the visible
4446     * hierarchy by an earlier call to {@link #startViewTransition(View)}.
4447     */
4448    public void endViewTransition(View view) {
4449        if (mTransitioningViews != null) {
4450            mTransitioningViews.remove(view);
4451            final ArrayList<View> disappearingChildren = mDisappearingChildren;
4452            if (disappearingChildren != null && disappearingChildren.contains(view)) {
4453                disappearingChildren.remove(view);
4454                if (mVisibilityChangingChildren != null &&
4455                        mVisibilityChangingChildren.contains(view)) {
4456                    mVisibilityChangingChildren.remove(view);
4457                } else {
4458                    if (view.mAttachInfo != null) {
4459                        view.dispatchDetachedFromWindow();
4460                    }
4461                    if (view.mParent != null) {
4462                        view.mParent = null;
4463                    }
4464                }
4465                mGroupFlags |= FLAG_INVALIDATE_REQUIRED;
4466            }
4467        }
4468    }
4469
4470    private LayoutTransition.TransitionListener mLayoutTransitionListener =
4471            new LayoutTransition.TransitionListener() {
4472        @Override
4473        public void startTransition(LayoutTransition transition, ViewGroup container,
4474                View view, int transitionType) {
4475            // We only care about disappearing items, since we need special logic to keep
4476            // those items visible after they've been 'removed'
4477            if (transitionType == LayoutTransition.DISAPPEARING) {
4478                startViewTransition(view);
4479            }
4480        }
4481
4482        @Override
4483        public void endTransition(LayoutTransition transition, ViewGroup container,
4484                View view, int transitionType) {
4485            if (mLayoutSuppressed && !transition.isChangingLayout()) {
4486                requestLayout();
4487                mLayoutSuppressed = false;
4488            }
4489            if (transitionType == LayoutTransition.DISAPPEARING && mTransitioningViews != null) {
4490                endViewTransition(view);
4491            }
4492        }
4493    };
4494
4495    /**
4496     * {@inheritDoc}
4497     */
4498    @Override
4499    public boolean gatherTransparentRegion(Region region) {
4500        // If no transparent regions requested, we are always opaque.
4501        final boolean meOpaque = (mPrivateFlags & View.REQUEST_TRANSPARENT_REGIONS) == 0;
4502        if (meOpaque && region == null) {
4503            // The caller doesn't care about the region, so stop now.
4504            return true;
4505        }
4506        super.gatherTransparentRegion(region);
4507        final View[] children = mChildren;
4508        final int count = mChildrenCount;
4509        boolean noneOfTheChildrenAreTransparent = true;
4510        for (int i = 0; i < count; i++) {
4511            final View child = children[i];
4512            if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
4513                if (!child.gatherTransparentRegion(region)) {
4514                    noneOfTheChildrenAreTransparent = false;
4515                }
4516            }
4517        }
4518        return meOpaque || noneOfTheChildrenAreTransparent;
4519    }
4520
4521    /**
4522     * {@inheritDoc}
4523     */
4524    public void requestTransparentRegion(View child) {
4525        if (child != null) {
4526            child.mPrivateFlags |= View.REQUEST_TRANSPARENT_REGIONS;
4527            if (mParent != null) {
4528                mParent.requestTransparentRegion(this);
4529            }
4530        }
4531    }
4532
4533
4534    @Override
4535    protected boolean fitSystemWindows(Rect insets) {
4536        boolean done = super.fitSystemWindows(insets);
4537        if (!done) {
4538            final int count = mChildrenCount;
4539            final View[] children = mChildren;
4540            for (int i = 0; i < count; i++) {
4541                done = children[i].fitSystemWindows(insets);
4542                if (done) {
4543                    break;
4544                }
4545            }
4546        }
4547        return done;
4548    }
4549
4550    /**
4551     * Returns the animation listener to which layout animation events are
4552     * sent.
4553     *
4554     * @return an {@link android.view.animation.Animation.AnimationListener}
4555     */
4556    public Animation.AnimationListener getLayoutAnimationListener() {
4557        return mAnimationListener;
4558    }
4559
4560    @Override
4561    protected void drawableStateChanged() {
4562        super.drawableStateChanged();
4563
4564        if ((mGroupFlags & FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE) != 0) {
4565            if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0) {
4566                throw new IllegalStateException("addStateFromChildren cannot be enabled if a"
4567                        + " child has duplicateParentState set to true");
4568            }
4569
4570            final View[] children = mChildren;
4571            final int count = mChildrenCount;
4572
4573            for (int i = 0; i < count; i++) {
4574                final View child = children[i];
4575                if ((child.mViewFlags & DUPLICATE_PARENT_STATE) != 0) {
4576                    child.refreshDrawableState();
4577                }
4578            }
4579        }
4580    }
4581
4582    @Override
4583    public void jumpDrawablesToCurrentState() {
4584        super.jumpDrawablesToCurrentState();
4585        final View[] children = mChildren;
4586        final int count = mChildrenCount;
4587        for (int i = 0; i < count; i++) {
4588            children[i].jumpDrawablesToCurrentState();
4589        }
4590    }
4591
4592    @Override
4593    protected int[] onCreateDrawableState(int extraSpace) {
4594        if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) == 0) {
4595            return super.onCreateDrawableState(extraSpace);
4596        }
4597
4598        int need = 0;
4599        int n = getChildCount();
4600        for (int i = 0; i < n; i++) {
4601            int[] childState = getChildAt(i).getDrawableState();
4602
4603            if (childState != null) {
4604                need += childState.length;
4605            }
4606        }
4607
4608        int[] state = super.onCreateDrawableState(extraSpace + need);
4609
4610        for (int i = 0; i < n; i++) {
4611            int[] childState = getChildAt(i).getDrawableState();
4612
4613            if (childState != null) {
4614                state = mergeDrawableStates(state, childState);
4615            }
4616        }
4617
4618        return state;
4619    }
4620
4621    /**
4622     * Sets whether this ViewGroup's drawable states also include
4623     * its children's drawable states.  This is used, for example, to
4624     * make a group appear to be focused when its child EditText or button
4625     * is focused.
4626     */
4627    public void setAddStatesFromChildren(boolean addsStates) {
4628        if (addsStates) {
4629            mGroupFlags |= FLAG_ADD_STATES_FROM_CHILDREN;
4630        } else {
4631            mGroupFlags &= ~FLAG_ADD_STATES_FROM_CHILDREN;
4632        }
4633
4634        refreshDrawableState();
4635    }
4636
4637    /**
4638     * Returns whether this ViewGroup's drawable states also include
4639     * its children's drawable states.  This is used, for example, to
4640     * make a group appear to be focused when its child EditText or button
4641     * is focused.
4642     */
4643    public boolean addStatesFromChildren() {
4644        return (mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0;
4645    }
4646
4647    /**
4648     * If {link #addStatesFromChildren} is true, refreshes this group's
4649     * drawable state (to include the states from its children).
4650     */
4651    public void childDrawableStateChanged(View child) {
4652        if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0) {
4653            refreshDrawableState();
4654        }
4655    }
4656
4657    /**
4658     * Specifies the animation listener to which layout animation events must
4659     * be sent. Only
4660     * {@link android.view.animation.Animation.AnimationListener#onAnimationStart(Animation)}
4661     * and
4662     * {@link android.view.animation.Animation.AnimationListener#onAnimationEnd(Animation)}
4663     * are invoked.
4664     *
4665     * @param animationListener the layout animation listener
4666     */
4667    public void setLayoutAnimationListener(Animation.AnimationListener animationListener) {
4668        mAnimationListener = animationListener;
4669    }
4670
4671    /**
4672     * LayoutParams are used by views to tell their parents how they want to be
4673     * laid out. See
4674     * {@link android.R.styleable#ViewGroup_Layout ViewGroup Layout Attributes}
4675     * for a list of all child view attributes that this class supports.
4676     *
4677     * <p>
4678     * The base LayoutParams class just describes how big the view wants to be
4679     * for both width and height. For each dimension, it can specify one of:
4680     * <ul>
4681     * <li>FILL_PARENT (renamed MATCH_PARENT in API Level 8 and higher), which
4682     * means that the view wants to be as big as its parent (minus padding)
4683     * <li> WRAP_CONTENT, which means that the view wants to be just big enough
4684     * to enclose its content (plus padding)
4685     * <li> an exact number
4686     * </ul>
4687     * There are subclasses of LayoutParams for different subclasses of
4688     * ViewGroup. For example, AbsoluteLayout has its own subclass of
4689     * LayoutParams which adds an X and Y value.
4690     *
4691     * @attr ref android.R.styleable#ViewGroup_Layout_layout_height
4692     * @attr ref android.R.styleable#ViewGroup_Layout_layout_width
4693     */
4694    public static class LayoutParams {
4695        /**
4696         * Special value for the height or width requested by a View.
4697         * FILL_PARENT means that the view wants to be as big as its parent,
4698         * minus the parent's padding, if any. This value is deprecated
4699         * starting in API Level 8 and replaced by {@link #MATCH_PARENT}.
4700         */
4701        @SuppressWarnings({"UnusedDeclaration"})
4702        @Deprecated
4703        public static final int FILL_PARENT = -1;
4704
4705        /**
4706         * Special value for the height or width requested by a View.
4707         * MATCH_PARENT means that the view wants to be as big as its parent,
4708         * minus the parent's padding, if any. Introduced in API Level 8.
4709         */
4710        public static final int MATCH_PARENT = -1;
4711
4712        /**
4713         * Special value for the height or width requested by a View.
4714         * WRAP_CONTENT means that the view wants to be just large enough to fit
4715         * its own internal content, taking its own padding into account.
4716         */
4717        public static final int WRAP_CONTENT = -2;
4718
4719        /**
4720         * Information about how wide the view wants to be. Can be one of the
4721         * constants FILL_PARENT (replaced by MATCH_PARENT ,
4722         * in API Level 8) or WRAP_CONTENT. or an exact size.
4723         */
4724        @ViewDebug.ExportedProperty(category = "layout", mapping = {
4725            @ViewDebug.IntToString(from = MATCH_PARENT, to = "MATCH_PARENT"),
4726            @ViewDebug.IntToString(from = WRAP_CONTENT, to = "WRAP_CONTENT")
4727        })
4728        public int width;
4729
4730        /**
4731         * Information about how tall the view wants to be. Can be one of the
4732         * constants FILL_PARENT (replaced by MATCH_PARENT ,
4733         * in API Level 8) or WRAP_CONTENT. or an exact size.
4734         */
4735        @ViewDebug.ExportedProperty(category = "layout", mapping = {
4736            @ViewDebug.IntToString(from = MATCH_PARENT, to = "MATCH_PARENT"),
4737            @ViewDebug.IntToString(from = WRAP_CONTENT, to = "WRAP_CONTENT")
4738        })
4739        public int height;
4740
4741        /**
4742         * Used to animate layouts.
4743         */
4744        public LayoutAnimationController.AnimationParameters layoutAnimationParameters;
4745
4746        /**
4747         * Creates a new set of layout parameters. The values are extracted from
4748         * the supplied attributes set and context. The XML attributes mapped
4749         * to this set of layout parameters are:
4750         *
4751         * <ul>
4752         *   <li><code>layout_width</code>: the width, either an exact value,
4753         *   {@link #WRAP_CONTENT}, or {@link #FILL_PARENT} (replaced by
4754         *   {@link #MATCH_PARENT} in API Level 8)</li>
4755         *   <li><code>layout_height</code>: the height, either an exact value,
4756         *   {@link #WRAP_CONTENT}, or {@link #FILL_PARENT} (replaced by
4757         *   {@link #MATCH_PARENT} in API Level 8)</li>
4758         * </ul>
4759         *
4760         * @param c the application environment
4761         * @param attrs the set of attributes from which to extract the layout
4762         *              parameters' values
4763         */
4764        public LayoutParams(Context c, AttributeSet attrs) {
4765            TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.ViewGroup_Layout);
4766            setBaseAttributes(a,
4767                    R.styleable.ViewGroup_Layout_layout_width,
4768                    R.styleable.ViewGroup_Layout_layout_height);
4769            a.recycle();
4770        }
4771
4772        /**
4773         * Creates a new set of layout parameters with the specified width
4774         * and height.
4775         *
4776         * @param width the width, either {@link #WRAP_CONTENT},
4777         *        {@link #FILL_PARENT} (replaced by {@link #MATCH_PARENT} in
4778         *        API Level 8), or a fixed size in pixels
4779         * @param height the height, either {@link #WRAP_CONTENT},
4780         *        {@link #FILL_PARENT} (replaced by {@link #MATCH_PARENT} in
4781         *        API Level 8), or a fixed size in pixels
4782         */
4783        public LayoutParams(int width, int height) {
4784            this.width = width;
4785            this.height = height;
4786        }
4787
4788        /**
4789         * Copy constructor. Clones the width and height values of the source.
4790         *
4791         * @param source The layout params to copy from.
4792         */
4793        public LayoutParams(LayoutParams source) {
4794            this.width = source.width;
4795            this.height = source.height;
4796        }
4797
4798        /**
4799         * Used internally by MarginLayoutParams.
4800         * @hide
4801         */
4802        LayoutParams() {
4803        }
4804
4805        /**
4806         * Extracts the layout parameters from the supplied attributes.
4807         *
4808         * @param a the style attributes to extract the parameters from
4809         * @param widthAttr the identifier of the width attribute
4810         * @param heightAttr the identifier of the height attribute
4811         */
4812        protected void setBaseAttributes(TypedArray a, int widthAttr, int heightAttr) {
4813            width = a.getLayoutDimension(widthAttr, "layout_width");
4814            height = a.getLayoutDimension(heightAttr, "layout_height");
4815        }
4816
4817        /**
4818         * Returns a String representation of this set of layout parameters.
4819         *
4820         * @param output the String to prepend to the internal representation
4821         * @return a String with the following format: output +
4822         *         "ViewGroup.LayoutParams={ width=WIDTH, height=HEIGHT }"
4823         *
4824         * @hide
4825         */
4826        public String debug(String output) {
4827            return output + "ViewGroup.LayoutParams={ width="
4828                    + sizeToString(width) + ", height=" + sizeToString(height) + " }";
4829        }
4830
4831        /**
4832         * Converts the specified size to a readable String.
4833         *
4834         * @param size the size to convert
4835         * @return a String instance representing the supplied size
4836         *
4837         * @hide
4838         */
4839        protected static String sizeToString(int size) {
4840            if (size == WRAP_CONTENT) {
4841                return "wrap-content";
4842            }
4843            if (size == MATCH_PARENT) {
4844                return "match-parent";
4845            }
4846            return String.valueOf(size);
4847        }
4848    }
4849
4850    /**
4851     * Per-child layout information for layouts that support margins.
4852     * See
4853     * {@link android.R.styleable#ViewGroup_MarginLayout ViewGroup Margin Layout Attributes}
4854     * for a list of all child view attributes that this class supports.
4855     */
4856    public static class MarginLayoutParams extends ViewGroup.LayoutParams {
4857        /**
4858         * The left margin in pixels of the child.
4859         */
4860        @ViewDebug.ExportedProperty(category = "layout")
4861        public int leftMargin;
4862
4863        /**
4864         * The top margin in pixels of the child.
4865         */
4866        @ViewDebug.ExportedProperty(category = "layout")
4867        public int topMargin;
4868
4869        /**
4870         * The right margin in pixels of the child.
4871         */
4872        @ViewDebug.ExportedProperty(category = "layout")
4873        public int rightMargin;
4874
4875        /**
4876         * The bottom margin in pixels of the child.
4877         */
4878        @ViewDebug.ExportedProperty(category = "layout")
4879        public int bottomMargin;
4880
4881        /**
4882         * Creates a new set of layout parameters. The values are extracted from
4883         * the supplied attributes set and context.
4884         *
4885         * @param c the application environment
4886         * @param attrs the set of attributes from which to extract the layout
4887         *              parameters' values
4888         */
4889        public MarginLayoutParams(Context c, AttributeSet attrs) {
4890            super();
4891
4892            TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.ViewGroup_MarginLayout);
4893            setBaseAttributes(a,
4894                    R.styleable.ViewGroup_MarginLayout_layout_width,
4895                    R.styleable.ViewGroup_MarginLayout_layout_height);
4896
4897            int margin = a.getDimensionPixelSize(
4898                    com.android.internal.R.styleable.ViewGroup_MarginLayout_layout_margin, -1);
4899            if (margin >= 0) {
4900                leftMargin = margin;
4901                topMargin = margin;
4902                rightMargin= margin;
4903                bottomMargin = margin;
4904            } else {
4905                leftMargin = a.getDimensionPixelSize(
4906                        R.styleable.ViewGroup_MarginLayout_layout_marginLeft, 0);
4907                topMargin = a.getDimensionPixelSize(
4908                        R.styleable.ViewGroup_MarginLayout_layout_marginTop, 0);
4909                rightMargin = a.getDimensionPixelSize(
4910                        R.styleable.ViewGroup_MarginLayout_layout_marginRight, 0);
4911                bottomMargin = a.getDimensionPixelSize(
4912                        R.styleable.ViewGroup_MarginLayout_layout_marginBottom, 0);
4913            }
4914
4915            a.recycle();
4916        }
4917
4918        /**
4919         * {@inheritDoc}
4920         */
4921        public MarginLayoutParams(int width, int height) {
4922            super(width, height);
4923        }
4924
4925        /**
4926         * Copy constructor. Clones the width, height and margin values of the source.
4927         *
4928         * @param source The layout params to copy from.
4929         */
4930        public MarginLayoutParams(MarginLayoutParams source) {
4931            this.width = source.width;
4932            this.height = source.height;
4933
4934            this.leftMargin = source.leftMargin;
4935            this.topMargin = source.topMargin;
4936            this.rightMargin = source.rightMargin;
4937            this.bottomMargin = source.bottomMargin;
4938        }
4939
4940        /**
4941         * {@inheritDoc}
4942         */
4943        public MarginLayoutParams(LayoutParams source) {
4944            super(source);
4945        }
4946
4947        /**
4948         * Sets the margins, in pixels.
4949         *
4950         * @param left the left margin size
4951         * @param top the top margin size
4952         * @param right the right margin size
4953         * @param bottom the bottom margin size
4954         *
4955         * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginLeft
4956         * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginTop
4957         * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginRight
4958         * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginBottom
4959         */
4960        public void setMargins(int left, int top, int right, int bottom) {
4961            leftMargin = left;
4962            topMargin = top;
4963            rightMargin = right;
4964            bottomMargin = bottom;
4965        }
4966    }
4967
4968    /* Describes a touched view and the ids of the pointers that it has captured.
4969     *
4970     * This code assumes that pointer ids are always in the range 0..31 such that
4971     * it can use a bitfield to track which pointer ids are present.
4972     * As it happens, the lower layers of the input dispatch pipeline also use the
4973     * same trick so the assumption should be safe here...
4974     */
4975    private static final class TouchTarget {
4976        private static final int MAX_RECYCLED = 32;
4977        private static final Object sRecycleLock = new Object();
4978        private static TouchTarget sRecycleBin;
4979        private static int sRecycledCount;
4980
4981        public static final int ALL_POINTER_IDS = -1; // all ones
4982
4983        // The touched child view.
4984        public View child;
4985
4986        // The combined bit mask of pointer ids for all pointers captured by the target.
4987        public int pointerIdBits;
4988
4989        // The next target in the target list.
4990        public TouchTarget next;
4991
4992        private TouchTarget() {
4993        }
4994
4995        public static TouchTarget obtain(View child, int pointerIdBits) {
4996            final TouchTarget target;
4997            synchronized (sRecycleLock) {
4998                if (sRecycleBin == null) {
4999                    target = new TouchTarget();
5000                } else {
5001                    target = sRecycleBin;
5002                    sRecycleBin = target.next;
5003                     sRecycledCount--;
5004                    target.next = null;
5005                }
5006            }
5007            target.child = child;
5008            target.pointerIdBits = pointerIdBits;
5009            return target;
5010        }
5011
5012        public void recycle() {
5013            synchronized (sRecycleLock) {
5014                if (sRecycledCount < MAX_RECYCLED) {
5015                    next = sRecycleBin;
5016                    sRecycleBin = this;
5017                    sRecycledCount += 1;
5018                } else {
5019                    next = null;
5020                }
5021                child = null;
5022            }
5023        }
5024    }
5025}
5026