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