• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package android.view;
18 
19 import com.android.internal.R;
20 
21 import android.content.Context;
22 import android.content.res.TypedArray;
23 import android.graphics.Bitmap;
24 import android.graphics.Canvas;
25 import android.graphics.Paint;
26 import android.graphics.Rect;
27 import android.graphics.RectF;
28 import android.graphics.Region;
29 import android.os.Parcelable;
30 import android.os.SystemClock;
31 import android.util.AttributeSet;
32 import android.util.Config;
33 import android.util.EventLog;
34 import android.util.Log;
35 import android.util.SparseArray;
36 import android.view.accessibility.AccessibilityEvent;
37 import android.view.animation.Animation;
38 import android.view.animation.AnimationUtils;
39 import android.view.animation.LayoutAnimationController;
40 import android.view.animation.Transformation;
41 
42 import java.util.ArrayList;
43 
44 /**
45  * <p>
46  * A <code>ViewGroup</code> is a special view that can contain other views
47  * (called children.) The view group is the base class for layouts and views
48  * containers. This class also defines the
49  * {@link android.view.ViewGroup.LayoutParams} class which serves as the base
50  * class for layouts parameters.
51  * </p>
52  *
53  * <p>
54  * Also see {@link LayoutParams} for layout attributes.
55  * </p>
56  *
57  * @attr ref android.R.styleable#ViewGroup_clipChildren
58  * @attr ref android.R.styleable#ViewGroup_clipToPadding
59  * @attr ref android.R.styleable#ViewGroup_layoutAnimation
60  * @attr ref android.R.styleable#ViewGroup_animationCache
61  * @attr ref android.R.styleable#ViewGroup_persistentDrawingCache
62  * @attr ref android.R.styleable#ViewGroup_alwaysDrawnWithCache
63  * @attr ref android.R.styleable#ViewGroup_addStatesFromChildren
64  * @attr ref android.R.styleable#ViewGroup_descendantFocusability
65  */
66 public abstract class ViewGroup extends View implements ViewParent, ViewManager {
67     private static final boolean DBG = false;
68 
69     /**
70      * Views which have been hidden or removed which need to be animated on
71      * their way out.
72      * This field should be made private, so it is hidden from the SDK.
73      * {@hide}
74      */
75     protected ArrayList<View> mDisappearingChildren;
76 
77     /**
78      * Listener used to propagate events indicating when children are added
79      * and/or removed from a view group.
80      * This field should be made private, so it is hidden from the SDK.
81      * {@hide}
82      */
83     protected OnHierarchyChangeListener mOnHierarchyChangeListener;
84 
85     // The view contained within this ViewGroup that has or contains focus.
86     private View mFocused;
87 
88     // The current transformation to apply on the child being drawn
89     private Transformation mChildTransformation;
90     private RectF mInvalidateRegion;
91 
92     // Target of Motion events
93     private View mMotionTarget;
94     private final Rect mTempRect = new Rect();
95 
96     // Layout animation
97     private LayoutAnimationController mLayoutAnimationController;
98     private Animation.AnimationListener mAnimationListener;
99 
100     /**
101      * Internal flags.
102      *
103      * This field should be made private, so it is hidden from the SDK.
104      * {@hide}
105      */
106     protected int mGroupFlags;
107 
108     // When set, ViewGroup invalidates only the child's rectangle
109     // Set by default
110     private static final int FLAG_CLIP_CHILDREN = 0x1;
111 
112     // When set, ViewGroup excludes the padding area from the invalidate rectangle
113     // Set by default
114     private static final int FLAG_CLIP_TO_PADDING = 0x2;
115 
116     // When set, dispatchDraw() will invoke invalidate(); this is set by drawChild() when
117     // a child needs to be invalidated and FLAG_OPTIMIZE_INVALIDATE is set
118     private static final int FLAG_INVALIDATE_REQUIRED  = 0x4;
119 
120     // When set, dispatchDraw() will run the layout animation and unset the flag
121     private static final int FLAG_RUN_ANIMATION = 0x8;
122 
123     // When set, there is either no layout animation on the ViewGroup or the layout
124     // animation is over
125     // Set by default
126     private static final int FLAG_ANIMATION_DONE = 0x10;
127 
128     // If set, this ViewGroup has padding; if unset there is no padding and we don't need
129     // to clip it, even if FLAG_CLIP_TO_PADDING is set
130     private static final int FLAG_PADDING_NOT_NULL = 0x20;
131 
132     // When set, this ViewGroup caches its children in a Bitmap before starting a layout animation
133     // Set by default
134     private static final int FLAG_ANIMATION_CACHE = 0x40;
135 
136     // When set, this ViewGroup converts calls to invalidate(Rect) to invalidate() during a
137     // layout animation; this avoid clobbering the hierarchy
138     // Automatically set when the layout animation starts, depending on the animation's
139     // characteristics
140     private static final int FLAG_OPTIMIZE_INVALIDATE = 0x80;
141 
142     // When set, the next call to drawChild() will clear mChildTransformation's matrix
143     private static final int FLAG_CLEAR_TRANSFORMATION = 0x100;
144 
145     // When set, this ViewGroup invokes mAnimationListener.onAnimationEnd() and removes
146     // the children's Bitmap caches if necessary
147     // This flag is set when the layout animation is over (after FLAG_ANIMATION_DONE is set)
148     private static final int FLAG_NOTIFY_ANIMATION_LISTENER = 0x200;
149 
150     /**
151      * When set, the drawing method will call {@link #getChildDrawingOrder(int, int)}
152      * to get the index of the child to draw for that iteration.
153      *
154      */
155     protected static final int FLAG_USE_CHILD_DRAWING_ORDER = 0x400;
156 
157     /**
158      * When set, this ViewGroup supports static transformations on children; this causes
159      * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} to be
160      * invoked when a child is drawn.
161      *
162      * Any subclass overriding
163      * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} should
164      * set this flags in {@link #mGroupFlags}.
165      *
166      * {@hide}
167      */
168     protected static final int FLAG_SUPPORT_STATIC_TRANSFORMATIONS = 0x800;
169 
170     // When the previous drawChild() invocation used an alpha value that was lower than
171     // 1.0 and set it in mCachePaint
172     private static final int FLAG_ALPHA_LOWER_THAN_ONE = 0x1000;
173 
174     /**
175      * When set, this ViewGroup's drawable states also include those
176      * of its children.
177      */
178     private static final int FLAG_ADD_STATES_FROM_CHILDREN = 0x2000;
179 
180     /**
181      * When set, this ViewGroup tries to always draw its children using their drawing cache.
182      */
183     private static final int FLAG_ALWAYS_DRAWN_WITH_CACHE = 0x4000;
184 
185     /**
186      * When set, and if FLAG_ALWAYS_DRAWN_WITH_CACHE is not set, this ViewGroup will try to
187      * draw its children with their drawing cache.
188      */
189     private static final int FLAG_CHILDREN_DRAWN_WITH_CACHE = 0x8000;
190 
191     /**
192      * When set, this group will go through its list of children to notify them of
193      * any drawable state change.
194      */
195     private static final int FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE = 0x10000;
196 
197     private static final int FLAG_MASK_FOCUSABILITY = 0x60000;
198 
199     /**
200      * This view will get focus before any of its descendants.
201      */
202     public static final int FOCUS_BEFORE_DESCENDANTS = 0x20000;
203 
204     /**
205      * This view will get focus only if none of its descendants want it.
206      */
207     public static final int FOCUS_AFTER_DESCENDANTS = 0x40000;
208 
209     /**
210      * This view will block any of its descendants from getting focus, even
211      * if they are focusable.
212      */
213     public static final int FOCUS_BLOCK_DESCENDANTS = 0x60000;
214 
215     /**
216      * Used to map between enum in attrubutes and flag values.
217      */
218     private static final int[] DESCENDANT_FOCUSABILITY_FLAGS =
219             {FOCUS_BEFORE_DESCENDANTS, FOCUS_AFTER_DESCENDANTS,
220                     FOCUS_BLOCK_DESCENDANTS};
221 
222     /**
223      * When set, this ViewGroup should not intercept touch events.
224      */
225     private static final int FLAG_DISALLOW_INTERCEPT = 0x80000;
226 
227     /**
228      * Indicates which types of drawing caches are to be kept in memory.
229      * This field should be made private, so it is hidden from the SDK.
230      * {@hide}
231      */
232     protected int mPersistentDrawingCache;
233 
234     /**
235      * Used to indicate that no drawing cache should be kept in memory.
236      */
237     public static final int PERSISTENT_NO_CACHE = 0x0;
238 
239     /**
240      * Used to indicate that the animation drawing cache should be kept in memory.
241      */
242     public static final int PERSISTENT_ANIMATION_CACHE = 0x1;
243 
244     /**
245      * Used to indicate that the scrolling drawing cache should be kept in memory.
246      */
247     public static final int PERSISTENT_SCROLLING_CACHE = 0x2;
248 
249     /**
250      * Used to indicate that all drawing caches should be kept in memory.
251      */
252     public static final int PERSISTENT_ALL_CACHES = 0x3;
253 
254     /**
255      * We clip to padding when FLAG_CLIP_TO_PADDING and FLAG_PADDING_NOT_NULL
256      * are set at the same time.
257      */
258     protected static final int CLIP_TO_PADDING_MASK = FLAG_CLIP_TO_PADDING | FLAG_PADDING_NOT_NULL;
259 
260     // Index of the child's left position in the mLocation array
261     private static final int CHILD_LEFT_INDEX = 0;
262     // Index of the child's top position in the mLocation array
263     private static final int CHILD_TOP_INDEX = 1;
264 
265     // Child views of this ViewGroup
266     private View[] mChildren;
267     // Number of valid children in the mChildren array, the rest should be null or not
268     // considered as children
269     private int mChildrenCount;
270 
271     private static final int ARRAY_INITIAL_CAPACITY = 12;
272     private static final int ARRAY_CAPACITY_INCREMENT = 12;
273 
274     // Used to draw cached views
275     private final Paint mCachePaint = new Paint();
276 
ViewGroup(Context context)277     public ViewGroup(Context context) {
278         super(context);
279         initViewGroup();
280     }
281 
ViewGroup(Context context, AttributeSet attrs)282     public ViewGroup(Context context, AttributeSet attrs) {
283         super(context, attrs);
284         initViewGroup();
285         initFromAttributes(context, attrs);
286     }
287 
ViewGroup(Context context, AttributeSet attrs, int defStyle)288     public ViewGroup(Context context, AttributeSet attrs, int defStyle) {
289         super(context, attrs, defStyle);
290         initViewGroup();
291         initFromAttributes(context, attrs);
292     }
293 
initViewGroup()294     private void initViewGroup() {
295         // ViewGroup doesn't draw by default
296         setFlags(WILL_NOT_DRAW, DRAW_MASK);
297         mGroupFlags |= FLAG_CLIP_CHILDREN;
298         mGroupFlags |= FLAG_CLIP_TO_PADDING;
299         mGroupFlags |= FLAG_ANIMATION_DONE;
300         mGroupFlags |= FLAG_ANIMATION_CACHE;
301         mGroupFlags |= FLAG_ALWAYS_DRAWN_WITH_CACHE;
302 
303         setDescendantFocusability(FOCUS_BEFORE_DESCENDANTS);
304 
305         mChildren = new View[ARRAY_INITIAL_CAPACITY];
306         mChildrenCount = 0;
307 
308         mCachePaint.setDither(false);
309 
310         mPersistentDrawingCache = PERSISTENT_SCROLLING_CACHE;
311     }
312 
initFromAttributes(Context context, AttributeSet attrs)313     private void initFromAttributes(Context context, AttributeSet attrs) {
314         TypedArray a = context.obtainStyledAttributes(attrs,
315                 R.styleable.ViewGroup);
316 
317         final int N = a.getIndexCount();
318         for (int i = 0; i < N; i++) {
319             int attr = a.getIndex(i);
320             switch (attr) {
321                 case R.styleable.ViewGroup_clipChildren:
322                     setClipChildren(a.getBoolean(attr, true));
323                     break;
324                 case R.styleable.ViewGroup_clipToPadding:
325                     setClipToPadding(a.getBoolean(attr, true));
326                     break;
327                 case R.styleable.ViewGroup_animationCache:
328                     setAnimationCacheEnabled(a.getBoolean(attr, true));
329                     break;
330                 case R.styleable.ViewGroup_persistentDrawingCache:
331                     setPersistentDrawingCache(a.getInt(attr, PERSISTENT_SCROLLING_CACHE));
332                     break;
333                 case R.styleable.ViewGroup_addStatesFromChildren:
334                     setAddStatesFromChildren(a.getBoolean(attr, false));
335                     break;
336                 case R.styleable.ViewGroup_alwaysDrawnWithCache:
337                     setAlwaysDrawnWithCacheEnabled(a.getBoolean(attr, true));
338                     break;
339                 case R.styleable.ViewGroup_layoutAnimation:
340                     int id = a.getResourceId(attr, -1);
341                     if (id > 0) {
342                         setLayoutAnimation(AnimationUtils.loadLayoutAnimation(mContext, id));
343                     }
344                     break;
345                 case R.styleable.ViewGroup_descendantFocusability:
346                     setDescendantFocusability(DESCENDANT_FOCUSABILITY_FLAGS[a.getInt(attr, 0)]);
347                     break;
348             }
349         }
350 
351         a.recycle();
352     }
353 
354     /**
355      * Gets the descendant focusability of this view group.  The descendant
356      * focusability defines the relationship between this view group and its
357      * descendants when looking for a view to take focus in
358      * {@link #requestFocus(int, android.graphics.Rect)}.
359      *
360      * @return one of {@link #FOCUS_BEFORE_DESCENDANTS}, {@link #FOCUS_AFTER_DESCENDANTS},
361      *   {@link #FOCUS_BLOCK_DESCENDANTS}.
362      */
363     @ViewDebug.ExportedProperty(mapping = {
364         @ViewDebug.IntToString(from = FOCUS_BEFORE_DESCENDANTS, to = "FOCUS_BEFORE_DESCENDANTS"),
365         @ViewDebug.IntToString(from = FOCUS_AFTER_DESCENDANTS, to = "FOCUS_AFTER_DESCENDANTS"),
366         @ViewDebug.IntToString(from = FOCUS_BLOCK_DESCENDANTS, to = "FOCUS_BLOCK_DESCENDANTS")
367     })
getDescendantFocusability()368     public int getDescendantFocusability() {
369         return mGroupFlags & FLAG_MASK_FOCUSABILITY;
370     }
371 
372     /**
373      * Set the descendant focusability of this view group. This defines the relationship
374      * between this view group and its descendants when looking for a view to
375      * take focus in {@link #requestFocus(int, android.graphics.Rect)}.
376      *
377      * @param focusability one of {@link #FOCUS_BEFORE_DESCENDANTS}, {@link #FOCUS_AFTER_DESCENDANTS},
378      *   {@link #FOCUS_BLOCK_DESCENDANTS}.
379      */
setDescendantFocusability(int focusability)380     public void setDescendantFocusability(int focusability) {
381         switch (focusability) {
382             case FOCUS_BEFORE_DESCENDANTS:
383             case FOCUS_AFTER_DESCENDANTS:
384             case FOCUS_BLOCK_DESCENDANTS:
385                 break;
386             default:
387                 throw new IllegalArgumentException("must be one of FOCUS_BEFORE_DESCENDANTS, "
388                         + "FOCUS_AFTER_DESCENDANTS, FOCUS_BLOCK_DESCENDANTS");
389         }
390         mGroupFlags &= ~FLAG_MASK_FOCUSABILITY;
391         mGroupFlags |= (focusability & FLAG_MASK_FOCUSABILITY);
392     }
393 
394     /**
395      * {@inheritDoc}
396      */
397     @Override
handleFocusGainInternal(int direction, Rect previouslyFocusedRect)398     void handleFocusGainInternal(int direction, Rect previouslyFocusedRect) {
399         if (mFocused != null) {
400             mFocused.unFocus();
401             mFocused = null;
402         }
403         super.handleFocusGainInternal(direction, previouslyFocusedRect);
404     }
405 
406     /**
407      * {@inheritDoc}
408      */
requestChildFocus(View child, View focused)409     public void requestChildFocus(View child, View focused) {
410         if (DBG) {
411             System.out.println(this + " requestChildFocus()");
412         }
413         if (getDescendantFocusability() == FOCUS_BLOCK_DESCENDANTS) {
414             return;
415         }
416 
417         // Unfocus us, if necessary
418         super.unFocus();
419 
420         // We had a previous notion of who had focus. Clear it.
421         if (mFocused != child) {
422             if (mFocused != null) {
423                 mFocused.unFocus();
424             }
425 
426             mFocused = child;
427         }
428         if (mParent != null) {
429             mParent.requestChildFocus(this, focused);
430         }
431     }
432 
433     /**
434      * {@inheritDoc}
435      */
focusableViewAvailable(View v)436     public void focusableViewAvailable(View v) {
437         if (mParent != null
438                 // shortcut: don't report a new focusable view if we block our descendants from
439                 // getting focus
440                 && (getDescendantFocusability() != FOCUS_BLOCK_DESCENDANTS)
441                 // shortcut: don't report a new focusable view if we already are focused
442                 // (and we don't prefer our descendants)
443                 //
444                 // note: knowing that mFocused is non-null is not a good enough reason
445                 // to break the traversal since in that case we'd actually have to find
446                 // the focused view and make sure it wasn't FOCUS_AFTER_DESCENDANTS and
447                 // an ancestor of v; this will get checked for at ViewRoot
448                 && !(isFocused() && getDescendantFocusability() != FOCUS_AFTER_DESCENDANTS)) {
449             mParent.focusableViewAvailable(v);
450         }
451     }
452 
453     /**
454      * {@inheritDoc}
455      */
showContextMenuForChild(View originalView)456     public boolean showContextMenuForChild(View originalView) {
457         return mParent != null && mParent.showContextMenuForChild(originalView);
458     }
459 
460     /**
461      * Find the nearest view in the specified direction that wants to take
462      * focus.
463      *
464      * @param focused The view that currently has focus
465      * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and
466      *        FOCUS_RIGHT, or 0 for not applicable.
467      */
focusSearch(View focused, int direction)468     public View focusSearch(View focused, int direction) {
469         if (isRootNamespace()) {
470             // root namespace means we should consider ourselves the top of the
471             // tree for focus searching; otherwise we could be focus searching
472             // into other tabs.  see LocalActivityManager and TabHost for more info
473             return FocusFinder.getInstance().findNextFocus(this, focused, direction);
474         } else if (mParent != null) {
475             return mParent.focusSearch(focused, direction);
476         }
477         return null;
478     }
479 
480     /**
481      * {@inheritDoc}
482      */
requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate)483     public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
484         return false;
485     }
486 
487     /**
488      * {@inheritDoc}
489      */
490     @Override
dispatchUnhandledMove(View focused, int direction)491     public boolean dispatchUnhandledMove(View focused, int direction) {
492         return mFocused != null &&
493                 mFocused.dispatchUnhandledMove(focused, direction);
494     }
495 
496     /**
497      * {@inheritDoc}
498      */
clearChildFocus(View child)499     public void clearChildFocus(View child) {
500         if (DBG) {
501             System.out.println(this + " clearChildFocus()");
502         }
503 
504         mFocused = null;
505         if (mParent != null) {
506             mParent.clearChildFocus(this);
507         }
508     }
509 
510     /**
511      * {@inheritDoc}
512      */
513     @Override
clearFocus()514     public void clearFocus() {
515         super.clearFocus();
516 
517         // clear any child focus if it exists
518         if (mFocused != null) {
519             mFocused.clearFocus();
520         }
521     }
522 
523     /**
524      * {@inheritDoc}
525      */
526     @Override
unFocus()527     void unFocus() {
528         if (DBG) {
529             System.out.println(this + " unFocus()");
530         }
531 
532         super.unFocus();
533         if (mFocused != null) {
534             mFocused.unFocus();
535         }
536         mFocused = null;
537     }
538 
539     /**
540      * Returns the focused child of this view, if any. The child may have focus
541      * or contain focus.
542      *
543      * @return the focused child or null.
544      */
getFocusedChild()545     public View getFocusedChild() {
546         return mFocused;
547     }
548 
549     /**
550      * Returns true if this view has or contains focus
551      *
552      * @return true if this view has or contains focus
553      */
554     @Override
hasFocus()555     public boolean hasFocus() {
556         return (mPrivateFlags & FOCUSED) != 0 || mFocused != null;
557     }
558 
559     /*
560      * (non-Javadoc)
561      *
562      * @see android.view.View#findFocus()
563      */
564     @Override
findFocus()565     public View findFocus() {
566         if (DBG) {
567             System.out.println("Find focus in " + this + ": flags="
568                     + isFocused() + ", child=" + mFocused);
569         }
570 
571         if (isFocused()) {
572             return this;
573         }
574 
575         if (mFocused != null) {
576             return mFocused.findFocus();
577         }
578         return null;
579     }
580 
581     /**
582      * {@inheritDoc}
583      */
584     @Override
hasFocusable()585     public boolean hasFocusable() {
586         if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) {
587             return false;
588         }
589 
590         if (isFocusable()) {
591             return true;
592         }
593 
594         final int descendantFocusability = getDescendantFocusability();
595         if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS) {
596             final int count = mChildrenCount;
597             final View[] children = mChildren;
598 
599             for (int i = 0; i < count; i++) {
600                 final View child = children[i];
601                 if (child.hasFocusable()) {
602                     return true;
603                 }
604             }
605         }
606 
607         return false;
608     }
609 
610     /**
611      * {@inheritDoc}
612      */
613     @Override
addFocusables(ArrayList<View> views, int direction)614     public void addFocusables(ArrayList<View> views, int direction) {
615         addFocusables(views, direction, FOCUSABLES_TOUCH_MODE);
616     }
617 
618     /**
619      * {@inheritDoc}
620      */
621     @Override
addFocusables(ArrayList<View> views, int direction, int focusableMode)622     public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
623         final int focusableCount = views.size();
624 
625         final int descendantFocusability = getDescendantFocusability();
626 
627         if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS) {
628             final int count = mChildrenCount;
629             final View[] children = mChildren;
630 
631             for (int i = 0; i < count; i++) {
632                 final View child = children[i];
633                 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
634                     child.addFocusables(views, direction, focusableMode);
635                 }
636             }
637         }
638 
639         // we add ourselves (if focusable) in all cases except for when we are
640         // FOCUS_AFTER_DESCENDANTS and there are some descendants focusable.  this is
641         // to avoid the focus search finding layouts when a more precise search
642         // among the focusable children would be more interesting.
643         if (
644             descendantFocusability != FOCUS_AFTER_DESCENDANTS ||
645                 // No focusable descendants
646                 (focusableCount == views.size())) {
647             super.addFocusables(views, direction, focusableMode);
648         }
649     }
650 
651     /**
652      * {@inheritDoc}
653      */
654     @Override
dispatchWindowFocusChanged(boolean hasFocus)655     public void dispatchWindowFocusChanged(boolean hasFocus) {
656         super.dispatchWindowFocusChanged(hasFocus);
657         final int count = mChildrenCount;
658         final View[] children = mChildren;
659         for (int i = 0; i < count; i++) {
660             children[i].dispatchWindowFocusChanged(hasFocus);
661         }
662     }
663 
664     /**
665      * {@inheritDoc}
666      */
667     @Override
addTouchables(ArrayList<View> views)668     public void addTouchables(ArrayList<View> views) {
669         super.addTouchables(views);
670 
671         final int count = mChildrenCount;
672         final View[] children = mChildren;
673 
674         for (int i = 0; i < count; i++) {
675             final View child = children[i];
676             if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
677                 child.addTouchables(views);
678             }
679         }
680     }
681 
682     /**
683      * {@inheritDoc}
684      */
685     @Override
dispatchWindowVisibilityChanged(int visibility)686     public void dispatchWindowVisibilityChanged(int visibility) {
687         super.dispatchWindowVisibilityChanged(visibility);
688         final int count = mChildrenCount;
689         final View[] children = mChildren;
690         for (int i = 0; i < count; i++) {
691             children[i].dispatchWindowVisibilityChanged(visibility);
692         }
693     }
694 
695     /**
696      * {@inheritDoc}
697      */
recomputeViewAttributes(View child)698     public void recomputeViewAttributes(View child) {
699         ViewParent parent = mParent;
700         if (parent != null) parent.recomputeViewAttributes(this);
701     }
702 
703     @Override
dispatchCollectViewAttributes(int visibility)704     void dispatchCollectViewAttributes(int visibility) {
705         visibility |= mViewFlags&VISIBILITY_MASK;
706         super.dispatchCollectViewAttributes(visibility);
707         final int count = mChildrenCount;
708         final View[] children = mChildren;
709         for (int i = 0; i < count; i++) {
710             children[i].dispatchCollectViewAttributes(visibility);
711         }
712     }
713 
714     /**
715      * {@inheritDoc}
716      */
bringChildToFront(View child)717     public void bringChildToFront(View child) {
718         int index = indexOfChild(child);
719         if (index >= 0) {
720             removeFromArray(index);
721             addInArray(child, mChildrenCount);
722             child.mParent = this;
723         }
724     }
725 
726     /**
727      * {@inheritDoc}
728      */
729     @Override
dispatchKeyEventPreIme(KeyEvent event)730     public boolean dispatchKeyEventPreIme(KeyEvent event) {
731         if ((mPrivateFlags & (FOCUSED | HAS_BOUNDS)) == (FOCUSED | HAS_BOUNDS)) {
732             return super.dispatchKeyEventPreIme(event);
733         } else if (mFocused != null && (mFocused.mPrivateFlags & HAS_BOUNDS) == HAS_BOUNDS) {
734             return mFocused.dispatchKeyEventPreIme(event);
735         }
736         return false;
737     }
738 
739     /**
740      * {@inheritDoc}
741      */
742     @Override
dispatchKeyEvent(KeyEvent event)743     public boolean dispatchKeyEvent(KeyEvent event) {
744         if ((mPrivateFlags & (FOCUSED | HAS_BOUNDS)) == (FOCUSED | HAS_BOUNDS)) {
745             return super.dispatchKeyEvent(event);
746         } else if (mFocused != null && (mFocused.mPrivateFlags & HAS_BOUNDS) == HAS_BOUNDS) {
747             return mFocused.dispatchKeyEvent(event);
748         }
749         return false;
750     }
751 
752     /**
753      * {@inheritDoc}
754      */
755     @Override
dispatchKeyShortcutEvent(KeyEvent event)756     public boolean dispatchKeyShortcutEvent(KeyEvent event) {
757         if ((mPrivateFlags & (FOCUSED | HAS_BOUNDS)) == (FOCUSED | HAS_BOUNDS)) {
758             return super.dispatchKeyShortcutEvent(event);
759         } else if (mFocused != null && (mFocused.mPrivateFlags & HAS_BOUNDS) == HAS_BOUNDS) {
760             return mFocused.dispatchKeyShortcutEvent(event);
761         }
762         return false;
763     }
764 
765     /**
766      * {@inheritDoc}
767      */
768     @Override
dispatchTrackballEvent(MotionEvent event)769     public boolean dispatchTrackballEvent(MotionEvent event) {
770         if ((mPrivateFlags & (FOCUSED | HAS_BOUNDS)) == (FOCUSED | HAS_BOUNDS)) {
771             return super.dispatchTrackballEvent(event);
772         } else if (mFocused != null && (mFocused.mPrivateFlags & HAS_BOUNDS) == HAS_BOUNDS) {
773             return mFocused.dispatchTrackballEvent(event);
774         }
775         return false;
776     }
777 
778     /**
779      * {@inheritDoc}
780      */
781     @Override
dispatchTouchEvent(MotionEvent ev)782     public boolean dispatchTouchEvent(MotionEvent ev) {
783         final int action = ev.getAction();
784         final float xf = ev.getX();
785         final float yf = ev.getY();
786         final float scrolledXFloat = xf + mScrollX;
787         final float scrolledYFloat = yf + mScrollY;
788         final Rect frame = mTempRect;
789 
790         boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
791 
792         if (action == MotionEvent.ACTION_DOWN) {
793             if (mMotionTarget != null) {
794                 // this is weird, we got a pen down, but we thought it was
795                 // already down!
796                 // XXX: We should probably send an ACTION_UP to the current
797                 // target.
798                 mMotionTarget = null;
799             }
800             // If we're disallowing intercept or if we're allowing and we didn't
801             // intercept
802             if (disallowIntercept || !onInterceptTouchEvent(ev)) {
803                 // reset this event's action (just to protect ourselves)
804                 ev.setAction(MotionEvent.ACTION_DOWN);
805                 // We know we want to dispatch the event down, find a child
806                 // who can handle it, start with the front-most child.
807                 final int scrolledXInt = (int) scrolledXFloat;
808                 final int scrolledYInt = (int) scrolledYFloat;
809                 final View[] children = mChildren;
810                 final int count = mChildrenCount;
811                 for (int i = count - 1; i >= 0; i--) {
812                     final View child = children[i];
813                     if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE
814                             || child.getAnimation() != null) {
815                         child.getHitRect(frame);
816                         if (frame.contains(scrolledXInt, scrolledYInt)) {
817                             // offset the event to the view's coordinate system
818                             final float xc = scrolledXFloat - child.mLeft;
819                             final float yc = scrolledYFloat - child.mTop;
820                             ev.setLocation(xc, yc);
821                             if (child.dispatchTouchEvent(ev))  {
822                                 // Event handled, we have a target now.
823                                 mMotionTarget = child;
824                                 return true;
825                             }
826                             // The event didn't get handled, try the next view.
827                             // Don't reset the event's location, it's not
828                             // necessary here.
829                         }
830                     }
831                 }
832             }
833         }
834 
835         boolean isUpOrCancel = (action == MotionEvent.ACTION_UP) ||
836                 (action == MotionEvent.ACTION_CANCEL);
837 
838         if (isUpOrCancel) {
839             // Note, we've already copied the previous state to our local
840             // variable, so this takes effect on the next event
841             mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
842         }
843 
844         // The event wasn't an ACTION_DOWN, dispatch it to our target if
845         // we have one.
846         final View target = mMotionTarget;
847         if (target == null) {
848             // We don't have a target, this means we're handling the
849             // event as a regular view.
850             ev.setLocation(xf, yf);
851             return super.dispatchTouchEvent(ev);
852         }
853 
854         // if have a target, see if we're allowed to and want to intercept its
855         // events
856         if (!disallowIntercept && onInterceptTouchEvent(ev)) {
857             final float xc = scrolledXFloat - (float) target.mLeft;
858             final float yc = scrolledYFloat - (float) target.mTop;
859             ev.setAction(MotionEvent.ACTION_CANCEL);
860             ev.setLocation(xc, yc);
861             if (!target.dispatchTouchEvent(ev)) {
862                 // target didn't handle ACTION_CANCEL. not much we can do
863                 // but they should have.
864             }
865             // clear the target
866             mMotionTarget = null;
867             // Don't dispatch this event to our own view, because we already
868             // saw it when intercepting; we just want to give the following
869             // event to the normal onTouchEvent().
870             return true;
871         }
872 
873         if (isUpOrCancel) {
874             mMotionTarget = null;
875         }
876 
877         // finally offset the event to the target's coordinate system and
878         // dispatch the event.
879         final float xc = scrolledXFloat - (float) target.mLeft;
880         final float yc = scrolledYFloat - (float) target.mTop;
881         ev.setLocation(xc, yc);
882 
883         return target.dispatchTouchEvent(ev);
884     }
885 
886     /**
887      * {@inheritDoc}
888      */
requestDisallowInterceptTouchEvent(boolean disallowIntercept)889     public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
890 
891         if (disallowIntercept == ((mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0)) {
892             // We're already in this state, assume our ancestors are too
893             return;
894         }
895 
896         if (disallowIntercept) {
897             mGroupFlags |= FLAG_DISALLOW_INTERCEPT;
898         } else {
899             mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
900         }
901 
902         // Pass it up to our parent
903         if (mParent != null) {
904             mParent.requestDisallowInterceptTouchEvent(disallowIntercept);
905         }
906     }
907 
908     /**
909      * Implement this method to intercept all touch screen motion events.  This
910      * allows you to watch events as they are dispatched to your children, and
911      * take ownership of the current gesture at any point.
912      *
913      * <p>Using this function takes some care, as it has a fairly complicated
914      * interaction with {@link View#onTouchEvent(MotionEvent)
915      * View.onTouchEvent(MotionEvent)}, and using it requires implementing
916      * that method as well as this one in the correct way.  Events will be
917      * received in the following order:
918      *
919      * <ol>
920      * <li> You will receive the down event here.
921      * <li> The down event will be handled either by a child of this view
922      * group, or given to your own onTouchEvent() method to handle; this means
923      * you should implement onTouchEvent() to return true, so you will
924      * continue to see the rest of the gesture (instead of looking for
925      * a parent view to handle it).  Also, by returning true from
926      * onTouchEvent(), you will not receive any following
927      * events in onInterceptTouchEvent() and all touch processing must
928      * happen in onTouchEvent() like normal.
929      * <li> For as long as you return false from this function, each following
930      * event (up to and including the final up) will be delivered first here
931      * and then to the target's onTouchEvent().
932      * <li> If you return true from here, you will not receive any
933      * following events: the target view will receive the same event but
934      * with the action {@link MotionEvent#ACTION_CANCEL}, and all further
935      * events will be delivered to your onTouchEvent() method and no longer
936      * appear here.
937      * </ol>
938      *
939      * @param ev The motion event being dispatched down the hierarchy.
940      * @return Return true to steal motion events from the children and have
941      * them dispatched to this ViewGroup through onTouchEvent().
942      * The current target will receive an ACTION_CANCEL event, and no further
943      * messages will be delivered here.
944      */
onInterceptTouchEvent(MotionEvent ev)945     public boolean onInterceptTouchEvent(MotionEvent ev) {
946         return false;
947     }
948 
949     /**
950      * {@inheritDoc}
951      *
952      * Looks for a view to give focus to respecting the setting specified by
953      * {@link #getDescendantFocusability()}.
954      *
955      * Uses {@link #onRequestFocusInDescendants(int, android.graphics.Rect)} to
956      * find focus within the children of this group when appropriate.
957      *
958      * @see #FOCUS_BEFORE_DESCENDANTS
959      * @see #FOCUS_AFTER_DESCENDANTS
960      * @see #FOCUS_BLOCK_DESCENDANTS
961      * @see #onRequestFocusInDescendants
962      */
963     @Override
requestFocus(int direction, Rect previouslyFocusedRect)964     public boolean requestFocus(int direction, Rect previouslyFocusedRect) {
965         if (DBG) {
966             System.out.println(this + " ViewGroup.requestFocus direction="
967                     + direction);
968         }
969         int descendantFocusability = getDescendantFocusability();
970 
971         switch (descendantFocusability) {
972             case FOCUS_BLOCK_DESCENDANTS:
973                 return super.requestFocus(direction, previouslyFocusedRect);
974             case FOCUS_BEFORE_DESCENDANTS: {
975                 final boolean took = super.requestFocus(direction, previouslyFocusedRect);
976                 return took ? took : onRequestFocusInDescendants(direction, previouslyFocusedRect);
977             }
978             case FOCUS_AFTER_DESCENDANTS: {
979                 final boolean took = onRequestFocusInDescendants(direction, previouslyFocusedRect);
980                 return took ? took : super.requestFocus(direction, previouslyFocusedRect);
981             }
982             default:
983                 throw new IllegalStateException("descendant focusability must be "
984                         + "one of FOCUS_BEFORE_DESCENDANTS, FOCUS_AFTER_DESCENDANTS, FOCUS_BLOCK_DESCENDANTS "
985                         + "but is " + descendantFocusability);
986         }
987     }
988 
989     /**
990      * Look for a descendant to call {@link View#requestFocus} on.
991      * Called by {@link ViewGroup#requestFocus(int, android.graphics.Rect)}
992      * when it wants to request focus within its children.  Override this to
993      * customize how your {@link ViewGroup} requests focus within its children.
994      * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT
995      * @param previouslyFocusedRect The rectangle (in this View's coordinate system)
996      *        to give a finer grained hint about where focus is coming from.  May be null
997      *        if there is no hint.
998      * @return Whether focus was taken.
999      */
1000     @SuppressWarnings({"ConstantConditions"})
onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect)1001     protected boolean onRequestFocusInDescendants(int direction,
1002             Rect previouslyFocusedRect) {
1003         int index;
1004         int increment;
1005         int end;
1006         int count = mChildrenCount;
1007         if ((direction & FOCUS_FORWARD) != 0) {
1008             index = 0;
1009             increment = 1;
1010             end = count;
1011         } else {
1012             index = count - 1;
1013             increment = -1;
1014             end = -1;
1015         }
1016         final View[] children = mChildren;
1017         for (int i = index; i != end; i += increment) {
1018             View child = children[i];
1019             if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
1020                 if (child.requestFocus(direction, previouslyFocusedRect)) {
1021                     return true;
1022                 }
1023             }
1024         }
1025         return false;
1026     }
1027 
1028     /**
1029      * {@inheritDoc}
1030      */
1031     @Override
dispatchAttachedToWindow(AttachInfo info, int visibility)1032     void dispatchAttachedToWindow(AttachInfo info, int visibility) {
1033         super.dispatchAttachedToWindow(info, visibility);
1034         visibility |= mViewFlags & VISIBILITY_MASK;
1035         final int count = mChildrenCount;
1036         final View[] children = mChildren;
1037         for (int i = 0; i < count; i++) {
1038             children[i].dispatchAttachedToWindow(info, visibility);
1039         }
1040     }
1041 
1042     @Override
dispatchPopulateAccessibilityEvent(AccessibilityEvent event)1043     public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
1044         boolean populated = false;
1045         for (int i = 0, count = getChildCount(); i < count; i++) {
1046             populated |= getChildAt(i).dispatchPopulateAccessibilityEvent(event);
1047         }
1048         return populated;
1049     }
1050 
1051     /**
1052      * {@inheritDoc}
1053      */
1054     @Override
dispatchDetachedFromWindow()1055     void dispatchDetachedFromWindow() {
1056         // If we still have a motion target, we are still in the process of
1057         // dispatching motion events to a child; we need to get rid of that
1058         // child to avoid dispatching events to it after the window is torn
1059         // down. To make sure we keep the child in a consistent state, we
1060         // first send it an ACTION_CANCEL motion event.
1061         if (mMotionTarget != null) {
1062             final long now = SystemClock.uptimeMillis();
1063             final MotionEvent event = MotionEvent.obtain(now, now,
1064                     MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
1065             mMotionTarget.dispatchTouchEvent(event);
1066             event.recycle();
1067             mMotionTarget = null;
1068         }
1069 
1070         final int count = mChildrenCount;
1071         final View[] children = mChildren;
1072         for (int i = 0; i < count; i++) {
1073             children[i].dispatchDetachedFromWindow();
1074         }
1075         super.dispatchDetachedFromWindow();
1076     }
1077 
1078     /**
1079      * {@inheritDoc}
1080      */
1081     @Override
setPadding(int left, int top, int right, int bottom)1082     public void setPadding(int left, int top, int right, int bottom) {
1083         super.setPadding(left, top, right, bottom);
1084 
1085         if ((mPaddingLeft | mPaddingTop | mPaddingRight | mPaddingRight) != 0) {
1086             mGroupFlags |= FLAG_PADDING_NOT_NULL;
1087         } else {
1088             mGroupFlags &= ~FLAG_PADDING_NOT_NULL;
1089         }
1090     }
1091 
1092     /**
1093      * {@inheritDoc}
1094      */
1095     @Override
dispatchSaveInstanceState(SparseArray<Parcelable> container)1096     protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {
1097         super.dispatchSaveInstanceState(container);
1098         final int count = mChildrenCount;
1099         final View[] children = mChildren;
1100         for (int i = 0; i < count; i++) {
1101             children[i].dispatchSaveInstanceState(container);
1102         }
1103     }
1104 
1105     /**
1106      * Perform dispatching of a {@link #saveHierarchyState freeze()} to only this view,
1107      * not to its children.  For use when overriding
1108      * {@link #dispatchSaveInstanceState dispatchFreeze()} to allow subclasses to freeze
1109      * their own state but not the state of their children.
1110      *
1111      * @param container the container
1112      */
dispatchFreezeSelfOnly(SparseArray<Parcelable> container)1113     protected void dispatchFreezeSelfOnly(SparseArray<Parcelable> container) {
1114         super.dispatchSaveInstanceState(container);
1115     }
1116 
1117     /**
1118      * {@inheritDoc}
1119      */
1120     @Override
dispatchRestoreInstanceState(SparseArray<Parcelable> container)1121     protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {
1122         super.dispatchRestoreInstanceState(container);
1123         final int count = mChildrenCount;
1124         final View[] children = mChildren;
1125         for (int i = 0; i < count; i++) {
1126             children[i].dispatchRestoreInstanceState(container);
1127         }
1128     }
1129 
1130     /**
1131      * Perform dispatching of a {@link #restoreHierarchyState thaw()} to only this view,
1132      * not to its children.  For use when overriding
1133      * {@link #dispatchRestoreInstanceState dispatchThaw()} to allow subclasses to thaw
1134      * their own state but not the state of their children.
1135      *
1136      * @param container the container
1137      */
dispatchThawSelfOnly(SparseArray<Parcelable> container)1138     protected void dispatchThawSelfOnly(SparseArray<Parcelable> container) {
1139         super.dispatchRestoreInstanceState(container);
1140     }
1141 
1142     /**
1143      * Enables or disables the drawing cache for each child of this view group.
1144      *
1145      * @param enabled true to enable the cache, false to dispose of it
1146      */
setChildrenDrawingCacheEnabled(boolean enabled)1147     protected void setChildrenDrawingCacheEnabled(boolean enabled) {
1148         if (enabled || (mPersistentDrawingCache & PERSISTENT_ALL_CACHES) != PERSISTENT_ALL_CACHES) {
1149             final View[] children = mChildren;
1150             final int count = mChildrenCount;
1151             for (int i = 0; i < count; i++) {
1152                 children[i].setDrawingCacheEnabled(enabled);
1153             }
1154         }
1155     }
1156 
1157     @Override
onAnimationStart()1158     protected void onAnimationStart() {
1159         super.onAnimationStart();
1160 
1161         // When this ViewGroup's animation starts, build the cache for the children
1162         if ((mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE) {
1163             final int count = mChildrenCount;
1164             final View[] children = mChildren;
1165 
1166             for (int i = 0; i < count; i++) {
1167                 final View child = children[i];
1168                 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
1169                     child.setDrawingCacheEnabled(true);
1170                     child.buildDrawingCache(true);
1171                 }
1172             }
1173 
1174             mGroupFlags |= FLAG_CHILDREN_DRAWN_WITH_CACHE;
1175         }
1176     }
1177 
1178     @Override
onAnimationEnd()1179     protected void onAnimationEnd() {
1180         super.onAnimationEnd();
1181 
1182         // When this ViewGroup's animation ends, destroy the cache of the children
1183         if ((mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE) {
1184             mGroupFlags &= ~FLAG_CHILDREN_DRAWN_WITH_CACHE;
1185 
1186             if ((mPersistentDrawingCache & PERSISTENT_ANIMATION_CACHE) == 0) {
1187                 setChildrenDrawingCacheEnabled(false);
1188             }
1189         }
1190     }
1191 
1192     /**
1193      * {@inheritDoc}
1194      */
1195     @Override
dispatchDraw(Canvas canvas)1196     protected void dispatchDraw(Canvas canvas) {
1197         final int count = mChildrenCount;
1198         final View[] children = mChildren;
1199         int flags = mGroupFlags;
1200 
1201         if ((flags & FLAG_RUN_ANIMATION) != 0 && canAnimate()) {
1202             final boolean cache = (mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE;
1203 
1204             for (int i = 0; i < count; i++) {
1205                 final View child = children[i];
1206                 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
1207                     final LayoutParams params = child.getLayoutParams();
1208                     attachLayoutAnimationParameters(child, params, i, count);
1209                     bindLayoutAnimation(child);
1210                     if (cache) {
1211                         child.setDrawingCacheEnabled(true);
1212                         child.buildDrawingCache(true);
1213                     }
1214                 }
1215             }
1216 
1217             final LayoutAnimationController controller = mLayoutAnimationController;
1218             if (controller.willOverlap()) {
1219                 mGroupFlags |= FLAG_OPTIMIZE_INVALIDATE;
1220             }
1221 
1222             controller.start();
1223 
1224             mGroupFlags &= ~FLAG_RUN_ANIMATION;
1225             mGroupFlags &= ~FLAG_ANIMATION_DONE;
1226 
1227             if (cache) {
1228                 mGroupFlags |= FLAG_CHILDREN_DRAWN_WITH_CACHE;
1229             }
1230 
1231             if (mAnimationListener != null) {
1232                 mAnimationListener.onAnimationStart(controller.getAnimation());
1233             }
1234         }
1235 
1236         int saveCount = 0;
1237         final boolean clipToPadding = (flags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK;
1238         if (clipToPadding) {
1239             saveCount = canvas.save();
1240             canvas.clipRect(mScrollX + mPaddingLeft, mScrollY + mPaddingTop,
1241                     mScrollX + mRight - mLeft - mPaddingRight,
1242                     mScrollY + mBottom - mTop - mPaddingBottom);
1243 
1244         }
1245 
1246         // We will draw our child's animation, let's reset the flag
1247         mPrivateFlags &= ~DRAW_ANIMATION;
1248         mGroupFlags &= ~FLAG_INVALIDATE_REQUIRED;
1249 
1250         boolean more = false;
1251         final long drawingTime = getDrawingTime();
1252 
1253         if ((flags & FLAG_USE_CHILD_DRAWING_ORDER) == 0) {
1254             for (int i = 0; i < count; i++) {
1255                 final View child = children[i];
1256                 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
1257                     more |= drawChild(canvas, child, drawingTime);
1258                 }
1259             }
1260         } else {
1261             for (int i = 0; i < count; i++) {
1262                 final View child = children[getChildDrawingOrder(count, i)];
1263                 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
1264                     more |= drawChild(canvas, child, drawingTime);
1265                 }
1266             }
1267         }
1268 
1269         // Draw any disappearing views that have animations
1270         if (mDisappearingChildren != null) {
1271             final ArrayList<View> disappearingChildren = mDisappearingChildren;
1272             final int disappearingCount = disappearingChildren.size() - 1;
1273             // Go backwards -- we may delete as animations finish
1274             for (int i = disappearingCount; i >= 0; i--) {
1275                 final View child = disappearingChildren.get(i);
1276                 more |= drawChild(canvas, child, drawingTime);
1277             }
1278         }
1279 
1280         if (clipToPadding) {
1281             canvas.restoreToCount(saveCount);
1282         }
1283 
1284         // mGroupFlags might have been updated by drawChild()
1285         flags = mGroupFlags;
1286 
1287         if ((flags & FLAG_INVALIDATE_REQUIRED) == FLAG_INVALIDATE_REQUIRED) {
1288             invalidate();
1289         }
1290 
1291         if ((flags & FLAG_ANIMATION_DONE) == 0 && (flags & FLAG_NOTIFY_ANIMATION_LISTENER) == 0 &&
1292                 mLayoutAnimationController.isDone() && !more) {
1293             // We want to erase the drawing cache and notify the listener after the
1294             // next frame is drawn because one extra invalidate() is caused by
1295             // drawChild() after the animation is over
1296             mGroupFlags |= FLAG_NOTIFY_ANIMATION_LISTENER;
1297             final Runnable end = new Runnable() {
1298                public void run() {
1299                    notifyAnimationListener();
1300                }
1301             };
1302             post(end);
1303         }
1304     }
1305 
1306     /**
1307      * Returns the index of the child to draw for this iteration. Override this
1308      * if you want to change the drawing order of children. By default, it
1309      * returns i.
1310      * <p>
1311      * NOTE: In order for this method to be called, the
1312      * {@link #FLAG_USE_CHILD_DRAWING_ORDER} must be set.
1313      *
1314      * @param i The current iteration.
1315      * @return The index of the child to draw this iteration.
1316      */
getChildDrawingOrder(int childCount, int i)1317     protected int getChildDrawingOrder(int childCount, int i) {
1318         return i;
1319     }
1320 
notifyAnimationListener()1321     private void notifyAnimationListener() {
1322         mGroupFlags &= ~FLAG_NOTIFY_ANIMATION_LISTENER;
1323         mGroupFlags |= FLAG_ANIMATION_DONE;
1324 
1325         if (mAnimationListener != null) {
1326            final Runnable end = new Runnable() {
1327                public void run() {
1328                    mAnimationListener.onAnimationEnd(mLayoutAnimationController.getAnimation());
1329                }
1330            };
1331            post(end);
1332         }
1333 
1334         if ((mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE) {
1335             mGroupFlags &= ~FLAG_CHILDREN_DRAWN_WITH_CACHE;
1336             if ((mPersistentDrawingCache & PERSISTENT_ANIMATION_CACHE) == 0) {
1337                 setChildrenDrawingCacheEnabled(false);
1338             }
1339         }
1340 
1341         invalidate();
1342     }
1343 
1344     /**
1345      * Draw one child of this View Group. This method is responsible for getting
1346      * the canvas in the right state. This includes clipping, translating so
1347      * that the child's scrolled origin is at 0, 0, and applying any animation
1348      * transformations.
1349      *
1350      * @param canvas The canvas on which to draw the child
1351      * @param child Who to draw
1352      * @param drawingTime The time at which draw is occuring
1353      * @return True if an invalidate() was issued
1354      */
drawChild(Canvas canvas, View child, long drawingTime)1355     protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
1356         boolean more = false;
1357 
1358         final int cl = child.mLeft;
1359         final int ct = child.mTop;
1360         final int cr = child.mRight;
1361         final int cb = child.mBottom;
1362 
1363         final int flags = mGroupFlags;
1364 
1365         if ((flags & FLAG_CLEAR_TRANSFORMATION) == FLAG_CLEAR_TRANSFORMATION) {
1366             if (mChildTransformation != null) {
1367                 mChildTransformation.clear();
1368             }
1369             mGroupFlags &= ~FLAG_CLEAR_TRANSFORMATION;
1370         }
1371 
1372         Transformation transformToApply = null;
1373         final Animation a = child.getAnimation();
1374         boolean concatMatrix = false;
1375 
1376         if (a != null) {
1377             if (mInvalidateRegion == null) {
1378                 mInvalidateRegion = new RectF();
1379             }
1380             final RectF region = mInvalidateRegion;
1381 
1382             final boolean initialized = a.isInitialized();
1383             if (!initialized) {
1384                 a.initialize(cr - cl, cb - ct, getWidth(), getHeight());
1385                 a.initializeInvalidateRegion(0, 0, cr - cl, cb - ct);
1386                 child.onAnimationStart();
1387             }
1388 
1389             if (mChildTransformation == null) {
1390                 mChildTransformation = new Transformation();
1391             }
1392             more = a.getTransformation(drawingTime, mChildTransformation);
1393             transformToApply = mChildTransformation;
1394 
1395             concatMatrix = a.willChangeTransformationMatrix();
1396 
1397             if (more) {
1398                 if (!a.willChangeBounds()) {
1399                     if ((flags & (FLAG_OPTIMIZE_INVALIDATE | FLAG_ANIMATION_DONE)) ==
1400                             FLAG_OPTIMIZE_INVALIDATE) {
1401                         mGroupFlags |= FLAG_INVALIDATE_REQUIRED;
1402                     } else if ((flags & FLAG_INVALIDATE_REQUIRED) == 0) {
1403                         // The child need to draw an animation, potentially offscreen, so
1404                         // make sure we do not cancel invalidate requests
1405                         mPrivateFlags |= DRAW_ANIMATION;
1406                         invalidate(cl, ct, cr, cb);
1407                     }
1408                 } else {
1409                     a.getInvalidateRegion(0, 0, cr - cl, cb - ct, region, transformToApply);
1410 
1411                     // The child need to draw an animation, potentially offscreen, so
1412                     // make sure we do not cancel invalidate requests
1413                     mPrivateFlags |= DRAW_ANIMATION;
1414 
1415                     final int left = cl + (int) region.left;
1416                     final int top = ct + (int) region.top;
1417                     invalidate(left, top, left + (int) region.width(), top + (int) region.height());
1418                 }
1419             }
1420         } else if ((flags & FLAG_SUPPORT_STATIC_TRANSFORMATIONS) ==
1421                 FLAG_SUPPORT_STATIC_TRANSFORMATIONS) {
1422             if (mChildTransformation == null) {
1423                 mChildTransformation = new Transformation();
1424             }
1425             final boolean hasTransform = getChildStaticTransformation(child, mChildTransformation);
1426             if (hasTransform) {
1427                 final int transformType = mChildTransformation.getTransformationType();
1428                 transformToApply = transformType != Transformation.TYPE_IDENTITY ?
1429                         mChildTransformation : null;
1430                 concatMatrix = (transformType & Transformation.TYPE_MATRIX) != 0;
1431             }
1432         }
1433 
1434         // Sets the flag as early as possible to allow draw() implementations
1435         // to call invalidate() successfully when doing animations
1436         child.mPrivateFlags |= DRAWN;
1437 
1438         if (!concatMatrix && canvas.quickReject(cl, ct, cr, cb, Canvas.EdgeType.BW) &&
1439                 (child.mPrivateFlags & DRAW_ANIMATION) == 0) {
1440             return more;
1441         }
1442 
1443         child.computeScroll();
1444 
1445         final int sx = child.mScrollX;
1446         final int sy = child.mScrollY;
1447 
1448         boolean scalingRequired = false;
1449         Bitmap cache = null;
1450         if ((flags & FLAG_CHILDREN_DRAWN_WITH_CACHE) == FLAG_CHILDREN_DRAWN_WITH_CACHE ||
1451                 (flags & FLAG_ALWAYS_DRAWN_WITH_CACHE) == FLAG_ALWAYS_DRAWN_WITH_CACHE) {
1452             cache = child.getDrawingCache(true);
1453             if (mAttachInfo != null) scalingRequired = mAttachInfo.mScalingRequired;
1454         }
1455 
1456         final boolean hasNoCache = cache == null;
1457 
1458         final int restoreTo = canvas.save();
1459         if (hasNoCache) {
1460             canvas.translate(cl - sx, ct - sy);
1461         } else {
1462             canvas.translate(cl, ct);
1463             if (scalingRequired) {
1464                 // mAttachInfo cannot be null, otherwise scalingRequired == false
1465                 final float scale = 1.0f / mAttachInfo.mApplicationScale;
1466                 canvas.scale(scale, scale);
1467             }
1468         }
1469 
1470         float alpha = 1.0f;
1471 
1472         if (transformToApply != null) {
1473             if (concatMatrix) {
1474                 int transX = 0;
1475                 int transY = 0;
1476                 if (hasNoCache) {
1477                     transX = -sx;
1478                     transY = -sy;
1479                 }
1480                 // Undo the scroll translation, apply the transformation matrix,
1481                 // then redo the scroll translate to get the correct result.
1482                 canvas.translate(-transX, -transY);
1483                 canvas.concat(transformToApply.getMatrix());
1484                 canvas.translate(transX, transY);
1485                 mGroupFlags |= FLAG_CLEAR_TRANSFORMATION;
1486             }
1487 
1488             alpha = transformToApply.getAlpha();
1489             if (alpha < 1.0f) {
1490                 mGroupFlags |= FLAG_CLEAR_TRANSFORMATION;
1491             }
1492 
1493             if (alpha < 1.0f && hasNoCache) {
1494                 final int multipliedAlpha = (int) (255 * alpha);
1495                 if (!child.onSetAlpha(multipliedAlpha)) {
1496                     canvas.saveLayerAlpha(sx, sy, sx + cr - cl, sy + cb - ct, multipliedAlpha,
1497                             Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG);
1498                 } else {
1499                     child.mPrivateFlags |= ALPHA_SET;
1500                 }
1501             }
1502         } else if ((child.mPrivateFlags & ALPHA_SET) == ALPHA_SET) {
1503             child.onSetAlpha(255);
1504         }
1505 
1506         if ((flags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN) {
1507             if (hasNoCache) {
1508                 canvas.clipRect(sx, sy, sx + (cr - cl), sy + (cb - ct));
1509             } else {
1510                 if (!scalingRequired) {
1511                     canvas.clipRect(0, 0, cr - cl, cb - ct);
1512                 } else {
1513                     canvas.clipRect(0, 0, cache.getWidth(), cache.getHeight());
1514                 }
1515             }
1516         }
1517 
1518         if (hasNoCache) {
1519             // Fast path for layouts with no backgrounds
1520             if ((child.mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
1521                 if (ViewDebug.TRACE_HIERARCHY) {
1522                     ViewDebug.trace(this, ViewDebug.HierarchyTraceType.DRAW);
1523                 }
1524                 child.mPrivateFlags &= ~DIRTY_MASK;
1525                 child.dispatchDraw(canvas);
1526             } else {
1527                 child.draw(canvas);
1528             }
1529         } else {
1530             final Paint cachePaint = mCachePaint;
1531             if (alpha < 1.0f) {
1532                 cachePaint.setAlpha((int) (alpha * 255));
1533                 mGroupFlags |= FLAG_ALPHA_LOWER_THAN_ONE;
1534             } else if  ((flags & FLAG_ALPHA_LOWER_THAN_ONE) == FLAG_ALPHA_LOWER_THAN_ONE) {
1535                 cachePaint.setAlpha(255);
1536                 mGroupFlags &= ~FLAG_ALPHA_LOWER_THAN_ONE;
1537             }
1538             if (Config.DEBUG && ViewDebug.profileDrawing) {
1539                 EventLog.writeEvent(60003, hashCode());
1540             }
1541             canvas.drawBitmap(cache, 0.0f, 0.0f, cachePaint);
1542         }
1543 
1544         canvas.restoreToCount(restoreTo);
1545 
1546         if (a != null && !more) {
1547             child.onSetAlpha(255);
1548             finishAnimatingView(child, a);
1549         }
1550 
1551         return more;
1552     }
1553 
1554     /**
1555      * By default, children are clipped to their bounds before drawing. This
1556      * allows view groups to override this behavior for animations, etc.
1557      *
1558      * @param clipChildren true to clip children to their bounds,
1559      *        false otherwise
1560      * @attr ref android.R.styleable#ViewGroup_clipChildren
1561      */
setClipChildren(boolean clipChildren)1562     public void setClipChildren(boolean clipChildren) {
1563         setBooleanFlag(FLAG_CLIP_CHILDREN, clipChildren);
1564     }
1565 
1566     /**
1567      * By default, children are clipped to the padding of the ViewGroup. This
1568      * allows view groups to override this behavior
1569      *
1570      * @param clipToPadding true to clip children to the padding of the
1571      *        group, false otherwise
1572      * @attr ref android.R.styleable#ViewGroup_clipToPadding
1573      */
setClipToPadding(boolean clipToPadding)1574     public void setClipToPadding(boolean clipToPadding) {
1575         setBooleanFlag(FLAG_CLIP_TO_PADDING, clipToPadding);
1576     }
1577 
1578     /**
1579      * {@inheritDoc}
1580      */
1581     @Override
dispatchSetSelected(boolean selected)1582     public void dispatchSetSelected(boolean selected) {
1583         final View[] children = mChildren;
1584         final int count = mChildrenCount;
1585         for (int i = 0; i < count; i++) {
1586             children[i].setSelected(selected);
1587         }
1588     }
1589 
1590     @Override
dispatchSetPressed(boolean pressed)1591     protected void dispatchSetPressed(boolean pressed) {
1592         final View[] children = mChildren;
1593         final int count = mChildrenCount;
1594         for (int i = 0; i < count; i++) {
1595             children[i].setPressed(pressed);
1596         }
1597     }
1598 
1599     /**
1600      * When this property is set to true, this ViewGroup supports static transformations on
1601      * children; this causes
1602      * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} to be
1603      * invoked when a child is drawn.
1604      *
1605      * Any subclass overriding
1606      * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} should
1607      * set this property to true.
1608      *
1609      * @param enabled True to enable static transformations on children, false otherwise.
1610      *
1611      * @see #FLAG_SUPPORT_STATIC_TRANSFORMATIONS
1612      */
setStaticTransformationsEnabled(boolean enabled)1613     protected void setStaticTransformationsEnabled(boolean enabled) {
1614         setBooleanFlag(FLAG_SUPPORT_STATIC_TRANSFORMATIONS, enabled);
1615     }
1616 
1617     /**
1618      * {@inheritDoc}
1619      *
1620      * @see #setStaticTransformationsEnabled(boolean)
1621      */
getChildStaticTransformation(View child, Transformation t)1622     protected boolean getChildStaticTransformation(View child, Transformation t) {
1623         return false;
1624     }
1625 
1626     /**
1627      * {@hide}
1628      */
1629     @Override
findViewTraversal(int id)1630     protected View findViewTraversal(int id) {
1631         if (id == mID) {
1632             return this;
1633         }
1634 
1635         final View[] where = mChildren;
1636         final int len = mChildrenCount;
1637 
1638         for (int i = 0; i < len; i++) {
1639             View v = where[i];
1640 
1641             if ((v.mPrivateFlags & IS_ROOT_NAMESPACE) == 0) {
1642                 v = v.findViewById(id);
1643 
1644                 if (v != null) {
1645                     return v;
1646                 }
1647             }
1648         }
1649 
1650         return null;
1651     }
1652 
1653     /**
1654      * {@hide}
1655      */
1656     @Override
findViewWithTagTraversal(Object tag)1657     protected View findViewWithTagTraversal(Object tag) {
1658         if (tag != null && tag.equals(mTag)) {
1659             return this;
1660         }
1661 
1662         final View[] where = mChildren;
1663         final int len = mChildrenCount;
1664 
1665         for (int i = 0; i < len; i++) {
1666             View v = where[i];
1667 
1668             if ((v.mPrivateFlags & IS_ROOT_NAMESPACE) == 0) {
1669                 v = v.findViewWithTag(tag);
1670 
1671                 if (v != null) {
1672                     return v;
1673                 }
1674             }
1675         }
1676 
1677         return null;
1678     }
1679 
1680     /**
1681      * Adds a child view. If no layout parameters are already set on the child, the
1682      * default parameters for this ViewGroup are set on the child.
1683      *
1684      * @param child the child view to add
1685      *
1686      * @see #generateDefaultLayoutParams()
1687      */
addView(View child)1688     public void addView(View child) {
1689         addView(child, -1);
1690     }
1691 
1692     /**
1693      * Adds a child view. If no layout parameters are already set on the child, the
1694      * default parameters for this ViewGroup are set on the child.
1695      *
1696      * @param child the child view to add
1697      * @param index the position at which to add the child
1698      *
1699      * @see #generateDefaultLayoutParams()
1700      */
addView(View child, int index)1701     public void addView(View child, int index) {
1702         LayoutParams params = child.getLayoutParams();
1703         if (params == null) {
1704             params = generateDefaultLayoutParams();
1705             if (params == null) {
1706                 throw new IllegalArgumentException("generateDefaultLayoutParams() cannot return null");
1707             }
1708         }
1709         addView(child, index, params);
1710     }
1711 
1712     /**
1713      * Adds a child view with this ViewGroup's default layout parameters and the
1714      * specified width and height.
1715      *
1716      * @param child the child view to add
1717      */
addView(View child, int width, int height)1718     public void addView(View child, int width, int height) {
1719         final LayoutParams params = generateDefaultLayoutParams();
1720         params.width = width;
1721         params.height = height;
1722         addView(child, -1, params);
1723     }
1724 
1725     /**
1726      * Adds a child view with the specified layout parameters.
1727      *
1728      * @param child the child view to add
1729      * @param params the layout parameters to set on the child
1730      */
addView(View child, LayoutParams params)1731     public void addView(View child, LayoutParams params) {
1732         addView(child, -1, params);
1733     }
1734 
1735     /**
1736      * Adds a child view with the specified layout parameters.
1737      *
1738      * @param child the child view to add
1739      * @param index the position at which to add the child
1740      * @param params the layout parameters to set on the child
1741      */
addView(View child, int index, LayoutParams params)1742     public void addView(View child, int index, LayoutParams params) {
1743         if (DBG) {
1744             System.out.println(this + " addView");
1745         }
1746 
1747         // addViewInner() will call child.requestLayout() when setting the new LayoutParams
1748         // therefore, we call requestLayout() on ourselves before, so that the child's request
1749         // will be blocked at our level
1750         requestLayout();
1751         invalidate();
1752         addViewInner(child, index, params, false);
1753     }
1754 
1755     /**
1756      * {@inheritDoc}
1757      */
updateViewLayout(View view, ViewGroup.LayoutParams params)1758     public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
1759         if (!checkLayoutParams(params)) {
1760             throw new IllegalArgumentException("Invalid LayoutParams supplied to " + this);
1761         }
1762         if (view.mParent != this) {
1763             throw new IllegalArgumentException("Given view not a child of " + this);
1764         }
1765         view.setLayoutParams(params);
1766     }
1767 
1768     /**
1769      * {@inheritDoc}
1770      */
checkLayoutParams(ViewGroup.LayoutParams p)1771     protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
1772         return  p != null;
1773     }
1774 
1775     /**
1776      * Interface definition for a callback to be invoked when the hierarchy
1777      * within this view changed. The hierarchy changes whenever a child is added
1778      * to or removed from this view.
1779      */
1780     public interface OnHierarchyChangeListener {
1781         /**
1782          * Called when a new child is added to a parent view.
1783          *
1784          * @param parent the view in which a child was added
1785          * @param child the new child view added in the hierarchy
1786          */
onChildViewAdded(View parent, View child)1787         void onChildViewAdded(View parent, View child);
1788 
1789         /**
1790          * Called when a child is removed from a parent view.
1791          *
1792          * @param parent the view from which the child was removed
1793          * @param child the child removed from the hierarchy
1794          */
onChildViewRemoved(View parent, View child)1795         void onChildViewRemoved(View parent, View child);
1796     }
1797 
1798     /**
1799      * Register a callback to be invoked when a child is added to or removed
1800      * from this view.
1801      *
1802      * @param listener the callback to invoke on hierarchy change
1803      */
setOnHierarchyChangeListener(OnHierarchyChangeListener listener)1804     public void setOnHierarchyChangeListener(OnHierarchyChangeListener listener) {
1805         mOnHierarchyChangeListener = listener;
1806     }
1807 
1808     /**
1809      * Adds a view during layout. This is useful if in your onLayout() method,
1810      * you need to add more views (as does the list view for example).
1811      *
1812      * If index is negative, it means put it at the end of the list.
1813      *
1814      * @param child the view to add to the group
1815      * @param index the index at which the child must be added
1816      * @param params the layout parameters to associate with the child
1817      * @return true if the child was added, false otherwise
1818      */
addViewInLayout(View child, int index, LayoutParams params)1819     protected boolean addViewInLayout(View child, int index, LayoutParams params) {
1820         return addViewInLayout(child, index, params, false);
1821     }
1822 
1823     /**
1824      * Adds a view during layout. This is useful if in your onLayout() method,
1825      * you need to add more views (as does the list view for example).
1826      *
1827      * If index is negative, it means put it at the end of the list.
1828      *
1829      * @param child the view to add to the group
1830      * @param index the index at which the child must be added
1831      * @param params the layout parameters to associate with the child
1832      * @param preventRequestLayout if true, calling this method will not trigger a
1833      *        layout request on child
1834      * @return true if the child was added, false otherwise
1835      */
addViewInLayout(View child, int index, LayoutParams params, boolean preventRequestLayout)1836     protected boolean addViewInLayout(View child, int index, LayoutParams params,
1837             boolean preventRequestLayout) {
1838         child.mParent = null;
1839         addViewInner(child, index, params, preventRequestLayout);
1840         child.mPrivateFlags = (child.mPrivateFlags & ~DIRTY_MASK) | DRAWN;
1841         return true;
1842     }
1843 
1844     /**
1845      * Prevents the specified child to be laid out during the next layout pass.
1846      *
1847      * @param child the child on which to perform the cleanup
1848      */
cleanupLayoutState(View child)1849     protected void cleanupLayoutState(View child) {
1850         child.mPrivateFlags &= ~View.FORCE_LAYOUT;
1851     }
1852 
addViewInner(View child, int index, LayoutParams params, boolean preventRequestLayout)1853     private void addViewInner(View child, int index, LayoutParams params,
1854             boolean preventRequestLayout) {
1855 
1856         if (child.getParent() != null) {
1857             throw new IllegalStateException("The specified child already has a parent. " +
1858                     "You must call removeView() on the child's parent first.");
1859         }
1860 
1861         if (!checkLayoutParams(params)) {
1862             params = generateLayoutParams(params);
1863         }
1864 
1865         if (preventRequestLayout) {
1866             child.mLayoutParams = params;
1867         } else {
1868             child.setLayoutParams(params);
1869         }
1870 
1871         if (index < 0) {
1872             index = mChildrenCount;
1873         }
1874 
1875         addInArray(child, index);
1876 
1877         // tell our children
1878         if (preventRequestLayout) {
1879             child.assignParent(this);
1880         } else {
1881             child.mParent = this;
1882         }
1883 
1884         if (child.hasFocus()) {
1885             requestChildFocus(child, child.findFocus());
1886         }
1887 
1888         AttachInfo ai = mAttachInfo;
1889         if (ai != null) {
1890             boolean lastKeepOn = ai.mKeepScreenOn;
1891             ai.mKeepScreenOn = false;
1892             child.dispatchAttachedToWindow(mAttachInfo, (mViewFlags&VISIBILITY_MASK));
1893             if (ai.mKeepScreenOn) {
1894                 needGlobalAttributesUpdate(true);
1895             }
1896             ai.mKeepScreenOn = lastKeepOn;
1897         }
1898 
1899         if (mOnHierarchyChangeListener != null) {
1900             mOnHierarchyChangeListener.onChildViewAdded(this, child);
1901         }
1902 
1903         if ((child.mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE) {
1904             mGroupFlags |= FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE;
1905         }
1906     }
1907 
addInArray(View child, int index)1908     private void addInArray(View child, int index) {
1909         View[] children = mChildren;
1910         final int count = mChildrenCount;
1911         final int size = children.length;
1912         if (index == count) {
1913             if (size == count) {
1914                 mChildren = new View[size + ARRAY_CAPACITY_INCREMENT];
1915                 System.arraycopy(children, 0, mChildren, 0, size);
1916                 children = mChildren;
1917             }
1918             children[mChildrenCount++] = child;
1919         } else if (index < count) {
1920             if (size == count) {
1921                 mChildren = new View[size + ARRAY_CAPACITY_INCREMENT];
1922                 System.arraycopy(children, 0, mChildren, 0, index);
1923                 System.arraycopy(children, index, mChildren, index + 1, count - index);
1924                 children = mChildren;
1925             } else {
1926                 System.arraycopy(children, index, children, index + 1, count - index);
1927             }
1928             children[index] = child;
1929             mChildrenCount++;
1930         } else {
1931             throw new IndexOutOfBoundsException("index=" + index + " count=" + count);
1932         }
1933     }
1934 
1935     // This method also sets the child's mParent to null
removeFromArray(int index)1936     private void removeFromArray(int index) {
1937         final View[] children = mChildren;
1938         children[index].mParent = null;
1939         final int count = mChildrenCount;
1940         if (index == count - 1) {
1941             children[--mChildrenCount] = null;
1942         } else if (index >= 0 && index < count) {
1943             System.arraycopy(children, index + 1, children, index, count - index - 1);
1944             children[--mChildrenCount] = null;
1945         } else {
1946             throw new IndexOutOfBoundsException();
1947         }
1948     }
1949 
1950     // This method also sets the children's mParent to null
removeFromArray(int start, int count)1951     private void removeFromArray(int start, int count) {
1952         final View[] children = mChildren;
1953         final int childrenCount = mChildrenCount;
1954 
1955         start = Math.max(0, start);
1956         final int end = Math.min(childrenCount, start + count);
1957 
1958         if (start == end) {
1959             return;
1960         }
1961 
1962         if (end == childrenCount) {
1963             for (int i = start; i < end; i++) {
1964                 children[i].mParent = null;
1965                 children[i] = null;
1966             }
1967         } else {
1968             for (int i = start; i < end; i++) {
1969                 children[i].mParent = null;
1970             }
1971 
1972             // Since we're looping above, we might as well do the copy, but is arraycopy()
1973             // faster than the extra 2 bounds checks we would do in the loop?
1974             System.arraycopy(children, end, children, start, childrenCount - end);
1975 
1976             for (int i = childrenCount - (end - start); i < childrenCount; i++) {
1977                 children[i] = null;
1978             }
1979         }
1980 
1981         mChildrenCount -= (end - start);
1982     }
1983 
bindLayoutAnimation(View child)1984     private void bindLayoutAnimation(View child) {
1985         Animation a = mLayoutAnimationController.getAnimationForView(child);
1986         child.setAnimation(a);
1987     }
1988 
1989     /**
1990      * Subclasses should override this method to set layout animation
1991      * parameters on the supplied child.
1992      *
1993      * @param child the child to associate with animation parameters
1994      * @param params the child's layout parameters which hold the animation
1995      *        parameters
1996      * @param index the index of the child in the view group
1997      * @param count the number of children in the view group
1998      */
attachLayoutAnimationParameters(View child, LayoutParams params, int index, int count)1999     protected void attachLayoutAnimationParameters(View child,
2000             LayoutParams params, int index, int count) {
2001         LayoutAnimationController.AnimationParameters animationParams =
2002                     params.layoutAnimationParameters;
2003         if (animationParams == null) {
2004             animationParams = new LayoutAnimationController.AnimationParameters();
2005             params.layoutAnimationParameters = animationParams;
2006         }
2007 
2008         animationParams.count = count;
2009         animationParams.index = index;
2010     }
2011 
2012     /**
2013      * {@inheritDoc}
2014      */
removeView(View view)2015     public void removeView(View view) {
2016         removeViewInternal(view);
2017         requestLayout();
2018         invalidate();
2019     }
2020 
2021     /**
2022      * Removes a view during layout. This is useful if in your onLayout() method,
2023      * you need to remove more views.
2024      *
2025      * @param view the view to remove from the group
2026      */
removeViewInLayout(View view)2027     public void removeViewInLayout(View view) {
2028         removeViewInternal(view);
2029     }
2030 
2031     /**
2032      * Removes a range of views during layout. This is useful if in your onLayout() method,
2033      * you need to remove more views.
2034      *
2035      * @param start the index of the first view to remove from the group
2036      * @param count the number of views to remove from the group
2037      */
removeViewsInLayout(int start, int count)2038     public void removeViewsInLayout(int start, int count) {
2039         removeViewsInternal(start, count);
2040     }
2041 
2042     /**
2043      * Removes the view at the specified position in the group.
2044      *
2045      * @param index the position in the group of the view to remove
2046      */
removeViewAt(int index)2047     public void removeViewAt(int index) {
2048         removeViewInternal(index, getChildAt(index));
2049         requestLayout();
2050         invalidate();
2051     }
2052 
2053     /**
2054      * Removes the specified range of views from the group.
2055      *
2056      * @param start the first position in the group of the range of views to remove
2057      * @param count the number of views to remove
2058      */
removeViews(int start, int count)2059     public void removeViews(int start, int count) {
2060         removeViewsInternal(start, count);
2061         requestLayout();
2062         invalidate();
2063     }
2064 
removeViewInternal(View view)2065     private void removeViewInternal(View view) {
2066         final int index = indexOfChild(view);
2067         if (index >= 0) {
2068             removeViewInternal(index, view);
2069         }
2070     }
2071 
removeViewInternal(int index, View view)2072     private void removeViewInternal(int index, View view) {
2073         boolean clearChildFocus = false;
2074         if (view == mFocused) {
2075             view.clearFocusForRemoval();
2076             clearChildFocus = true;
2077         }
2078 
2079         if (view.getAnimation() != null) {
2080             addDisappearingView(view);
2081         } else if (view.mAttachInfo != null) {
2082            view.dispatchDetachedFromWindow();
2083         }
2084 
2085         if (mOnHierarchyChangeListener != null) {
2086             mOnHierarchyChangeListener.onChildViewRemoved(this, view);
2087         }
2088 
2089         needGlobalAttributesUpdate(false);
2090 
2091         removeFromArray(index);
2092 
2093         if (clearChildFocus) {
2094             clearChildFocus(view);
2095         }
2096     }
2097 
removeViewsInternal(int start, int count)2098     private void removeViewsInternal(int start, int count) {
2099         final OnHierarchyChangeListener onHierarchyChangeListener = mOnHierarchyChangeListener;
2100         final boolean notifyListener = onHierarchyChangeListener != null;
2101         final View focused = mFocused;
2102         final boolean detach = mAttachInfo != null;
2103         View clearChildFocus = null;
2104 
2105         final View[] children = mChildren;
2106         final int end = start + count;
2107 
2108         for (int i = start; i < end; i++) {
2109             final View view = children[i];
2110 
2111             if (view == focused) {
2112                 view.clearFocusForRemoval();
2113                 clearChildFocus = view;
2114             }
2115 
2116             if (view.getAnimation() != null) {
2117                 addDisappearingView(view);
2118             } else if (detach) {
2119                view.dispatchDetachedFromWindow();
2120             }
2121 
2122             needGlobalAttributesUpdate(false);
2123 
2124             if (notifyListener) {
2125                 onHierarchyChangeListener.onChildViewRemoved(this, view);
2126             }
2127         }
2128 
2129         removeFromArray(start, count);
2130 
2131         if (clearChildFocus != null) {
2132             clearChildFocus(clearChildFocus);
2133         }
2134     }
2135 
2136     /**
2137      * Call this method to remove all child views from the
2138      * ViewGroup.
2139      */
removeAllViews()2140     public void removeAllViews() {
2141         removeAllViewsInLayout();
2142         requestLayout();
2143         invalidate();
2144     }
2145 
2146     /**
2147      * Called by a ViewGroup subclass to remove child views from itself,
2148      * when it must first know its size on screen before it can calculate how many
2149      * child views it will render. An example is a Gallery or a ListView, which
2150      * may "have" 50 children, but actually only render the number of children
2151      * that can currently fit inside the object on screen. Do not call
2152      * this method unless you are extending ViewGroup and understand the
2153      * view measuring and layout pipeline.
2154      */
removeAllViewsInLayout()2155     public void removeAllViewsInLayout() {
2156         final int count = mChildrenCount;
2157         if (count <= 0) {
2158             return;
2159         }
2160 
2161         final View[] children = mChildren;
2162         mChildrenCount = 0;
2163 
2164         final OnHierarchyChangeListener listener = mOnHierarchyChangeListener;
2165         final boolean notify = listener != null;
2166         final View focused = mFocused;
2167         final boolean detach = mAttachInfo != null;
2168         View clearChildFocus = null;
2169 
2170         needGlobalAttributesUpdate(false);
2171 
2172         for (int i = count - 1; i >= 0; i--) {
2173             final View view = children[i];
2174 
2175             if (view == focused) {
2176                 view.clearFocusForRemoval();
2177                 clearChildFocus = view;
2178             }
2179 
2180             if (view.getAnimation() != null) {
2181                 addDisappearingView(view);
2182             } else if (detach) {
2183                view.dispatchDetachedFromWindow();
2184             }
2185 
2186             if (notify) {
2187                 listener.onChildViewRemoved(this, view);
2188             }
2189 
2190             view.mParent = null;
2191             children[i] = null;
2192         }
2193 
2194         if (clearChildFocus != null) {
2195             clearChildFocus(clearChildFocus);
2196         }
2197     }
2198 
2199     /**
2200      * Finishes the removal of a detached view. This method will dispatch the detached from
2201      * window event and notify the hierarchy change listener.
2202      *
2203      * @param child the child to be definitely removed from the view hierarchy
2204      * @param animate if true and the view has an animation, the view is placed in the
2205      *                disappearing views list, otherwise, it is detached from the window
2206      *
2207      * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
2208      * @see #detachAllViewsFromParent()
2209      * @see #detachViewFromParent(View)
2210      * @see #detachViewFromParent(int)
2211      */
removeDetachedView(View child, boolean animate)2212     protected void removeDetachedView(View child, boolean animate) {
2213         if (child == mFocused) {
2214             child.clearFocus();
2215         }
2216 
2217         if (animate && child.getAnimation() != null) {
2218             addDisappearingView(child);
2219         } else if (child.mAttachInfo != null) {
2220             child.dispatchDetachedFromWindow();
2221         }
2222 
2223         if (mOnHierarchyChangeListener != null) {
2224             mOnHierarchyChangeListener.onChildViewRemoved(this, child);
2225         }
2226     }
2227 
2228     /**
2229      * Attaches a view to this view group. Attaching a view assigns this group as the parent,
2230      * sets the layout parameters and puts the view in the list of children so it can be retrieved
2231      * by calling {@link #getChildAt(int)}.
2232      *
2233      * This method should be called only for view which were detached from their parent.
2234      *
2235      * @param child the child to attach
2236      * @param index the index at which the child should be attached
2237      * @param params the layout parameters of the child
2238      *
2239      * @see #removeDetachedView(View, boolean)
2240      * @see #detachAllViewsFromParent()
2241      * @see #detachViewFromParent(View)
2242      * @see #detachViewFromParent(int)
2243      */
attachViewToParent(View child, int index, LayoutParams params)2244     protected void attachViewToParent(View child, int index, LayoutParams params) {
2245         child.mLayoutParams = params;
2246 
2247         if (index < 0) {
2248             index = mChildrenCount;
2249         }
2250 
2251         addInArray(child, index);
2252 
2253         child.mParent = this;
2254         child.mPrivateFlags = (child.mPrivateFlags & ~DIRTY_MASK) | DRAWN;
2255 
2256         if (child.hasFocus()) {
2257             requestChildFocus(child, child.findFocus());
2258         }
2259     }
2260 
2261     /**
2262      * Detaches a view from its parent. Detaching a view should be temporary and followed
2263      * either by a call to {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
2264      * or a call to {@link #removeDetachedView(View, boolean)}. When a view is detached,
2265      * its parent is null and cannot be retrieved by a call to {@link #getChildAt(int)}.
2266      *
2267      * @param child the child to detach
2268      *
2269      * @see #detachViewFromParent(int)
2270      * @see #detachViewsFromParent(int, int)
2271      * @see #detachAllViewsFromParent()
2272      * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
2273      * @see #removeDetachedView(View, boolean)
2274      */
detachViewFromParent(View child)2275     protected void detachViewFromParent(View child) {
2276         removeFromArray(indexOfChild(child));
2277     }
2278 
2279     /**
2280      * Detaches a view from its parent. Detaching a view should be temporary and followed
2281      * either by a call to {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
2282      * or a call to {@link #removeDetachedView(View, boolean)}. When a view is detached,
2283      * its parent is null and cannot be retrieved by a call to {@link #getChildAt(int)}.
2284      *
2285      * @param index the index of the child to detach
2286      *
2287      * @see #detachViewFromParent(View)
2288      * @see #detachAllViewsFromParent()
2289      * @see #detachViewsFromParent(int, int)
2290      * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
2291      * @see #removeDetachedView(View, boolean)
2292      */
detachViewFromParent(int index)2293     protected void detachViewFromParent(int index) {
2294         removeFromArray(index);
2295     }
2296 
2297     /**
2298      * Detaches a range of view from their parent. Detaching a view should be temporary and followed
2299      * either by a call to {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
2300      * or a call to {@link #removeDetachedView(View, boolean)}. When a view is detached, its
2301      * parent is null and cannot be retrieved by a call to {@link #getChildAt(int)}.
2302      *
2303      * @param start the first index of the childrend range to detach
2304      * @param count the number of children to detach
2305      *
2306      * @see #detachViewFromParent(View)
2307      * @see #detachViewFromParent(int)
2308      * @see #detachAllViewsFromParent()
2309      * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
2310      * @see #removeDetachedView(View, boolean)
2311      */
detachViewsFromParent(int start, int count)2312     protected void detachViewsFromParent(int start, int count) {
2313         removeFromArray(start, count);
2314     }
2315 
2316     /**
2317      * Detaches all views from the parent. Detaching a view should be temporary and followed
2318      * either by a call to {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
2319      * or a call to {@link #removeDetachedView(View, boolean)}. When a view is detached,
2320      * its parent is null and cannot be retrieved by a call to {@link #getChildAt(int)}.
2321      *
2322      * @see #detachViewFromParent(View)
2323      * @see #detachViewFromParent(int)
2324      * @see #detachViewsFromParent(int, int)
2325      * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
2326      * @see #removeDetachedView(View, boolean)
2327      */
detachAllViewsFromParent()2328     protected void detachAllViewsFromParent() {
2329         final int count = mChildrenCount;
2330         if (count <= 0) {
2331             return;
2332         }
2333 
2334         final View[] children = mChildren;
2335         mChildrenCount = 0;
2336 
2337         for (int i = count - 1; i >= 0; i--) {
2338             children[i].mParent = null;
2339             children[i] = null;
2340         }
2341     }
2342 
2343     /**
2344      * Don't call or override this method. It is used for the implementation of
2345      * the view hierarchy.
2346      */
invalidateChild(View child, final Rect dirty)2347     public final void invalidateChild(View child, final Rect dirty) {
2348         if (ViewDebug.TRACE_HIERARCHY) {
2349             ViewDebug.trace(this, ViewDebug.HierarchyTraceType.INVALIDATE_CHILD);
2350         }
2351 
2352         ViewParent parent = this;
2353 
2354         final AttachInfo attachInfo = mAttachInfo;
2355         if (attachInfo != null) {
2356             final int[] location = attachInfo.mInvalidateChildLocation;
2357             location[CHILD_LEFT_INDEX] = child.mLeft;
2358             location[CHILD_TOP_INDEX] = child.mTop;
2359 
2360             // If the child is drawing an animation, we want to copy this flag onto
2361             // ourselves and the parent to make sure the invalidate request goes
2362             // through
2363             final boolean drawAnimation = (child.mPrivateFlags & DRAW_ANIMATION) == DRAW_ANIMATION;
2364 
2365             // Check whether the child that requests the invalidate is fully opaque
2366             final boolean isOpaque = child.isOpaque() && !drawAnimation &&
2367                     child.getAnimation() != null;
2368             // Mark the child as dirty, using the appropriate flag
2369             // Make sure we do not set both flags at the same time
2370             final int opaqueFlag = isOpaque ? DIRTY_OPAQUE : DIRTY;
2371 
2372             do {
2373                 View view = null;
2374                 if (parent instanceof View) {
2375                     view = (View) parent;
2376                 }
2377 
2378                 if (drawAnimation) {
2379                     if (view != null) {
2380                         view.mPrivateFlags |= DRAW_ANIMATION;
2381                     } else if (parent instanceof ViewRoot) {
2382                         ((ViewRoot) parent).mIsAnimating = true;
2383                     }
2384                 }
2385 
2386                 // If the parent is dirty opaque or not dirty, mark it dirty with the opaque
2387                 // flag coming from the child that initiated the invalidate
2388                 if (view != null && (view.mPrivateFlags & DIRTY_MASK) != DIRTY) {
2389                     view.mPrivateFlags = (view.mPrivateFlags & ~DIRTY_MASK) | opaqueFlag;
2390                 }
2391 
2392                 parent = parent.invalidateChildInParent(location, dirty);
2393             } while (parent != null);
2394         }
2395     }
2396 
2397     /**
2398      * Don't call or override this method. It is used for the implementation of
2399      * the view hierarchy.
2400      *
2401      * This implementation returns null if this ViewGroup does not have a parent,
2402      * if this ViewGroup is already fully invalidated or if the dirty rectangle
2403      * does not intersect with this ViewGroup's bounds.
2404      */
invalidateChildInParent(final int[] location, final Rect dirty)2405     public ViewParent invalidateChildInParent(final int[] location, final Rect dirty) {
2406         if (ViewDebug.TRACE_HIERARCHY) {
2407             ViewDebug.trace(this, ViewDebug.HierarchyTraceType.INVALIDATE_CHILD_IN_PARENT);
2408         }
2409 
2410         if ((mPrivateFlags & DRAWN) == DRAWN) {
2411             if ((mGroupFlags & (FLAG_OPTIMIZE_INVALIDATE | FLAG_ANIMATION_DONE)) !=
2412                         FLAG_OPTIMIZE_INVALIDATE) {
2413                 dirty.offset(location[CHILD_LEFT_INDEX] - mScrollX,
2414                         location[CHILD_TOP_INDEX] - mScrollY);
2415 
2416                 final int left = mLeft;
2417                 final int top = mTop;
2418 
2419                 if (dirty.intersect(0, 0, mRight - left, mBottom - top) ||
2420                         (mPrivateFlags & DRAW_ANIMATION) == DRAW_ANIMATION) {
2421                     mPrivateFlags &= ~DRAWING_CACHE_VALID;
2422 
2423                     location[CHILD_LEFT_INDEX] = left;
2424                     location[CHILD_TOP_INDEX] = top;
2425 
2426                     return mParent;
2427                 }
2428             } else {
2429                 mPrivateFlags &= ~DRAWN & ~DRAWING_CACHE_VALID;
2430 
2431                 location[CHILD_LEFT_INDEX] = mLeft;
2432                 location[CHILD_TOP_INDEX] = mTop;
2433 
2434                 dirty.set(0, 0, mRight - location[CHILD_LEFT_INDEX],
2435                         mBottom - location[CHILD_TOP_INDEX]);
2436 
2437                 return mParent;
2438             }
2439         }
2440 
2441         return null;
2442     }
2443 
2444     /**
2445      * Offset a rectangle that is in a descendant's coordinate
2446      * space into our coordinate space.
2447      * @param descendant A descendant of this view
2448      * @param rect A rectangle defined in descendant's coordinate space.
2449      */
offsetDescendantRectToMyCoords(View descendant, Rect rect)2450     public final void offsetDescendantRectToMyCoords(View descendant, Rect rect) {
2451         offsetRectBetweenParentAndChild(descendant, rect, true, false);
2452     }
2453 
2454     /**
2455      * Offset a rectangle that is in our coordinate space into an ancestor's
2456      * coordinate space.
2457      * @param descendant A descendant of this view
2458      * @param rect A rectangle defined in descendant's coordinate space.
2459      */
offsetRectIntoDescendantCoords(View descendant, Rect rect)2460     public final void offsetRectIntoDescendantCoords(View descendant, Rect rect) {
2461         offsetRectBetweenParentAndChild(descendant, rect, false, false);
2462     }
2463 
2464     /**
2465      * Helper method that offsets a rect either from parent to descendant or
2466      * descendant to parent.
2467      */
offsetRectBetweenParentAndChild(View descendant, Rect rect, boolean offsetFromChildToParent, boolean clipToBounds)2468     void offsetRectBetweenParentAndChild(View descendant, Rect rect,
2469             boolean offsetFromChildToParent, boolean clipToBounds) {
2470 
2471         // already in the same coord system :)
2472         if (descendant == this) {
2473             return;
2474         }
2475 
2476         ViewParent theParent = descendant.mParent;
2477 
2478         // search and offset up to the parent
2479         while ((theParent != null)
2480                 && (theParent instanceof View)
2481                 && (theParent != this)) {
2482 
2483             if (offsetFromChildToParent) {
2484                 rect.offset(descendant.mLeft - descendant.mScrollX,
2485                         descendant.mTop - descendant.mScrollY);
2486                 if (clipToBounds) {
2487                     View p = (View) theParent;
2488                     rect.intersect(0, 0, p.mRight - p.mLeft, p.mBottom - p.mTop);
2489                 }
2490             } else {
2491                 if (clipToBounds) {
2492                     View p = (View) theParent;
2493                     rect.intersect(0, 0, p.mRight - p.mLeft, p.mBottom - p.mTop);
2494                 }
2495                 rect.offset(descendant.mScrollX - descendant.mLeft,
2496                         descendant.mScrollY - descendant.mTop);
2497             }
2498 
2499             descendant = (View) theParent;
2500             theParent = descendant.mParent;
2501         }
2502 
2503         // now that we are up to this view, need to offset one more time
2504         // to get into our coordinate space
2505         if (theParent == this) {
2506             if (offsetFromChildToParent) {
2507                 rect.offset(descendant.mLeft - descendant.mScrollX,
2508                         descendant.mTop - descendant.mScrollY);
2509             } else {
2510                 rect.offset(descendant.mScrollX - descendant.mLeft,
2511                         descendant.mScrollY - descendant.mTop);
2512             }
2513         } else {
2514             throw new IllegalArgumentException("parameter must be a descendant of this view");
2515         }
2516     }
2517 
2518     /**
2519      * Offset the vertical location of all children of this view by the specified number of pixels.
2520      *
2521      * @param offset the number of pixels to offset
2522      *
2523      * @hide
2524      */
offsetChildrenTopAndBottom(int offset)2525     public void offsetChildrenTopAndBottom(int offset) {
2526         final int count = mChildrenCount;
2527         final View[] children = mChildren;
2528 
2529         for (int i = 0; i < count; i++) {
2530             final View v = children[i];
2531             v.mTop += offset;
2532             v.mBottom += offset;
2533         }
2534     }
2535 
2536     /**
2537      * {@inheritDoc}
2538      */
getChildVisibleRect(View child, Rect r, android.graphics.Point offset)2539     public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) {
2540         int dx = child.mLeft - mScrollX;
2541         int dy = child.mTop - mScrollY;
2542         if (offset != null) {
2543             offset.x += dx;
2544             offset.y += dy;
2545         }
2546         r.offset(dx, dy);
2547         return r.intersect(0, 0, mRight - mLeft, mBottom - mTop) &&
2548                (mParent == null || mParent.getChildVisibleRect(this, r, offset));
2549     }
2550 
2551     /**
2552      * {@inheritDoc}
2553      */
2554     @Override
onLayout(boolean changed, int l, int t, int r, int b)2555     protected abstract void onLayout(boolean changed,
2556             int l, int t, int r, int b);
2557 
2558     /**
2559      * Indicates whether the view group has the ability to animate its children
2560      * after the first layout.
2561      *
2562      * @return true if the children can be animated, false otherwise
2563      */
canAnimate()2564     protected boolean canAnimate() {
2565         return mLayoutAnimationController != null;
2566     }
2567 
2568     /**
2569      * Runs the layout animation. Calling this method triggers a relayout of
2570      * this view group.
2571      */
startLayoutAnimation()2572     public void startLayoutAnimation() {
2573         if (mLayoutAnimationController != null) {
2574             mGroupFlags |= FLAG_RUN_ANIMATION;
2575             requestLayout();
2576         }
2577     }
2578 
2579     /**
2580      * Schedules the layout animation to be played after the next layout pass
2581      * of this view group. This can be used to restart the layout animation
2582      * when the content of the view group changes or when the activity is
2583      * paused and resumed.
2584      */
scheduleLayoutAnimation()2585     public void scheduleLayoutAnimation() {
2586         mGroupFlags |= FLAG_RUN_ANIMATION;
2587     }
2588 
2589     /**
2590      * Sets the layout animation controller used to animate the group's
2591      * children after the first layout.
2592      *
2593      * @param controller the animation controller
2594      */
setLayoutAnimation(LayoutAnimationController controller)2595     public void setLayoutAnimation(LayoutAnimationController controller) {
2596         mLayoutAnimationController = controller;
2597         if (mLayoutAnimationController != null) {
2598             mGroupFlags |= FLAG_RUN_ANIMATION;
2599         }
2600     }
2601 
2602     /**
2603      * Returns the layout animation controller used to animate the group's
2604      * children.
2605      *
2606      * @return the current animation controller
2607      */
getLayoutAnimation()2608     public LayoutAnimationController getLayoutAnimation() {
2609         return mLayoutAnimationController;
2610     }
2611 
2612     /**
2613      * Indicates whether the children's drawing cache is used during a layout
2614      * animation. By default, the drawing cache is enabled but this will prevent
2615      * nested layout animations from working. To nest animations, you must disable
2616      * the cache.
2617      *
2618      * @return true if the animation cache is enabled, false otherwise
2619      *
2620      * @see #setAnimationCacheEnabled(boolean)
2621      * @see View#setDrawingCacheEnabled(boolean)
2622      */
2623     @ViewDebug.ExportedProperty
isAnimationCacheEnabled()2624     public boolean isAnimationCacheEnabled() {
2625         return (mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE;
2626     }
2627 
2628     /**
2629      * Enables or disables the children's drawing cache during a layout animation.
2630      * By default, the drawing cache is enabled but this will prevent nested
2631      * layout animations from working. To nest animations, you must disable the
2632      * cache.
2633      *
2634      * @param enabled true to enable the animation cache, false otherwise
2635      *
2636      * @see #isAnimationCacheEnabled()
2637      * @see View#setDrawingCacheEnabled(boolean)
2638      */
setAnimationCacheEnabled(boolean enabled)2639     public void setAnimationCacheEnabled(boolean enabled) {
2640         setBooleanFlag(FLAG_ANIMATION_CACHE, enabled);
2641     }
2642 
2643     /**
2644      * Indicates whether this ViewGroup will always try to draw its children using their
2645      * drawing cache. By default this property is enabled.
2646      *
2647      * @return true if the animation cache is enabled, false otherwise
2648      *
2649      * @see #setAlwaysDrawnWithCacheEnabled(boolean)
2650      * @see #setChildrenDrawnWithCacheEnabled(boolean)
2651      * @see View#setDrawingCacheEnabled(boolean)
2652      */
2653     @ViewDebug.ExportedProperty
isAlwaysDrawnWithCacheEnabled()2654     public boolean isAlwaysDrawnWithCacheEnabled() {
2655         return (mGroupFlags & FLAG_ALWAYS_DRAWN_WITH_CACHE) == FLAG_ALWAYS_DRAWN_WITH_CACHE;
2656     }
2657 
2658     /**
2659      * Indicates whether this ViewGroup will always try to draw its children using their
2660      * drawing cache. This property can be set to true when the cache rendering is
2661      * slightly different from the children's normal rendering. Renderings can be different,
2662      * for instance, when the cache's quality is set to low.
2663      *
2664      * When this property is disabled, the ViewGroup will use the drawing cache of its
2665      * children only when asked to. It's usually the task of subclasses to tell ViewGroup
2666      * when to start using the drawing cache and when to stop using it.
2667      *
2668      * @param always true to always draw with the drawing cache, false otherwise
2669      *
2670      * @see #isAlwaysDrawnWithCacheEnabled()
2671      * @see #setChildrenDrawnWithCacheEnabled(boolean)
2672      * @see View#setDrawingCacheEnabled(boolean)
2673      * @see View#setDrawingCacheQuality(int)
2674      */
setAlwaysDrawnWithCacheEnabled(boolean always)2675     public void setAlwaysDrawnWithCacheEnabled(boolean always) {
2676         setBooleanFlag(FLAG_ALWAYS_DRAWN_WITH_CACHE, always);
2677     }
2678 
2679     /**
2680      * Indicates whether the ViewGroup is currently drawing its children using
2681      * their drawing cache.
2682      *
2683      * @return true if children should be drawn with their cache, false otherwise
2684      *
2685      * @see #setAlwaysDrawnWithCacheEnabled(boolean)
2686      * @see #setChildrenDrawnWithCacheEnabled(boolean)
2687      */
2688     @ViewDebug.ExportedProperty
isChildrenDrawnWithCacheEnabled()2689     protected boolean isChildrenDrawnWithCacheEnabled() {
2690         return (mGroupFlags & FLAG_CHILDREN_DRAWN_WITH_CACHE) == FLAG_CHILDREN_DRAWN_WITH_CACHE;
2691     }
2692 
2693     /**
2694      * Tells the ViewGroup to draw its children using their drawing cache. This property
2695      * is ignored when {@link #isAlwaysDrawnWithCacheEnabled()} is true. A child's drawing cache
2696      * will be used only if it has been enabled.
2697      *
2698      * Subclasses should call this method to start and stop using the drawing cache when
2699      * they perform performance sensitive operations, like scrolling or animating.
2700      *
2701      * @param enabled true if children should be drawn with their cache, false otherwise
2702      *
2703      * @see #setAlwaysDrawnWithCacheEnabled(boolean)
2704      * @see #isChildrenDrawnWithCacheEnabled()
2705      */
setChildrenDrawnWithCacheEnabled(boolean enabled)2706     protected void setChildrenDrawnWithCacheEnabled(boolean enabled) {
2707         setBooleanFlag(FLAG_CHILDREN_DRAWN_WITH_CACHE, enabled);
2708     }
2709 
2710     /**
2711      * Indicates whether the ViewGroup is drawing its children in the order defined by
2712      * {@link #getChildDrawingOrder(int, int)}.
2713      *
2714      * @return true if children drawing order is defined by {@link #getChildDrawingOrder(int, int)},
2715      *         false otherwise
2716      *
2717      * @see #setChildrenDrawingOrderEnabled(boolean)
2718      * @see #getChildDrawingOrder(int, int)
2719      * @hide
2720      */
2721     @ViewDebug.ExportedProperty
isChildrenDrawingOrderEnabled()2722     protected boolean isChildrenDrawingOrderEnabled() {
2723         return (mGroupFlags & FLAG_USE_CHILD_DRAWING_ORDER) == FLAG_USE_CHILD_DRAWING_ORDER;
2724     }
2725 
2726     /**
2727      * Tells the ViewGroup whether to draw its children in the order defined by the method
2728      * {@link #getChildDrawingOrder(int, int)}.
2729      *
2730      * @param enabled true if the order of the children when drawing is determined by
2731      *        {@link #getChildDrawingOrder(int, int)}, false otherwise
2732      *
2733      * @see #isChildrenDrawingOrderEnabled()
2734      * @see #getChildDrawingOrder(int, int)
2735      * @hide
2736      */
setChildrenDrawingOrderEnabled(boolean enabled)2737     protected void setChildrenDrawingOrderEnabled(boolean enabled) {
2738         setBooleanFlag(FLAG_USE_CHILD_DRAWING_ORDER, enabled);
2739     }
2740 
setBooleanFlag(int flag, boolean value)2741     private void setBooleanFlag(int flag, boolean value) {
2742         if (value) {
2743             mGroupFlags |= flag;
2744         } else {
2745             mGroupFlags &= ~flag;
2746         }
2747     }
2748 
2749     /**
2750      * Returns an integer indicating what types of drawing caches are kept in memory.
2751      *
2752      * @see #setPersistentDrawingCache(int)
2753      * @see #setAnimationCacheEnabled(boolean)
2754      *
2755      * @return one or a combination of {@link #PERSISTENT_NO_CACHE},
2756      *         {@link #PERSISTENT_ANIMATION_CACHE}, {@link #PERSISTENT_SCROLLING_CACHE}
2757      *         and {@link #PERSISTENT_ALL_CACHES}
2758      */
2759     @ViewDebug.ExportedProperty(mapping = {
2760         @ViewDebug.IntToString(from = PERSISTENT_NO_CACHE,        to = "NONE"),
2761         @ViewDebug.IntToString(from = PERSISTENT_ALL_CACHES,      to = "ANIMATION"),
2762         @ViewDebug.IntToString(from = PERSISTENT_SCROLLING_CACHE, to = "SCROLLING"),
2763         @ViewDebug.IntToString(from = PERSISTENT_ALL_CACHES,      to = "ALL")
2764     })
getPersistentDrawingCache()2765     public int getPersistentDrawingCache() {
2766         return mPersistentDrawingCache;
2767     }
2768 
2769     /**
2770      * Indicates what types of drawing caches should be kept in memory after
2771      * they have been created.
2772      *
2773      * @see #getPersistentDrawingCache()
2774      * @see #setAnimationCacheEnabled(boolean)
2775      *
2776      * @param drawingCacheToKeep one or a combination of {@link #PERSISTENT_NO_CACHE},
2777      *        {@link #PERSISTENT_ANIMATION_CACHE}, {@link #PERSISTENT_SCROLLING_CACHE}
2778      *        and {@link #PERSISTENT_ALL_CACHES}
2779      */
setPersistentDrawingCache(int drawingCacheToKeep)2780     public void setPersistentDrawingCache(int drawingCacheToKeep) {
2781         mPersistentDrawingCache = drawingCacheToKeep & PERSISTENT_ALL_CACHES;
2782     }
2783 
2784     /**
2785      * Returns a new set of layout parameters based on the supplied attributes set.
2786      *
2787      * @param attrs the attributes to build the layout parameters from
2788      *
2789      * @return an instance of {@link android.view.ViewGroup.LayoutParams} or one
2790      *         of its descendants
2791      */
generateLayoutParams(AttributeSet attrs)2792     public LayoutParams generateLayoutParams(AttributeSet attrs) {
2793         return new LayoutParams(getContext(), attrs);
2794     }
2795 
2796     /**
2797      * Returns a safe set of layout parameters based on the supplied layout params.
2798      * When a ViewGroup is passed a View whose layout params do not pass the test of
2799      * {@link #checkLayoutParams(android.view.ViewGroup.LayoutParams)}, this method
2800      * is invoked. This method should return a new set of layout params suitable for
2801      * this ViewGroup, possibly by copying the appropriate attributes from the
2802      * specified set of layout params.
2803      *
2804      * @param p The layout parameters to convert into a suitable set of layout parameters
2805      *          for this ViewGroup.
2806      *
2807      * @return an instance of {@link android.view.ViewGroup.LayoutParams} or one
2808      *         of its descendants
2809      */
generateLayoutParams(ViewGroup.LayoutParams p)2810     protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
2811         return p;
2812     }
2813 
2814     /**
2815      * Returns a set of default layout parameters. These parameters are requested
2816      * when the View passed to {@link #addView(View)} has no layout parameters
2817      * already set. If null is returned, an exception is thrown from addView.
2818      *
2819      * @return a set of default layout parameters or null
2820      */
generateDefaultLayoutParams()2821     protected LayoutParams generateDefaultLayoutParams() {
2822         return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
2823     }
2824 
2825     /**
2826      * @hide
2827      */
2828     @Override
dispatchConsistencyCheck(int consistency)2829     protected boolean dispatchConsistencyCheck(int consistency) {
2830         boolean result = super.dispatchConsistencyCheck(consistency);
2831 
2832         final int count = mChildrenCount;
2833         final View[] children = mChildren;
2834         for (int i = 0; i < count; i++) {
2835             if (!children[i].dispatchConsistencyCheck(consistency)) result = false;
2836         }
2837 
2838         return result;
2839     }
2840 
2841     /**
2842      * @hide
2843      */
2844     @Override
onConsistencyCheck(int consistency)2845     protected boolean onConsistencyCheck(int consistency) {
2846         boolean result = super.onConsistencyCheck(consistency);
2847 
2848         final boolean checkLayout = (consistency & ViewDebug.CONSISTENCY_LAYOUT) != 0;
2849         final boolean checkDrawing = (consistency & ViewDebug.CONSISTENCY_DRAWING) != 0;
2850 
2851         if (checkLayout) {
2852             final int count = mChildrenCount;
2853             final View[] children = mChildren;
2854             for (int i = 0; i < count; i++) {
2855                 if (children[i].getParent() != this) {
2856                     result = false;
2857                     android.util.Log.d(ViewDebug.CONSISTENCY_LOG_TAG,
2858                             "View " + children[i] + " has no parent/a parent that is not " + this);
2859                 }
2860             }
2861         }
2862 
2863         if (checkDrawing) {
2864             // If this group is dirty, check that the parent is dirty as well
2865             if ((mPrivateFlags & DIRTY_MASK) != 0) {
2866                 final ViewParent parent = getParent();
2867                 if (parent != null && !(parent instanceof ViewRoot)) {
2868                     if ((((View) parent).mPrivateFlags & DIRTY_MASK) == 0) {
2869                         result = false;
2870                         android.util.Log.d(ViewDebug.CONSISTENCY_LOG_TAG,
2871                                 "ViewGroup " + this + " is dirty but its parent is not: " + this);
2872                     }
2873                 }
2874             }
2875         }
2876 
2877         return result;
2878     }
2879 
2880     /**
2881      * {@inheritDoc}
2882      */
2883     @Override
debug(int depth)2884     protected void debug(int depth) {
2885         super.debug(depth);
2886         String output;
2887 
2888         if (mFocused != null) {
2889             output = debugIndent(depth);
2890             output += "mFocused";
2891             Log.d(VIEW_LOG_TAG, output);
2892         }
2893         if (mChildrenCount != 0) {
2894             output = debugIndent(depth);
2895             output += "{";
2896             Log.d(VIEW_LOG_TAG, output);
2897         }
2898         int count = mChildrenCount;
2899         for (int i = 0; i < count; i++) {
2900             View child = mChildren[i];
2901             child.debug(depth + 1);
2902         }
2903 
2904         if (mChildrenCount != 0) {
2905             output = debugIndent(depth);
2906             output += "}";
2907             Log.d(VIEW_LOG_TAG, output);
2908         }
2909     }
2910 
2911     /**
2912      * Returns the position in the group of the specified child view.
2913      *
2914      * @param child the view for which to get the position
2915      * @return a positive integer representing the position of the view in the
2916      *         group, or -1 if the view does not exist in the group
2917      */
indexOfChild(View child)2918     public int indexOfChild(View child) {
2919         final int count = mChildrenCount;
2920         final View[] children = mChildren;
2921         for (int i = 0; i < count; i++) {
2922             if (children[i] == child) {
2923                 return i;
2924             }
2925         }
2926         return -1;
2927     }
2928 
2929     /**
2930      * Returns the number of children in the group.
2931      *
2932      * @return a positive integer representing the number of children in
2933      *         the group
2934      */
getChildCount()2935     public int getChildCount() {
2936         return mChildrenCount;
2937     }
2938 
2939     /**
2940      * Returns the view at the specified position in the group.
2941      *
2942      * @param index the position at which to get the view from
2943      * @return the view at the specified position or null if the position
2944      *         does not exist within the group
2945      */
getChildAt(int index)2946     public View getChildAt(int index) {
2947         try {
2948             return mChildren[index];
2949         } catch (IndexOutOfBoundsException ex) {
2950             return null;
2951         }
2952     }
2953 
2954     /**
2955      * Ask all of the children of this view to measure themselves, taking into
2956      * account both the MeasureSpec requirements for this view and its padding.
2957      * We skip children that are in the GONE state The heavy lifting is done in
2958      * getChildMeasureSpec.
2959      *
2960      * @param widthMeasureSpec The width requirements for this view
2961      * @param heightMeasureSpec The height requirements for this view
2962      */
measureChildren(int widthMeasureSpec, int heightMeasureSpec)2963     protected void measureChildren(int widthMeasureSpec, int heightMeasureSpec) {
2964         final int size = mChildrenCount;
2965         final View[] children = mChildren;
2966         for (int i = 0; i < size; ++i) {
2967             final View child = children[i];
2968             if ((child.mViewFlags & VISIBILITY_MASK) != GONE) {
2969                 measureChild(child, widthMeasureSpec, heightMeasureSpec);
2970             }
2971         }
2972     }
2973 
2974     /**
2975      * Ask one of the children of this view to measure itself, taking into
2976      * account both the MeasureSpec requirements for this view and its padding.
2977      * The heavy lifting is done in getChildMeasureSpec.
2978      *
2979      * @param child The child to measure
2980      * @param parentWidthMeasureSpec The width requirements for this view
2981      * @param parentHeightMeasureSpec The height requirements for this view
2982      */
measureChild(View child, int parentWidthMeasureSpec, int parentHeightMeasureSpec)2983     protected void measureChild(View child, int parentWidthMeasureSpec,
2984             int parentHeightMeasureSpec) {
2985         final LayoutParams lp = child.getLayoutParams();
2986 
2987         final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
2988                 mPaddingLeft + mPaddingRight, lp.width);
2989         final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
2990                 mPaddingTop + mPaddingBottom, lp.height);
2991 
2992         child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
2993     }
2994 
2995     /**
2996      * Ask one of the children of this view to measure itself, taking into
2997      * account both the MeasureSpec requirements for this view and its padding
2998      * and margins. The child must have MarginLayoutParams The heavy lifting is
2999      * done in getChildMeasureSpec.
3000      *
3001      * @param child The child to measure
3002      * @param parentWidthMeasureSpec The width requirements for this view
3003      * @param widthUsed Extra space that has been used up by the parent
3004      *        horizontally (possibly by other children of the parent)
3005      * @param parentHeightMeasureSpec The height requirements for this view
3006      * @param heightUsed Extra space that has been used up by the parent
3007      *        vertically (possibly by other children of the parent)
3008      */
measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed)3009     protected void measureChildWithMargins(View child,
3010             int parentWidthMeasureSpec, int widthUsed,
3011             int parentHeightMeasureSpec, int heightUsed) {
3012         final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
3013 
3014         final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
3015                 mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin
3016                         + widthUsed, lp.width);
3017         final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
3018                 mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin
3019                         + heightUsed, lp.height);
3020 
3021         child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
3022     }
3023 
3024     /**
3025      * Does the hard part of measureChildren: figuring out the MeasureSpec to
3026      * pass to a particular child. This method figures out the right MeasureSpec
3027      * for one dimension (height or width) of one child view.
3028      *
3029      * The goal is to combine information from our MeasureSpec with the
3030      * LayoutParams of the child to get the best possible results. For example,
3031      * if the this view knows its size (because its MeasureSpec has a mode of
3032      * EXACTLY), and the child has indicated in its LayoutParams that it wants
3033      * to be the same size as the parent, the parent should ask the child to
3034      * layout given an exact size.
3035      *
3036      * @param spec The requirements for this view
3037      * @param padding The padding of this view for the current dimension and
3038      *        margins, if applicable
3039      * @param childDimension How big the child wants to be in the current
3040      *        dimension
3041      * @return a MeasureSpec integer for the child
3042      */
getChildMeasureSpec(int spec, int padding, int childDimension)3043     public static int getChildMeasureSpec(int spec, int padding, int childDimension) {
3044         int specMode = MeasureSpec.getMode(spec);
3045         int specSize = MeasureSpec.getSize(spec);
3046 
3047         int size = Math.max(0, specSize - padding);
3048 
3049         int resultSize = 0;
3050         int resultMode = 0;
3051 
3052         switch (specMode) {
3053         // Parent has imposed an exact size on us
3054         case MeasureSpec.EXACTLY:
3055             if (childDimension >= 0) {
3056                 resultSize = childDimension;
3057                 resultMode = MeasureSpec.EXACTLY;
3058             } else if (childDimension == LayoutParams.FILL_PARENT) {
3059                 // Child wants to be our size. So be it.
3060                 resultSize = size;
3061                 resultMode = MeasureSpec.EXACTLY;
3062             } else if (childDimension == LayoutParams.WRAP_CONTENT) {
3063                 // Child wants to determine its own size. It can't be
3064                 // bigger than us.
3065                 resultSize = size;
3066                 resultMode = MeasureSpec.AT_MOST;
3067             }
3068             break;
3069 
3070         // Parent has imposed a maximum size on us
3071         case MeasureSpec.AT_MOST:
3072             if (childDimension >= 0) {
3073                 // Child wants a specific size... so be it
3074                 resultSize = childDimension;
3075                 resultMode = MeasureSpec.EXACTLY;
3076             } else if (childDimension == LayoutParams.FILL_PARENT) {
3077                 // Child wants to be our size, but our size is not fixed.
3078                 // Constrain child to not be bigger than us.
3079                 resultSize = size;
3080                 resultMode = MeasureSpec.AT_MOST;
3081             } else if (childDimension == LayoutParams.WRAP_CONTENT) {
3082                 // Child wants to determine its own size. It can't be
3083                 // bigger than us.
3084                 resultSize = size;
3085                 resultMode = MeasureSpec.AT_MOST;
3086             }
3087             break;
3088 
3089         // Parent asked to see how big we want to be
3090         case MeasureSpec.UNSPECIFIED:
3091             if (childDimension >= 0) {
3092                 // Child wants a specific size... let him have it
3093                 resultSize = childDimension;
3094                 resultMode = MeasureSpec.EXACTLY;
3095             } else if (childDimension == LayoutParams.FILL_PARENT) {
3096                 // Child wants to be our size... find out how big it should
3097                 // be
3098                 resultSize = 0;
3099                 resultMode = MeasureSpec.UNSPECIFIED;
3100             } else if (childDimension == LayoutParams.WRAP_CONTENT) {
3101                 // Child wants to determine its own size.... find out how
3102                 // big it should be
3103                 resultSize = 0;
3104                 resultMode = MeasureSpec.UNSPECIFIED;
3105             }
3106             break;
3107         }
3108         return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
3109     }
3110 
3111 
3112     /**
3113      * Removes any pending animations for views that have been removed. Call
3114      * this if you don't want animations for exiting views to stack up.
3115      */
clearDisappearingChildren()3116     public void clearDisappearingChildren() {
3117         if (mDisappearingChildren != null) {
3118             mDisappearingChildren.clear();
3119         }
3120     }
3121 
3122     /**
3123      * Add a view which is removed from mChildren but still needs animation
3124      *
3125      * @param v View to add
3126      */
addDisappearingView(View v)3127     private void addDisappearingView(View v) {
3128         ArrayList<View> disappearingChildren = mDisappearingChildren;
3129 
3130         if (disappearingChildren == null) {
3131             disappearingChildren = mDisappearingChildren = new ArrayList<View>();
3132         }
3133 
3134         disappearingChildren.add(v);
3135     }
3136 
3137     /**
3138      * Cleanup a view when its animation is done. This may mean removing it from
3139      * the list of disappearing views.
3140      *
3141      * @param view The view whose animation has finished
3142      * @param animation The animation, cannot be null
3143      */
finishAnimatingView(final View view, Animation animation)3144     private void finishAnimatingView(final View view, Animation animation) {
3145         final ArrayList<View> disappearingChildren = mDisappearingChildren;
3146         if (disappearingChildren != null) {
3147             if (disappearingChildren.contains(view)) {
3148                 disappearingChildren.remove(view);
3149 
3150                 if (view.mAttachInfo != null) {
3151                     view.dispatchDetachedFromWindow();
3152                 }
3153 
3154                 view.clearAnimation();
3155                 mGroupFlags |= FLAG_INVALIDATE_REQUIRED;
3156             }
3157         }
3158 
3159         if (animation != null && !animation.getFillAfter()) {
3160             view.clearAnimation();
3161         }
3162 
3163         if ((view.mPrivateFlags & ANIMATION_STARTED) == ANIMATION_STARTED) {
3164             view.onAnimationEnd();
3165             // Should be performed by onAnimationEnd() but this avoid an infinite loop,
3166             // so we'd rather be safe than sorry
3167             view.mPrivateFlags &= ~ANIMATION_STARTED;
3168             // Draw one more frame after the animation is done
3169             mGroupFlags |= FLAG_INVALIDATE_REQUIRED;
3170         }
3171     }
3172 
3173     /**
3174      * {@inheritDoc}
3175      */
3176     @Override
gatherTransparentRegion(Region region)3177     public boolean gatherTransparentRegion(Region region) {
3178         // If no transparent regions requested, we are always opaque.
3179         final boolean meOpaque = (mPrivateFlags & View.REQUEST_TRANSPARENT_REGIONS) == 0;
3180         if (meOpaque && region == null) {
3181             // The caller doesn't care about the region, so stop now.
3182             return true;
3183         }
3184         super.gatherTransparentRegion(region);
3185         final View[] children = mChildren;
3186         final int count = mChildrenCount;
3187         boolean noneOfTheChildrenAreTransparent = true;
3188         for (int i = 0; i < count; i++) {
3189             final View child = children[i];
3190             if ((child.mViewFlags & VISIBILITY_MASK) != GONE || child.getAnimation() != null) {
3191                 if (!child.gatherTransparentRegion(region)) {
3192                     noneOfTheChildrenAreTransparent = false;
3193                 }
3194             }
3195         }
3196         return meOpaque || noneOfTheChildrenAreTransparent;
3197     }
3198 
3199     /**
3200      * {@inheritDoc}
3201      */
requestTransparentRegion(View child)3202     public void requestTransparentRegion(View child) {
3203         if (child != null) {
3204             child.mPrivateFlags |= View.REQUEST_TRANSPARENT_REGIONS;
3205             if (mParent != null) {
3206                 mParent.requestTransparentRegion(this);
3207             }
3208         }
3209     }
3210 
3211 
3212     @Override
fitSystemWindows(Rect insets)3213     protected boolean fitSystemWindows(Rect insets) {
3214         boolean done = super.fitSystemWindows(insets);
3215         if (!done) {
3216             final int count = mChildrenCount;
3217             final View[] children = mChildren;
3218             for (int i = 0; i < count; i++) {
3219                 done = children[i].fitSystemWindows(insets);
3220                 if (done) {
3221                     break;
3222                 }
3223             }
3224         }
3225         return done;
3226     }
3227 
3228     /**
3229      * Returns the animation listener to which layout animation events are
3230      * sent.
3231      *
3232      * @return an {@link android.view.animation.Animation.AnimationListener}
3233      */
getLayoutAnimationListener()3234     public Animation.AnimationListener getLayoutAnimationListener() {
3235         return mAnimationListener;
3236     }
3237 
3238     @Override
drawableStateChanged()3239     protected void drawableStateChanged() {
3240         super.drawableStateChanged();
3241 
3242         if ((mGroupFlags & FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE) != 0) {
3243             if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0) {
3244                 throw new IllegalStateException("addStateFromChildren cannot be enabled if a"
3245                         + " child has duplicateParentState set to true");
3246             }
3247 
3248             final View[] children = mChildren;
3249             final int count = mChildrenCount;
3250 
3251             for (int i = 0; i < count; i++) {
3252                 final View child = children[i];
3253                 if ((child.mViewFlags & DUPLICATE_PARENT_STATE) != 0) {
3254                     child.refreshDrawableState();
3255                 }
3256             }
3257         }
3258     }
3259 
3260     @Override
onCreateDrawableState(int extraSpace)3261     protected int[] onCreateDrawableState(int extraSpace) {
3262         if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) == 0) {
3263             return super.onCreateDrawableState(extraSpace);
3264         }
3265 
3266         int need = 0;
3267         int n = getChildCount();
3268         for (int i = 0; i < n; i++) {
3269             int[] childState = getChildAt(i).getDrawableState();
3270 
3271             if (childState != null) {
3272                 need += childState.length;
3273             }
3274         }
3275 
3276         int[] state = super.onCreateDrawableState(extraSpace + need);
3277 
3278         for (int i = 0; i < n; i++) {
3279             int[] childState = getChildAt(i).getDrawableState();
3280 
3281             if (childState != null) {
3282                 state = mergeDrawableStates(state, childState);
3283             }
3284         }
3285 
3286         return state;
3287     }
3288 
3289     /**
3290      * Sets whether this ViewGroup's drawable states also include
3291      * its children's drawable states.  This is used, for example, to
3292      * make a group appear to be focused when its child EditText or button
3293      * is focused.
3294      */
setAddStatesFromChildren(boolean addsStates)3295     public void setAddStatesFromChildren(boolean addsStates) {
3296         if (addsStates) {
3297             mGroupFlags |= FLAG_ADD_STATES_FROM_CHILDREN;
3298         } else {
3299             mGroupFlags &= ~FLAG_ADD_STATES_FROM_CHILDREN;
3300         }
3301 
3302         refreshDrawableState();
3303     }
3304 
3305     /**
3306      * Returns whether this ViewGroup's drawable states also include
3307      * its children's drawable states.  This is used, for example, to
3308      * make a group appear to be focused when its child EditText or button
3309      * is focused.
3310      */
addStatesFromChildren()3311     public boolean addStatesFromChildren() {
3312         return (mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0;
3313     }
3314 
3315     /**
3316      * If {link #addStatesFromChildren} is true, refreshes this group's
3317      * drawable state (to include the states from its children).
3318      */
childDrawableStateChanged(View child)3319     public void childDrawableStateChanged(View child) {
3320         if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0) {
3321             refreshDrawableState();
3322         }
3323     }
3324 
3325     /**
3326      * Specifies the animation listener to which layout animation events must
3327      * be sent. Only
3328      * {@link android.view.animation.Animation.AnimationListener#onAnimationStart(Animation)}
3329      * and
3330      * {@link android.view.animation.Animation.AnimationListener#onAnimationEnd(Animation)}
3331      * are invoked.
3332      *
3333      * @param animationListener the layout animation listener
3334      */
setLayoutAnimationListener(Animation.AnimationListener animationListener)3335     public void setLayoutAnimationListener(Animation.AnimationListener animationListener) {
3336         mAnimationListener = animationListener;
3337     }
3338 
3339     /**
3340      * LayoutParams are used by views to tell their parents how they want to be
3341      * laid out. See
3342      * {@link android.R.styleable#ViewGroup_Layout ViewGroup Layout Attributes}
3343      * for a list of all child view attributes that this class supports.
3344      *
3345      * <p>
3346      * The base LayoutParams class just describes how big the view wants to be
3347      * for both width and height. For each dimension, it can specify one of:
3348      * <ul>
3349      * <li> an exact number
3350      * <li>FILL_PARENT, which means the view wants to be as big as its parent
3351      * (minus padding)
3352      * <li> WRAP_CONTENT, which means that the view wants to be just big enough
3353      * to enclose its content (plus padding)
3354      * </ul>
3355      * There are subclasses of LayoutParams for different subclasses of
3356      * ViewGroup. For example, AbsoluteLayout has its own subclass of
3357      * LayoutParams which adds an X and Y value.
3358      *
3359      * @attr ref android.R.styleable#ViewGroup_Layout_layout_height
3360      * @attr ref android.R.styleable#ViewGroup_Layout_layout_width
3361      */
3362     public static class LayoutParams {
3363         /**
3364          * Special value for the height or width requested by a View.
3365          * FILL_PARENT means that the view wants to fill the available space
3366          * within the parent, taking the parent's padding into account.
3367          */
3368         public static final int FILL_PARENT = -1;
3369 
3370         /**
3371          * Special value for the height or width requested by a View.
3372          * WRAP_CONTENT means that the view wants to be just large enough to fit
3373          * its own internal content, taking its own padding into account.
3374          */
3375         public static final int WRAP_CONTENT = -2;
3376 
3377         /**
3378          * Information about how wide the view wants to be. Can be an exact
3379          * size, or one of the constants FILL_PARENT or WRAP_CONTENT.
3380          */
3381         @ViewDebug.ExportedProperty(mapping = {
3382             @ViewDebug.IntToString(from = FILL_PARENT, to = "FILL_PARENT"),
3383             @ViewDebug.IntToString(from = WRAP_CONTENT, to = "WRAP_CONTENT")
3384         })
3385         public int width;
3386 
3387         /**
3388          * Information about how tall the view wants to be. Can be an exact
3389          * size, or one of the constants FILL_PARENT or WRAP_CONTENT.
3390          */
3391         @ViewDebug.ExportedProperty(mapping = {
3392             @ViewDebug.IntToString(from = FILL_PARENT, to = "FILL_PARENT"),
3393             @ViewDebug.IntToString(from = WRAP_CONTENT, to = "WRAP_CONTENT")
3394         })
3395         public int height;
3396 
3397         /**
3398          * Used to animate layouts.
3399          */
3400         public LayoutAnimationController.AnimationParameters layoutAnimationParameters;
3401 
3402         /**
3403          * Creates a new set of layout parameters. The values are extracted from
3404          * the supplied attributes set and context. The XML attributes mapped
3405          * to this set of layout parameters are:
3406          *
3407          * <ul>
3408          *   <li><code>layout_width</code>: the width, either an exact value,
3409          *   {@link #WRAP_CONTENT} or {@link #FILL_PARENT}</li>
3410          *   <li><code>layout_height</code>: the height, either an exact value,
3411          *   {@link #WRAP_CONTENT} or {@link #FILL_PARENT}</li>
3412          * </ul>
3413          *
3414          * @param c the application environment
3415          * @param attrs the set of attributes from which to extract the layout
3416          *              parameters' values
3417          */
LayoutParams(Context c, AttributeSet attrs)3418         public LayoutParams(Context c, AttributeSet attrs) {
3419             TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.ViewGroup_Layout);
3420             setBaseAttributes(a,
3421                     R.styleable.ViewGroup_Layout_layout_width,
3422                     R.styleable.ViewGroup_Layout_layout_height);
3423             a.recycle();
3424         }
3425 
3426         /**
3427          * Creates a new set of layout parameters with the specified width
3428          * and height.
3429          *
3430          * @param width the width, either {@link #FILL_PARENT},
3431          *        {@link #WRAP_CONTENT} or a fixed size in pixels
3432          * @param height the height, either {@link #FILL_PARENT},
3433          *        {@link #WRAP_CONTENT} or a fixed size in pixels
3434          */
LayoutParams(int width, int height)3435         public LayoutParams(int width, int height) {
3436             this.width = width;
3437             this.height = height;
3438         }
3439 
3440         /**
3441          * Copy constructor. Clones the width and height values of the source.
3442          *
3443          * @param source The layout params to copy from.
3444          */
LayoutParams(LayoutParams source)3445         public LayoutParams(LayoutParams source) {
3446             this.width = source.width;
3447             this.height = source.height;
3448         }
3449 
3450         /**
3451          * Used internally by MarginLayoutParams.
3452          * @hide
3453          */
LayoutParams()3454         LayoutParams() {
3455         }
3456 
3457         /**
3458          * Extracts the layout parameters from the supplied attributes.
3459          *
3460          * @param a the style attributes to extract the parameters from
3461          * @param widthAttr the identifier of the width attribute
3462          * @param heightAttr the identifier of the height attribute
3463          */
setBaseAttributes(TypedArray a, int widthAttr, int heightAttr)3464         protected void setBaseAttributes(TypedArray a, int widthAttr, int heightAttr) {
3465             width = a.getLayoutDimension(widthAttr, "layout_width");
3466             height = a.getLayoutDimension(heightAttr, "layout_height");
3467         }
3468 
3469         /**
3470          * Returns a String representation of this set of layout parameters.
3471          *
3472          * @param output the String to prepend to the internal representation
3473          * @return a String with the following format: output +
3474          *         "ViewGroup.LayoutParams={ width=WIDTH, height=HEIGHT }"
3475          *
3476          * @hide
3477          */
debug(String output)3478         public String debug(String output) {
3479             return output + "ViewGroup.LayoutParams={ width="
3480                     + sizeToString(width) + ", height=" + sizeToString(height) + " }";
3481         }
3482 
3483         /**
3484          * Converts the specified size to a readable String.
3485          *
3486          * @param size the size to convert
3487          * @return a String instance representing the supplied size
3488          *
3489          * @hide
3490          */
sizeToString(int size)3491         protected static String sizeToString(int size) {
3492             if (size == WRAP_CONTENT) {
3493                 return "wrap-content";
3494             }
3495             if (size == FILL_PARENT) {
3496                 return "fill-parent";
3497             }
3498             return String.valueOf(size);
3499         }
3500     }
3501 
3502     /**
3503      * Per-child layout information for layouts that support margins.
3504      * See
3505      * {@link android.R.styleable#ViewGroup_MarginLayout ViewGroup Margin Layout Attributes}
3506      * for a list of all child view attributes that this class supports.
3507      */
3508     public static class MarginLayoutParams extends ViewGroup.LayoutParams {
3509         /**
3510          * The left margin in pixels of the child.
3511          */
3512         @ViewDebug.ExportedProperty
3513         public int leftMargin;
3514 
3515         /**
3516          * The top margin in pixels of the child.
3517          */
3518         @ViewDebug.ExportedProperty
3519         public int topMargin;
3520 
3521         /**
3522          * The right margin in pixels of the child.
3523          */
3524         @ViewDebug.ExportedProperty
3525         public int rightMargin;
3526 
3527         /**
3528          * The bottom margin in pixels of the child.
3529          */
3530         @ViewDebug.ExportedProperty
3531         public int bottomMargin;
3532 
3533         /**
3534          * Creates a new set of layout parameters. The values are extracted from
3535          * the supplied attributes set and context.
3536          *
3537          * @param c the application environment
3538          * @param attrs the set of attributes from which to extract the layout
3539          *              parameters' values
3540          */
MarginLayoutParams(Context c, AttributeSet attrs)3541         public MarginLayoutParams(Context c, AttributeSet attrs) {
3542             super();
3543 
3544             TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.ViewGroup_MarginLayout);
3545             setBaseAttributes(a,
3546                     R.styleable.ViewGroup_MarginLayout_layout_width,
3547                     R.styleable.ViewGroup_MarginLayout_layout_height);
3548 
3549             int margin = a.getDimensionPixelSize(
3550                     com.android.internal.R.styleable.ViewGroup_MarginLayout_layout_margin, -1);
3551             if (margin >= 0) {
3552                 leftMargin = margin;
3553                 topMargin = margin;
3554                 rightMargin= margin;
3555                 bottomMargin = margin;
3556             } else {
3557                 leftMargin = a.getDimensionPixelSize(
3558                         R.styleable.ViewGroup_MarginLayout_layout_marginLeft, 0);
3559                 topMargin = a.getDimensionPixelSize(
3560                         R.styleable.ViewGroup_MarginLayout_layout_marginTop, 0);
3561                 rightMargin = a.getDimensionPixelSize(
3562                         R.styleable.ViewGroup_MarginLayout_layout_marginRight, 0);
3563                 bottomMargin = a.getDimensionPixelSize(
3564                         R.styleable.ViewGroup_MarginLayout_layout_marginBottom, 0);
3565             }
3566 
3567             a.recycle();
3568         }
3569 
3570         /**
3571          * {@inheritDoc}
3572          */
MarginLayoutParams(int width, int height)3573         public MarginLayoutParams(int width, int height) {
3574             super(width, height);
3575         }
3576 
3577         /**
3578          * Copy constructor. Clones the width, height and margin values of the source.
3579          *
3580          * @param source The layout params to copy from.
3581          */
MarginLayoutParams(MarginLayoutParams source)3582         public MarginLayoutParams(MarginLayoutParams source) {
3583             this.width = source.width;
3584             this.height = source.height;
3585 
3586             this.leftMargin = source.leftMargin;
3587             this.topMargin = source.topMargin;
3588             this.rightMargin = source.rightMargin;
3589             this.bottomMargin = source.bottomMargin;
3590         }
3591 
3592         /**
3593          * {@inheritDoc}
3594          */
MarginLayoutParams(LayoutParams source)3595         public MarginLayoutParams(LayoutParams source) {
3596             super(source);
3597         }
3598 
3599         /**
3600          * Sets the margins, in pixels.
3601          *
3602          * @param left the left margin size
3603          * @param top the top margin size
3604          * @param right the right margin size
3605          * @param bottom the bottom margin size
3606          *
3607          * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginLeft
3608          * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginTop
3609          * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginRight
3610          * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginBottom
3611          */
setMargins(int left, int top, int right, int bottom)3612         public void setMargins(int left, int top, int right, int bottom) {
3613             leftMargin = left;
3614             topMargin = top;
3615             rightMargin = right;
3616             bottomMargin = bottom;
3617         }
3618     }
3619 }
3620