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