blob: 98b895d893cc6437a67a37d2f021c524a97035ff [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.view;
18
Chet Haase21cd1382010-09-01 17:42:29 -070019import android.animation.LayoutTransition;
Tor Norbye7b9c9122013-05-30 16:48:33 -070020import android.annotation.IdRes;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021import android.content.Context;
Clara Bayarrid5bf3ed2015-03-27 17:32:45 +000022import android.content.Intent;
Adam Powellff0d2982014-07-10 20:34:14 -070023import android.content.pm.PackageManager;
Dianne Hackborne36d6e22010-02-17 19:46:25 -080024import android.content.res.Configuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025import android.content.res.TypedArray;
26import android.graphics.Bitmap;
27import android.graphics.Canvas;
Philip Milne10ca24a2012-04-23 15:38:27 -070028import android.graphics.Color;
29import android.graphics.Insets;
Adam Powell6e346362010-07-23 10:18:23 -070030import android.graphics.Matrix;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031import android.graphics.Paint;
Christopher Tatea53146c2010-09-07 11:57:52 -070032import android.graphics.PointF;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080033import android.graphics.Rect;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034import android.graphics.RectF;
svetoslavganov75986cf2009-05-14 22:28:01 -070035import android.graphics.Region;
Jeff Brown995e7742010-12-22 16:59:36 -080036import android.os.Build;
Adam Powellb6ab0982015-01-07 17:00:12 -080037import android.os.Bundle;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038import android.os.Parcelable;
39import android.os.SystemClock;
40import android.util.AttributeSet;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041import android.util.Log;
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -080042import android.util.Pools.SynchronizedPool;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043import android.util.SparseArray;
svetoslavganov75986cf2009-05-14 22:28:01 -070044import android.view.accessibility.AccessibilityEvent;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070045import android.view.accessibility.AccessibilityNodeInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046import android.view.animation.Animation;
47import android.view.animation.AnimationUtils;
48import android.view.animation.LayoutAnimationController;
49import android.view.animation.Transformation;
Doug Feltcb3791202011-07-07 11:57:48 -070050
Romain Guy0211a0a2011-02-14 16:34:59 -080051import com.android.internal.R;
52import com.android.internal.util.Predicate;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053
54import java.util.ArrayList;
Svetoslav Ganov42138042012-03-20 11:51:39 -070055import java.util.Collections;
Christopher Tate86cab1b2011-01-13 20:28:55 -080056import java.util.HashSet;
George Mounte1803372014-02-26 19:00:52 +000057import java.util.List;
58import java.util.Map;
Fabrice Di Meglio0072f642013-03-26 15:50:24 -070059import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
60
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080061/**
62 * <p>
63 * A <code>ViewGroup</code> is a special view that can contain other views
64 * (called children.) The view group is the base class for layouts and views
65 * containers. This class also defines the
66 * {@link android.view.ViewGroup.LayoutParams} class which serves as the base
67 * class for layouts parameters.
68 * </p>
69 *
70 * <p>
71 * Also see {@link LayoutParams} for layout attributes.
72 * </p>
Romain Guyd6a463a2009-05-21 23:10:10 -070073 *
Joe Fernandez558459f2011-10-13 16:47:36 -070074 * <div class="special reference">
75 * <h3>Developer Guides</h3>
76 * <p>For more information about creating user interface layouts, read the
77 * <a href="{@docRoot}guide/topics/ui/declaring-layout.html">XML Layouts</a> developer
78 * guide.</p></div>
79 *
Dianne Hackborn7caab0f2013-03-06 13:47:04 -080080 * <p>Here is a complete implementation of a custom ViewGroup that implements
81 * a simple {@link android.widget.FrameLayout} along with the ability to stack
82 * children in left and right gutters.</p>
83 *
84 * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/CustomLayout.java
85 * Complete}
86 *
87 * <p>If you are implementing XML layout attributes as shown in the example, this is the
88 * corresponding definition for them that would go in <code>res/values/attrs.xml</code>:</p>
89 *
90 * {@sample development/samples/ApiDemos/res/values/attrs.xml CustomLayout}
91 *
92 * <p>Finally the layout manager can be used in an XML layout like so:</p>
93 *
94 * {@sample development/samples/ApiDemos/res/layout/custom_layout.xml Complete}
95 *
Romain Guyd6a463a2009-05-21 23:10:10 -070096 * @attr ref android.R.styleable#ViewGroup_clipChildren
97 * @attr ref android.R.styleable#ViewGroup_clipToPadding
98 * @attr ref android.R.styleable#ViewGroup_layoutAnimation
99 * @attr ref android.R.styleable#ViewGroup_animationCache
100 * @attr ref android.R.styleable#ViewGroup_persistentDrawingCache
101 * @attr ref android.R.styleable#ViewGroup_alwaysDrawnWithCache
102 * @attr ref android.R.styleable#ViewGroup_addStatesFromChildren
103 * @attr ref android.R.styleable#ViewGroup_descendantFocusability
Chet Haase13cc1202010-09-03 15:39:20 -0700104 * @attr ref android.R.styleable#ViewGroup_animateLayoutChanges
Scott Main27a85082013-06-10 10:39:48 -0700105 * @attr ref android.R.styleable#ViewGroup_splitMotionEvents
106 * @attr ref android.R.styleable#ViewGroup_layoutMode
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800107 */
108public abstract class ViewGroup extends View implements ViewParent, ViewManager {
Adam Powell539ee872012-02-03 19:00:49 -0800109 private static final String TAG = "ViewGroup";
Chet Haase21cd1382010-09-01 17:42:29 -0700110
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800111 private static final boolean DBG = false;
Philip Milne7b757812012-09-19 18:13:44 -0700112 /** @hide */
113 public static boolean DEBUG_DRAW = false;
Gilles Debunnecea45132011-11-24 02:19:27 +0100114
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800115 /**
116 * Views which have been hidden or removed which need to be animated on
117 * their way out.
118 * This field should be made private, so it is hidden from the SDK.
119 * {@hide}
120 */
121 protected ArrayList<View> mDisappearingChildren;
122
123 /**
124 * Listener used to propagate events indicating when children are added
125 * and/or removed from a view group.
126 * This field should be made private, so it is hidden from the SDK.
127 * {@hide}
128 */
129 protected OnHierarchyChangeListener mOnHierarchyChangeListener;
130
131 // The view contained within this ViewGroup that has or contains focus.
132 private View mFocused;
133
Chet Haase48460322010-06-11 14:22:25 -0700134 /**
135 * A Transformation used when drawing children, to
136 * apply on the child being drawn.
137 */
Romain Guyf6991302013-06-05 17:19:01 -0700138 private Transformation mChildTransformation;
Chet Haase48460322010-06-11 14:22:25 -0700139
140 /**
141 * Used to track the current invalidation region.
142 */
Chet Haase64a48c12012-02-13 16:33:29 -0800143 RectF mInvalidateRegion;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800144
Chet Haase48460322010-06-11 14:22:25 -0700145 /**
146 * A Transformation used to calculate a correct
147 * invalidation area when the application is autoscaled.
148 */
Chet Haase64a48c12012-02-13 16:33:29 -0800149 Transformation mInvalidationTransformation;
Chet Haase48460322010-06-11 14:22:25 -0700150
Christopher Tatea53146c2010-09-07 11:57:52 -0700151 // View currently under an ongoing drag
152 private View mCurrentDragView;
153
Christopher Tate86cab1b2011-01-13 20:28:55 -0800154 // Metadata about the ongoing drag
155 private DragEvent mCurrentDrag;
156 private HashSet<View> mDragNotifiedChildren;
157
Christopher Tatea53146c2010-09-07 11:57:52 -0700158 // Does this group have a child that can accept the current drag payload?
159 private boolean mChildAcceptsDrag;
160
161 // Used during drag dispatch
Romain Guy6410c0a2013-06-17 11:21:58 -0700162 private PointF mLocalPoint;
Christopher Tatea53146c2010-09-07 11:57:52 -0700163
Alan Viveretteb942b6f2014-12-08 10:37:39 -0800164 // Lazily-created holder for point computations.
165 private float[] mTempPoint;
166
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800167 // Layout animation
168 private LayoutAnimationController mLayoutAnimationController;
169 private Animation.AnimationListener mAnimationListener;
170
Jeff Brown20e987b2010-08-23 12:01:02 -0700171 // First touch target in the linked list of touch targets.
172 private TouchTarget mFirstTouchTarget;
173
Joe Onorato03ab0c72011-01-06 15:46:27 -0800174 // For debugging only. You can see these in hierarchyviewer.
Romain Guye95003e2011-01-09 13:53:06 -0800175 @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"})
Joe Onorato03ab0c72011-01-06 15:46:27 -0800176 @ViewDebug.ExportedProperty(category = "events")
177 private long mLastTouchDownTime;
178 @ViewDebug.ExportedProperty(category = "events")
179 private int mLastTouchDownIndex = -1;
Romain Guye95003e2011-01-09 13:53:06 -0800180 @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"})
Joe Onorato03ab0c72011-01-06 15:46:27 -0800181 @ViewDebug.ExportedProperty(category = "events")
182 private float mLastTouchDownX;
Romain Guye95003e2011-01-09 13:53:06 -0800183 @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"})
Joe Onorato03ab0c72011-01-06 15:46:27 -0800184 @ViewDebug.ExportedProperty(category = "events")
185 private float mLastTouchDownY;
186
Jeff Brown87b7f802011-06-21 18:35:45 -0700187 // First hover target in the linked list of hover targets.
188 // The hover targets are children which have received ACTION_HOVER_ENTER.
189 // They might not have actually handled the hover event, but we will
190 // continue sending hover events to them as long as the pointer remains over
191 // their bounds and the view group does not intercept hover.
192 private HoverTarget mFirstHoverTarget;
Jeff Browna032cc02011-03-07 16:56:21 -0800193
Jeff Brown10b62902011-06-20 16:40:37 -0700194 // True if the view group itself received a hover event.
195 // It might not have actually handled the hover event.
196 private boolean mHoveredSelf;
197
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800198 /**
199 * Internal flags.
Romain Guy8506ab42009-06-11 17:35:47 -0700200 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800201 * This field should be made private, so it is hidden from the SDK.
202 * {@hide}
203 */
Romain Guy2440e672012-08-07 14:43:43 -0700204 @ViewDebug.ExportedProperty(flagMapping = {
205 @ViewDebug.FlagToString(mask = FLAG_CLIP_CHILDREN, equals = FLAG_CLIP_CHILDREN,
206 name = "CLIP_CHILDREN"),
207 @ViewDebug.FlagToString(mask = FLAG_CLIP_TO_PADDING, equals = FLAG_CLIP_TO_PADDING,
208 name = "CLIP_TO_PADDING"),
209 @ViewDebug.FlagToString(mask = FLAG_PADDING_NOT_NULL, equals = FLAG_PADDING_NOT_NULL,
210 name = "PADDING_NOT_NULL")
Jon Miranda4597e982014-07-29 07:25:49 -0700211 }, formatToHexString = true)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800212 protected int mGroupFlags;
213
Philip Milne7b757812012-09-19 18:13:44 -0700214 /**
215 * Either {@link #LAYOUT_MODE_CLIP_BOUNDS} or {@link #LAYOUT_MODE_OPTICAL_BOUNDS}.
Philip Milne1557fd72012-04-04 23:41:34 -0700216 */
Philip Milnecfb631b2012-10-26 10:51:46 -0700217 private int mLayoutMode = LAYOUT_MODE_UNDEFINED;
Philip Milne1557fd72012-04-04 23:41:34 -0700218
Romain Guy33f6beb2012-02-16 19:24:51 -0800219 /**
220 * NOTE: If you change the flags below make sure to reflect the changes
221 * the DisplayList class
222 */
223
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800224 // When set, ViewGroup invalidates only the child's rectangle
225 // Set by default
Chet Haase64a48c12012-02-13 16:33:29 -0800226 static final int FLAG_CLIP_CHILDREN = 0x1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800227
228 // When set, ViewGroup excludes the padding area from the invalidate rectangle
229 // Set by default
230 private static final int FLAG_CLIP_TO_PADDING = 0x2;
231
232 // When set, dispatchDraw() will invoke invalidate(); this is set by drawChild() when
233 // a child needs to be invalidated and FLAG_OPTIMIZE_INVALIDATE is set
Chet Haase64a48c12012-02-13 16:33:29 -0800234 static final int FLAG_INVALIDATE_REQUIRED = 0x4;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800235
236 // When set, dispatchDraw() will run the layout animation and unset the flag
237 private static final int FLAG_RUN_ANIMATION = 0x8;
238
239 // When set, there is either no layout animation on the ViewGroup or the layout
240 // animation is over
241 // Set by default
Chet Haase64a48c12012-02-13 16:33:29 -0800242 static final int FLAG_ANIMATION_DONE = 0x10;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800243
244 // If set, this ViewGroup has padding; if unset there is no padding and we don't need
245 // to clip it, even if FLAG_CLIP_TO_PADDING is set
246 private static final int FLAG_PADDING_NOT_NULL = 0x20;
247
Chris Craik5a6bbae2015-04-10 17:41:34 -0700248 /** @deprecated - functionality removed */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800249 private static final int FLAG_ANIMATION_CACHE = 0x40;
250
251 // When set, this ViewGroup converts calls to invalidate(Rect) to invalidate() during a
252 // layout animation; this avoid clobbering the hierarchy
253 // Automatically set when the layout animation starts, depending on the animation's
254 // characteristics
Chet Haase64a48c12012-02-13 16:33:29 -0800255 static final int FLAG_OPTIMIZE_INVALIDATE = 0x80;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800256
257 // When set, the next call to drawChild() will clear mChildTransformation's matrix
Chet Haase64a48c12012-02-13 16:33:29 -0800258 static final int FLAG_CLEAR_TRANSFORMATION = 0x100;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800259
260 // When set, this ViewGroup invokes mAnimationListener.onAnimationEnd() and removes
261 // the children's Bitmap caches if necessary
262 // This flag is set when the layout animation is over (after FLAG_ANIMATION_DONE is set)
263 private static final int FLAG_NOTIFY_ANIMATION_LISTENER = 0x200;
264
265 /**
266 * When set, the drawing method will call {@link #getChildDrawingOrder(int, int)}
267 * to get the index of the child to draw for that iteration.
Romain Guy293451e2009-11-04 13:59:48 -0800268 *
269 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800270 */
271 protected static final int FLAG_USE_CHILD_DRAWING_ORDER = 0x400;
Romain Guy8506ab42009-06-11 17:35:47 -0700272
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800273 /**
274 * When set, this ViewGroup supports static transformations on children; this causes
275 * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} to be
276 * invoked when a child is drawn.
277 *
278 * Any subclass overriding
279 * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} should
280 * set this flags in {@link #mGroupFlags}.
Romain Guy8506ab42009-06-11 17:35:47 -0700281 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800282 * {@hide}
283 */
284 protected static final int FLAG_SUPPORT_STATIC_TRANSFORMATIONS = 0x800;
285
John Reckfb5899d2014-08-15 18:51:27 -0700286 // UNUSED FLAG VALUE: 0x1000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800287
288 /**
289 * When set, this ViewGroup's drawable states also include those
290 * of its children.
291 */
292 private static final int FLAG_ADD_STATES_FROM_CHILDREN = 0x2000;
293
Chris Craik5a6bbae2015-04-10 17:41:34 -0700294 /** @deprecated functionality removed */
295 private static final int FLAG_ALWAYS_DRAWN_WITH_CACHE = 0x4000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800296
Chris Craik5a6bbae2015-04-10 17:41:34 -0700297 /** @deprecated functionality removed */
298 private static final int FLAG_CHILDREN_DRAWN_WITH_CACHE = 0x8000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800299
300 /**
301 * When set, this group will go through its list of children to notify them of
302 * any drawable state change.
303 */
304 private static final int FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE = 0x10000;
305
306 private static final int FLAG_MASK_FOCUSABILITY = 0x60000;
307
308 /**
309 * This view will get focus before any of its descendants.
310 */
311 public static final int FOCUS_BEFORE_DESCENDANTS = 0x20000;
312
313 /**
314 * This view will get focus only if none of its descendants want it.
315 */
316 public static final int FOCUS_AFTER_DESCENDANTS = 0x40000;
317
318 /**
319 * This view will block any of its descendants from getting focus, even
320 * if they are focusable.
321 */
322 public static final int FOCUS_BLOCK_DESCENDANTS = 0x60000;
323
324 /**
325 * Used to map between enum in attrubutes and flag values.
326 */
327 private static final int[] DESCENDANT_FOCUSABILITY_FLAGS =
328 {FOCUS_BEFORE_DESCENDANTS, FOCUS_AFTER_DESCENDANTS,
329 FOCUS_BLOCK_DESCENDANTS};
330
331 /**
332 * When set, this ViewGroup should not intercept touch events.
Adam Powell110486f2010-06-22 17:14:44 -0700333 * {@hide}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800334 */
Adam Powell110486f2010-06-22 17:14:44 -0700335 protected static final int FLAG_DISALLOW_INTERCEPT = 0x80000;
Romain Guy8506ab42009-06-11 17:35:47 -0700336
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800337 /**
Adam Powell2b342f02010-08-18 18:14:13 -0700338 * When set, this ViewGroup will split MotionEvents to multiple child Views when appropriate.
339 */
Adam Powellf37df072010-09-17 16:22:49 -0700340 private static final int FLAG_SPLIT_MOTION_EVENTS = 0x200000;
Adam Powell2b342f02010-08-18 18:14:13 -0700341
342 /**
Adam Powell4b867882011-09-16 12:59:46 -0700343 * When set, this ViewGroup will not dispatch onAttachedToWindow calls
344 * to children when adding new views. This is used to prevent multiple
345 * onAttached calls when a ViewGroup adds children in its own onAttached method.
346 */
347 private static final int FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW = 0x400000;
348
349 /**
Philip Milnecfb631b2012-10-26 10:51:46 -0700350 * When true, indicates that a layoutMode has been explicitly set, either with
351 * an explicit call to {@link #setLayoutMode(int)} in code or from an XML resource.
352 * This distinguishes the situation in which a layout mode was inherited from
353 * one of the ViewGroup's ancestors and cached locally.
354 */
355 private static final int FLAG_LAYOUT_MODE_WAS_EXPLICITLY_SET = 0x800000;
356
Chris Craikb49f4462014-03-20 12:44:20 -0700357 static final int FLAG_IS_TRANSITION_GROUP = 0x1000000;
Chris Craikd863a102013-12-19 13:31:15 -0800358
Chris Craikb49f4462014-03-20 12:44:20 -0700359 static final int FLAG_IS_TRANSITION_GROUP_SET = 0x2000000;
George Mount0a778ed2013-12-13 13:35:36 -0800360
Chris Craikd863a102013-12-19 13:31:15 -0800361 /**
Adam Powellff0d2982014-07-10 20:34:14 -0700362 * When set, focus will not be permitted to enter this group if a touchscreen is present.
363 */
364 static final int FLAG_TOUCHSCREEN_BLOCKS_FOCUS = 0x4000000;
365
366 /**
Clara Bayarri4423d912015-03-02 19:42:48 +0000367 * When true, indicates that a call to startActionModeForChild was made with the type parameter
368 * and should not be ignored. This helps in backwards compatibility with the existing method
369 * without a type.
370 *
371 * @see #startActionModeForChild(View, android.view.ActionMode.Callback)
372 * @see #startActionModeForChild(View, android.view.ActionMode.Callback, int)
373 */
374 private static final int FLAG_START_ACTION_MODE_FOR_CHILD_IS_TYPED = 0x8000000;
375
376 /**
377 * When true, indicates that a call to startActionModeForChild was made without the type
378 * parameter. This helps in backwards compatibility with the existing method
379 * without a type.
380 *
381 * @see #startActionModeForChild(View, android.view.ActionMode.Callback)
382 * @see #startActionModeForChild(View, android.view.ActionMode.Callback, int)
383 */
384 private static final int FLAG_START_ACTION_MODE_FOR_CHILD_IS_NOT_TYPED = 0x10000000;
385
386 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800387 * Indicates which types of drawing caches are to be kept in memory.
388 * This field should be made private, so it is hidden from the SDK.
389 * {@hide}
390 */
391 protected int mPersistentDrawingCache;
392
393 /**
394 * Used to indicate that no drawing cache should be kept in memory.
395 */
396 public static final int PERSISTENT_NO_CACHE = 0x0;
397
398 /**
399 * Used to indicate that the animation drawing cache should be kept in memory.
400 */
401 public static final int PERSISTENT_ANIMATION_CACHE = 0x1;
402
403 /**
404 * Used to indicate that the scrolling drawing cache should be kept in memory.
405 */
406 public static final int PERSISTENT_SCROLLING_CACHE = 0x2;
407
408 /**
409 * Used to indicate that all drawing caches should be kept in memory.
410 */
411 public static final int PERSISTENT_ALL_CACHES = 0x3;
412
Philip Milne1557fd72012-04-04 23:41:34 -0700413 // Layout Modes
414
Philip Milnecfb631b2012-10-26 10:51:46 -0700415 private static final int LAYOUT_MODE_UNDEFINED = -1;
416
Philip Milne1557fd72012-04-04 23:41:34 -0700417 /**
418 * This constant is a {@link #setLayoutMode(int) layoutMode}.
Philip Milne7a23b492012-04-24 22:12:36 -0700419 * Clip bounds are the raw values of {@link #getLeft() left}, {@link #getTop() top},
Philip Milne1557fd72012-04-04 23:41:34 -0700420 * {@link #getRight() right} and {@link #getBottom() bottom}.
421 */
Philip Milne7b757812012-09-19 18:13:44 -0700422 public static final int LAYOUT_MODE_CLIP_BOUNDS = 0;
Philip Milne1557fd72012-04-04 23:41:34 -0700423
424 /**
425 * This constant is a {@link #setLayoutMode(int) layoutMode}.
Philip Milne7a23b492012-04-24 22:12:36 -0700426 * Optical bounds describe where a widget appears to be. They sit inside the clip
427 * bounds which need to cover a larger area to allow other effects,
428 * such as shadows and glows, to be drawn.
Philip Milne1557fd72012-04-04 23:41:34 -0700429 */
Philip Milne7b757812012-09-19 18:13:44 -0700430 public static final int LAYOUT_MODE_OPTICAL_BOUNDS = 1;
431
432 /** @hide */
Philip Milnecfb631b2012-10-26 10:51:46 -0700433 public static int LAYOUT_MODE_DEFAULT = LAYOUT_MODE_CLIP_BOUNDS;
Philip Milne1557fd72012-04-04 23:41:34 -0700434
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800435 /**
436 * We clip to padding when FLAG_CLIP_TO_PADDING and FLAG_PADDING_NOT_NULL
437 * are set at the same time.
438 */
439 protected static final int CLIP_TO_PADDING_MASK = FLAG_CLIP_TO_PADDING | FLAG_PADDING_NOT_NULL;
440
441 // Index of the child's left position in the mLocation array
442 private static final int CHILD_LEFT_INDEX = 0;
443 // Index of the child's top position in the mLocation array
444 private static final int CHILD_TOP_INDEX = 1;
445
446 // Child views of this ViewGroup
447 private View[] mChildren;
448 // Number of valid children in the mChildren array, the rest should be null or not
449 // considered as children
450 private int mChildrenCount;
451
Chet Haaseb9895022013-04-02 15:10:58 -0700452 // Whether layout calls are currently being suppressed, controlled by calls to
453 // suppressLayout()
454 boolean mSuppressLayout = false;
455
456 // Whether any layout calls have actually been suppressed while mSuppressLayout
457 // has been true. This tracks whether we need to issue a requestLayout() when
458 // layout is later re-enabled.
459 private boolean mLayoutCalledWhileSuppressed = false;
460
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800461 private static final int ARRAY_INITIAL_CAPACITY = 12;
462 private static final int ARRAY_CAPACITY_INCREMENT = 12;
463
Romain Guycbc67742012-04-27 16:12:57 -0700464 private static Paint sDebugPaint;
465 private static float[] sDebugLines;
Philip Milne604f4402012-04-24 19:27:11 -0700466
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800467 // Used to draw cached views
Chet Haase64a48c12012-02-13 16:33:29 -0800468 Paint mCachePaint;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800469
Chet Haase21cd1382010-09-01 17:42:29 -0700470 // Used to animate add/remove changes in layout
471 private LayoutTransition mTransition;
472
473 // The set of views that are currently being transitioned. This list is used to track views
474 // being removed that should not actually be removed from the parent yet because they are
475 // being animated.
476 private ArrayList<View> mTransitioningViews;
477
Chet Haase5e25c2c2010-09-16 11:15:56 -0700478 // List of children changing visibility. This is used to potentially keep rendering
479 // views during a transition when they otherwise would have become gone/invisible
480 private ArrayList<View> mVisibilityChangingChildren;
481
Chris Craikab008f02014-05-23 17:55:03 -0700482 // Temporary holder of presorted children, only used for
483 // input/software draw dispatch for correctly Z ordering.
484 private ArrayList<View> mPreSortedChildren;
485
Adam Powell539ee872012-02-03 19:00:49 -0800486 // Indicates how many of this container's child subtrees contain transient state
487 @ViewDebug.ExportedProperty(category = "layout")
488 private int mChildCountWithTransientState = 0;
489
Adam Powell10ba2772014-04-15 09:46:51 -0700490 /**
491 * Currently registered axes for nested scrolling. Flag set consisting of
492 * {@link #SCROLL_AXIS_HORIZONTAL} {@link #SCROLL_AXIS_VERTICAL} or {@link #SCROLL_AXIS_NONE}
493 * for null.
494 */
495 private int mNestedScrollAxes;
496
Clara Bayarri4423d912015-03-02 19:42:48 +0000497 /**
498 * Empty ActionMode used as a sentinel in recursive entries to startActionModeForChild.
499 *
500 * @see #startActionModeForChild(View, android.view.ActionMode.Callback)
501 * @see #startActionModeForChild(View, android.view.ActionMode.Callback, int)
502 */
503 private static final ActionMode SENTINEL_ACTION_MODE = new ActionMode() {
504 @Override
505 public void setTitle(CharSequence title) {}
506
507 @Override
508 public void setTitle(int resId) {}
509
510 @Override
511 public void setSubtitle(CharSequence subtitle) {}
512
513 @Override
514 public void setSubtitle(int resId) {}
515
516 @Override
517 public void setCustomView(View view) {}
518
519 @Override
520 public void invalidate() {}
521
522 @Override
523 public void finish() {}
524
525 @Override
526 public Menu getMenu() {
527 return null;
528 }
529
530 @Override
531 public CharSequence getTitle() {
532 return null;
533 }
534
535 @Override
536 public CharSequence getSubtitle() {
537 return null;
538 }
539
540 @Override
541 public View getCustomView() {
542 return null;
543 }
544
545 @Override
546 public MenuInflater getMenuInflater() {
547 return null;
548 }
549 };
550
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800551 public ViewGroup(Context context) {
Alan Viveretted6479ec2013-09-10 17:03:02 -0700552 this(context, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800553 }
554
555 public ViewGroup(Context context, AttributeSet attrs) {
Alan Viveretted6479ec2013-09-10 17:03:02 -0700556 this(context, attrs, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800557 }
558
Alan Viverette617feb92013-09-09 18:09:13 -0700559 public ViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {
Alan Viveretted6479ec2013-09-10 17:03:02 -0700560 this(context, attrs, defStyleAttr, 0);
Alan Viverette617feb92013-09-09 18:09:13 -0700561 }
562
563 public ViewGroup(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
564 super(context, attrs, defStyleAttr, defStyleRes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800565 initViewGroup();
Alan Viveretted6479ec2013-09-10 17:03:02 -0700566 initFromAttributes(context, attrs, defStyleAttr, defStyleRes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800567 }
568
Philip Milne10ca24a2012-04-23 15:38:27 -0700569 private boolean debugDraw() {
Philip Milne7b757812012-09-19 18:13:44 -0700570 return DEBUG_DRAW || mAttachInfo != null && mAttachInfo.mDebugLayout;
Philip Milne10ca24a2012-04-23 15:38:27 -0700571 }
572
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800573 private void initViewGroup() {
574 // ViewGroup doesn't draw by default
Philip Milne10ca24a2012-04-23 15:38:27 -0700575 if (!debugDraw()) {
576 setFlags(WILL_NOT_DRAW, DRAW_MASK);
577 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800578 mGroupFlags |= FLAG_CLIP_CHILDREN;
579 mGroupFlags |= FLAG_CLIP_TO_PADDING;
580 mGroupFlags |= FLAG_ANIMATION_DONE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800581
Jeff Brown995e7742010-12-22 16:59:36 -0800582 if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB) {
583 mGroupFlags |= FLAG_SPLIT_MOTION_EVENTS;
584 }
585
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800586 setDescendantFocusability(FOCUS_BEFORE_DESCENDANTS);
587
588 mChildren = new View[ARRAY_INITIAL_CAPACITY];
589 mChildrenCount = 0;
590
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800591 mPersistentDrawingCache = PERSISTENT_SCROLLING_CACHE;
592 }
593
Alan Viveretted6479ec2013-09-10 17:03:02 -0700594 private void initFromAttributes(
595 Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
Filip Gruszczyńskib50cea02014-03-05 17:54:58 -0800596 final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ViewGroup, defStyleAttr,
597 defStyleRes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800598
599 final int N = a.getIndexCount();
600 for (int i = 0; i < N; i++) {
601 int attr = a.getIndex(i);
602 switch (attr) {
603 case R.styleable.ViewGroup_clipChildren:
604 setClipChildren(a.getBoolean(attr, true));
605 break;
606 case R.styleable.ViewGroup_clipToPadding:
607 setClipToPadding(a.getBoolean(attr, true));
608 break;
609 case R.styleable.ViewGroup_animationCache:
610 setAnimationCacheEnabled(a.getBoolean(attr, true));
611 break;
612 case R.styleable.ViewGroup_persistentDrawingCache:
613 setPersistentDrawingCache(a.getInt(attr, PERSISTENT_SCROLLING_CACHE));
614 break;
615 case R.styleable.ViewGroup_addStatesFromChildren:
616 setAddStatesFromChildren(a.getBoolean(attr, false));
617 break;
618 case R.styleable.ViewGroup_alwaysDrawnWithCache:
619 setAlwaysDrawnWithCacheEnabled(a.getBoolean(attr, true));
620 break;
621 case R.styleable.ViewGroup_layoutAnimation:
622 int id = a.getResourceId(attr, -1);
623 if (id > 0) {
624 setLayoutAnimation(AnimationUtils.loadLayoutAnimation(mContext, id));
625 }
626 break;
627 case R.styleable.ViewGroup_descendantFocusability:
628 setDescendantFocusability(DESCENDANT_FOCUSABILITY_FLAGS[a.getInt(attr, 0)]);
629 break;
Adam Powell2b342f02010-08-18 18:14:13 -0700630 case R.styleable.ViewGroup_splitMotionEvents:
631 setMotionEventSplittingEnabled(a.getBoolean(attr, false));
632 break;
Chet Haase13cc1202010-09-03 15:39:20 -0700633 case R.styleable.ViewGroup_animateLayoutChanges:
634 boolean animateLayoutChanges = a.getBoolean(attr, false);
635 if (animateLayoutChanges) {
636 setLayoutTransition(new LayoutTransition());
637 }
638 break;
Philip Milne7b757812012-09-19 18:13:44 -0700639 case R.styleable.ViewGroup_layoutMode:
Philip Milnecfb631b2012-10-26 10:51:46 -0700640 setLayoutMode(a.getInt(attr, LAYOUT_MODE_UNDEFINED));
Philip Milne7b757812012-09-19 18:13:44 -0700641 break;
George Mount0a778ed2013-12-13 13:35:36 -0800642 case R.styleable.ViewGroup_transitionGroup:
643 setTransitionGroup(a.getBoolean(attr, false));
644 break;
Adam Powellff0d2982014-07-10 20:34:14 -0700645 case R.styleable.ViewGroup_touchscreenBlocksFocus:
646 setTouchscreenBlocksFocus(a.getBoolean(attr, false));
647 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800648 }
649 }
650
651 a.recycle();
652 }
653
654 /**
655 * Gets the descendant focusability of this view group. The descendant
656 * focusability defines the relationship between this view group and its
657 * descendants when looking for a view to take focus in
658 * {@link #requestFocus(int, android.graphics.Rect)}.
659 *
660 * @return one of {@link #FOCUS_BEFORE_DESCENDANTS}, {@link #FOCUS_AFTER_DESCENDANTS},
661 * {@link #FOCUS_BLOCK_DESCENDANTS}.
662 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -0700663 @ViewDebug.ExportedProperty(category = "focus", mapping = {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800664 @ViewDebug.IntToString(from = FOCUS_BEFORE_DESCENDANTS, to = "FOCUS_BEFORE_DESCENDANTS"),
665 @ViewDebug.IntToString(from = FOCUS_AFTER_DESCENDANTS, to = "FOCUS_AFTER_DESCENDANTS"),
666 @ViewDebug.IntToString(from = FOCUS_BLOCK_DESCENDANTS, to = "FOCUS_BLOCK_DESCENDANTS")
667 })
668 public int getDescendantFocusability() {
669 return mGroupFlags & FLAG_MASK_FOCUSABILITY;
670 }
671
672 /**
673 * Set the descendant focusability of this view group. This defines the relationship
674 * between this view group and its descendants when looking for a view to
675 * take focus in {@link #requestFocus(int, android.graphics.Rect)}.
676 *
677 * @param focusability one of {@link #FOCUS_BEFORE_DESCENDANTS}, {@link #FOCUS_AFTER_DESCENDANTS},
678 * {@link #FOCUS_BLOCK_DESCENDANTS}.
679 */
680 public void setDescendantFocusability(int focusability) {
681 switch (focusability) {
682 case FOCUS_BEFORE_DESCENDANTS:
683 case FOCUS_AFTER_DESCENDANTS:
684 case FOCUS_BLOCK_DESCENDANTS:
685 break;
686 default:
687 throw new IllegalArgumentException("must be one of FOCUS_BEFORE_DESCENDANTS, "
688 + "FOCUS_AFTER_DESCENDANTS, FOCUS_BLOCK_DESCENDANTS");
689 }
690 mGroupFlags &= ~FLAG_MASK_FOCUSABILITY;
691 mGroupFlags |= (focusability & FLAG_MASK_FOCUSABILITY);
692 }
693
694 /**
695 * {@inheritDoc}
696 */
697 @Override
698 void handleFocusGainInternal(int direction, Rect previouslyFocusedRect) {
699 if (mFocused != null) {
Alan Viverette223622a2013-12-17 13:29:02 -0800700 mFocused.unFocus(this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800701 mFocused = null;
702 }
703 super.handleFocusGainInternal(direction, previouslyFocusedRect);
704 }
705
706 /**
707 * {@inheritDoc}
708 */
709 public void requestChildFocus(View child, View focused) {
710 if (DBG) {
711 System.out.println(this + " requestChildFocus()");
712 }
713 if (getDescendantFocusability() == FOCUS_BLOCK_DESCENDANTS) {
714 return;
715 }
716
717 // Unfocus us, if necessary
Alan Viverette223622a2013-12-17 13:29:02 -0800718 super.unFocus(focused);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800719
720 // We had a previous notion of who had focus. Clear it.
721 if (mFocused != child) {
722 if (mFocused != null) {
Alan Viverette223622a2013-12-17 13:29:02 -0800723 mFocused.unFocus(focused);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800724 }
725
726 mFocused = child;
727 }
728 if (mParent != null) {
729 mParent.requestChildFocus(this, focused);
730 }
731 }
732
733 /**
734 * {@inheritDoc}
735 */
736 public void focusableViewAvailable(View v) {
737 if (mParent != null
738 // shortcut: don't report a new focusable view if we block our descendants from
739 // getting focus
740 && (getDescendantFocusability() != FOCUS_BLOCK_DESCENDANTS)
Adam Powell88c11752014-07-21 17:19:16 -0700741 && (isFocusableInTouchMode() || !shouldBlockFocusForTouchscreen())
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800742 // shortcut: don't report a new focusable view if we already are focused
743 // (and we don't prefer our descendants)
744 //
745 // note: knowing that mFocused is non-null is not a good enough reason
746 // to break the traversal since in that case we'd actually have to find
747 // the focused view and make sure it wasn't FOCUS_AFTER_DESCENDANTS and
Joe Onoratoc6cc0f82011-04-12 11:53:13 -0700748 // an ancestor of v; this will get checked for at ViewAncestor
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800749 && !(isFocused() && getDescendantFocusability() != FOCUS_AFTER_DESCENDANTS)) {
750 mParent.focusableViewAvailable(v);
751 }
752 }
753
754 /**
755 * {@inheritDoc}
756 */
757 public boolean showContextMenuForChild(View originalView) {
758 return mParent != null && mParent.showContextMenuForChild(originalView);
759 }
760
761 /**
Adam Powell6e346362010-07-23 10:18:23 -0700762 * {@inheritDoc}
763 */
Clara Bayarri4423d912015-03-02 19:42:48 +0000764 @Override
Adam Powell6e346362010-07-23 10:18:23 -0700765 public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback) {
Clara Bayarri4423d912015-03-02 19:42:48 +0000766 if ((mGroupFlags & FLAG_START_ACTION_MODE_FOR_CHILD_IS_TYPED) == 0) {
767 // This is the original call.
768 try {
769 mGroupFlags |= FLAG_START_ACTION_MODE_FOR_CHILD_IS_NOT_TYPED;
770 return startActionModeForChild(originalView, callback, ActionMode.TYPE_PRIMARY);
771 } finally {
772 mGroupFlags &= ~FLAG_START_ACTION_MODE_FOR_CHILD_IS_NOT_TYPED;
773 }
774 } else {
775 // We are being called from the new method with type.
776 return SENTINEL_ACTION_MODE;
777 }
778 }
779
780 /**
781 * {@inheritDoc}
782 */
783 @Override
784 public ActionMode startActionModeForChild(
785 View originalView, ActionMode.Callback callback, int type) {
786 if ((mGroupFlags & FLAG_START_ACTION_MODE_FOR_CHILD_IS_NOT_TYPED) == 0) {
787 ActionMode mode;
788 try {
789 mGroupFlags |= FLAG_START_ACTION_MODE_FOR_CHILD_IS_TYPED;
790 mode = startActionModeForChild(originalView, callback);
791 } finally {
792 mGroupFlags &= ~FLAG_START_ACTION_MODE_FOR_CHILD_IS_TYPED;
793 }
794 if (mode != SENTINEL_ACTION_MODE) {
795 return mode;
796 }
797 }
798 if (mParent != null) {
799 try {
800 return mParent.startActionModeForChild(originalView, callback, type);
801 } catch (AbstractMethodError ame) {
802 // Custom view parents might not implement this method.
803 return mParent.startActionModeForChild(originalView, callback);
804 }
805 }
806 return null;
Adam Powell6e346362010-07-23 10:18:23 -0700807 }
808
809 /**
Clara Bayarrid5bf3ed2015-03-27 17:32:45 +0000810 * @hide
811 */
812 @Override
813 public boolean dispatchActivityResult(
814 String who, int requestCode, int resultCode, Intent data) {
815 if (super.dispatchActivityResult(who, requestCode, resultCode, data)) {
816 return true;
817 }
818 int childCount = getChildCount();
819 for (int i = 0; i < childCount; i++) {
820 View child = getChildAt(i);
821 if (child.dispatchActivityResult(who, requestCode, resultCode, data)) {
822 return true;
823 }
824 }
825 return false;
826 }
827
828 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800829 * Find the nearest view in the specified direction that wants to take
830 * focus.
831 *
832 * @param focused The view that currently has focus
833 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and
834 * FOCUS_RIGHT, or 0 for not applicable.
835 */
836 public View focusSearch(View focused, int direction) {
Svetoslav Ganov27e2da72012-07-02 18:12:00 -0700837 if (isRootNamespace()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800838 // root namespace means we should consider ourselves the top of the
839 // tree for focus searching; otherwise we could be focus searching
840 // into other tabs. see LocalActivityManager and TabHost for more info
841 return FocusFinder.getInstance().findNextFocus(this, focused, direction);
842 } else if (mParent != null) {
843 return mParent.focusSearch(focused, direction);
844 }
845 return null;
846 }
847
848 /**
849 * {@inheritDoc}
850 */
851 public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
852 return false;
853 }
854
855 /**
856 * {@inheritDoc}
857 */
Svetoslav Ganov42138042012-03-20 11:51:39 -0700858 @Override
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700859 public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event) {
Svetoslav Ganov42138042012-03-20 11:51:39 -0700860 ViewParent parent = mParent;
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700861 if (parent == null) {
862 return false;
863 }
864 final boolean propagate = onRequestSendAccessibilityEvent(child, event);
865 if (!propagate) {
866 return false;
867 }
868 return parent.requestSendAccessibilityEvent(this, event);
869 }
870
871 /**
872 * Called when a child has requested sending an {@link AccessibilityEvent} and
873 * gives an opportunity to its parent to augment the event.
Svetoslav Ganov031d9c12011-09-09 16:41:13 -0700874 * <p>
Adam Powell2fcbbd02011-09-28 18:56:43 -0700875 * If an {@link android.view.View.AccessibilityDelegate} has been specified via calling
876 * {@link android.view.View#setAccessibilityDelegate(android.view.View.AccessibilityDelegate)} its
877 * {@link android.view.View.AccessibilityDelegate#onRequestSendAccessibilityEvent(ViewGroup, View, AccessibilityEvent)}
Svetoslav Ganov031d9c12011-09-09 16:41:13 -0700878 * is responsible for handling this call.
879 * </p>
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700880 *
881 * @param child The child which requests sending the event.
882 * @param event The event to be sent.
883 * @return True if the event should be sent.
884 *
885 * @see #requestSendAccessibilityEvent(View, AccessibilityEvent)
886 */
887 public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
Svetoslav Ganov031d9c12011-09-09 16:41:13 -0700888 if (mAccessibilityDelegate != null) {
889 return mAccessibilityDelegate.onRequestSendAccessibilityEvent(this, child, event);
890 } else {
891 return onRequestSendAccessibilityEventInternal(child, event);
892 }
893 }
894
895 /**
896 * @see #onRequestSendAccessibilityEvent(View, AccessibilityEvent)
897 *
898 * Note: Called from the default {@link View.AccessibilityDelegate}.
Alan Viverettea54956a2015-01-07 16:05:02 -0800899 *
900 * @hide
Svetoslav Ganov031d9c12011-09-09 16:41:13 -0700901 */
Alan Viverettea54956a2015-01-07 16:05:02 -0800902 public boolean onRequestSendAccessibilityEventInternal(View child, AccessibilityEvent event) {
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700903 return true;
904 }
905
906 /**
Adam Powell539ee872012-02-03 19:00:49 -0800907 * Called when a child view has changed whether or not it is tracking transient state.
Adam Powell539ee872012-02-03 19:00:49 -0800908 */
909 public void childHasTransientStateChanged(View child, boolean childHasTransientState) {
910 final boolean oldHasTransientState = hasTransientState();
911 if (childHasTransientState) {
912 mChildCountWithTransientState++;
913 } else {
914 mChildCountWithTransientState--;
915 }
916
917 final boolean newHasTransientState = hasTransientState();
918 if (mParent != null && oldHasTransientState != newHasTransientState) {
919 try {
920 mParent.childHasTransientStateChanged(this, newHasTransientState);
921 } catch (AbstractMethodError e) {
922 Log.e(TAG, mParent.getClass().getSimpleName() +
923 " does not fully implement ViewParent", e);
924 }
925 }
926 }
927
Adam Powell539ee872012-02-03 19:00:49 -0800928 @Override
929 public boolean hasTransientState() {
930 return mChildCountWithTransientState > 0 || super.hasTransientState();
931 }
932
933 /**
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700934 * {@inheritDoc}
935 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800936 @Override
937 public boolean dispatchUnhandledMove(View focused, int direction) {
938 return mFocused != null &&
939 mFocused.dispatchUnhandledMove(focused, direction);
940 }
941
942 /**
943 * {@inheritDoc}
944 */
945 public void clearChildFocus(View child) {
946 if (DBG) {
947 System.out.println(this + " clearChildFocus()");
948 }
949
950 mFocused = null;
951 if (mParent != null) {
952 mParent.clearChildFocus(this);
953 }
954 }
955
956 /**
957 * {@inheritDoc}
958 */
959 @Override
960 public void clearFocus() {
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -0800961 if (DBG) {
962 System.out.println(this + " clearFocus()");
963 }
964 if (mFocused == null) {
965 super.clearFocus();
966 } else {
Svetoslav Ganovb552d892012-06-02 14:35:02 -0700967 View focused = mFocused;
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -0800968 mFocused = null;
Svetoslav Ganovb552d892012-06-02 14:35:02 -0700969 focused.clearFocus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800970 }
971 }
972
973 /**
974 * {@inheritDoc}
975 */
976 @Override
Alan Viverette223622a2013-12-17 13:29:02 -0800977 void unFocus(View focused) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800978 if (DBG) {
979 System.out.println(this + " unFocus()");
980 }
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -0800981 if (mFocused == null) {
Alan Viverette223622a2013-12-17 13:29:02 -0800982 super.unFocus(focused);
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -0800983 } else {
Alan Viverette223622a2013-12-17 13:29:02 -0800984 mFocused.unFocus(focused);
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -0800985 mFocused = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800986 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800987 }
988
989 /**
990 * Returns the focused child of this view, if any. The child may have focus
991 * or contain focus.
992 *
993 * @return the focused child or null.
994 */
995 public View getFocusedChild() {
996 return mFocused;
997 }
998
Adam Powell88c11752014-07-21 17:19:16 -0700999 View getDeepestFocusedChild() {
1000 View v = this;
1001 while (v != null) {
1002 if (v.isFocused()) {
1003 return v;
1004 }
1005 v = v instanceof ViewGroup ? ((ViewGroup) v).getFocusedChild() : null;
1006 }
1007 return null;
1008 }
1009
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001010 /**
1011 * Returns true if this view has or contains focus
1012 *
1013 * @return true if this view has or contains focus
1014 */
1015 @Override
1016 public boolean hasFocus() {
Dianne Hackborn4702a852012-08-17 15:18:29 -07001017 return (mPrivateFlags & PFLAG_FOCUSED) != 0 || mFocused != null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001018 }
1019
1020 /*
1021 * (non-Javadoc)
1022 *
1023 * @see android.view.View#findFocus()
1024 */
1025 @Override
1026 public View findFocus() {
1027 if (DBG) {
1028 System.out.println("Find focus in " + this + ": flags="
1029 + isFocused() + ", child=" + mFocused);
1030 }
1031
1032 if (isFocused()) {
1033 return this;
1034 }
1035
1036 if (mFocused != null) {
1037 return mFocused.findFocus();
1038 }
1039 return null;
1040 }
1041
1042 /**
1043 * {@inheritDoc}
1044 */
1045 @Override
1046 public boolean hasFocusable() {
1047 if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) {
1048 return false;
1049 }
1050
1051 if (isFocusable()) {
1052 return true;
1053 }
1054
1055 final int descendantFocusability = getDescendantFocusability();
Adam Powell88c11752014-07-21 17:19:16 -07001056 if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001057 final int count = mChildrenCount;
1058 final View[] children = mChildren;
1059
1060 for (int i = 0; i < count; i++) {
1061 final View child = children[i];
1062 if (child.hasFocusable()) {
1063 return true;
1064 }
1065 }
1066 }
1067
1068 return false;
1069 }
1070
1071 /**
1072 * {@inheritDoc}
1073 */
1074 @Override
svetoslavganov75986cf2009-05-14 22:28:01 -07001075 public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001076 final int focusableCount = views.size();
1077
1078 final int descendantFocusability = getDescendantFocusability();
1079
Adam Powell88c11752014-07-21 17:19:16 -07001080 if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS) {
1081 if (shouldBlockFocusForTouchscreen()) {
1082 focusableMode |= FOCUSABLES_TOUCH_MODE;
1083 }
1084
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001085 final int count = mChildrenCount;
1086 final View[] children = mChildren;
1087
1088 for (int i = 0; i < count; i++) {
1089 final View child = children[i];
1090 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
svetoslavganov75986cf2009-05-14 22:28:01 -07001091 child.addFocusables(views, direction, focusableMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001092 }
1093 }
1094 }
1095
1096 // we add ourselves (if focusable) in all cases except for when we are
1097 // FOCUS_AFTER_DESCENDANTS and there are some descendants focusable. this is
1098 // to avoid the focus search finding layouts when a more precise search
1099 // among the focusable children would be more interesting.
Adam Powellff0d2982014-07-10 20:34:14 -07001100 if ((descendantFocusability != FOCUS_AFTER_DESCENDANTS
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001101 // No focusable descendants
Adam Powell88c11752014-07-21 17:19:16 -07001102 || (focusableCount == views.size())) &&
1103 (isFocusableInTouchMode() || !shouldBlockFocusForTouchscreen())) {
svetoslavganov75986cf2009-05-14 22:28:01 -07001104 super.addFocusables(views, direction, focusableMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001105 }
1106 }
1107
Adam Powellff0d2982014-07-10 20:34:14 -07001108 /**
1109 * Set whether this ViewGroup should ignore focus requests for itself and its children.
1110 * If this option is enabled and the ViewGroup or a descendant currently has focus, focus
1111 * will proceed forward.
1112 *
1113 * @param touchscreenBlocksFocus true to enable blocking focus in the presence of a touchscreen
1114 */
1115 public void setTouchscreenBlocksFocus(boolean touchscreenBlocksFocus) {
1116 if (touchscreenBlocksFocus) {
1117 mGroupFlags |= FLAG_TOUCHSCREEN_BLOCKS_FOCUS;
1118 if (hasFocus()) {
Adam Powell88c11752014-07-21 17:19:16 -07001119 final View focusedChild = getDeepestFocusedChild();
1120 if (!focusedChild.isFocusableInTouchMode()) {
1121 final View newFocus = focusSearch(FOCUS_FORWARD);
1122 if (newFocus != null) {
1123 newFocus.requestFocus();
1124 }
Adam Powellff0d2982014-07-10 20:34:14 -07001125 }
1126 }
1127 } else {
1128 mGroupFlags &= ~FLAG_TOUCHSCREEN_BLOCKS_FOCUS;
1129 }
1130 }
1131
1132 /**
1133 * Check whether this ViewGroup should ignore focus requests for itself and its children.
1134 */
1135 public boolean getTouchscreenBlocksFocus() {
1136 return (mGroupFlags & FLAG_TOUCHSCREEN_BLOCKS_FOCUS) != 0;
1137 }
1138
1139 boolean shouldBlockFocusForTouchscreen() {
1140 return getTouchscreenBlocksFocus() &&
1141 mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN);
1142 }
1143
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001144 @Override
Svetoslav Ganovea515ae2011-09-14 18:15:32 -07001145 public void findViewsWithText(ArrayList<View> outViews, CharSequence text, int flags) {
1146 super.findViewsWithText(outViews, text, flags);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001147 final int childrenCount = mChildrenCount;
1148 final View[] children = mChildren;
1149 for (int i = 0; i < childrenCount; i++) {
1150 View child = children[i];
Svetoslav Ganovea515ae2011-09-14 18:15:32 -07001151 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE
Dianne Hackborn4702a852012-08-17 15:18:29 -07001152 && (child.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) {
Svetoslav Ganovea515ae2011-09-14 18:15:32 -07001153 child.findViewsWithText(outViews, text, flags);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001154 }
1155 }
1156 }
1157
Svetoslav5b578da2013-05-08 14:23:32 -07001158 /** @hide */
Svetoslav Ganov2cdedff2011-10-03 14:18:42 -07001159 @Override
Svetoslav5b578da2013-05-08 14:23:32 -07001160 public View findViewByAccessibilityIdTraversal(int accessibilityId) {
Svetoslav Ganov2cdedff2011-10-03 14:18:42 -07001161 View foundView = super.findViewByAccessibilityIdTraversal(accessibilityId);
1162 if (foundView != null) {
1163 return foundView;
1164 }
1165 final int childrenCount = mChildrenCount;
1166 final View[] children = mChildren;
1167 for (int i = 0; i < childrenCount; i++) {
1168 View child = children[i];
1169 foundView = child.findViewByAccessibilityIdTraversal(accessibilityId);
1170 if (foundView != null) {
1171 return foundView;
1172 }
1173 }
1174 return null;
1175 }
1176
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001177 /**
1178 * {@inheritDoc}
1179 */
1180 @Override
1181 public void dispatchWindowFocusChanged(boolean hasFocus) {
1182 super.dispatchWindowFocusChanged(hasFocus);
1183 final int count = mChildrenCount;
1184 final View[] children = mChildren;
1185 for (int i = 0; i < count; i++) {
1186 children[i].dispatchWindowFocusChanged(hasFocus);
1187 }
1188 }
1189
1190 /**
1191 * {@inheritDoc}
1192 */
1193 @Override
1194 public void addTouchables(ArrayList<View> views) {
1195 super.addTouchables(views);
1196
1197 final int count = mChildrenCount;
1198 final View[] children = mChildren;
1199
1200 for (int i = 0; i < count; i++) {
1201 final View child = children[i];
1202 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
1203 child.addTouchables(views);
1204 }
1205 }
1206 }
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001207
1208 /**
1209 * @hide
1210 */
1211 @Override
1212 public void makeOptionalFitsSystemWindows() {
1213 super.makeOptionalFitsSystemWindows();
1214 final int count = mChildrenCount;
1215 final View[] children = mChildren;
1216 for (int i = 0; i < count; i++) {
1217 children[i].makeOptionalFitsSystemWindows();
1218 }
1219 }
1220
Romain Guy43c9cdf2010-01-27 13:53:55 -08001221 /**
1222 * {@inheritDoc}
1223 */
1224 @Override
1225 public void dispatchDisplayHint(int hint) {
1226 super.dispatchDisplayHint(hint);
1227 final int count = mChildrenCount;
1228 final View[] children = mChildren;
1229 for (int i = 0; i < count; i++) {
1230 children[i].dispatchDisplayHint(hint);
1231 }
1232 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001233
1234 /**
Chet Haase0d299362012-01-26 10:51:48 -08001235 * Called when a view's visibility has changed. Notify the parent to take any appropriate
1236 * action.
1237 *
1238 * @param child The view whose visibility has changed
1239 * @param oldVisibility The previous visibility value (GONE, INVISIBLE, or VISIBLE).
1240 * @param newVisibility The new visibility value (GONE, INVISIBLE, or VISIBLE).
Chet Haase5e25c2c2010-09-16 11:15:56 -07001241 * @hide
Chet Haase5e25c2c2010-09-16 11:15:56 -07001242 */
Chet Haase0d299362012-01-26 10:51:48 -08001243 protected void onChildVisibilityChanged(View child, int oldVisibility, int newVisibility) {
Chet Haase5e25c2c2010-09-16 11:15:56 -07001244 if (mTransition != null) {
Chet Haase0d299362012-01-26 10:51:48 -08001245 if (newVisibility == VISIBLE) {
1246 mTransition.showChild(this, child, oldVisibility);
Chet Haase5e25c2c2010-09-16 11:15:56 -07001247 } else {
Chet Haase0d299362012-01-26 10:51:48 -08001248 mTransition.hideChild(this, child, newVisibility);
Chet Haase5e25c2c2010-09-16 11:15:56 -07001249 if (mTransitioningViews != null && mTransitioningViews.contains(child)) {
Chet Haaseddbb3462012-06-19 13:54:29 -07001250 // Only track this on disappearing views - appearing views are already visible
1251 // and don't need special handling during drawChild()
1252 if (mVisibilityChangingChildren == null) {
1253 mVisibilityChangingChildren = new ArrayList<View>();
1254 }
1255 mVisibilityChangingChildren.add(child);
Chet Haase5e25c2c2010-09-16 11:15:56 -07001256 addDisappearingView(child);
1257 }
1258 }
1259 }
Christopher Tate86cab1b2011-01-13 20:28:55 -08001260
1261 // in all cases, for drags
1262 if (mCurrentDrag != null) {
Chet Haase0d299362012-01-26 10:51:48 -08001263 if (newVisibility == VISIBLE) {
Christopher Tate86cab1b2011-01-13 20:28:55 -08001264 notifyChildOfDrag(child);
1265 }
1266 }
Chet Haase5e25c2c2010-09-16 11:15:56 -07001267 }
1268
1269 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001270 * {@inheritDoc}
1271 */
1272 @Override
Adam Powell326d8082009-12-09 15:10:07 -08001273 protected void dispatchVisibilityChanged(View changedView, int visibility) {
1274 super.dispatchVisibilityChanged(changedView, visibility);
1275 final int count = mChildrenCount;
1276 final View[] children = mChildren;
1277 for (int i = 0; i < count; i++) {
1278 children[i].dispatchVisibilityChanged(changedView, visibility);
1279 }
1280 }
1281
1282 /**
1283 * {@inheritDoc}
1284 */
1285 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001286 public void dispatchWindowVisibilityChanged(int visibility) {
1287 super.dispatchWindowVisibilityChanged(visibility);
1288 final int count = mChildrenCount;
1289 final View[] children = mChildren;
1290 for (int i = 0; i < count; i++) {
1291 children[i].dispatchWindowVisibilityChanged(visibility);
1292 }
1293 }
1294
1295 /**
1296 * {@inheritDoc}
1297 */
Dianne Hackborne36d6e22010-02-17 19:46:25 -08001298 @Override
1299 public void dispatchConfigurationChanged(Configuration newConfig) {
1300 super.dispatchConfigurationChanged(newConfig);
1301 final int count = mChildrenCount;
1302 final View[] children = mChildren;
1303 for (int i = 0; i < count; i++) {
1304 children[i].dispatchConfigurationChanged(newConfig);
1305 }
1306 }
1307
1308 /**
1309 * {@inheritDoc}
1310 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001311 public void recomputeViewAttributes(View child) {
Joe Onorato664644d2011-01-23 17:53:23 -08001312 if (mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) {
1313 ViewParent parent = mParent;
1314 if (parent != null) parent.recomputeViewAttributes(this);
1315 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001316 }
Romain Guy8506ab42009-06-11 17:35:47 -07001317
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001318 @Override
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001319 void dispatchCollectViewAttributes(AttachInfo attachInfo, int visibility) {
1320 if ((visibility & VISIBILITY_MASK) == VISIBLE) {
1321 super.dispatchCollectViewAttributes(attachInfo, visibility);
1322 final int count = mChildrenCount;
1323 final View[] children = mChildren;
1324 for (int i = 0; i < count; i++) {
1325 final View child = children[i];
1326 child.dispatchCollectViewAttributes(attachInfo,
1327 visibility | (child.mViewFlags&VISIBILITY_MASK));
1328 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001329 }
1330 }
1331
1332 /**
1333 * {@inheritDoc}
1334 */
1335 public void bringChildToFront(View child) {
Alan Viverette77bb6f12015-02-11 17:24:33 -08001336 final int index = indexOfChild(child);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001337 if (index >= 0) {
1338 removeFromArray(index);
1339 addInArray(child, mChildrenCount);
1340 child.mParent = this;
Chet Haasecb96db82013-09-04 10:21:46 -07001341 requestLayout();
1342 invalidate();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001343 }
1344 }
1345
Romain Guy6410c0a2013-06-17 11:21:58 -07001346 private PointF getLocalPoint() {
1347 if (mLocalPoint == null) mLocalPoint = new PointF();
1348 return mLocalPoint;
1349 }
1350
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001351 /**
1352 * {@inheritDoc}
Christopher Tatea53146c2010-09-07 11:57:52 -07001353 */
Steve Block8a7259b2012-03-01 11:24:41 +00001354 // TODO: Write real docs
Christopher Tatea53146c2010-09-07 11:57:52 -07001355 @Override
1356 public boolean dispatchDragEvent(DragEvent event) {
1357 boolean retval = false;
1358 final float tx = event.mX;
1359 final float ty = event.mY;
1360
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07001361 ViewRootImpl root = getViewRootImpl();
Christopher Tatea53146c2010-09-07 11:57:52 -07001362
1363 // Dispatch down the view hierarchy
Romain Guy6410c0a2013-06-17 11:21:58 -07001364 final PointF localPoint = getLocalPoint();
1365
Christopher Tatea53146c2010-09-07 11:57:52 -07001366 switch (event.mAction) {
1367 case DragEvent.ACTION_DRAG_STARTED: {
1368 // clear state to recalculate which views we drag over
Chris Tate9d1ab882010-11-02 15:55:39 -07001369 mCurrentDragView = null;
Christopher Tatea53146c2010-09-07 11:57:52 -07001370
Christopher Tate86cab1b2011-01-13 20:28:55 -08001371 // Set up our tracking of drag-started notifications
1372 mCurrentDrag = DragEvent.obtain(event);
1373 if (mDragNotifiedChildren == null) {
1374 mDragNotifiedChildren = new HashSet<View>();
1375 } else {
1376 mDragNotifiedChildren.clear();
1377 }
1378
Christopher Tatea53146c2010-09-07 11:57:52 -07001379 // Now dispatch down to our children, caching the responses
1380 mChildAcceptsDrag = false;
1381 final int count = mChildrenCount;
1382 final View[] children = mChildren;
1383 for (int i = 0; i < count; i++) {
Christopher Tate2c095f32010-10-04 14:13:40 -07001384 final View child = children[i];
Christopher Tate3d4bf172011-03-28 16:16:46 -07001385 child.mPrivateFlags2 &= ~View.DRAG_MASK;
Christopher Tate2c095f32010-10-04 14:13:40 -07001386 if (child.getVisibility() == VISIBLE) {
Christopher Tate86cab1b2011-01-13 20:28:55 -08001387 final boolean handled = notifyChildOfDrag(children[i]);
Christopher Tate2c095f32010-10-04 14:13:40 -07001388 if (handled) {
1389 mChildAcceptsDrag = true;
1390 }
Christopher Tatea53146c2010-09-07 11:57:52 -07001391 }
1392 }
1393
1394 // Return HANDLED if one of our children can accept the drag
1395 if (mChildAcceptsDrag) {
1396 retval = true;
1397 }
1398 } break;
1399
1400 case DragEvent.ACTION_DRAG_ENDED: {
Christopher Tate86cab1b2011-01-13 20:28:55 -08001401 // Release the bookkeeping now that the drag lifecycle has ended
Christopher Tate1fc014f2011-01-19 12:56:26 -08001402 if (mDragNotifiedChildren != null) {
1403 for (View child : mDragNotifiedChildren) {
1404 // If a child was notified about an ongoing drag, it's told that it's over
1405 child.dispatchDragEvent(event);
Christopher Tate3d4bf172011-03-28 16:16:46 -07001406 child.mPrivateFlags2 &= ~View.DRAG_MASK;
1407 child.refreshDrawableState();
Christopher Tate1fc014f2011-01-19 12:56:26 -08001408 }
1409
1410 mDragNotifiedChildren.clear();
Christopher Tatee9accff2013-03-04 12:57:23 -08001411 if (mCurrentDrag != null) {
1412 mCurrentDrag.recycle();
1413 mCurrentDrag = null;
1414 }
Christopher Tate1fc014f2011-01-19 12:56:26 -08001415 }
Christopher Tate86cab1b2011-01-13 20:28:55 -08001416
Christopher Tatea53146c2010-09-07 11:57:52 -07001417 // We consider drag-ended to have been handled if one of our children
1418 // had offered to handle the drag.
1419 if (mChildAcceptsDrag) {
1420 retval = true;
1421 }
1422 } break;
1423
1424 case DragEvent.ACTION_DRAG_LOCATION: {
1425 // Find the [possibly new] drag target
Romain Guy6410c0a2013-06-17 11:21:58 -07001426 final View target = findFrontmostDroppableChildAt(event.mX, event.mY, localPoint);
Christopher Tatea53146c2010-09-07 11:57:52 -07001427
1428 // If we've changed apparent drag target, tell the view root which view
Chris Tate9d1ab882010-11-02 15:55:39 -07001429 // we're over now [for purposes of the eventual drag-recipient-changed
1430 // notifications to the framework] and tell the new target that the drag
1431 // has entered its bounds. The root will see setDragFocus() calls all
1432 // the way down to the final leaf view that is handling the LOCATION event
1433 // before reporting the new potential recipient to the framework.
Christopher Tatea53146c2010-09-07 11:57:52 -07001434 if (mCurrentDragView != target) {
Chris Tate9d1ab882010-11-02 15:55:39 -07001435 root.setDragFocus(target);
1436
1437 final int action = event.mAction;
1438 // If we've dragged off of a child view, send it the EXITED message
1439 if (mCurrentDragView != null) {
Christopher Tate3d4bf172011-03-28 16:16:46 -07001440 final View view = mCurrentDragView;
Chris Tate9d1ab882010-11-02 15:55:39 -07001441 event.mAction = DragEvent.ACTION_DRAG_EXITED;
Christopher Tate3d4bf172011-03-28 16:16:46 -07001442 view.dispatchDragEvent(event);
Dianne Hackborn4702a852012-08-17 15:18:29 -07001443 view.mPrivateFlags2 &= ~View.PFLAG2_DRAG_HOVERED;
Christopher Tate3d4bf172011-03-28 16:16:46 -07001444 view.refreshDrawableState();
Chris Tate9d1ab882010-11-02 15:55:39 -07001445 }
Christopher Tatea53146c2010-09-07 11:57:52 -07001446 mCurrentDragView = target;
Chris Tate9d1ab882010-11-02 15:55:39 -07001447
1448 // If we've dragged over a new child view, send it the ENTERED message
1449 if (target != null) {
1450 event.mAction = DragEvent.ACTION_DRAG_ENTERED;
1451 target.dispatchDragEvent(event);
Dianne Hackborn4702a852012-08-17 15:18:29 -07001452 target.mPrivateFlags2 |= View.PFLAG2_DRAG_HOVERED;
Christopher Tate3d4bf172011-03-28 16:16:46 -07001453 target.refreshDrawableState();
Chris Tate9d1ab882010-11-02 15:55:39 -07001454 }
1455 event.mAction = action; // restore the event's original state
Christopher Tatea53146c2010-09-07 11:57:52 -07001456 }
Christopher Tate2c095f32010-10-04 14:13:40 -07001457
Christopher Tatea53146c2010-09-07 11:57:52 -07001458 // Dispatch the actual drag location notice, localized into its coordinates
1459 if (target != null) {
Romain Guy6410c0a2013-06-17 11:21:58 -07001460 event.mX = localPoint.x;
1461 event.mY = localPoint.y;
Christopher Tatea53146c2010-09-07 11:57:52 -07001462
1463 retval = target.dispatchDragEvent(event);
1464
1465 event.mX = tx;
1466 event.mY = ty;
1467 }
1468 } break;
1469
Chris Tate9d1ab882010-11-02 15:55:39 -07001470 /* Entered / exited dispatch
1471 *
1472 * DRAG_ENTERED is not dispatched downwards from ViewGroup. The reason for this is
1473 * that we're about to get the corresponding LOCATION event, which we will use to
1474 * determine which of our children is the new target; at that point we will
1475 * push a DRAG_ENTERED down to the new target child [which may itself be a ViewGroup].
1476 *
1477 * DRAG_EXITED *is* dispatched all the way down immediately: once we know the
1478 * drag has left this ViewGroup, we know by definition that every contained subview
1479 * is also no longer under the drag point.
1480 */
1481
1482 case DragEvent.ACTION_DRAG_EXITED: {
1483 if (mCurrentDragView != null) {
Christopher Tate3d4bf172011-03-28 16:16:46 -07001484 final View view = mCurrentDragView;
1485 view.dispatchDragEvent(event);
Dianne Hackborn4702a852012-08-17 15:18:29 -07001486 view.mPrivateFlags2 &= ~View.PFLAG2_DRAG_HOVERED;
Christopher Tate3d4bf172011-03-28 16:16:46 -07001487 view.refreshDrawableState();
1488
Chris Tate9d1ab882010-11-02 15:55:39 -07001489 mCurrentDragView = null;
1490 }
1491 } break;
1492
Christopher Tatea53146c2010-09-07 11:57:52 -07001493 case DragEvent.ACTION_DROP: {
Christopher Tate2c095f32010-10-04 14:13:40 -07001494 if (ViewDebug.DEBUG_DRAG) Log.d(View.VIEW_LOG_TAG, "Drop event: " + event);
Romain Guy6410c0a2013-06-17 11:21:58 -07001495 View target = findFrontmostDroppableChildAt(event.mX, event.mY, localPoint);
Christopher Tatea53146c2010-09-07 11:57:52 -07001496 if (target != null) {
Christopher Tate5ada6cb2010-10-05 14:15:29 -07001497 if (ViewDebug.DEBUG_DRAG) Log.d(View.VIEW_LOG_TAG, " dispatch drop to " + target);
Romain Guy6410c0a2013-06-17 11:21:58 -07001498 event.mX = localPoint.x;
1499 event.mY = localPoint.y;
Christopher Tatea53146c2010-09-07 11:57:52 -07001500 retval = target.dispatchDragEvent(event);
1501 event.mX = tx;
1502 event.mY = ty;
Christopher Tate5ada6cb2010-10-05 14:15:29 -07001503 } else {
1504 if (ViewDebug.DEBUG_DRAG) {
1505 Log.d(View.VIEW_LOG_TAG, " not dropped on an accepting view");
1506 }
Christopher Tatea53146c2010-09-07 11:57:52 -07001507 }
1508 } break;
1509 }
1510
1511 // If none of our children could handle the event, try here
1512 if (!retval) {
Chris Tate32affef2010-10-18 15:29:21 -07001513 // Call up to the View implementation that dispatches to installed listeners
1514 retval = super.dispatchDragEvent(event);
Christopher Tatea53146c2010-09-07 11:57:52 -07001515 }
1516 return retval;
1517 }
1518
1519 // Find the frontmost child view that lies under the given point, and calculate
1520 // the position within its own local coordinate system.
1521 View findFrontmostDroppableChildAt(float x, float y, PointF outLocalPoint) {
Christopher Tatea53146c2010-09-07 11:57:52 -07001522 final int count = mChildrenCount;
1523 final View[] children = mChildren;
1524 for (int i = count - 1; i >= 0; i--) {
1525 final View child = children[i];
Christopher Tate3d4bf172011-03-28 16:16:46 -07001526 if (!child.canAcceptDrag()) {
Christopher Tatea53146c2010-09-07 11:57:52 -07001527 continue;
1528 }
1529
Christopher Tate2c095f32010-10-04 14:13:40 -07001530 if (isTransformedTouchPointInView(x, y, child, outLocalPoint)) {
Christopher Tatea53146c2010-09-07 11:57:52 -07001531 return child;
1532 }
1533 }
1534 return null;
1535 }
1536
Christopher Tate86cab1b2011-01-13 20:28:55 -08001537 boolean notifyChildOfDrag(View child) {
1538 if (ViewDebug.DEBUG_DRAG) {
1539 Log.d(View.VIEW_LOG_TAG, "Sending drag-started to view: " + child);
1540 }
1541
Christopher Tate3d4bf172011-03-28 16:16:46 -07001542 boolean canAccept = false;
Christopher Tate86cab1b2011-01-13 20:28:55 -08001543 if (! mDragNotifiedChildren.contains(child)) {
1544 mDragNotifiedChildren.add(child);
Christopher Tate3d4bf172011-03-28 16:16:46 -07001545 canAccept = child.dispatchDragEvent(mCurrentDrag);
1546 if (canAccept && !child.canAcceptDrag()) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07001547 child.mPrivateFlags2 |= View.PFLAG2_DRAG_CAN_ACCEPT;
Christopher Tate3d4bf172011-03-28 16:16:46 -07001548 child.refreshDrawableState();
1549 }
Christopher Tate86cab1b2011-01-13 20:28:55 -08001550 }
Christopher Tate3d4bf172011-03-28 16:16:46 -07001551 return canAccept;
Christopher Tate86cab1b2011-01-13 20:28:55 -08001552 }
1553
Joe Onorato664644d2011-01-23 17:53:23 -08001554 @Override
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001555 public void dispatchWindowSystemUiVisiblityChanged(int visible) {
1556 super.dispatchWindowSystemUiVisiblityChanged(visible);
1557
1558 final int count = mChildrenCount;
1559 final View[] children = mChildren;
1560 for (int i=0; i <count; i++) {
1561 final View child = children[i];
1562 child.dispatchWindowSystemUiVisiblityChanged(visible);
1563 }
1564 }
1565
1566 @Override
Joe Onorato664644d2011-01-23 17:53:23 -08001567 public void dispatchSystemUiVisibilityChanged(int visible) {
1568 super.dispatchSystemUiVisibilityChanged(visible);
1569
1570 final int count = mChildrenCount;
1571 final View[] children = mChildren;
1572 for (int i=0; i <count; i++) {
1573 final View child = children[i];
1574 child.dispatchSystemUiVisibilityChanged(visible);
1575 }
1576 }
1577
Dianne Hackborn9a230e02011-10-06 11:51:27 -07001578 @Override
Dianne Hackborncf675782012-05-10 15:07:24 -07001579 boolean updateLocalSystemUiVisibility(int localValue, int localChanges) {
1580 boolean changed = super.updateLocalSystemUiVisibility(localValue, localChanges);
Dianne Hackborn9a230e02011-10-06 11:51:27 -07001581
1582 final int count = mChildrenCount;
1583 final View[] children = mChildren;
1584 for (int i=0; i <count; i++) {
1585 final View child = children[i];
Dianne Hackborncf675782012-05-10 15:07:24 -07001586 changed |= child.updateLocalSystemUiVisibility(localValue, localChanges);
Dianne Hackborn9a230e02011-10-06 11:51:27 -07001587 }
Dianne Hackborncf675782012-05-10 15:07:24 -07001588 return changed;
Dianne Hackborn9a230e02011-10-06 11:51:27 -07001589 }
1590
Christopher Tatea53146c2010-09-07 11:57:52 -07001591 /**
1592 * {@inheritDoc}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001593 */
1594 @Override
1595 public boolean dispatchKeyEventPreIme(KeyEvent event) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07001596 if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
1597 == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001598 return super.dispatchKeyEventPreIme(event);
Dianne Hackborn4702a852012-08-17 15:18:29 -07001599 } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
1600 == PFLAG_HAS_BOUNDS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001601 return mFocused.dispatchKeyEventPreIme(event);
1602 }
1603 return false;
1604 }
1605
1606 /**
1607 * {@inheritDoc}
1608 */
1609 @Override
1610 public boolean dispatchKeyEvent(KeyEvent event) {
Jeff Brown21bc5c92011-02-28 18:27:14 -08001611 if (mInputEventConsistencyVerifier != null) {
1612 mInputEventConsistencyVerifier.onKeyEvent(event, 1);
1613 }
1614
Dianne Hackborn4702a852012-08-17 15:18:29 -07001615 if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
1616 == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001617 if (super.dispatchKeyEvent(event)) {
1618 return true;
1619 }
Dianne Hackborn4702a852012-08-17 15:18:29 -07001620 } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
1621 == PFLAG_HAS_BOUNDS) {
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001622 if (mFocused.dispatchKeyEvent(event)) {
1623 return true;
1624 }
1625 }
1626
1627 if (mInputEventConsistencyVerifier != null) {
1628 mInputEventConsistencyVerifier.onUnhandledEvent(event, 1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001629 }
1630 return false;
1631 }
1632
1633 /**
1634 * {@inheritDoc}
1635 */
1636 @Override
1637 public boolean dispatchKeyShortcutEvent(KeyEvent event) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07001638 if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
1639 == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001640 return super.dispatchKeyShortcutEvent(event);
Dianne Hackborn4702a852012-08-17 15:18:29 -07001641 } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
1642 == PFLAG_HAS_BOUNDS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001643 return mFocused.dispatchKeyShortcutEvent(event);
1644 }
1645 return false;
1646 }
1647
1648 /**
1649 * {@inheritDoc}
1650 */
1651 @Override
1652 public boolean dispatchTrackballEvent(MotionEvent event) {
Jeff Brown21bc5c92011-02-28 18:27:14 -08001653 if (mInputEventConsistencyVerifier != null) {
1654 mInputEventConsistencyVerifier.onTrackballEvent(event, 1);
1655 }
1656
Dianne Hackborn4702a852012-08-17 15:18:29 -07001657 if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
1658 == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001659 if (super.dispatchTrackballEvent(event)) {
1660 return true;
1661 }
Dianne Hackborn4702a852012-08-17 15:18:29 -07001662 } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
1663 == PFLAG_HAS_BOUNDS) {
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001664 if (mFocused.dispatchTrackballEvent(event)) {
1665 return true;
1666 }
1667 }
1668
1669 if (mInputEventConsistencyVerifier != null) {
1670 mInputEventConsistencyVerifier.onUnhandledEvent(event, 1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001671 }
1672 return false;
1673 }
1674
Jeff Brown10b62902011-06-20 16:40:37 -07001675 /**
1676 * {@inheritDoc}
1677 */
Romain Guya9489272011-06-22 20:58:11 -07001678 @SuppressWarnings({"ConstantConditions"})
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001679 @Override
Jeff Browna032cc02011-03-07 16:56:21 -08001680 protected boolean dispatchHoverEvent(MotionEvent event) {
Jeff Browna032cc02011-03-07 16:56:21 -08001681 final int action = event.getAction();
Jeff Browna032cc02011-03-07 16:56:21 -08001682
Jeff Brown10b62902011-06-20 16:40:37 -07001683 // First check whether the view group wants to intercept the hover event.
1684 final boolean interceptHover = onInterceptHoverEvent(event);
1685 event.setAction(action); // restore action in case it was changed
1686
Jeff Brown87b7f802011-06-21 18:35:45 -07001687 MotionEvent eventNoHistory = event;
1688 boolean handled = false;
1689
1690 // Send events to the hovered children and build a new list of hover targets until
1691 // one is found that handles the event.
1692 HoverTarget firstOldHoverTarget = mFirstHoverTarget;
1693 mFirstHoverTarget = null;
Jeff Brown10b62902011-06-20 16:40:37 -07001694 if (!interceptHover && action != MotionEvent.ACTION_HOVER_EXIT) {
Jeff Browna032cc02011-03-07 16:56:21 -08001695 final float x = event.getX();
1696 final float y = event.getY();
Jeff Brown33bbfd22011-02-24 20:55:35 -08001697 final int childrenCount = mChildrenCount;
1698 if (childrenCount != 0) {
Chris Craikab008f02014-05-23 17:55:03 -07001699 final ArrayList<View> preorderedList = buildOrderedChildList();
1700 final boolean customOrder = preorderedList == null
1701 && isChildrenDrawingOrderEnabled();
Jeff Brown33bbfd22011-02-24 20:55:35 -08001702 final View[] children = mChildren;
Jeff Brown87b7f802011-06-21 18:35:45 -07001703 HoverTarget lastHoverTarget = null;
Jeff Brown33bbfd22011-02-24 20:55:35 -08001704 for (int i = childrenCount - 1; i >= 0; i--) {
Chris Craikab008f02014-05-23 17:55:03 -07001705 int childIndex = customOrder ? getChildDrawingOrder(childrenCount, i) : i;
1706 final View child = (preorderedList == null)
1707 ? children[childIndex] : preorderedList.get(childIndex);
Jeff Brown87b7f802011-06-21 18:35:45 -07001708 if (!canViewReceivePointerEvents(child)
1709 || !isTransformedTouchPointInView(x, y, child, null)) {
1710 continue;
1711 }
1712
1713 // Obtain a hover target for this child. Dequeue it from the
1714 // old hover target list if the child was previously hovered.
1715 HoverTarget hoverTarget = firstOldHoverTarget;
1716 final boolean wasHovered;
1717 for (HoverTarget predecessor = null; ;) {
1718 if (hoverTarget == null) {
1719 hoverTarget = HoverTarget.obtain(child);
1720 wasHovered = false;
1721 break;
1722 }
1723
1724 if (hoverTarget.child == child) {
1725 if (predecessor != null) {
1726 predecessor.next = hoverTarget.next;
1727 } else {
1728 firstOldHoverTarget = hoverTarget.next;
1729 }
1730 hoverTarget.next = null;
1731 wasHovered = true;
1732 break;
1733 }
1734
1735 predecessor = hoverTarget;
1736 hoverTarget = hoverTarget.next;
1737 }
1738
1739 // Enqueue the hover target onto the new hover target list.
1740 if (lastHoverTarget != null) {
1741 lastHoverTarget.next = hoverTarget;
1742 } else {
Jeff Brown87b7f802011-06-21 18:35:45 -07001743 mFirstHoverTarget = hoverTarget;
1744 }
Sangkyu Lee8725f362013-03-13 09:38:45 +09001745 lastHoverTarget = hoverTarget;
Jeff Brown87b7f802011-06-21 18:35:45 -07001746
1747 // Dispatch the event to the child.
1748 if (action == MotionEvent.ACTION_HOVER_ENTER) {
1749 if (!wasHovered) {
1750 // Send the enter as is.
1751 handled |= dispatchTransformedGenericPointerEvent(
1752 event, child); // enter
1753 }
1754 } else if (action == MotionEvent.ACTION_HOVER_MOVE) {
1755 if (!wasHovered) {
1756 // Synthesize an enter from a move.
1757 eventNoHistory = obtainMotionEventNoHistoryOrSelf(eventNoHistory);
1758 eventNoHistory.setAction(MotionEvent.ACTION_HOVER_ENTER);
1759 handled |= dispatchTransformedGenericPointerEvent(
1760 eventNoHistory, child); // enter
1761 eventNoHistory.setAction(action);
1762
1763 handled |= dispatchTransformedGenericPointerEvent(
1764 eventNoHistory, child); // move
1765 } else {
1766 // Send the move as is.
1767 handled |= dispatchTransformedGenericPointerEvent(event, child);
1768 }
1769 }
1770 if (handled) {
Jeff Brown10b62902011-06-20 16:40:37 -07001771 break;
Jeff Brown33bbfd22011-02-24 20:55:35 -08001772 }
Jeff Brown10b62902011-06-20 16:40:37 -07001773 }
Chris Craikab008f02014-05-23 17:55:03 -07001774 if (preorderedList != null) preorderedList.clear();
Jeff Brown10b62902011-06-20 16:40:37 -07001775 }
1776 }
Jeff Brown33bbfd22011-02-24 20:55:35 -08001777
Jeff Brown87b7f802011-06-21 18:35:45 -07001778 // Send exit events to all previously hovered children that are no longer hovered.
1779 while (firstOldHoverTarget != null) {
1780 final View child = firstOldHoverTarget.child;
Jeff Brown10b62902011-06-20 16:40:37 -07001781
Jeff Brown87b7f802011-06-21 18:35:45 -07001782 // Exit the old hovered child.
1783 if (action == MotionEvent.ACTION_HOVER_EXIT) {
1784 // Send the exit as is.
1785 handled |= dispatchTransformedGenericPointerEvent(
1786 event, child); // exit
1787 } else {
1788 // Synthesize an exit from a move or enter.
1789 // Ignore the result because hover focus has moved to a different view.
1790 if (action == MotionEvent.ACTION_HOVER_MOVE) {
Jeff Brown10b62902011-06-20 16:40:37 -07001791 dispatchTransformedGenericPointerEvent(
Jeff Brown87b7f802011-06-21 18:35:45 -07001792 event, child); // move
Jeff Brown10b62902011-06-20 16:40:37 -07001793 }
Jeff Brown87b7f802011-06-21 18:35:45 -07001794 eventNoHistory = obtainMotionEventNoHistoryOrSelf(eventNoHistory);
1795 eventNoHistory.setAction(MotionEvent.ACTION_HOVER_EXIT);
1796 dispatchTransformedGenericPointerEvent(
1797 eventNoHistory, child); // exit
1798 eventNoHistory.setAction(action);
Jeff Brown10b62902011-06-20 16:40:37 -07001799 }
1800
Jeff Brown87b7f802011-06-21 18:35:45 -07001801 final HoverTarget nextOldHoverTarget = firstOldHoverTarget.next;
1802 firstOldHoverTarget.recycle();
1803 firstOldHoverTarget = nextOldHoverTarget;
Jeff Brown10b62902011-06-20 16:40:37 -07001804 }
1805
Jeff Brown87b7f802011-06-21 18:35:45 -07001806 // Send events to the view group itself if no children have handled it.
Jeff Brown10b62902011-06-20 16:40:37 -07001807 boolean newHoveredSelf = !handled;
1808 if (newHoveredSelf == mHoveredSelf) {
1809 if (newHoveredSelf) {
1810 // Send event to the view group as before.
1811 handled |= super.dispatchHoverEvent(event);
1812 }
1813 } else {
1814 if (mHoveredSelf) {
1815 // Exit the view group.
1816 if (action == MotionEvent.ACTION_HOVER_EXIT) {
1817 // Send the exit as is.
1818 handled |= super.dispatchHoverEvent(event); // exit
1819 } else {
1820 // Synthesize an exit from a move or enter.
1821 // Ignore the result because hover focus is moving to a different view.
1822 if (action == MotionEvent.ACTION_HOVER_MOVE) {
1823 super.dispatchHoverEvent(event); // move
1824 }
1825 eventNoHistory = obtainMotionEventNoHistoryOrSelf(eventNoHistory);
1826 eventNoHistory.setAction(MotionEvent.ACTION_HOVER_EXIT);
1827 super.dispatchHoverEvent(eventNoHistory); // exit
1828 eventNoHistory.setAction(action);
1829 }
1830 mHoveredSelf = false;
1831 }
1832
1833 if (newHoveredSelf) {
1834 // Enter the view group.
1835 if (action == MotionEvent.ACTION_HOVER_ENTER) {
1836 // Send the enter as is.
1837 handled |= super.dispatchHoverEvent(event); // enter
1838 mHoveredSelf = true;
1839 } else if (action == MotionEvent.ACTION_HOVER_MOVE) {
1840 // Synthesize an enter from a move.
1841 eventNoHistory = obtainMotionEventNoHistoryOrSelf(eventNoHistory);
1842 eventNoHistory.setAction(MotionEvent.ACTION_HOVER_ENTER);
1843 handled |= super.dispatchHoverEvent(eventNoHistory); // enter
1844 eventNoHistory.setAction(action);
1845
1846 handled |= super.dispatchHoverEvent(eventNoHistory); // move
1847 mHoveredSelf = true;
Jeff Brown33bbfd22011-02-24 20:55:35 -08001848 }
1849 }
Jeff Brown33bbfd22011-02-24 20:55:35 -08001850 }
1851
Jeff Browna032cc02011-03-07 16:56:21 -08001852 // Recycle the copy of the event that we made.
1853 if (eventNoHistory != event) {
1854 eventNoHistory.recycle();
1855 }
1856
Jeff Browna032cc02011-03-07 16:56:21 -08001857 // Done.
1858 return handled;
1859 }
1860
Jeff Brown59a422e2012-04-19 15:19:19 -07001861 private void exitHoverTargets() {
1862 if (mHoveredSelf || mFirstHoverTarget != null) {
1863 final long now = SystemClock.uptimeMillis();
1864 MotionEvent event = MotionEvent.obtain(now, now,
1865 MotionEvent.ACTION_HOVER_EXIT, 0.0f, 0.0f, 0);
1866 event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
1867 dispatchHoverEvent(event);
1868 event.recycle();
1869 }
1870 }
1871
1872 private void cancelHoverTarget(View view) {
1873 HoverTarget predecessor = null;
1874 HoverTarget target = mFirstHoverTarget;
1875 while (target != null) {
1876 final HoverTarget next = target.next;
1877 if (target.child == view) {
1878 if (predecessor == null) {
1879 mFirstHoverTarget = next;
1880 } else {
1881 predecessor.next = next;
1882 }
1883 target.recycle();
1884
1885 final long now = SystemClock.uptimeMillis();
1886 MotionEvent event = MotionEvent.obtain(now, now,
1887 MotionEvent.ACTION_HOVER_EXIT, 0.0f, 0.0f, 0);
1888 event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
1889 view.dispatchHoverEvent(event);
1890 event.recycle();
1891 return;
1892 }
1893 predecessor = target;
1894 target = next;
1895 }
1896 }
1897
Jeff Brown87b7f802011-06-21 18:35:45 -07001898 /** @hide */
1899 @Override
1900 protected boolean hasHoveredChild() {
1901 return mFirstHoverTarget != null;
1902 }
1903
Svetoslav Ganov42138042012-03-20 11:51:39 -07001904 @Override
1905 public void addChildrenForAccessibility(ArrayList<View> childrenForAccessibility) {
Svetoslav Ganov76f287e2012-04-23 11:02:36 -07001906 ChildListForAccessibility children = ChildListForAccessibility.obtain(this, true);
1907 try {
1908 final int childrenCount = children.getChildCount();
1909 for (int i = 0; i < childrenCount; i++) {
1910 View child = children.getChildAt(i);
Svetoslav Ganovc406be92012-05-11 16:12:32 -07001911 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
Svetoslav Ganov76f287e2012-04-23 11:02:36 -07001912 if (child.includeForAccessibility()) {
1913 childrenForAccessibility.add(child);
1914 } else {
1915 child.addChildrenForAccessibility(childrenForAccessibility);
1916 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07001917 }
1918 }
Svetoslav Ganov76f287e2012-04-23 11:02:36 -07001919 } finally {
1920 children.recycle();
Svetoslav Ganov42138042012-03-20 11:51:39 -07001921 }
1922 }
1923
1924 /**
Jeff Brown10b62902011-06-20 16:40:37 -07001925 * Implement this method to intercept hover events before they are handled
1926 * by child views.
1927 * <p>
1928 * This method is called before dispatching a hover event to a child of
1929 * the view group or to the view group's own {@link #onHoverEvent} to allow
1930 * the view group a chance to intercept the hover event.
1931 * This method can also be used to watch all pointer motions that occur within
1932 * the bounds of the view group even when the pointer is hovering over
1933 * a child of the view group rather than over the view group itself.
1934 * </p><p>
1935 * The view group can prevent its children from receiving hover events by
1936 * implementing this method and returning <code>true</code> to indicate
1937 * that it would like to intercept hover events. The view group must
1938 * continuously return <code>true</code> from {@link #onInterceptHoverEvent}
1939 * for as long as it wishes to continue intercepting hover events from
1940 * its children.
1941 * </p><p>
1942 * Interception preserves the invariant that at most one view can be
1943 * hovered at a time by transferring hover focus from the currently hovered
1944 * child to the view group or vice-versa as needed.
1945 * </p><p>
1946 * If this method returns <code>true</code> and a child is already hovered, then the
1947 * child view will first receive a hover exit event and then the view group
1948 * itself will receive a hover enter event in {@link #onHoverEvent}.
1949 * Likewise, if this method had previously returned <code>true</code> to intercept hover
1950 * events and instead returns <code>false</code> while the pointer is hovering
1951 * within the bounds of one of a child, then the view group will first receive a
1952 * hover exit event in {@link #onHoverEvent} and then the hovered child will
1953 * receive a hover enter event.
1954 * </p><p>
1955 * The default implementation always returns false.
1956 * </p>
1957 *
1958 * @param event The motion event that describes the hover.
1959 * @return True if the view group would like to intercept the hover event
1960 * and prevent its children from receiving it.
1961 */
1962 public boolean onInterceptHoverEvent(MotionEvent event) {
Svetoslav Ganov736c2752011-04-22 18:30:36 -07001963 return false;
1964 }
1965
Jeff Browna032cc02011-03-07 16:56:21 -08001966 private static MotionEvent obtainMotionEventNoHistoryOrSelf(MotionEvent event) {
1967 if (event.getHistorySize() == 0) {
1968 return event;
1969 }
1970 return MotionEvent.obtainNoHistory(event);
1971 }
1972
Jeff Brown10b62902011-06-20 16:40:37 -07001973 /**
1974 * {@inheritDoc}
1975 */
Jeff Browna032cc02011-03-07 16:56:21 -08001976 @Override
1977 protected boolean dispatchGenericPointerEvent(MotionEvent event) {
1978 // Send the event to the child under the pointer.
1979 final int childrenCount = mChildrenCount;
1980 if (childrenCount != 0) {
Jeff Browna032cc02011-03-07 16:56:21 -08001981 final float x = event.getX();
1982 final float y = event.getY();
1983
Chris Craikab008f02014-05-23 17:55:03 -07001984 final ArrayList<View> preorderedList = buildOrderedChildList();
1985 final boolean customOrder = preorderedList == null
1986 && isChildrenDrawingOrderEnabled();
1987 final View[] children = mChildren;
Jeff Browna032cc02011-03-07 16:56:21 -08001988 for (int i = childrenCount - 1; i >= 0; i--) {
Chris Craikab008f02014-05-23 17:55:03 -07001989 int childIndex = customOrder ? getChildDrawingOrder(childrenCount, i) : i;
1990 final View child = (preorderedList == null)
1991 ? children[childIndex] : preorderedList.get(childIndex);
Jeff Browna032cc02011-03-07 16:56:21 -08001992 if (!canViewReceivePointerEvents(child)
1993 || !isTransformedTouchPointInView(x, y, child, null)) {
1994 continue;
1995 }
1996
1997 if (dispatchTransformedGenericPointerEvent(event, child)) {
Chris Craikab008f02014-05-23 17:55:03 -07001998 if (preorderedList != null) preorderedList.clear();
Jeff Browna032cc02011-03-07 16:56:21 -08001999 return true;
2000 }
2001 }
Chris Craikab008f02014-05-23 17:55:03 -07002002 if (preorderedList != null) preorderedList.clear();
Jeff Browna032cc02011-03-07 16:56:21 -08002003 }
2004
2005 // No child handled the event. Send it to this view group.
2006 return super.dispatchGenericPointerEvent(event);
2007 }
2008
Jeff Brown10b62902011-06-20 16:40:37 -07002009 /**
2010 * {@inheritDoc}
2011 */
Jeff Browna032cc02011-03-07 16:56:21 -08002012 @Override
2013 protected boolean dispatchGenericFocusedEvent(MotionEvent event) {
Jeff Brown33bbfd22011-02-24 20:55:35 -08002014 // Send the event to the focused child or to this view group if it has focus.
Dianne Hackborn4702a852012-08-17 15:18:29 -07002015 if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
2016 == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
Jeff Browna032cc02011-03-07 16:56:21 -08002017 return super.dispatchGenericFocusedEvent(event);
Dianne Hackborn4702a852012-08-17 15:18:29 -07002018 } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
2019 == PFLAG_HAS_BOUNDS) {
Jeff Browncb1404e2011-01-15 18:14:15 -08002020 return mFocused.dispatchGenericMotionEvent(event);
2021 }
2022 return false;
2023 }
2024
2025 /**
Jeff Browna032cc02011-03-07 16:56:21 -08002026 * Dispatches a generic pointer event to a child, taking into account
2027 * transformations that apply to the child.
2028 *
2029 * @param event The event to send.
2030 * @param child The view to send the event to.
2031 * @return {@code true} if the child handled the event.
2032 */
2033 private boolean dispatchTransformedGenericPointerEvent(MotionEvent event, View child) {
2034 final float offsetX = mScrollX - child.mLeft;
2035 final float offsetY = mScrollY - child.mTop;
2036
2037 boolean handled;
2038 if (!child.hasIdentityMatrix()) {
2039 MotionEvent transformedEvent = MotionEvent.obtain(event);
2040 transformedEvent.offsetLocation(offsetX, offsetY);
2041 transformedEvent.transform(child.getInverseMatrix());
2042 handled = child.dispatchGenericMotionEvent(transformedEvent);
2043 transformedEvent.recycle();
2044 } else {
2045 event.offsetLocation(offsetX, offsetY);
2046 handled = child.dispatchGenericMotionEvent(event);
2047 event.offsetLocation(-offsetX, -offsetY);
2048 }
2049 return handled;
2050 }
2051
2052 /**
Jeff Browncb1404e2011-01-15 18:14:15 -08002053 * {@inheritDoc}
2054 */
2055 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002056 public boolean dispatchTouchEvent(MotionEvent ev) {
Jeff Brown21bc5c92011-02-28 18:27:14 -08002057 if (mInputEventConsistencyVerifier != null) {
2058 mInputEventConsistencyVerifier.onTouchEvent(ev, 1);
2059 }
2060
Svet Ganov0a2ccee2015-02-06 10:12:32 -08002061 // If the event targets the accessibility focused view and this is it, start
2062 // normal event dispatch. Maybe a descendant is what will handle the click.
Svet Ganovf33fe1f2015-02-06 19:23:31 -08002063 if (ev.isTargetAccessibilityFocus() && isAccessibilityFocusedViewOrHost()) {
Svet Ganov0a2ccee2015-02-06 10:12:32 -08002064 ev.setTargetAccessibilityFocus(false);
2065 }
2066
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002067 boolean handled = false;
2068 if (onFilterTouchEventForSecurity(ev)) {
2069 final int action = ev.getAction();
2070 final int actionMasked = action & MotionEvent.ACTION_MASK;
Jeff Brown85a31762010-09-01 17:01:00 -07002071
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002072 // Handle an initial down.
2073 if (actionMasked == MotionEvent.ACTION_DOWN) {
2074 // Throw away all previous state when starting a new touch gesture.
2075 // The framework may have dropped the up or cancel event for the previous gesture
2076 // due to an app switch, ANR, or some other state change.
2077 cancelAndClearTouchTargets(ev);
2078 resetTouchState();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002079 }
Adam Powellb08013c2010-09-16 16:28:11 -07002080
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002081 // Check for interception.
2082 final boolean intercepted;
Svet Ganovf33fe1f2015-02-06 19:23:31 -08002083 if (actionMasked == MotionEvent.ACTION_DOWN
2084 || mFirstTouchTarget != null) {
2085 final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
2086 if (!disallowIntercept) {
2087 intercepted = onInterceptTouchEvent(ev);
2088 ev.setAction(action); // restore action in case it was changed
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002089 } else {
Svet Ganovf33fe1f2015-02-06 19:23:31 -08002090 intercepted = false;
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002091 }
2092 } else {
Svet Ganovf33fe1f2015-02-06 19:23:31 -08002093 // There are no touch targets and this action is not an initial down
2094 // so this view group continues to intercept touches.
2095 intercepted = true;
2096 }
2097
2098 // If intercepted, start normal event dispatch. Also if there is already
2099 // a view that is handling the gesture, do normal event dispatch.
2100 if (intercepted || mFirstTouchTarget != null) {
2101 ev.setTargetAccessibilityFocus(false);
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002102 }
Jeff Brown20e987b2010-08-23 12:01:02 -07002103
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002104 // Check for cancelation.
2105 final boolean canceled = resetCancelNextUpFlag(this)
2106 || actionMasked == MotionEvent.ACTION_CANCEL;
Jeff Brown20e987b2010-08-23 12:01:02 -07002107
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002108 // Update list of touch targets for pointer down, if needed.
2109 final boolean split = (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) != 0;
2110 TouchTarget newTouchTarget = null;
2111 boolean alreadyDispatchedToNewTouchTarget = false;
2112 if (!canceled && !intercepted) {
Svetoslavc73cfa02015-02-09 17:14:28 -08002113
2114 // If the event is targeting accessiiblity focus we give it to the
2115 // view that has accessibility focus and if it does not handle it
2116 // we clear the flag and dispatch the event to all children as usual.
2117 // We are looking up the accessibility focused host to avoid keeping
2118 // state since these events are very rare.
2119 View childWithAccessibilityFocus = ev.isTargetAccessibilityFocus()
2120 ? findChildWithAccessibilityFocus() : null;
2121
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002122 if (actionMasked == MotionEvent.ACTION_DOWN
2123 || (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN)
Svet Ganovf33fe1f2015-02-06 19:23:31 -08002124 || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002125 final int actionIndex = ev.getActionIndex(); // always 0 for down
2126 final int idBitsToAssign = split ? 1 << ev.getPointerId(actionIndex)
2127 : TouchTarget.ALL_POINTER_IDS;
Jeff Brown20e987b2010-08-23 12:01:02 -07002128
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002129 // Clean up earlier touch targets for this pointer id in case they
2130 // have become out of sync.
2131 removePointersFromTouchTargets(idBitsToAssign);
2132
2133 final int childrenCount = mChildrenCount;
Chet Haase9c17fe62013-03-22 17:05:55 -07002134 if (newTouchTarget == null && childrenCount != 0) {
Chet Haaseedf6f4b2013-03-26 07:55:30 -07002135 final float x = ev.getX(actionIndex);
2136 final float y = ev.getY(actionIndex);
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002137 // Find a child that can receive the event.
2138 // Scan children from front to back.
Chris Craikab008f02014-05-23 17:55:03 -07002139 final ArrayList<View> preorderedList = buildOrderedChildList();
2140 final boolean customOrder = preorderedList == null
2141 && isChildrenDrawingOrderEnabled();
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002142 final View[] children = mChildren;
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002143 for (int i = childrenCount - 1; i >= 0; i--) {
Chris Craikab008f02014-05-23 17:55:03 -07002144 final int childIndex = customOrder
2145 ? getChildDrawingOrder(childrenCount, i) : i;
2146 final View child = (preorderedList == null)
2147 ? children[childIndex] : preorderedList.get(childIndex);
Svetoslavc73cfa02015-02-09 17:14:28 -08002148
2149 // If there is a view that has accessibility focus we want it
2150 // to get the event first and if not handled we will perform a
2151 // normal dispatch. We may do a double iteration but this is
2152 // safer given the timeframe.
2153 if (childWithAccessibilityFocus != null) {
2154 if (childWithAccessibilityFocus != child) {
2155 continue;
2156 }
2157 childWithAccessibilityFocus = null;
2158 i = childrenCount - 1;
2159 }
2160
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002161 if (!canViewReceivePointerEvents(child)
2162 || !isTransformedTouchPointInView(x, y, child, null)) {
Svetoslavc73cfa02015-02-09 17:14:28 -08002163 ev.setTargetAccessibilityFocus(false);
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002164 continue;
2165 }
2166
2167 newTouchTarget = getTouchTarget(child);
2168 if (newTouchTarget != null) {
2169 // Child is already receiving touch within its bounds.
2170 // Give it the new pointer in addition to the ones it is handling.
2171 newTouchTarget.pointerIdBits |= idBitsToAssign;
2172 break;
2173 }
2174
2175 resetCancelNextUpFlag(child);
2176 if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
2177 // Child wants to receive touch within its bounds.
2178 mLastTouchDownTime = ev.getDownTime();
Chris Craikab008f02014-05-23 17:55:03 -07002179 if (preorderedList != null) {
2180 // childIndex points into presorted list, find original index
2181 for (int j = 0; j < childrenCount; j++) {
2182 if (children[childIndex] == mChildren[j]) {
2183 mLastTouchDownIndex = j;
2184 break;
2185 }
2186 }
2187 } else {
2188 mLastTouchDownIndex = childIndex;
2189 }
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002190 mLastTouchDownX = ev.getX();
2191 mLastTouchDownY = ev.getY();
2192 newTouchTarget = addTouchTarget(child, idBitsToAssign);
2193 alreadyDispatchedToNewTouchTarget = true;
2194 break;
2195 }
Svetoslavc73cfa02015-02-09 17:14:28 -08002196
2197 // The accessibility focus didn't handle the event, so clear
2198 // the flag and do a normal dispatch to all children.
2199 ev.setTargetAccessibilityFocus(false);
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002200 }
Chris Craikab008f02014-05-23 17:55:03 -07002201 if (preorderedList != null) preorderedList.clear();
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002202 }
2203
2204 if (newTouchTarget == null && mFirstTouchTarget != null) {
2205 // Did not find a child to receive the event.
2206 // Assign the pointer to the least recently added target.
2207 newTouchTarget = mFirstTouchTarget;
2208 while (newTouchTarget.next != null) {
2209 newTouchTarget = newTouchTarget.next;
2210 }
2211 newTouchTarget.pointerIdBits |= idBitsToAssign;
2212 }
2213 }
2214 }
2215
2216 // Dispatch to touch targets.
2217 if (mFirstTouchTarget == null) {
2218 // No touch targets so treat this as an ordinary view.
2219 handled = dispatchTransformedTouchEvent(ev, canceled, null,
2220 TouchTarget.ALL_POINTER_IDS);
2221 } else {
2222 // Dispatch to touch targets, excluding the new touch target if we already
2223 // dispatched to it. Cancel touch targets if necessary.
2224 TouchTarget predecessor = null;
2225 TouchTarget target = mFirstTouchTarget;
2226 while (target != null) {
2227 final TouchTarget next = target.next;
2228 if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) {
2229 handled = true;
2230 } else {
2231 final boolean cancelChild = resetCancelNextUpFlag(target.child)
Chet Haase9c17fe62013-03-22 17:05:55 -07002232 || intercepted;
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002233 if (dispatchTransformedTouchEvent(ev, cancelChild,
2234 target.child, target.pointerIdBits)) {
2235 handled = true;
2236 }
2237 if (cancelChild) {
2238 if (predecessor == null) {
2239 mFirstTouchTarget = next;
2240 } else {
2241 predecessor.next = next;
2242 }
2243 target.recycle();
2244 target = next;
Jeff Brown20e987b2010-08-23 12:01:02 -07002245 continue;
2246 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002247 }
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002248 predecessor = target;
2249 target = next;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002250 }
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002251 }
Jeff Brown20e987b2010-08-23 12:01:02 -07002252
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002253 // Update list of touch targets for pointer up or cancel, if needed.
2254 if (canceled
2255 || actionMasked == MotionEvent.ACTION_UP
2256 || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
2257 resetTouchState();
2258 } else if (split && actionMasked == MotionEvent.ACTION_POINTER_UP) {
2259 final int actionIndex = ev.getActionIndex();
2260 final int idBitsToRemove = 1 << ev.getPointerId(actionIndex);
2261 removePointersFromTouchTargets(idBitsToRemove);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002262 }
2263 }
Romain Guy8506ab42009-06-11 17:35:47 -07002264
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002265 if (!handled && mInputEventConsistencyVerifier != null) {
2266 mInputEventConsistencyVerifier.onUnhandledEvent(ev, 1);
Jeff Brown20e987b2010-08-23 12:01:02 -07002267 }
Jeff Brown20e987b2010-08-23 12:01:02 -07002268 return handled;
2269 }
2270
Romain Guy469b1db2010-10-05 11:49:57 -07002271 /**
Svetoslavc73cfa02015-02-09 17:14:28 -08002272 * Finds the child which has accessibility focus.
2273 *
2274 * @return The child that has focus.
2275 */
2276 private View findChildWithAccessibilityFocus() {
2277 ViewRootImpl viewRoot = getViewRootImpl();
2278 if (viewRoot == null) {
2279 return null;
2280 }
2281
2282 View current = viewRoot.getAccessibilityFocusedHost();
2283 if (current == null) {
2284 return null;
2285 }
2286
2287 ViewParent parent = current.getParent();
2288 while (parent instanceof View) {
2289 if (parent == this) {
2290 return current;
2291 }
2292 current = (View) parent;
2293 parent = current.getParent();
2294 }
2295
2296 return null;
2297 }
2298
2299 /**
Romain Guy469b1db2010-10-05 11:49:57 -07002300 * Resets all touch state in preparation for a new cycle.
2301 */
2302 private void resetTouchState() {
Jeff Brown20e987b2010-08-23 12:01:02 -07002303 clearTouchTargets();
2304 resetCancelNextUpFlag(this);
2305 mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
Adam Powell10ba2772014-04-15 09:46:51 -07002306 mNestedScrollAxes = SCROLL_AXIS_NONE;
Jeff Brown20e987b2010-08-23 12:01:02 -07002307 }
2308
Romain Guy469b1db2010-10-05 11:49:57 -07002309 /**
2310 * Resets the cancel next up flag.
2311 * Returns true if the flag was previously set.
2312 */
Romain Guya998dff2012-03-23 18:58:36 -07002313 private static boolean resetCancelNextUpFlag(View view) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07002314 if ((view.mPrivateFlags & PFLAG_CANCEL_NEXT_UP_EVENT) != 0) {
2315 view.mPrivateFlags &= ~PFLAG_CANCEL_NEXT_UP_EVENT;
Jeff Brown20e987b2010-08-23 12:01:02 -07002316 return true;
Adam Cohen9b073942010-08-19 16:49:52 -07002317 }
2318 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002319 }
2320
Romain Guy469b1db2010-10-05 11:49:57 -07002321 /**
2322 * Clears all touch targets.
2323 */
2324 private void clearTouchTargets() {
Jeff Brown20e987b2010-08-23 12:01:02 -07002325 TouchTarget target = mFirstTouchTarget;
2326 if (target != null) {
2327 do {
2328 TouchTarget next = target.next;
2329 target.recycle();
2330 target = next;
2331 } while (target != null);
2332 mFirstTouchTarget = null;
2333 }
2334 }
2335
Romain Guy469b1db2010-10-05 11:49:57 -07002336 /**
2337 * Cancels and clears all touch targets.
2338 */
2339 private void cancelAndClearTouchTargets(MotionEvent event) {
Jeff Brown20e987b2010-08-23 12:01:02 -07002340 if (mFirstTouchTarget != null) {
2341 boolean syntheticEvent = false;
2342 if (event == null) {
2343 final long now = SystemClock.uptimeMillis();
2344 event = MotionEvent.obtain(now, now,
2345 MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
Jeff Brown2fdbc5a2011-06-30 12:25:54 -07002346 event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
Jeff Brown20e987b2010-08-23 12:01:02 -07002347 syntheticEvent = true;
2348 }
2349
2350 for (TouchTarget target = mFirstTouchTarget; target != null; target = target.next) {
2351 resetCancelNextUpFlag(target.child);
2352 dispatchTransformedTouchEvent(event, true, target.child, target.pointerIdBits);
2353 }
2354 clearTouchTargets();
2355
2356 if (syntheticEvent) {
2357 event.recycle();
2358 }
2359 }
2360 }
2361
Romain Guy469b1db2010-10-05 11:49:57 -07002362 /**
2363 * Gets the touch target for specified child view.
2364 * Returns null if not found.
2365 */
2366 private TouchTarget getTouchTarget(View child) {
Jeff Brown20e987b2010-08-23 12:01:02 -07002367 for (TouchTarget target = mFirstTouchTarget; target != null; target = target.next) {
2368 if (target.child == child) {
2369 return target;
2370 }
2371 }
2372 return null;
2373 }
2374
Romain Guy469b1db2010-10-05 11:49:57 -07002375 /**
2376 * Adds a touch target for specified child to the beginning of the list.
2377 * Assumes the target child is not already present.
2378 */
2379 private TouchTarget addTouchTarget(View child, int pointerIdBits) {
Jeff Brown20e987b2010-08-23 12:01:02 -07002380 TouchTarget target = TouchTarget.obtain(child, pointerIdBits);
2381 target.next = mFirstTouchTarget;
2382 mFirstTouchTarget = target;
2383 return target;
2384 }
2385
Romain Guy469b1db2010-10-05 11:49:57 -07002386 /**
2387 * Removes the pointer ids from consideration.
2388 */
2389 private void removePointersFromTouchTargets(int pointerIdBits) {
Jeff Brown20e987b2010-08-23 12:01:02 -07002390 TouchTarget predecessor = null;
2391 TouchTarget target = mFirstTouchTarget;
2392 while (target != null) {
2393 final TouchTarget next = target.next;
2394 if ((target.pointerIdBits & pointerIdBits) != 0) {
2395 target.pointerIdBits &= ~pointerIdBits;
2396 if (target.pointerIdBits == 0) {
2397 if (predecessor == null) {
2398 mFirstTouchTarget = next;
2399 } else {
2400 predecessor.next = next;
2401 }
2402 target.recycle();
2403 target = next;
2404 continue;
2405 }
2406 }
2407 predecessor = target;
2408 target = next;
2409 }
2410 }
2411
Jeff Brown59a422e2012-04-19 15:19:19 -07002412 private void cancelTouchTarget(View view) {
2413 TouchTarget predecessor = null;
2414 TouchTarget target = mFirstTouchTarget;
2415 while (target != null) {
2416 final TouchTarget next = target.next;
2417 if (target.child == view) {
2418 if (predecessor == null) {
2419 mFirstTouchTarget = next;
2420 } else {
2421 predecessor.next = next;
2422 }
2423 target.recycle();
2424
2425 final long now = SystemClock.uptimeMillis();
2426 MotionEvent event = MotionEvent.obtain(now, now,
2427 MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
2428 event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
2429 view.dispatchTouchEvent(event);
2430 event.recycle();
2431 return;
2432 }
2433 predecessor = target;
2434 target = next;
2435 }
2436 }
2437
Romain Guy469b1db2010-10-05 11:49:57 -07002438 /**
Jeff Browna032cc02011-03-07 16:56:21 -08002439 * Returns true if a child view can receive pointer events.
2440 * @hide
2441 */
2442 private static boolean canViewReceivePointerEvents(View child) {
2443 return (child.mViewFlags & VISIBILITY_MASK) == VISIBLE
2444 || child.getAnimation() != null;
2445 }
2446
Alan Viveretteb942b6f2014-12-08 10:37:39 -08002447 private float[] getTempPoint() {
2448 if (mTempPoint == null) {
2449 mTempPoint = new float[2];
2450 }
2451 return mTempPoint;
2452 }
2453
Jeff Browna032cc02011-03-07 16:56:21 -08002454 /**
Romain Guy469b1db2010-10-05 11:49:57 -07002455 * Returns true if a child view contains the specified point when transformed
Jeff Brown20e987b2010-08-23 12:01:02 -07002456 * into its coordinate space.
Romain Guy469b1db2010-10-05 11:49:57 -07002457 * Child must not be null.
Adam Cohena32edd42010-10-26 10:35:01 -07002458 * @hide
Romain Guy469b1db2010-10-05 11:49:57 -07002459 */
Adam Cohena32edd42010-10-26 10:35:01 -07002460 protected boolean isTransformedTouchPointInView(float x, float y, View child,
Christopher Tate2c095f32010-10-04 14:13:40 -07002461 PointF outLocalPoint) {
Alan Viveretteb942b6f2014-12-08 10:37:39 -08002462 final float[] point = getTempPoint();
2463 point[0] = x;
2464 point[1] = y;
2465 transformPointToViewLocal(point, child);
2466 final boolean isInView = child.pointInView(point[0], point[1]);
Christopher Tate2c095f32010-10-04 14:13:40 -07002467 if (isInView && outLocalPoint != null) {
Alan Viveretteb942b6f2014-12-08 10:37:39 -08002468 outLocalPoint.set(point[0], point[1]);
Christopher Tate2c095f32010-10-04 14:13:40 -07002469 }
2470 return isInView;
Adam Powell2b342f02010-08-18 18:14:13 -07002471 }
2472
Romain Guy469b1db2010-10-05 11:49:57 -07002473 /**
Alan Viveretteb942b6f2014-12-08 10:37:39 -08002474 * @hide
2475 */
2476 public void transformPointToViewLocal(float[] point, View child) {
2477 point[0] += mScrollX - child.mLeft;
2478 point[1] += mScrollY - child.mTop;
2479
2480 if (!child.hasIdentityMatrix()) {
2481 child.getInverseMatrix().mapPoints(point);
2482 }
2483 }
2484
2485 /**
Romain Guy469b1db2010-10-05 11:49:57 -07002486 * Transforms a motion event into the coordinate space of a particular child view,
Jeff Brown20e987b2010-08-23 12:01:02 -07002487 * filters out irrelevant pointer ids, and overrides its action if necessary.
Romain Guy469b1db2010-10-05 11:49:57 -07002488 * If child is null, assumes the MotionEvent will be sent to this ViewGroup instead.
2489 */
2490 private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,
Jeff Brown20e987b2010-08-23 12:01:02 -07002491 View child, int desiredPointerIdBits) {
2492 final boolean handled;
Adam Powell2b342f02010-08-18 18:14:13 -07002493
Jeff Brown20e987b2010-08-23 12:01:02 -07002494 // Canceling motions is a special case. We don't need to perform any transformations
2495 // or filtering. The important part is the action, not the contents.
2496 final int oldAction = event.getAction();
2497 if (cancel || oldAction == MotionEvent.ACTION_CANCEL) {
2498 event.setAction(MotionEvent.ACTION_CANCEL);
2499 if (child == null) {
2500 handled = super.dispatchTouchEvent(event);
2501 } else {
2502 handled = child.dispatchTouchEvent(event);
2503 }
2504 event.setAction(oldAction);
2505 return handled;
2506 }
Adam Powell2b342f02010-08-18 18:14:13 -07002507
Jeff Brown20e987b2010-08-23 12:01:02 -07002508 // Calculate the number of pointers to deliver.
Jeff Brownfe9f8ab2011-05-06 18:20:01 -07002509 final int oldPointerIdBits = event.getPointerIdBits();
2510 final int newPointerIdBits = oldPointerIdBits & desiredPointerIdBits;
Adam Powell2b342f02010-08-18 18:14:13 -07002511
Jeff Brown20e987b2010-08-23 12:01:02 -07002512 // If for some reason we ended up in an inconsistent state where it looks like we
2513 // might produce a motion event with no pointers in it, then drop the event.
Jeff Brownfe9f8ab2011-05-06 18:20:01 -07002514 if (newPointerIdBits == 0) {
Jeff Brown20e987b2010-08-23 12:01:02 -07002515 return false;
2516 }
Adam Powell2b342f02010-08-18 18:14:13 -07002517
Jeff Brown20e987b2010-08-23 12:01:02 -07002518 // If the number of pointers is the same and we don't need to perform any fancy
2519 // irreversible transformations, then we can reuse the motion event for this
2520 // dispatch as long as we are careful to revert any changes we make.
Jeff Brownfe9f8ab2011-05-06 18:20:01 -07002521 // Otherwise we need to make a copy.
2522 final MotionEvent transformedEvent;
2523 if (newPointerIdBits == oldPointerIdBits) {
2524 if (child == null || child.hasIdentityMatrix()) {
2525 if (child == null) {
2526 handled = super.dispatchTouchEvent(event);
2527 } else {
2528 final float offsetX = mScrollX - child.mLeft;
2529 final float offsetY = mScrollY - child.mTop;
2530 event.offsetLocation(offsetX, offsetY);
Adam Powell2b342f02010-08-18 18:14:13 -07002531
Jeff Brownfe9f8ab2011-05-06 18:20:01 -07002532 handled = child.dispatchTouchEvent(event);
Jeff Brown20e987b2010-08-23 12:01:02 -07002533
Jeff Brownfe9f8ab2011-05-06 18:20:01 -07002534 event.offsetLocation(-offsetX, -offsetY);
2535 }
2536 return handled;
Jeff Brown20e987b2010-08-23 12:01:02 -07002537 }
Jeff Brown20e987b2010-08-23 12:01:02 -07002538 transformedEvent = MotionEvent.obtain(event);
2539 } else {
Jeff Brownfe9f8ab2011-05-06 18:20:01 -07002540 transformedEvent = event.split(newPointerIdBits);
Adam Powell2b342f02010-08-18 18:14:13 -07002541 }
2542
Jeff Brown20e987b2010-08-23 12:01:02 -07002543 // Perform any necessary transformations and dispatch.
2544 if (child == null) {
2545 handled = super.dispatchTouchEvent(transformedEvent);
2546 } else {
2547 final float offsetX = mScrollX - child.mLeft;
2548 final float offsetY = mScrollY - child.mTop;
2549 transformedEvent.offsetLocation(offsetX, offsetY);
2550 if (! child.hasIdentityMatrix()) {
2551 transformedEvent.transform(child.getInverseMatrix());
Adam Powell2b342f02010-08-18 18:14:13 -07002552 }
2553
Jeff Brown20e987b2010-08-23 12:01:02 -07002554 handled = child.dispatchTouchEvent(transformedEvent);
Adam Powell2b342f02010-08-18 18:14:13 -07002555 }
2556
Jeff Brown20e987b2010-08-23 12:01:02 -07002557 // Done.
2558 transformedEvent.recycle();
Adam Powell2b342f02010-08-18 18:14:13 -07002559 return handled;
2560 }
2561
Romain Guy469b1db2010-10-05 11:49:57 -07002562 /**
Adam Powell2b342f02010-08-18 18:14:13 -07002563 * Enable or disable the splitting of MotionEvents to multiple children during touch event
Jeff Brown995e7742010-12-22 16:59:36 -08002564 * dispatch. This behavior is enabled by default for applications that target an
2565 * SDK version of {@link Build.VERSION_CODES#HONEYCOMB} or newer.
Adam Powell2b342f02010-08-18 18:14:13 -07002566 *
2567 * <p>When this option is enabled MotionEvents may be split and dispatched to different child
2568 * views depending on where each pointer initially went down. This allows for user interactions
2569 * such as scrolling two panes of content independently, chording of buttons, and performing
2570 * independent gestures on different pieces of content.
2571 *
2572 * @param split <code>true</code> to allow MotionEvents to be split and dispatched to multiple
2573 * child views. <code>false</code> to only allow one child view to be the target of
2574 * any MotionEvent received by this ViewGroup.
Scott Main27a85082013-06-10 10:39:48 -07002575 * @attr ref android.R.styleable#ViewGroup_splitMotionEvents
Adam Powell2b342f02010-08-18 18:14:13 -07002576 */
2577 public void setMotionEventSplittingEnabled(boolean split) {
2578 // TODO Applications really shouldn't change this setting mid-touch event,
2579 // but perhaps this should handle that case and send ACTION_CANCELs to any child views
2580 // with gestures in progress when this is changed.
2581 if (split) {
Adam Powell2b342f02010-08-18 18:14:13 -07002582 mGroupFlags |= FLAG_SPLIT_MOTION_EVENTS;
2583 } else {
2584 mGroupFlags &= ~FLAG_SPLIT_MOTION_EVENTS;
Adam Powell2b342f02010-08-18 18:14:13 -07002585 }
2586 }
2587
2588 /**
Jeff Brown995e7742010-12-22 16:59:36 -08002589 * Returns true if MotionEvents dispatched to this ViewGroup can be split to multiple children.
Adam Powell2b342f02010-08-18 18:14:13 -07002590 * @return true if MotionEvents dispatched to this ViewGroup can be split to multiple children.
2591 */
2592 public boolean isMotionEventSplittingEnabled() {
2593 return (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) == FLAG_SPLIT_MOTION_EVENTS;
2594 }
2595
2596 /**
George Mount0a778ed2013-12-13 13:35:36 -08002597 * Returns true if this ViewGroup should be considered as a single entity for removal
2598 * when executing an Activity transition. If this is false, child elements will move
2599 * individually during the transition.
George Mount427c6412014-11-05 16:45:36 -08002600 *
George Mount0a778ed2013-12-13 13:35:36 -08002601 * @return True if the ViewGroup should be acted on together during an Activity transition.
George Mount427c6412014-11-05 16:45:36 -08002602 * The default value is true when there is a non-null background or if
2603 * {@link #getTransitionName()} is not null or if a
2604 * non-null {@link android.view.ViewOutlineProvider} other than
2605 * {@link android.view.ViewOutlineProvider#BACKGROUND} was given to
2606 * {@link #setOutlineProvider(ViewOutlineProvider)} and false otherwise.
George Mount0a778ed2013-12-13 13:35:36 -08002607 */
2608 public boolean isTransitionGroup() {
2609 if ((mGroupFlags & FLAG_IS_TRANSITION_GROUP_SET) != 0) {
2610 return ((mGroupFlags & FLAG_IS_TRANSITION_GROUP) != 0);
2611 } else {
George Mount427c6412014-11-05 16:45:36 -08002612 final ViewOutlineProvider outlineProvider = getOutlineProvider();
2613 return getBackground() != null || getTransitionName() != null ||
2614 (outlineProvider != null && outlineProvider != ViewOutlineProvider.BACKGROUND);
George Mount0a778ed2013-12-13 13:35:36 -08002615 }
2616 }
2617
2618 /**
2619 * Changes whether or not this ViewGroup should be treated as a single entity during
George Mount31a21722014-03-24 17:44:36 -07002620 * Activity Transitions.
George Mount0a778ed2013-12-13 13:35:36 -08002621 * @param isTransitionGroup Whether or not the ViewGroup should be treated as a unit
2622 * in Activity transitions. If false, the ViewGroup won't transition,
2623 * only its children. If true, the entire ViewGroup will transition
2624 * together.
George Mount62ab9b72014-05-02 13:51:17 -07002625 * @see android.app.ActivityOptions#makeSceneTransitionAnimation(android.app.Activity,
2626 * android.util.Pair[])
George Mount0a778ed2013-12-13 13:35:36 -08002627 */
2628 public void setTransitionGroup(boolean isTransitionGroup) {
2629 mGroupFlags |= FLAG_IS_TRANSITION_GROUP_SET;
2630 if (isTransitionGroup) {
2631 mGroupFlags |= FLAG_IS_TRANSITION_GROUP;
2632 } else {
2633 mGroupFlags &= ~FLAG_IS_TRANSITION_GROUP;
2634 }
2635 }
2636
2637 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002638 * {@inheritDoc}
2639 */
2640 public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
Romain Guy8506ab42009-06-11 17:35:47 -07002641
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002642 if (disallowIntercept == ((mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0)) {
2643 // We're already in this state, assume our ancestors are too
2644 return;
2645 }
Romain Guy8506ab42009-06-11 17:35:47 -07002646
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002647 if (disallowIntercept) {
2648 mGroupFlags |= FLAG_DISALLOW_INTERCEPT;
2649 } else {
2650 mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
2651 }
Romain Guy8506ab42009-06-11 17:35:47 -07002652
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002653 // Pass it up to our parent
2654 if (mParent != null) {
2655 mParent.requestDisallowInterceptTouchEvent(disallowIntercept);
2656 }
2657 }
2658
2659 /**
2660 * Implement this method to intercept all touch screen motion events. This
2661 * allows you to watch events as they are dispatched to your children, and
2662 * take ownership of the current gesture at any point.
2663 *
2664 * <p>Using this function takes some care, as it has a fairly complicated
2665 * interaction with {@link View#onTouchEvent(MotionEvent)
2666 * View.onTouchEvent(MotionEvent)}, and using it requires implementing
2667 * that method as well as this one in the correct way. Events will be
2668 * received in the following order:
2669 *
2670 * <ol>
2671 * <li> You will receive the down event here.
2672 * <li> The down event will be handled either by a child of this view
2673 * group, or given to your own onTouchEvent() method to handle; this means
2674 * you should implement onTouchEvent() to return true, so you will
2675 * continue to see the rest of the gesture (instead of looking for
2676 * a parent view to handle it). Also, by returning true from
2677 * onTouchEvent(), you will not receive any following
2678 * events in onInterceptTouchEvent() and all touch processing must
2679 * happen in onTouchEvent() like normal.
2680 * <li> For as long as you return false from this function, each following
2681 * event (up to and including the final up) will be delivered first here
2682 * and then to the target's onTouchEvent().
2683 * <li> If you return true from here, you will not receive any
2684 * following events: the target view will receive the same event but
2685 * with the action {@link MotionEvent#ACTION_CANCEL}, and all further
2686 * events will be delivered to your onTouchEvent() method and no longer
2687 * appear here.
2688 * </ol>
2689 *
2690 * @param ev The motion event being dispatched down the hierarchy.
2691 * @return Return true to steal motion events from the children and have
2692 * them dispatched to this ViewGroup through onTouchEvent().
2693 * The current target will receive an ACTION_CANCEL event, and no further
2694 * messages will be delivered here.
2695 */
2696 public boolean onInterceptTouchEvent(MotionEvent ev) {
2697 return false;
2698 }
2699
2700 /**
2701 * {@inheritDoc}
2702 *
2703 * Looks for a view to give focus to respecting the setting specified by
2704 * {@link #getDescendantFocusability()}.
2705 *
2706 * Uses {@link #onRequestFocusInDescendants(int, android.graphics.Rect)} to
2707 * find focus within the children of this group when appropriate.
2708 *
2709 * @see #FOCUS_BEFORE_DESCENDANTS
2710 * @see #FOCUS_AFTER_DESCENDANTS
2711 * @see #FOCUS_BLOCK_DESCENDANTS
Romain Guy02739a82011-05-16 11:43:18 -07002712 * @see #onRequestFocusInDescendants(int, android.graphics.Rect)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002713 */
2714 @Override
2715 public boolean requestFocus(int direction, Rect previouslyFocusedRect) {
2716 if (DBG) {
2717 System.out.println(this + " ViewGroup.requestFocus direction="
2718 + direction);
2719 }
2720 int descendantFocusability = getDescendantFocusability();
2721
2722 switch (descendantFocusability) {
2723 case FOCUS_BLOCK_DESCENDANTS:
2724 return super.requestFocus(direction, previouslyFocusedRect);
2725 case FOCUS_BEFORE_DESCENDANTS: {
2726 final boolean took = super.requestFocus(direction, previouslyFocusedRect);
2727 return took ? took : onRequestFocusInDescendants(direction, previouslyFocusedRect);
2728 }
2729 case FOCUS_AFTER_DESCENDANTS: {
2730 final boolean took = onRequestFocusInDescendants(direction, previouslyFocusedRect);
2731 return took ? took : super.requestFocus(direction, previouslyFocusedRect);
2732 }
2733 default:
2734 throw new IllegalStateException("descendant focusability must be "
2735 + "one of FOCUS_BEFORE_DESCENDANTS, FOCUS_AFTER_DESCENDANTS, FOCUS_BLOCK_DESCENDANTS "
2736 + "but is " + descendantFocusability);
2737 }
2738 }
2739
2740 /**
2741 * Look for a descendant to call {@link View#requestFocus} on.
2742 * Called by {@link ViewGroup#requestFocus(int, android.graphics.Rect)}
2743 * when it wants to request focus within its children. Override this to
2744 * customize how your {@link ViewGroup} requests focus within its children.
2745 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT
2746 * @param previouslyFocusedRect The rectangle (in this View's coordinate system)
2747 * to give a finer grained hint about where focus is coming from. May be null
2748 * if there is no hint.
2749 * @return Whether focus was taken.
2750 */
2751 @SuppressWarnings({"ConstantConditions"})
2752 protected boolean onRequestFocusInDescendants(int direction,
2753 Rect previouslyFocusedRect) {
2754 int index;
2755 int increment;
2756 int end;
2757 int count = mChildrenCount;
2758 if ((direction & FOCUS_FORWARD) != 0) {
2759 index = 0;
2760 increment = 1;
2761 end = count;
2762 } else {
2763 index = count - 1;
2764 increment = -1;
2765 end = -1;
2766 }
2767 final View[] children = mChildren;
2768 for (int i = index; i != end; i += increment) {
2769 View child = children[i];
2770 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
2771 if (child.requestFocus(direction, previouslyFocusedRect)) {
2772 return true;
2773 }
2774 }
2775 }
2776 return false;
2777 }
Chet Haase5c13d892010-10-08 08:37:55 -07002778
Romain Guya440b002010-02-24 15:57:54 -08002779 /**
2780 * {@inheritDoc}
Chet Haase5c13d892010-10-08 08:37:55 -07002781 *
Romain Guydcc490f2010-02-24 17:59:35 -08002782 * @hide
Romain Guya440b002010-02-24 15:57:54 -08002783 */
2784 @Override
2785 public void dispatchStartTemporaryDetach() {
2786 super.dispatchStartTemporaryDetach();
2787 final int count = mChildrenCount;
2788 final View[] children = mChildren;
2789 for (int i = 0; i < count; i++) {
2790 children[i].dispatchStartTemporaryDetach();
2791 }
2792 }
Chet Haase5c13d892010-10-08 08:37:55 -07002793
Romain Guya440b002010-02-24 15:57:54 -08002794 /**
2795 * {@inheritDoc}
Chet Haase5c13d892010-10-08 08:37:55 -07002796 *
Romain Guydcc490f2010-02-24 17:59:35 -08002797 * @hide
Romain Guya440b002010-02-24 15:57:54 -08002798 */
2799 @Override
2800 public void dispatchFinishTemporaryDetach() {
2801 super.dispatchFinishTemporaryDetach();
2802 final int count = mChildrenCount;
2803 final View[] children = mChildren;
2804 for (int i = 0; i < count; i++) {
2805 children[i].dispatchFinishTemporaryDetach();
2806 }
2807 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002808
2809 /**
2810 * {@inheritDoc}
2811 */
2812 @Override
2813 void dispatchAttachedToWindow(AttachInfo info, int visibility) {
Adam Powell4b867882011-09-16 12:59:46 -07002814 mGroupFlags |= FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002815 super.dispatchAttachedToWindow(info, visibility);
Adam Powell4b867882011-09-16 12:59:46 -07002816 mGroupFlags &= ~FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW;
2817
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002818 final int count = mChildrenCount;
2819 final View[] children = mChildren;
2820 for (int i = 0; i < count; i++) {
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07002821 final View child = children[i];
2822 child.dispatchAttachedToWindow(info,
Philip Milne7b757812012-09-19 18:13:44 -07002823 visibility | (child.mViewFlags & VISIBILITY_MASK));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002824 }
2825 }
2826
svetoslavganov75986cf2009-05-14 22:28:01 -07002827 @Override
Romain Guybb9908b2012-03-08 11:14:07 -08002828 void dispatchScreenStateChanged(int screenState) {
2829 super.dispatchScreenStateChanged(screenState);
2830
2831 final int count = mChildrenCount;
2832 final View[] children = mChildren;
2833 for (int i = 0; i < count; i++) {
2834 children[i].dispatchScreenStateChanged(screenState);
2835 }
2836 }
2837
Alan Viverettea54956a2015-01-07 16:05:02 -08002838 /** @hide */
Romain Guybb9908b2012-03-08 11:14:07 -08002839 @Override
Alan Viverettea54956a2015-01-07 16:05:02 -08002840 public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07002841 boolean handled = false;
2842 if (includeForAccessibility()) {
2843 handled = super.dispatchPopulateAccessibilityEventInternal(event);
2844 if (handled) {
2845 return handled;
2846 }
Svetoslav Ganovb84b94e2011-09-22 19:26:56 -07002847 }
Svetoslav Ganov736c2752011-04-22 18:30:36 -07002848 // Let our children have a shot in populating the event.
Svetoslav Ganov42138042012-03-20 11:51:39 -07002849 ChildListForAccessibility children = ChildListForAccessibility.obtain(this, true);
Svetoslav Ganov76f287e2012-04-23 11:02:36 -07002850 try {
2851 final int childCount = children.getChildCount();
2852 for (int i = 0; i < childCount; i++) {
2853 View child = children.getChildAt(i);
2854 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
2855 handled = child.dispatchPopulateAccessibilityEvent(event);
2856 if (handled) {
Svetoslav Ganov76f287e2012-04-23 11:02:36 -07002857 return handled;
2858 }
Svetoslav Ganov6179ea32011-06-28 01:12:41 -07002859 }
Svetoslav Ganov736c2752011-04-22 18:30:36 -07002860 }
Svetoslav Ganov76f287e2012-04-23 11:02:36 -07002861 } finally {
2862 children.recycle();
svetoslavganov75986cf2009-05-14 22:28:01 -07002863 }
Svetoslav Ganov736c2752011-04-22 18:30:36 -07002864 return false;
svetoslavganov75986cf2009-05-14 22:28:01 -07002865 }
2866
Dianne Hackborn6251f0d2015-04-01 16:45:03 -07002867 /**
2868 * Dispatch creation of {@link ViewAssistStructure} down the hierarchy. This implementation
2869 * adds in all child views of the view group, in addition to calling the default View
2870 * implementation.
2871 */
2872 public void dispatchProvideAssistStructure(ViewAssistStructure structure) {
2873 super.dispatchProvideAssistStructure(structure);
2874 if (structure.getChildCount() == 0) {
2875 final int childrenCount = getChildCount();
2876 if (childrenCount > 0) {
2877 structure.setChildCount(childrenCount);
2878 final ArrayList<View> preorderedList = buildOrderedChildList();
2879 final boolean customOrder = preorderedList == null
2880 && isChildrenDrawingOrderEnabled();
2881 final View[] children = mChildren;
2882 for (int i=0; i<childrenCount; i++) {
2883 final int childIndex = customOrder
2884 ? getChildDrawingOrder(childrenCount, i) : i;
2885 final View child = (preorderedList == null)
2886 ? children[childIndex] : preorderedList.get(childIndex);
2887 ViewAssistStructure cstructure = structure.newChild(i);
2888 child.dispatchProvideAssistStructure(cstructure);
2889 }
2890 }
2891 }
2892 }
2893
Alan Viverettea54956a2015-01-07 16:05:02 -08002894 /** @hide */
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002895 @Override
Alan Viverettea54956a2015-01-07 16:05:02 -08002896 public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
Svetoslav Ganov031d9c12011-09-09 16:41:13 -07002897 super.onInitializeAccessibilityNodeInfoInternal(info);
Svet Ganov55bdb102015-02-06 12:41:17 -08002898 if (getAccessibilityNodeProvider() != null) {
2899 return;
2900 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07002901 if (mAttachInfo != null) {
Alan Viverettef0aed092013-11-06 15:33:03 -08002902 final ArrayList<View> childrenForAccessibility = mAttachInfo.mTempArrayList;
Svetoslav Ganov42138042012-03-20 11:51:39 -07002903 childrenForAccessibility.clear();
2904 addChildrenForAccessibility(childrenForAccessibility);
2905 final int childrenForAccessibilityCount = childrenForAccessibility.size();
2906 for (int i = 0; i < childrenForAccessibilityCount; i++) {
Alan Viverettef0aed092013-11-06 15:33:03 -08002907 final View child = childrenForAccessibility.get(i);
2908 info.addChildUnchecked(child);
Svetoslav Ganovea1da3d2011-06-15 17:16:02 -07002909 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07002910 childrenForAccessibility.clear();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002911 }
2912 }
2913
Alan Viverettea54956a2015-01-07 16:05:02 -08002914 /** @hide */
Svetoslav Ganov8a78fd42012-01-17 14:36:46 -08002915 @Override
Alan Viverettea54956a2015-01-07 16:05:02 -08002916 public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
Svetoslav Ganov8a78fd42012-01-17 14:36:46 -08002917 super.onInitializeAccessibilityEventInternal(event);
2918 event.setClassName(ViewGroup.class.getName());
2919 }
2920
Svetoslav Ganov42138042012-03-20 11:51:39 -07002921 @Override
Alan Viverette77e9a282013-09-12 17:16:09 -07002922 public void notifySubtreeAccessibilityStateChanged(View child, View source, int changeType) {
2923 // If this is a live region, we should send a subtree change event
2924 // from this view. Otherwise, we can let it propagate up.
2925 if (getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE) {
2926 notifyViewAccessibilityStateChangedIfNeeded(changeType);
2927 } else if (mParent != null) {
Adam Powell504a10f2013-07-11 15:25:59 -07002928 try {
Alan Viverette77e9a282013-09-12 17:16:09 -07002929 mParent.notifySubtreeAccessibilityStateChanged(this, source, changeType);
Adam Powell504a10f2013-07-11 15:25:59 -07002930 } catch (AbstractMethodError e) {
2931 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() +
2932 " does not fully implement ViewParent", e);
2933 }
Svetoslav6254f482013-06-04 17:22:14 -07002934 }
2935 }
2936
2937 @Override
2938 void resetSubtreeAccessibilityStateChanged() {
2939 super.resetSubtreeAccessibilityStateChanged();
Svetoslav Ganov42138042012-03-20 11:51:39 -07002940 View[] children = mChildren;
2941 final int childCount = mChildrenCount;
2942 for (int i = 0; i < childCount; i++) {
Svetoslav6254f482013-06-04 17:22:14 -07002943 children[i].resetSubtreeAccessibilityStateChanged();
Svetoslav Ganov42138042012-03-20 11:51:39 -07002944 }
2945 }
2946
2947 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002948 * {@inheritDoc}
Adam Powellb6ab0982015-01-07 17:00:12 -08002949 *
2950 * <p>Subclasses should always call <code>super.onNestedPrePerformAccessibilityAction</code></p>
2951 *
2952 * @param target The target view dispatching this action
2953 * @param action Action being performed; see
2954 * {@link android.view.accessibility.AccessibilityNodeInfo}
2955 * @param args Optional action arguments
2956 * @return false by default. Subclasses should return true if they handle the event.
2957 */
2958 @Override
2959 public boolean onNestedPrePerformAccessibilityAction(View target, int action, Bundle args) {
2960 return false;
2961 }
2962
2963 /**
2964 * {@inheritDoc}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002965 */
2966 @Override
2967 void dispatchDetachedFromWindow() {
Jeff Brown20e987b2010-08-23 12:01:02 -07002968 // If we still have a touch target, we are still in the process of
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002969 // dispatching motion events to a child; we need to get rid of that
2970 // child to avoid dispatching events to it after the window is torn
2971 // down. To make sure we keep the child in a consistent state, we
2972 // first send it an ACTION_CANCEL motion event.
Jeff Brown20e987b2010-08-23 12:01:02 -07002973 cancelAndClearTouchTargets(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002974
Jeff Brown59a422e2012-04-19 15:19:19 -07002975 // Similarly, set ACTION_EXIT to all hover targets and clear them.
2976 exitHoverTargets();
2977
Chet Haase9c087442011-01-12 16:20:16 -08002978 // In case view is detached while transition is running
Chet Haaseb9895022013-04-02 15:10:58 -07002979 mLayoutCalledWhileSuppressed = false;
Chet Haase9c087442011-01-12 16:20:16 -08002980
Christopher Tate86cab1b2011-01-13 20:28:55 -08002981 // Tear down our drag tracking
2982 mDragNotifiedChildren = null;
2983 if (mCurrentDrag != null) {
2984 mCurrentDrag.recycle();
2985 mCurrentDrag = null;
2986 }
2987
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002988 final int count = mChildrenCount;
2989 final View[] children = mChildren;
2990 for (int i = 0; i < count; i++) {
2991 children[i].dispatchDetachedFromWindow();
2992 }
John Reckca7a9da2014-03-05 16:29:07 -08002993 clearDisappearingChildren();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002994 super.dispatchDetachedFromWindow();
2995 }
2996
Fabrice Di Meglio23c89fd2012-08-13 12:17:42 -07002997 /**
2998 * @hide
2999 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003000 @Override
Fabrice Di Meglio23c89fd2012-08-13 12:17:42 -07003001 protected void internalSetPadding(int left, int top, int right, int bottom) {
Romain Guy2440e672012-08-07 14:43:43 -07003002 super.internalSetPadding(left, top, right, bottom);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003003
Romain Guy13f35f32011-03-24 12:03:17 -07003004 if ((mPaddingLeft | mPaddingTop | mPaddingRight | mPaddingBottom) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003005 mGroupFlags |= FLAG_PADDING_NOT_NULL;
3006 } else {
3007 mGroupFlags &= ~FLAG_PADDING_NOT_NULL;
3008 }
3009 }
3010
3011 /**
3012 * {@inheritDoc}
3013 */
3014 @Override
3015 protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {
3016 super.dispatchSaveInstanceState(container);
3017 final int count = mChildrenCount;
3018 final View[] children = mChildren;
3019 for (int i = 0; i < count; i++) {
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07003020 View c = children[i];
3021 if ((c.mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED) {
3022 c.dispatchSaveInstanceState(container);
3023 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003024 }
3025 }
3026
3027 /**
Romain Guy9fc27812011-04-27 14:21:41 -07003028 * Perform dispatching of a {@link #saveHierarchyState(android.util.SparseArray)} freeze()}
3029 * to only this view, not to its children. For use when overriding
3030 * {@link #dispatchSaveInstanceState(android.util.SparseArray)} dispatchFreeze()} to allow
3031 * subclasses to freeze their own state but not the state of their children.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003032 *
3033 * @param container the container
3034 */
3035 protected void dispatchFreezeSelfOnly(SparseArray<Parcelable> container) {
3036 super.dispatchSaveInstanceState(container);
3037 }
3038
3039 /**
3040 * {@inheritDoc}
3041 */
3042 @Override
3043 protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {
3044 super.dispatchRestoreInstanceState(container);
3045 final int count = mChildrenCount;
3046 final View[] children = mChildren;
3047 for (int i = 0; i < count; i++) {
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07003048 View c = children[i];
3049 if ((c.mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED) {
3050 c.dispatchRestoreInstanceState(container);
3051 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003052 }
3053 }
3054
3055 /**
Romain Guy02739a82011-05-16 11:43:18 -07003056 * Perform dispatching of a {@link #restoreHierarchyState(android.util.SparseArray)}
3057 * to only this view, not to its children. For use when overriding
3058 * {@link #dispatchRestoreInstanceState(android.util.SparseArray)} to allow
3059 * subclasses to thaw their own state but not the state of their children.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003060 *
3061 * @param container the container
3062 */
3063 protected void dispatchThawSelfOnly(SparseArray<Parcelable> container) {
3064 super.dispatchRestoreInstanceState(container);
3065 }
3066
3067 /**
3068 * Enables or disables the drawing cache for each child of this view group.
3069 *
3070 * @param enabled true to enable the cache, false to dispose of it
3071 */
3072 protected void setChildrenDrawingCacheEnabled(boolean enabled) {
3073 if (enabled || (mPersistentDrawingCache & PERSISTENT_ALL_CACHES) != PERSISTENT_ALL_CACHES) {
3074 final View[] children = mChildren;
3075 final int count = mChildrenCount;
3076 for (int i = 0; i < count; i++) {
3077 children[i].setDrawingCacheEnabled(enabled);
3078 }
3079 }
3080 }
3081
3082 @Override
Romain Guy223ff5c2010-03-02 17:07:47 -08003083 Bitmap createSnapshot(Bitmap.Config quality, int backgroundColor, boolean skipChildren) {
Romain Guy65554f22010-03-22 18:58:21 -07003084 int count = mChildrenCount;
3085 int[] visibilities = null;
3086
Romain Guy223ff5c2010-03-02 17:07:47 -08003087 if (skipChildren) {
Romain Guy65554f22010-03-22 18:58:21 -07003088 visibilities = new int[count];
3089 for (int i = 0; i < count; i++) {
3090 View child = getChildAt(i);
3091 visibilities[i] = child.getVisibility();
3092 if (visibilities[i] == View.VISIBLE) {
3093 child.setVisibility(INVISIBLE);
3094 }
3095 }
Romain Guy223ff5c2010-03-02 17:07:47 -08003096 }
3097
3098 Bitmap b = super.createSnapshot(quality, backgroundColor, skipChildren);
Romain Guy65554f22010-03-22 18:58:21 -07003099
3100 if (skipChildren) {
3101 for (int i = 0; i < count; i++) {
3102 getChildAt(i).setVisibility(visibilities[i]);
Chet Haase5c13d892010-10-08 08:37:55 -07003103 }
Romain Guy65554f22010-03-22 18:58:21 -07003104 }
Romain Guy223ff5c2010-03-02 17:07:47 -08003105
3106 return b;
3107 }
3108
Philip Milne7b757812012-09-19 18:13:44 -07003109 /** Return true if this ViewGroup is laying out using optical bounds. */
3110 boolean isLayoutModeOptical() {
3111 return mLayoutMode == LAYOUT_MODE_OPTICAL_BOUNDS;
3112 }
Romain Guycbc67742012-04-27 16:12:57 -07003113
Philip Milne7b757812012-09-19 18:13:44 -07003114 Insets computeOpticalInsets() {
3115 if (isLayoutModeOptical()) {
3116 int left = 0;
3117 int top = 0;
3118 int right = 0;
3119 int bottom = 0;
3120 for (int i = 0; i < mChildrenCount; i++) {
3121 View child = getChildAt(i);
3122 if (child.getVisibility() == VISIBLE) {
3123 Insets insets = child.getOpticalInsets();
3124 left = Math.max(left, insets.left);
3125 top = Math.max(top, insets.top);
3126 right = Math.max(right, insets.right);
3127 bottom = Math.max(bottom, insets.bottom);
3128 }
3129 }
3130 return Insets.of(left, top, right, bottom);
3131 } else {
3132 return Insets.NONE;
3133 }
3134 }
3135
3136 private static void fillRect(Canvas canvas, Paint paint, int x1, int y1, int x2, int y2) {
3137 if (x1 != x2 && y1 != y2) {
3138 if (x1 > x2) {
3139 int tmp = x1; x1 = x2; x2 = tmp;
3140 }
3141 if (y1 > y2) {
3142 int tmp = y1; y1 = y2; y2 = tmp;
3143 }
3144 canvas.drawRect(x1, y1, x2, y2, paint);
3145 }
3146 }
3147
3148 private static int sign(int x) {
3149 return (x >= 0) ? 1 : -1;
3150 }
3151
3152 private static void drawCorner(Canvas c, Paint paint, int x1, int y1, int dx, int dy, int lw) {
3153 fillRect(c, paint, x1, y1, x1 + dx, y1 + lw * sign(dy));
3154 fillRect(c, paint, x1, y1, x1 + lw * sign(dx), y1 + dy);
3155 }
3156
3157 private int dipsToPixels(int dips) {
3158 float scale = getContext().getResources().getDisplayMetrics().density;
3159 return (int) (dips * scale + 0.5f);
3160 }
3161
Romain Guy6410c0a2013-06-17 11:21:58 -07003162 private static void drawRectCorners(Canvas canvas, int x1, int y1, int x2, int y2, Paint paint,
3163 int lineLength, int lineWidth) {
Philip Milne7b757812012-09-19 18:13:44 -07003164 drawCorner(canvas, paint, x1, y1, lineLength, lineLength, lineWidth);
3165 drawCorner(canvas, paint, x1, y2, lineLength, -lineLength, lineWidth);
3166 drawCorner(canvas, paint, x2, y1, -lineLength, lineLength, lineWidth);
3167 drawCorner(canvas, paint, x2, y2, -lineLength, -lineLength, lineWidth);
3168 }
3169
3170 private static void fillDifference(Canvas canvas,
3171 int x2, int y2, int x3, int y3,
3172 int dx1, int dy1, int dx2, int dy2, Paint paint) {
3173 int x1 = x2 - dx1;
3174 int y1 = y2 - dy1;
3175
3176 int x4 = x3 + dx2;
3177 int y4 = y3 + dy2;
3178
3179 fillRect(canvas, paint, x1, y1, x4, y2);
3180 fillRect(canvas, paint, x1, y2, x2, y3);
3181 fillRect(canvas, paint, x3, y2, x4, y3);
3182 fillRect(canvas, paint, x1, y3, x4, y4);
Philip Milne10ca24a2012-04-23 15:38:27 -07003183 }
3184
3185 /**
3186 * @hide
3187 */
Philip Milne7b757812012-09-19 18:13:44 -07003188 protected void onDebugDrawMargins(Canvas canvas, Paint paint) {
Philip Milne10ca24a2012-04-23 15:38:27 -07003189 for (int i = 0; i < getChildCount(); i++) {
3190 View c = getChildAt(i);
Philip Milne7b757812012-09-19 18:13:44 -07003191 c.getLayoutParams().onDebugDraw(c, canvas, paint);
Philip Milne10ca24a2012-04-23 15:38:27 -07003192 }
3193 }
3194
3195 /**
3196 * @hide
3197 */
3198 protected void onDebugDraw(Canvas canvas) {
Philip Milne7b757812012-09-19 18:13:44 -07003199 Paint paint = getDebugPaint();
3200
Philip Milne10ca24a2012-04-23 15:38:27 -07003201 // Draw optical bounds
Philip Milne7b757812012-09-19 18:13:44 -07003202 {
3203 paint.setColor(Color.RED);
3204 paint.setStyle(Paint.Style.STROKE);
Philip Milne7b757812012-09-19 18:13:44 -07003205
Philip Milne10ca24a2012-04-23 15:38:27 -07003206 for (int i = 0; i < getChildCount(); i++) {
3207 View c = getChildAt(i);
Philip Milne7a23b492012-04-24 22:12:36 -07003208 Insets insets = c.getOpticalInsets();
Philip Milne7b757812012-09-19 18:13:44 -07003209
3210 drawRect(canvas, paint,
3211 c.getLeft() + insets.left,
3212 c.getTop() + insets.top,
3213 c.getRight() - insets.right - 1,
3214 c.getBottom() - insets.bottom - 1);
Philip Milne10ca24a2012-04-23 15:38:27 -07003215 }
3216 }
3217
Philip Milne10ca24a2012-04-23 15:38:27 -07003218 // Draw margins
Philip Milne7b757812012-09-19 18:13:44 -07003219 {
3220 paint.setColor(Color.argb(63, 255, 0, 255));
3221 paint.setStyle(Paint.Style.FILL);
Philip Milne604f4402012-04-24 19:27:11 -07003222
Philip Milne7b757812012-09-19 18:13:44 -07003223 onDebugDrawMargins(canvas, paint);
3224 }
3225
3226 // Draw clip bounds
3227 {
3228 paint.setColor(Color.rgb(63, 127, 255));
3229 paint.setStyle(Paint.Style.FILL);
3230
3231 int lineLength = dipsToPixels(8);
3232 int lineWidth = dipsToPixels(1);
3233 for (int i = 0; i < getChildCount(); i++) {
3234 View c = getChildAt(i);
3235 drawRectCorners(canvas, c.getLeft(), c.getTop(), c.getRight(), c.getBottom(),
3236 paint, lineLength, lineWidth);
3237 }
Philip Milne604f4402012-04-24 19:27:11 -07003238 }
Philip Milne10ca24a2012-04-23 15:38:27 -07003239 }
3240
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003241 /**
3242 * {@inheritDoc}
3243 */
3244 @Override
3245 protected void dispatchDraw(Canvas canvas) {
Chris Craika753f4c2014-07-24 12:39:17 -07003246 boolean usingRenderNodeProperties = canvas.isRecordingFor(mRenderNode);
Chris Craikab008f02014-05-23 17:55:03 -07003247 final int childrenCount = mChildrenCount;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003248 final View[] children = mChildren;
3249 int flags = mGroupFlags;
3250
3251 if ((flags & FLAG_RUN_ANIMATION) != 0 && canAnimate()) {
Romain Guy0d9275e2010-10-26 14:22:30 -07003252 final boolean buildCache = !isHardwareAccelerated();
Chris Craikab008f02014-05-23 17:55:03 -07003253 for (int i = 0; i < childrenCount; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003254 final View child = children[i];
3255 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
3256 final LayoutParams params = child.getLayoutParams();
Chris Craikab008f02014-05-23 17:55:03 -07003257 attachLayoutAnimationParameters(child, params, i, childrenCount);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003258 bindLayoutAnimation(child);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003259 }
3260 }
3261
3262 final LayoutAnimationController controller = mLayoutAnimationController;
3263 if (controller.willOverlap()) {
3264 mGroupFlags |= FLAG_OPTIMIZE_INVALIDATE;
3265 }
3266
3267 controller.start();
3268
3269 mGroupFlags &= ~FLAG_RUN_ANIMATION;
3270 mGroupFlags &= ~FLAG_ANIMATION_DONE;
3271
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003272 if (mAnimationListener != null) {
3273 mAnimationListener.onAnimationStart(controller.getAnimation());
3274 }
3275 }
3276
Selim Cinek19cadc22014-04-16 17:27:19 +02003277 int clipSaveCount = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003278 final boolean clipToPadding = (flags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK;
3279 if (clipToPadding) {
Chris Craike4cf1522014-08-04 17:55:22 -07003280 clipSaveCount = canvas.save();
Romain Guy8f2d94f2009-03-25 18:04:42 -07003281 canvas.clipRect(mScrollX + mPaddingLeft, mScrollY + mPaddingTop,
3282 mScrollX + mRight - mLeft - mPaddingRight,
3283 mScrollY + mBottom - mTop - mPaddingBottom);
Selim Cinek19cadc22014-04-16 17:27:19 +02003284 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003285
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003286 // We will draw our child's animation, let's reset the flag
Dianne Hackborn4702a852012-08-17 15:18:29 -07003287 mPrivateFlags &= ~PFLAG_DRAW_ANIMATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003288 mGroupFlags &= ~FLAG_INVALIDATE_REQUIRED;
3289
3290 boolean more = false;
3291 final long drawingTime = getDrawingTime();
3292
Chris Craik8afd0f22014-08-21 17:41:57 -07003293 if (usingRenderNodeProperties) canvas.insertReorderBarrier();
Chris Craikab008f02014-05-23 17:55:03 -07003294 // Only use the preordered list if not HW accelerated, since the HW pipeline will do the
3295 // draw reordering internally
Chris Craika753f4c2014-07-24 12:39:17 -07003296 final ArrayList<View> preorderedList = usingRenderNodeProperties
Chris Craikab008f02014-05-23 17:55:03 -07003297 ? null : buildOrderedChildList();
3298 final boolean customOrder = preorderedList == null
3299 && isChildrenDrawingOrderEnabled();
3300 for (int i = 0; i < childrenCount; i++) {
3301 int childIndex = customOrder ? getChildDrawingOrder(childrenCount, i) : i;
3302 final View child = (preorderedList == null)
3303 ? children[childIndex] : preorderedList.get(childIndex);
3304 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
3305 more |= drawChild(canvas, child, drawingTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003306 }
3307 }
Chris Craikab008f02014-05-23 17:55:03 -07003308 if (preorderedList != null) preorderedList.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003309
3310 // Draw any disappearing views that have animations
3311 if (mDisappearingChildren != null) {
3312 final ArrayList<View> disappearingChildren = mDisappearingChildren;
3313 final int disappearingCount = disappearingChildren.size() - 1;
3314 // Go backwards -- we may delete as animations finish
3315 for (int i = disappearingCount; i >= 0; i--) {
3316 final View child = disappearingChildren.get(i);
3317 more |= drawChild(canvas, child, drawingTime);
3318 }
3319 }
Chris Craik8afd0f22014-08-21 17:41:57 -07003320 if (usingRenderNodeProperties) canvas.insertInorderBarrier();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003321
Philip Milne10ca24a2012-04-23 15:38:27 -07003322 if (debugDraw()) {
3323 onDebugDraw(canvas);
3324 }
3325
Chris Craike4cf1522014-08-04 17:55:22 -07003326 if (clipToPadding) {
Selim Cinek19cadc22014-04-16 17:27:19 +02003327 canvas.restoreToCount(clipSaveCount);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003328 }
3329
3330 // mGroupFlags might have been updated by drawChild()
3331 flags = mGroupFlags;
3332
3333 if ((flags & FLAG_INVALIDATE_REQUIRED) == FLAG_INVALIDATE_REQUIRED) {
Romain Guy849d0a32011-02-01 17:20:48 -08003334 invalidate(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003335 }
3336
3337 if ((flags & FLAG_ANIMATION_DONE) == 0 && (flags & FLAG_NOTIFY_ANIMATION_LISTENER) == 0 &&
3338 mLayoutAnimationController.isDone() && !more) {
3339 // We want to erase the drawing cache and notify the listener after the
3340 // next frame is drawn because one extra invalidate() is caused by
3341 // drawChild() after the animation is over
3342 mGroupFlags |= FLAG_NOTIFY_ANIMATION_LISTENER;
3343 final Runnable end = new Runnable() {
3344 public void run() {
3345 notifyAnimationListener();
3346 }
3347 };
3348 post(end);
3349 }
3350 }
Romain Guy8506ab42009-06-11 17:35:47 -07003351
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003352 /**
Chet Haaseedf6f4b2013-03-26 07:55:30 -07003353 * Returns the ViewGroupOverlay for this view group, creating it if it does
3354 * not yet exist. In addition to {@link ViewOverlay}'s support for drawables,
3355 * {@link ViewGroupOverlay} allows views to be added to the overlay. These
3356 * views, like overlay drawables, are visual-only; they do not receive input
3357 * events and should not be used as anything other than a temporary
3358 * representation of a view in a parent container, such as might be used
3359 * by an animation effect.
3360 *
Chet Haase95399492013-04-08 14:30:31 -07003361 * <p>Note: Overlays do not currently work correctly with {@link
3362 * SurfaceView} or {@link TextureView}; contents in overlays for these
3363 * types of views may not display correctly.</p>
3364 *
Chet Haaseedf6f4b2013-03-26 07:55:30 -07003365 * @return The ViewGroupOverlay object for this view.
3366 * @see ViewGroupOverlay
3367 */
3368 @Override
3369 public ViewGroupOverlay getOverlay() {
3370 if (mOverlay == null) {
3371 mOverlay = new ViewGroupOverlay(mContext, this);
3372 }
3373 return (ViewGroupOverlay) mOverlay;
3374 }
3375
3376 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003377 * Returns the index of the child to draw for this iteration. Override this
3378 * if you want to change the drawing order of children. By default, it
3379 * returns i.
3380 * <p>
Romain Guy293451e2009-11-04 13:59:48 -08003381 * NOTE: In order for this method to be called, you must enable child ordering
3382 * first by calling {@link #setChildrenDrawingOrderEnabled(boolean)}.
Romain Guy8506ab42009-06-11 17:35:47 -07003383 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003384 * @param i The current iteration.
3385 * @return The index of the child to draw this iteration.
Chet Haase5c13d892010-10-08 08:37:55 -07003386 *
Romain Guy293451e2009-11-04 13:59:48 -08003387 * @see #setChildrenDrawingOrderEnabled(boolean)
3388 * @see #isChildrenDrawingOrderEnabled()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003389 */
3390 protected int getChildDrawingOrder(int childCount, int i) {
3391 return i;
3392 }
Romain Guy8506ab42009-06-11 17:35:47 -07003393
Chris Craikab008f02014-05-23 17:55:03 -07003394 private boolean hasChildWithZ() {
3395 for (int i = 0; i < mChildrenCount; i++) {
3396 if (mChildren[i].getZ() != 0) return true;
3397 }
3398 return false;
3399 }
3400
3401 /**
3402 * Populates (and returns) mPreSortedChildren with a pre-ordered list of the View's children,
Chris Craik57c79c82014-09-30 12:54:31 -07003403 * sorted first by Z, then by child drawing order (if applicable). This list must be cleared
3404 * after use to avoid leaking child Views.
Chris Craikab008f02014-05-23 17:55:03 -07003405 *
3406 * Uses a stable, insertion sort which is commonly O(n) for ViewGroups with very few elevated
3407 * children.
3408 */
George Mount81206522014-09-26 21:53:39 -07003409 ArrayList<View> buildOrderedChildList() {
Chris Craikab008f02014-05-23 17:55:03 -07003410 final int count = mChildrenCount;
3411 if (count <= 1 || !hasChildWithZ()) return null;
3412
3413 if (mPreSortedChildren == null) {
3414 mPreSortedChildren = new ArrayList<View>(count);
3415 } else {
3416 mPreSortedChildren.ensureCapacity(count);
3417 }
3418
3419 final boolean useCustomOrder = isChildrenDrawingOrderEnabled();
3420 for (int i = 0; i < mChildrenCount; i++) {
3421 // add next child (in child order) to end of list
3422 int childIndex = useCustomOrder ? getChildDrawingOrder(mChildrenCount, i) : i;
3423 View nextChild = mChildren[childIndex];
3424 float currentZ = nextChild.getZ();
3425
3426 // insert ahead of any Views with greater Z
3427 int insertIndex = i;
3428 while (insertIndex > 0 && mPreSortedChildren.get(insertIndex - 1).getZ() > currentZ) {
3429 insertIndex--;
3430 }
3431 mPreSortedChildren.add(insertIndex, nextChild);
3432 }
3433 return mPreSortedChildren;
3434 }
3435
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003436 private void notifyAnimationListener() {
3437 mGroupFlags &= ~FLAG_NOTIFY_ANIMATION_LISTENER;
3438 mGroupFlags |= FLAG_ANIMATION_DONE;
3439
3440 if (mAnimationListener != null) {
3441 final Runnable end = new Runnable() {
3442 public void run() {
3443 mAnimationListener.onAnimationEnd(mLayoutAnimationController.getAnimation());
3444 }
3445 };
3446 post(end);
3447 }
3448
Romain Guy849d0a32011-02-01 17:20:48 -08003449 invalidate(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003450 }
3451
3452 /**
Chet Haasedaf98e92011-01-10 14:10:36 -08003453 * This method is used to cause children of this ViewGroup to restore or recreate their
3454 * display lists. It is called by getDisplayList() when the parent ViewGroup does not need
3455 * to recreate its own display list, which would happen if it went through the normal
3456 * draw/dispatchDraw mechanisms.
3457 *
3458 * @hide
3459 */
3460 @Override
3461 protected void dispatchGetDisplayList() {
3462 final int count = mChildrenCount;
3463 final View[] children = mChildren;
3464 for (int i = 0; i < count; i++) {
3465 final View child = children[i];
Romain Guy59c7f802011-09-29 17:21:45 -07003466 if (((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) &&
3467 child.hasStaticLayer()) {
Chet Haase6c0665f2014-08-01 13:32:27 -07003468 recreateChildDisplayList(child);
Romain Guy2f57ba52011-02-03 18:03:29 -08003469 }
Chet Haasedaf98e92011-01-10 14:10:36 -08003470 }
Chet Haase91cedf12013-03-11 07:56:30 -07003471 if (mOverlay != null) {
Chet Haaseedf6f4b2013-03-26 07:55:30 -07003472 View overlayView = mOverlay.getOverlayView();
Chet Haase6c0665f2014-08-01 13:32:27 -07003473 recreateChildDisplayList(overlayView);
Chet Haase91cedf12013-03-11 07:56:30 -07003474 }
Chet Haase6c0665f2014-08-01 13:32:27 -07003475 if (mDisappearingChildren != null) {
3476 final ArrayList<View> disappearingChildren = mDisappearingChildren;
3477 final int disappearingCount = disappearingChildren.size();
3478 for (int i = 0; i < disappearingCount; ++i) {
3479 final View child = disappearingChildren.get(i);
3480 recreateChildDisplayList(child);
3481 }
3482 }
3483 }
3484
3485 private void recreateChildDisplayList(View child) {
3486 child.mRecreateDisplayList = (child.mPrivateFlags & PFLAG_INVALIDATED)
3487 == PFLAG_INVALIDATED;
3488 child.mPrivateFlags &= ~PFLAG_INVALIDATED;
3489 child.getDisplayList();
3490 child.mRecreateDisplayList = false;
Chet Haasedaf98e92011-01-10 14:10:36 -08003491 }
3492
3493 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003494 * Draw one child of this View Group. This method is responsible for getting
3495 * the canvas in the right state. This includes clipping, translating so
3496 * that the child's scrolled origin is at 0, 0, and applying any animation
3497 * transformations.
3498 *
3499 * @param canvas The canvas on which to draw the child
3500 * @param child Who to draw
Chet Haasebcca79a2012-02-14 08:45:14 -08003501 * @param drawingTime The time at which draw is occurring
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003502 * @return True if an invalidate() was issued
3503 */
3504 protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
Chet Haase64a48c12012-02-13 16:33:29 -08003505 return child.draw(canvas, this, drawingTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003506 }
3507
3508 /**
Chris Craikd863a102013-12-19 13:31:15 -08003509 * Returns whether this group's children are clipped to their bounds before drawing.
Chet Haase430742f2013-04-12 11:18:36 -07003510 * The default value is true.
3511 * @see #setClipChildren(boolean)
3512 *
3513 * @return True if the group's children will be clipped to their bounds,
3514 * false otherwise.
3515 */
Chris Craik5c75c522014-09-05 14:08:08 -07003516 @ViewDebug.ExportedProperty(category = "drawing")
Chet Haase430742f2013-04-12 11:18:36 -07003517 public boolean getClipChildren() {
3518 return ((mGroupFlags & FLAG_CLIP_CHILDREN) != 0);
3519 }
3520
3521 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003522 * By default, children are clipped to their bounds before drawing. This
3523 * allows view groups to override this behavior for animations, etc.
3524 *
3525 * @param clipChildren true to clip children to their bounds,
3526 * false otherwise
3527 * @attr ref android.R.styleable#ViewGroup_clipChildren
3528 */
3529 public void setClipChildren(boolean clipChildren) {
Chet Haasea1cff502012-02-21 13:43:44 -08003530 boolean previousValue = (mGroupFlags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN;
3531 if (clipChildren != previousValue) {
3532 setBooleanFlag(FLAG_CLIP_CHILDREN, clipChildren);
Chet Haase1271e2c2012-04-20 09:54:27 -07003533 for (int i = 0; i < mChildrenCount; ++i) {
3534 View child = getChildAt(i);
Chris Craik64a12e12014-03-28 18:12:12 -07003535 if (child.mRenderNode != null) {
3536 child.mRenderNode.setClipToBounds(clipChildren);
Chet Haasea1cff502012-02-21 13:43:44 -08003537 }
3538 }
John Reckaae9f3b2014-07-28 09:30:36 -07003539 invalidate(true);
Chet Haasea1cff502012-02-21 13:43:44 -08003540 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003541 }
3542
3543 /**
Chris Craikb1652962014-11-14 17:05:06 -08003544 * Sets whether this ViewGroup will clip its children to its padding, if
3545 * padding is present.
3546 * <p>
3547 * By default, children are clipped to the padding of their parent
3548 * Viewgroup. This clipping behavior is only enabled if padding is non-zero.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003549 *
3550 * @param clipToPadding true to clip children to the padding of the
3551 * group, false otherwise
3552 * @attr ref android.R.styleable#ViewGroup_clipToPadding
3553 */
3554 public void setClipToPadding(boolean clipToPadding) {
John Reck9fa3a242014-06-27 15:57:19 -07003555 if (hasBooleanFlag(FLAG_CLIP_TO_PADDING) != clipToPadding) {
3556 setBooleanFlag(FLAG_CLIP_TO_PADDING, clipToPadding);
John Reckaae9f3b2014-07-28 09:30:36 -07003557 invalidate(true);
John Reck9fa3a242014-06-27 15:57:19 -07003558 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003559 }
3560
3561 /**
Chris Craikb1652962014-11-14 17:05:06 -08003562 * Returns whether this ViewGroup will clip its children to its padding, if
3563 * padding is present.
3564 * <p>
3565 * By default, children are clipped to the padding of their parent
3566 * Viewgroup. This clipping behavior is only enabled if padding is non-zero.
Adam Powell1c35b082014-07-11 15:37:15 -07003567 *
3568 * @return true if this ViewGroup clips children to its padding, false otherwise
3569 *
3570 * @attr ref android.R.styleable#ViewGroup_clipToPadding
3571 */
Chris Craik5c75c522014-09-05 14:08:08 -07003572 @ViewDebug.ExportedProperty(category = "drawing")
Adam Powell1c35b082014-07-11 15:37:15 -07003573 public boolean getClipToPadding() {
3574 return hasBooleanFlag(FLAG_CLIP_TO_PADDING);
3575 }
3576
3577 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003578 * {@inheritDoc}
3579 */
3580 @Override
3581 public void dispatchSetSelected(boolean selected) {
3582 final View[] children = mChildren;
3583 final int count = mChildrenCount;
3584 for (int i = 0; i < count; i++) {
3585 children[i].setSelected(selected);
3586 }
3587 }
Romain Guy8506ab42009-06-11 17:35:47 -07003588
Dianne Hackbornd0fa3712010-09-14 18:57:14 -07003589 /**
3590 * {@inheritDoc}
3591 */
3592 @Override
3593 public void dispatchSetActivated(boolean activated) {
3594 final View[] children = mChildren;
3595 final int count = mChildrenCount;
3596 for (int i = 0; i < count; i++) {
Dianne Hackbornd0fa3712010-09-14 18:57:14 -07003597 children[i].setActivated(activated);
3598 }
3599 }
3600
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003601 @Override
3602 protected void dispatchSetPressed(boolean pressed) {
3603 final View[] children = mChildren;
3604 final int count = mChildrenCount;
3605 for (int i = 0; i < count; i++) {
Adam Powell035a1fc2012-02-27 15:23:50 -08003606 final View child = children[i];
3607 // Children that are clickable on their own should not
3608 // show a pressed state when their parent view does.
3609 // Clearing a pressed state always propagates.
3610 if (!pressed || (!child.isClickable() && !child.isLongClickable())) {
3611 child.setPressed(pressed);
3612 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003613 }
3614 }
3615
Alan Viveretteb942b6f2014-12-08 10:37:39 -08003616 /**
3617 * Dispatches drawable hotspot changes to child views that meet at least
3618 * one of the following criteria:
3619 * <ul>
3620 * <li>Returns {@code false} from both {@link View#isClickable()} and
3621 * {@link View#isLongClickable()}</li>
3622 * <li>Requests duplication of parent state via
3623 * {@link View#setDuplicateParentStateEnabled(boolean)}</li>
3624 * </ul>
3625 *
3626 * @param x hotspot x coordinate
3627 * @param y hotspot y coordinate
3628 * @see #drawableHotspotChanged(float, float)
3629 */
3630 @Override
3631 public void dispatchDrawableHotspotChanged(float x, float y) {
3632 final int count = mChildrenCount;
3633 if (count == 0) {
3634 return;
3635 }
3636
3637 final View[] children = mChildren;
3638 for (int i = 0; i < count; i++) {
3639 final View child = children[i];
3640 // Children that are clickable on their own should not
3641 // receive hotspots when their parent view does.
3642 final boolean nonActionable = !child.isClickable() && !child.isLongClickable();
3643 final boolean duplicatesState = (child.mViewFlags & DUPLICATE_PARENT_STATE) != 0;
3644 if (nonActionable || duplicatesState) {
3645 final float[] point = getTempPoint();
3646 point[0] = x;
3647 point[1] = y;
3648 transformPointToViewLocal(point, child);
3649 child.drawableHotspotChanged(point[0], point[1]);
3650 }
3651 }
3652 }
3653
Adam Powell14874662013-07-18 19:42:41 -07003654 @Override
3655 void dispatchCancelPendingInputEvents() {
3656 super.dispatchCancelPendingInputEvents();
3657
3658 final View[] children = mChildren;
3659 final int count = mChildrenCount;
3660 for (int i = 0; i < count; i++) {
3661 children[i].dispatchCancelPendingInputEvents();
3662 }
3663 }
3664
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003665 /**
3666 * When this property is set to true, this ViewGroup supports static transformations on
3667 * children; this causes
3668 * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} to be
3669 * invoked when a child is drawn.
3670 *
3671 * Any subclass overriding
3672 * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} should
3673 * set this property to true.
3674 *
3675 * @param enabled True to enable static transformations on children, false otherwise.
3676 *
Chet Haase599913d2012-07-23 16:22:05 -07003677 * @see #getChildStaticTransformation(View, android.view.animation.Transformation)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003678 */
3679 protected void setStaticTransformationsEnabled(boolean enabled) {
3680 setBooleanFlag(FLAG_SUPPORT_STATIC_TRANSFORMATIONS, enabled);
3681 }
3682
3683 /**
Chet Haase2d46fcc2011-12-19 18:01:05 -08003684 * Sets <code>t</code> to be the static transformation of the child, if set, returning a
3685 * boolean to indicate whether a static transform was set. The default implementation
3686 * simply returns <code>false</code>; subclasses may override this method for different
Chet Haase599913d2012-07-23 16:22:05 -07003687 * behavior. {@link #setStaticTransformationsEnabled(boolean)} must be set to true
3688 * for this method to be called.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003689 *
Chet Haase2d46fcc2011-12-19 18:01:05 -08003690 * @param child The child view whose static transform is being requested
3691 * @param t The Transformation which will hold the result
3692 * @return true if the transformation was set, false otherwise
Romain Guy8506ab42009-06-11 17:35:47 -07003693 * @see #setStaticTransformationsEnabled(boolean)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003694 */
3695 protected boolean getChildStaticTransformation(View child, Transformation t) {
3696 return false;
3697 }
3698
Romain Guyf6991302013-06-05 17:19:01 -07003699 Transformation getChildTransformation() {
3700 if (mChildTransformation == null) {
3701 mChildTransformation = new Transformation();
3702 }
3703 return mChildTransformation;
3704 }
3705
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003706 /**
3707 * {@hide}
3708 */
3709 @Override
Tor Norbye7b9c9122013-05-30 16:48:33 -07003710 protected View findViewTraversal(@IdRes int id) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003711 if (id == mID) {
3712 return this;
3713 }
3714
3715 final View[] where = mChildren;
3716 final int len = mChildrenCount;
3717
3718 for (int i = 0; i < len; i++) {
3719 View v = where[i];
3720
Dianne Hackborn4702a852012-08-17 15:18:29 -07003721 if ((v.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003722 v = v.findViewById(id);
3723
3724 if (v != null) {
3725 return v;
3726 }
3727 }
3728 }
3729
3730 return null;
3731 }
3732
3733 /**
3734 * {@hide}
3735 */
3736 @Override
3737 protected View findViewWithTagTraversal(Object tag) {
3738 if (tag != null && tag.equals(mTag)) {
3739 return this;
3740 }
3741
3742 final View[] where = mChildren;
3743 final int len = mChildrenCount;
3744
3745 for (int i = 0; i < len; i++) {
3746 View v = where[i];
3747
Dianne Hackborn4702a852012-08-17 15:18:29 -07003748 if ((v.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003749 v = v.findViewWithTag(tag);
3750
3751 if (v != null) {
3752 return v;
3753 }
3754 }
3755 }
3756
3757 return null;
3758 }
3759
3760 /**
Jeff Brown4e6319b2010-12-13 10:36:51 -08003761 * {@hide}
3762 */
3763 @Override
Jeff Brown4dfbec22011-08-15 14:55:37 -07003764 protected View findViewByPredicateTraversal(Predicate<View> predicate, View childToSkip) {
Jeff Brown4e6319b2010-12-13 10:36:51 -08003765 if (predicate.apply(this)) {
3766 return this;
3767 }
3768
3769 final View[] where = mChildren;
3770 final int len = mChildrenCount;
3771
3772 for (int i = 0; i < len; i++) {
3773 View v = where[i];
3774
Dianne Hackborn4702a852012-08-17 15:18:29 -07003775 if (v != childToSkip && (v.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) {
Jeff Brown4e6319b2010-12-13 10:36:51 -08003776 v = v.findViewByPredicate(predicate);
3777
3778 if (v != null) {
3779 return v;
3780 }
3781 }
3782 }
3783
3784 return null;
3785 }
3786
3787 /**
Romain Guy393a52c2012-05-22 20:21:08 -07003788 * <p>Adds a child view. If no layout parameters are already set on the child, the
3789 * default parameters for this ViewGroup are set on the child.</p>
3790 *
3791 * <p><strong>Note:</strong> do not invoke this method from
3792 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3793 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003794 *
3795 * @param child the child view to add
3796 *
3797 * @see #generateDefaultLayoutParams()
3798 */
3799 public void addView(View child) {
3800 addView(child, -1);
3801 }
3802
3803 /**
3804 * Adds a child view. If no layout parameters are already set on the child, the
3805 * default parameters for this ViewGroup are set on the child.
Romain Guy393a52c2012-05-22 20:21:08 -07003806 *
3807 * <p><strong>Note:</strong> do not invoke this method from
3808 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3809 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003810 *
3811 * @param child the child view to add
3812 * @param index the position at which to add the child
3813 *
3814 * @see #generateDefaultLayoutParams()
3815 */
3816 public void addView(View child, int index) {
Adam Powell45a9da52014-10-09 09:44:18 -07003817 if (child == null) {
3818 throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup");
3819 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003820 LayoutParams params = child.getLayoutParams();
3821 if (params == null) {
3822 params = generateDefaultLayoutParams();
3823 if (params == null) {
3824 throw new IllegalArgumentException("generateDefaultLayoutParams() cannot return null");
3825 }
3826 }
3827 addView(child, index, params);
3828 }
3829
3830 /**
3831 * Adds a child view with this ViewGroup's default layout parameters and the
3832 * specified width and height.
3833 *
Romain Guy393a52c2012-05-22 20:21:08 -07003834 * <p><strong>Note:</strong> do not invoke this method from
3835 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3836 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
3837 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003838 * @param child the child view to add
3839 */
3840 public void addView(View child, int width, int height) {
3841 final LayoutParams params = generateDefaultLayoutParams();
3842 params.width = width;
3843 params.height = height;
3844 addView(child, -1, params);
3845 }
3846
3847 /**
3848 * Adds a child view with the specified layout parameters.
3849 *
Romain Guy393a52c2012-05-22 20:21:08 -07003850 * <p><strong>Note:</strong> do not invoke this method from
3851 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3852 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
3853 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003854 * @param child the child view to add
3855 * @param params the layout parameters to set on the child
3856 */
3857 public void addView(View child, LayoutParams params) {
3858 addView(child, -1, params);
3859 }
3860
3861 /**
3862 * Adds a child view with the specified layout parameters.
3863 *
Romain Guy393a52c2012-05-22 20:21:08 -07003864 * <p><strong>Note:</strong> do not invoke this method from
3865 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3866 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
3867 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003868 * @param child the child view to add
Alan Viverette77bb6f12015-02-11 17:24:33 -08003869 * @param index the position at which to add the child or -1 to add last
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003870 * @param params the layout parameters to set on the child
3871 */
3872 public void addView(View child, int index, LayoutParams params) {
3873 if (DBG) {
3874 System.out.println(this + " addView");
3875 }
3876
Adam Powell45a9da52014-10-09 09:44:18 -07003877 if (child == null) {
3878 throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup");
3879 }
3880
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003881 // addViewInner() will call child.requestLayout() when setting the new LayoutParams
3882 // therefore, we call requestLayout() on ourselves before, so that the child's request
3883 // will be blocked at our level
3884 requestLayout();
Romain Guy849d0a32011-02-01 17:20:48 -08003885 invalidate(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003886 addViewInner(child, index, params, false);
3887 }
3888
3889 /**
3890 * {@inheritDoc}
3891 */
3892 public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
3893 if (!checkLayoutParams(params)) {
3894 throw new IllegalArgumentException("Invalid LayoutParams supplied to " + this);
3895 }
3896 if (view.mParent != this) {
3897 throw new IllegalArgumentException("Given view not a child of " + this);
3898 }
3899 view.setLayoutParams(params);
3900 }
3901
3902 /**
3903 * {@inheritDoc}
3904 */
3905 protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
3906 return p != null;
3907 }
3908
3909 /**
3910 * Interface definition for a callback to be invoked when the hierarchy
3911 * within this view changed. The hierarchy changes whenever a child is added
3912 * to or removed from this view.
3913 */
3914 public interface OnHierarchyChangeListener {
3915 /**
3916 * Called when a new child is added to a parent view.
3917 *
3918 * @param parent the view in which a child was added
3919 * @param child the new child view added in the hierarchy
3920 */
3921 void onChildViewAdded(View parent, View child);
3922
3923 /**
3924 * Called when a child is removed from a parent view.
3925 *
3926 * @param parent the view from which the child was removed
3927 * @param child the child removed from the hierarchy
3928 */
3929 void onChildViewRemoved(View parent, View child);
3930 }
3931
3932 /**
3933 * Register a callback to be invoked when a child is added to or removed
3934 * from this view.
3935 *
3936 * @param listener the callback to invoke on hierarchy change
3937 */
3938 public void setOnHierarchyChangeListener(OnHierarchyChangeListener listener) {
3939 mOnHierarchyChangeListener = listener;
3940 }
3941
3942 /**
Philip Milnef51d91c2011-07-18 16:12:19 -07003943 * @hide
3944 */
3945 protected void onViewAdded(View child) {
3946 if (mOnHierarchyChangeListener != null) {
3947 mOnHierarchyChangeListener.onChildViewAdded(this, child);
3948 }
3949 }
3950
3951 /**
3952 * @hide
3953 */
3954 protected void onViewRemoved(View child) {
3955 if (mOnHierarchyChangeListener != null) {
3956 mOnHierarchyChangeListener.onChildViewRemoved(this, child);
3957 }
3958 }
3959
Philip Milnecfb631b2012-10-26 10:51:46 -07003960 private void clearCachedLayoutMode() {
Svetoslav6254f482013-06-04 17:22:14 -07003961 if (!hasBooleanFlag(FLAG_LAYOUT_MODE_WAS_EXPLICITLY_SET)) {
Philip Milnecfb631b2012-10-26 10:51:46 -07003962 mLayoutMode = LAYOUT_MODE_UNDEFINED;
3963 }
3964 }
3965
3966 @Override
3967 protected void onAttachedToWindow() {
3968 super.onAttachedToWindow();
3969 clearCachedLayoutMode();
3970 }
3971
3972 @Override
3973 protected void onDetachedFromWindow() {
3974 super.onDetachedFromWindow();
3975 clearCachedLayoutMode();
3976 }
3977
Philip Milnef51d91c2011-07-18 16:12:19 -07003978 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003979 * Adds a view during layout. This is useful if in your onLayout() method,
3980 * you need to add more views (as does the list view for example).
3981 *
3982 * If index is negative, it means put it at the end of the list.
3983 *
3984 * @param child the view to add to the group
Alan Viverette77bb6f12015-02-11 17:24:33 -08003985 * @param index the index at which the child must be added or -1 to add last
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003986 * @param params the layout parameters to associate with the child
3987 * @return true if the child was added, false otherwise
3988 */
3989 protected boolean addViewInLayout(View child, int index, LayoutParams params) {
3990 return addViewInLayout(child, index, params, false);
3991 }
3992
3993 /**
3994 * Adds a view during layout. This is useful if in your onLayout() method,
3995 * you need to add more views (as does the list view for example).
3996 *
3997 * If index is negative, it means put it at the end of the list.
3998 *
3999 * @param child the view to add to the group
Alan Viverette77bb6f12015-02-11 17:24:33 -08004000 * @param index the index at which the child must be added or -1 to add last
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004001 * @param params the layout parameters to associate with the child
4002 * @param preventRequestLayout if true, calling this method will not trigger a
4003 * layout request on child
4004 * @return true if the child was added, false otherwise
4005 */
4006 protected boolean addViewInLayout(View child, int index, LayoutParams params,
4007 boolean preventRequestLayout) {
Adam Powell45a9da52014-10-09 09:44:18 -07004008 if (child == null) {
4009 throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup");
4010 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004011 child.mParent = null;
4012 addViewInner(child, index, params, preventRequestLayout);
Dianne Hackborn4702a852012-08-17 15:18:29 -07004013 child.mPrivateFlags = (child.mPrivateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004014 return true;
4015 }
4016
4017 /**
4018 * Prevents the specified child to be laid out during the next layout pass.
4019 *
4020 * @param child the child on which to perform the cleanup
4021 */
4022 protected void cleanupLayoutState(View child) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07004023 child.mPrivateFlags &= ~View.PFLAG_FORCE_LAYOUT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004024 }
4025
4026 private void addViewInner(View child, int index, LayoutParams params,
4027 boolean preventRequestLayout) {
4028
Chet Haasee8e45d32011-03-02 17:07:35 -08004029 if (mTransition != null) {
4030 // Don't prevent other add transitions from completing, but cancel remove
4031 // transitions to let them complete the process before we add to the container
4032 mTransition.cancel(LayoutTransition.DISAPPEARING);
Chet Haaseadd65772011-02-09 16:47:29 -08004033 }
4034
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004035 if (child.getParent() != null) {
4036 throw new IllegalStateException("The specified child already has a parent. " +
4037 "You must call removeView() on the child's parent first.");
4038 }
4039
Chet Haase21cd1382010-09-01 17:42:29 -07004040 if (mTransition != null) {
Chet Haase5e25c2c2010-09-16 11:15:56 -07004041 mTransition.addChild(this, child);
Chet Haase21cd1382010-09-01 17:42:29 -07004042 }
4043
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004044 if (!checkLayoutParams(params)) {
4045 params = generateLayoutParams(params);
4046 }
4047
4048 if (preventRequestLayout) {
4049 child.mLayoutParams = params;
4050 } else {
4051 child.setLayoutParams(params);
4052 }
4053
4054 if (index < 0) {
4055 index = mChildrenCount;
4056 }
4057
4058 addInArray(child, index);
4059
4060 // tell our children
4061 if (preventRequestLayout) {
4062 child.assignParent(this);
4063 } else {
4064 child.mParent = this;
4065 }
4066
4067 if (child.hasFocus()) {
4068 requestChildFocus(child, child.findFocus());
4069 }
Romain Guy8506ab42009-06-11 17:35:47 -07004070
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004071 AttachInfo ai = mAttachInfo;
Adam Powell4b867882011-09-16 12:59:46 -07004072 if (ai != null && (mGroupFlags & FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW) == 0) {
Romain Guy8506ab42009-06-11 17:35:47 -07004073 boolean lastKeepOn = ai.mKeepScreenOn;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004074 ai.mKeepScreenOn = false;
4075 child.dispatchAttachedToWindow(mAttachInfo, (mViewFlags&VISIBILITY_MASK));
4076 if (ai.mKeepScreenOn) {
4077 needGlobalAttributesUpdate(true);
4078 }
4079 ai.mKeepScreenOn = lastKeepOn;
4080 }
4081
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07004082 if (child.isLayoutDirectionInherited()) {
Fabrice Di Meglioa7e0bcd2012-10-16 19:55:01 -07004083 child.resetRtlProperties();
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07004084 }
4085
Philip Milnef51d91c2011-07-18 16:12:19 -07004086 onViewAdded(child);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004087
4088 if ((child.mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE) {
4089 mGroupFlags |= FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE;
4090 }
Adam Powell539ee872012-02-03 19:00:49 -08004091
4092 if (child.hasTransientState()) {
4093 childHasTransientStateChanged(child, true);
4094 }
Svetoslav6254f482013-06-04 17:22:14 -07004095
Svetoslav8e3feb12014-02-24 13:46:47 -08004096 if (child.getVisibility() != View.GONE) {
Svetoslav00dbe812013-06-10 12:51:09 -07004097 notifySubtreeAccessibilityStateChangedIfNeeded();
Svetoslav6254f482013-06-04 17:22:14 -07004098 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004099 }
4100
4101 private void addInArray(View child, int index) {
4102 View[] children = mChildren;
4103 final int count = mChildrenCount;
4104 final int size = children.length;
4105 if (index == count) {
4106 if (size == count) {
4107 mChildren = new View[size + ARRAY_CAPACITY_INCREMENT];
4108 System.arraycopy(children, 0, mChildren, 0, size);
4109 children = mChildren;
4110 }
4111 children[mChildrenCount++] = child;
4112 } else if (index < count) {
4113 if (size == count) {
4114 mChildren = new View[size + ARRAY_CAPACITY_INCREMENT];
4115 System.arraycopy(children, 0, mChildren, 0, index);
4116 System.arraycopy(children, index, mChildren, index + 1, count - index);
4117 children = mChildren;
4118 } else {
4119 System.arraycopy(children, index, children, index + 1, count - index);
4120 }
4121 children[index] = child;
4122 mChildrenCount++;
Joe Onorato03ab0c72011-01-06 15:46:27 -08004123 if (mLastTouchDownIndex >= index) {
4124 mLastTouchDownIndex++;
4125 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004126 } else {
4127 throw new IndexOutOfBoundsException("index=" + index + " count=" + count);
4128 }
4129 }
4130
4131 // This method also sets the child's mParent to null
4132 private void removeFromArray(int index) {
4133 final View[] children = mChildren;
Chet Haase21cd1382010-09-01 17:42:29 -07004134 if (!(mTransitioningViews != null && mTransitioningViews.contains(children[index]))) {
4135 children[index].mParent = null;
4136 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004137 final int count = mChildrenCount;
4138 if (index == count - 1) {
4139 children[--mChildrenCount] = null;
4140 } else if (index >= 0 && index < count) {
4141 System.arraycopy(children, index + 1, children, index, count - index - 1);
4142 children[--mChildrenCount] = null;
4143 } else {
4144 throw new IndexOutOfBoundsException();
4145 }
Joe Onorato03ab0c72011-01-06 15:46:27 -08004146 if (mLastTouchDownIndex == index) {
4147 mLastTouchDownTime = 0;
4148 mLastTouchDownIndex = -1;
4149 } else if (mLastTouchDownIndex > index) {
4150 mLastTouchDownIndex--;
4151 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004152 }
4153
4154 // This method also sets the children's mParent to null
4155 private void removeFromArray(int start, int count) {
4156 final View[] children = mChildren;
4157 final int childrenCount = mChildrenCount;
4158
4159 start = Math.max(0, start);
4160 final int end = Math.min(childrenCount, start + count);
4161
4162 if (start == end) {
4163 return;
4164 }
4165
4166 if (end == childrenCount) {
4167 for (int i = start; i < end; i++) {
4168 children[i].mParent = null;
4169 children[i] = null;
4170 }
4171 } else {
4172 for (int i = start; i < end; i++) {
4173 children[i].mParent = null;
4174 }
4175
4176 // Since we're looping above, we might as well do the copy, but is arraycopy()
4177 // faster than the extra 2 bounds checks we would do in the loop?
4178 System.arraycopy(children, end, children, start, childrenCount - end);
4179
4180 for (int i = childrenCount - (end - start); i < childrenCount; i++) {
4181 children[i] = null;
4182 }
4183 }
4184
4185 mChildrenCount -= (end - start);
4186 }
4187
4188 private void bindLayoutAnimation(View child) {
4189 Animation a = mLayoutAnimationController.getAnimationForView(child);
4190 child.setAnimation(a);
4191 }
4192
4193 /**
4194 * Subclasses should override this method to set layout animation
4195 * parameters on the supplied child.
4196 *
4197 * @param child the child to associate with animation parameters
4198 * @param params the child's layout parameters which hold the animation
4199 * parameters
4200 * @param index the index of the child in the view group
4201 * @param count the number of children in the view group
4202 */
4203 protected void attachLayoutAnimationParameters(View child,
4204 LayoutParams params, int index, int count) {
4205 LayoutAnimationController.AnimationParameters animationParams =
4206 params.layoutAnimationParameters;
4207 if (animationParams == null) {
4208 animationParams = new LayoutAnimationController.AnimationParameters();
4209 params.layoutAnimationParameters = animationParams;
4210 }
4211
4212 animationParams.count = count;
4213 animationParams.index = index;
4214 }
4215
4216 /**
4217 * {@inheritDoc}
Romain Guy393a52c2012-05-22 20:21:08 -07004218 *
4219 * <p><strong>Note:</strong> do not invoke this method from
4220 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
4221 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004222 */
4223 public void removeView(View view) {
Alan Viverette177ec4602014-10-17 13:34:50 -07004224 if (removeViewInternal(view)) {
4225 requestLayout();
4226 invalidate(true);
4227 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004228 }
4229
4230 /**
4231 * Removes a view during layout. This is useful if in your onLayout() method,
4232 * you need to remove more views.
4233 *
Romain Guy393a52c2012-05-22 20:21:08 -07004234 * <p><strong>Note:</strong> do not invoke this method from
4235 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
4236 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
4237 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004238 * @param view the view to remove from the group
4239 */
4240 public void removeViewInLayout(View view) {
4241 removeViewInternal(view);
4242 }
4243
4244 /**
4245 * Removes a range of views during layout. This is useful if in your onLayout() method,
4246 * you need to remove more views.
4247 *
Romain Guy393a52c2012-05-22 20:21:08 -07004248 * <p><strong>Note:</strong> do not invoke this method from
4249 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
4250 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
4251 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004252 * @param start the index of the first view to remove from the group
4253 * @param count the number of views to remove from the group
4254 */
4255 public void removeViewsInLayout(int start, int count) {
4256 removeViewsInternal(start, count);
4257 }
4258
4259 /**
4260 * Removes the view at the specified position in the group.
4261 *
Romain Guy393a52c2012-05-22 20:21:08 -07004262 * <p><strong>Note:</strong> do not invoke this method from
4263 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
4264 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
4265 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004266 * @param index the position in the group of the view to remove
4267 */
4268 public void removeViewAt(int index) {
4269 removeViewInternal(index, getChildAt(index));
4270 requestLayout();
Romain Guy849d0a32011-02-01 17:20:48 -08004271 invalidate(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004272 }
4273
4274 /**
4275 * Removes the specified range of views from the group.
4276 *
Romain Guy393a52c2012-05-22 20:21:08 -07004277 * <p><strong>Note:</strong> do not invoke this method from
4278 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
4279 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
4280 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004281 * @param start the first position in the group of the range of views to remove
4282 * @param count the number of views to remove
4283 */
4284 public void removeViews(int start, int count) {
4285 removeViewsInternal(start, count);
4286 requestLayout();
Romain Guy849d0a32011-02-01 17:20:48 -08004287 invalidate(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004288 }
4289
Alan Viverette177ec4602014-10-17 13:34:50 -07004290 private boolean removeViewInternal(View view) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004291 final int index = indexOfChild(view);
4292 if (index >= 0) {
4293 removeViewInternal(index, view);
Alan Viverette177ec4602014-10-17 13:34:50 -07004294 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004295 }
Alan Viverette177ec4602014-10-17 13:34:50 -07004296 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004297 }
4298
4299 private void removeViewInternal(int index, View view) {
Chet Haase21cd1382010-09-01 17:42:29 -07004300
4301 if (mTransition != null) {
Chet Haase5e25c2c2010-09-16 11:15:56 -07004302 mTransition.removeChild(this, view);
Chet Haase21cd1382010-09-01 17:42:29 -07004303 }
4304
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004305 boolean clearChildFocus = false;
4306 if (view == mFocused) {
Alan Viverette223622a2013-12-17 13:29:02 -08004307 view.unFocus(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004308 clearChildFocus = true;
4309 }
4310
Alan Viverette632af842014-10-28 13:45:11 -07004311 view.clearAccessibilityFocus();
Svetoslav Ganov961bf0e2012-05-08 09:40:03 -07004312
Jeff Brown59a422e2012-04-19 15:19:19 -07004313 cancelTouchTarget(view);
4314 cancelHoverTarget(view);
4315
Chet Haase21cd1382010-09-01 17:42:29 -07004316 if (view.getAnimation() != null ||
4317 (mTransitioningViews != null && mTransitioningViews.contains(view))) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004318 addDisappearingView(view);
4319 } else if (view.mAttachInfo != null) {
4320 view.dispatchDetachedFromWindow();
4321 }
4322
Adam Powell539ee872012-02-03 19:00:49 -08004323 if (view.hasTransientState()) {
4324 childHasTransientStateChanged(view, false);
4325 }
4326
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004327 needGlobalAttributesUpdate(false);
Romain Guy8506ab42009-06-11 17:35:47 -07004328
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004329 removeFromArray(index);
4330
4331 if (clearChildFocus) {
4332 clearChildFocus(view);
Svetoslav Ganov149567f2013-01-08 15:23:34 -08004333 if (!rootViewRequestFocus()) {
4334 notifyGlobalFocusCleared(this);
4335 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07004336 }
Romain Guy6fb05632012-11-29 10:50:33 -08004337
4338 onViewRemoved(view);
Svetoslav6254f482013-06-04 17:22:14 -07004339
Svetoslav8e3feb12014-02-24 13:46:47 -08004340 if (view.getVisibility() != View.GONE) {
Svetoslav00dbe812013-06-10 12:51:09 -07004341 notifySubtreeAccessibilityStateChangedIfNeeded();
Svetoslav6254f482013-06-04 17:22:14 -07004342 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004343 }
4344
Chet Haase21cd1382010-09-01 17:42:29 -07004345 /**
4346 * Sets the LayoutTransition object for this ViewGroup. If the LayoutTransition object is
4347 * not null, changes in layout which occur because of children being added to or removed from
4348 * the ViewGroup will be animated according to the animations defined in that LayoutTransition
4349 * object. By default, the transition object is null (so layout changes are not animated).
4350 *
Chet Haaseef3cbfd2013-08-21 14:01:02 -07004351 * <p>Replacing a non-null transition will cause that previous transition to be
4352 * canceled, if it is currently running, to restore this container to
4353 * its correct post-transition state.</p>
4354 *
Chet Haase21cd1382010-09-01 17:42:29 -07004355 * @param transition The LayoutTransition object that will animated changes in layout. A value
4356 * of <code>null</code> means no transition will run on layout changes.
Chet Haase13cc1202010-09-03 15:39:20 -07004357 * @attr ref android.R.styleable#ViewGroup_animateLayoutChanges
Chet Haase21cd1382010-09-01 17:42:29 -07004358 */
4359 public void setLayoutTransition(LayoutTransition transition) {
Chet Haaseb20db3e2010-09-10 13:07:30 -07004360 if (mTransition != null) {
Chet Haasefee6f2b2013-08-27 12:22:29 -07004361 LayoutTransition previousTransition = mTransition;
4362 previousTransition.cancel();
4363 previousTransition.removeTransitionListener(mLayoutTransitionListener);
Chet Haaseb20db3e2010-09-10 13:07:30 -07004364 }
Chet Haase21cd1382010-09-01 17:42:29 -07004365 mTransition = transition;
Chet Haase13cc1202010-09-03 15:39:20 -07004366 if (mTransition != null) {
4367 mTransition.addTransitionListener(mLayoutTransitionListener);
4368 }
4369 }
4370
4371 /**
4372 * Gets the LayoutTransition object for this ViewGroup. If the LayoutTransition object is
4373 * not null, changes in layout which occur because of children being added to or removed from
4374 * the ViewGroup will be animated according to the animations defined in that LayoutTransition
4375 * object. By default, the transition object is null (so layout changes are not animated).
4376 *
4377 * @return LayoutTranstion The LayoutTransition object that will animated changes in layout.
4378 * A value of <code>null</code> means no transition will run on layout changes.
4379 */
4380 public LayoutTransition getLayoutTransition() {
4381 return mTransition;
Chet Haase21cd1382010-09-01 17:42:29 -07004382 }
4383
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004384 private void removeViewsInternal(int start, int count) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004385 final View focused = mFocused;
4386 final boolean detach = mAttachInfo != null;
Svetoslav Ganov149567f2013-01-08 15:23:34 -08004387 boolean clearChildFocus = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004388
4389 final View[] children = mChildren;
4390 final int end = start + count;
4391
4392 for (int i = start; i < end; i++) {
4393 final View view = children[i];
4394
Chet Haase21cd1382010-09-01 17:42:29 -07004395 if (mTransition != null) {
Chet Haase5e25c2c2010-09-16 11:15:56 -07004396 mTransition.removeChild(this, view);
Chet Haase21cd1382010-09-01 17:42:29 -07004397 }
4398
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004399 if (view == focused) {
Alan Viverette223622a2013-12-17 13:29:02 -08004400 view.unFocus(null);
Svetoslav Ganov149567f2013-01-08 15:23:34 -08004401 clearChildFocus = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004402 }
4403
Alan Viverette632af842014-10-28 13:45:11 -07004404 view.clearAccessibilityFocus();
Svetoslav Ganov961bf0e2012-05-08 09:40:03 -07004405
Jeff Brown59a422e2012-04-19 15:19:19 -07004406 cancelTouchTarget(view);
4407 cancelHoverTarget(view);
4408
Chet Haase21cd1382010-09-01 17:42:29 -07004409 if (view.getAnimation() != null ||
4410 (mTransitioningViews != null && mTransitioningViews.contains(view))) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004411 addDisappearingView(view);
4412 } else if (detach) {
4413 view.dispatchDetachedFromWindow();
4414 }
4415
Adam Powell539ee872012-02-03 19:00:49 -08004416 if (view.hasTransientState()) {
4417 childHasTransientStateChanged(view, false);
4418 }
4419
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004420 needGlobalAttributesUpdate(false);
Romain Guy8506ab42009-06-11 17:35:47 -07004421
Philip Milnef51d91c2011-07-18 16:12:19 -07004422 onViewRemoved(view);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004423 }
4424
4425 removeFromArray(start, count);
4426
Svetoslav Ganov149567f2013-01-08 15:23:34 -08004427 if (clearChildFocus) {
4428 clearChildFocus(focused);
4429 if (!rootViewRequestFocus()) {
4430 notifyGlobalFocusCleared(focused);
4431 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004432 }
4433 }
4434
4435 /**
4436 * Call this method to remove all child views from the
4437 * ViewGroup.
Romain Guy393a52c2012-05-22 20:21:08 -07004438 *
4439 * <p><strong>Note:</strong> do not invoke this method from
4440 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
4441 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004442 */
4443 public void removeAllViews() {
4444 removeAllViewsInLayout();
4445 requestLayout();
Romain Guy849d0a32011-02-01 17:20:48 -08004446 invalidate(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004447 }
4448
4449 /**
4450 * Called by a ViewGroup subclass to remove child views from itself,
4451 * when it must first know its size on screen before it can calculate how many
4452 * child views it will render. An example is a Gallery or a ListView, which
4453 * may "have" 50 children, but actually only render the number of children
4454 * that can currently fit inside the object on screen. Do not call
4455 * this method unless you are extending ViewGroup and understand the
4456 * view measuring and layout pipeline.
Romain Guy393a52c2012-05-22 20:21:08 -07004457 *
4458 * <p><strong>Note:</strong> do not invoke this method from
4459 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
4460 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004461 */
4462 public void removeAllViewsInLayout() {
4463 final int count = mChildrenCount;
4464 if (count <= 0) {
4465 return;
4466 }
4467
4468 final View[] children = mChildren;
4469 mChildrenCount = 0;
4470
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004471 final View focused = mFocused;
4472 final boolean detach = mAttachInfo != null;
Svetoslav Ganov149567f2013-01-08 15:23:34 -08004473 boolean clearChildFocus = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004474
4475 needGlobalAttributesUpdate(false);
Romain Guy8506ab42009-06-11 17:35:47 -07004476
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004477 for (int i = count - 1; i >= 0; i--) {
4478 final View view = children[i];
4479
Chet Haase21cd1382010-09-01 17:42:29 -07004480 if (mTransition != null) {
Chet Haase5e25c2c2010-09-16 11:15:56 -07004481 mTransition.removeChild(this, view);
Chet Haase21cd1382010-09-01 17:42:29 -07004482 }
4483
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004484 if (view == focused) {
Alan Viverette223622a2013-12-17 13:29:02 -08004485 view.unFocus(null);
Svetoslav Ganov149567f2013-01-08 15:23:34 -08004486 clearChildFocus = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004487 }
4488
Alan Viverette632af842014-10-28 13:45:11 -07004489 view.clearAccessibilityFocus();
Svetoslav Ganov961bf0e2012-05-08 09:40:03 -07004490
Jeff Brown59a422e2012-04-19 15:19:19 -07004491 cancelTouchTarget(view);
4492 cancelHoverTarget(view);
4493
Chet Haase21cd1382010-09-01 17:42:29 -07004494 if (view.getAnimation() != null ||
4495 (mTransitioningViews != null && mTransitioningViews.contains(view))) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004496 addDisappearingView(view);
4497 } else if (detach) {
4498 view.dispatchDetachedFromWindow();
4499 }
4500
Adam Powell539ee872012-02-03 19:00:49 -08004501 if (view.hasTransientState()) {
4502 childHasTransientStateChanged(view, false);
4503 }
4504
Philip Milnef51d91c2011-07-18 16:12:19 -07004505 onViewRemoved(view);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004506
4507 view.mParent = null;
4508 children[i] = null;
4509 }
4510
Svetoslav Ganov149567f2013-01-08 15:23:34 -08004511 if (clearChildFocus) {
4512 clearChildFocus(focused);
4513 if (!rootViewRequestFocus()) {
4514 notifyGlobalFocusCleared(focused);
4515 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004516 }
4517 }
4518
4519 /**
4520 * Finishes the removal of a detached view. This method will dispatch the detached from
4521 * window event and notify the hierarchy change listener.
Chet Haaseca479d42012-08-30 17:20:08 -07004522 * <p>
4523 * This method is intended to be lightweight and makes no assumptions about whether the
4524 * parent or child should be redrawn. Proper use of this method will include also making
4525 * any appropriate {@link #requestLayout()} or {@link #invalidate()} calls.
4526 * For example, callers can {@link #post(Runnable) post} a {@link Runnable}
4527 * which performs a {@link #requestLayout()} on the next frame, after all detach/remove
4528 * calls are finished, causing layout to be run prior to redrawing the view hierarchy.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004529 *
4530 * @param child the child to be definitely removed from the view hierarchy
4531 * @param animate if true and the view has an animation, the view is placed in the
4532 * disappearing views list, otherwise, it is detached from the window
4533 *
4534 * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
4535 * @see #detachAllViewsFromParent()
4536 * @see #detachViewFromParent(View)
4537 * @see #detachViewFromParent(int)
4538 */
4539 protected void removeDetachedView(View child, boolean animate) {
Chet Haase21cd1382010-09-01 17:42:29 -07004540 if (mTransition != null) {
Chet Haase5e25c2c2010-09-16 11:15:56 -07004541 mTransition.removeChild(this, child);
Chet Haase21cd1382010-09-01 17:42:29 -07004542 }
4543
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004544 if (child == mFocused) {
4545 child.clearFocus();
4546 }
Romain Guy8506ab42009-06-11 17:35:47 -07004547
Svetoslav Ganov961bf0e2012-05-08 09:40:03 -07004548 child.clearAccessibilityFocus();
4549
Jeff Brown59a422e2012-04-19 15:19:19 -07004550 cancelTouchTarget(child);
4551 cancelHoverTarget(child);
4552
Chet Haase21cd1382010-09-01 17:42:29 -07004553 if ((animate && child.getAnimation() != null) ||
4554 (mTransitioningViews != null && mTransitioningViews.contains(child))) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004555 addDisappearingView(child);
4556 } else if (child.mAttachInfo != null) {
4557 child.dispatchDetachedFromWindow();
4558 }
4559
Adam Powell539ee872012-02-03 19:00:49 -08004560 if (child.hasTransientState()) {
4561 childHasTransientStateChanged(child, false);
4562 }
4563
Philip Milnef51d91c2011-07-18 16:12:19 -07004564 onViewRemoved(child);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004565 }
4566
4567 /**
4568 * Attaches a view to this view group. Attaching a view assigns this group as the parent,
Chet Haaseca479d42012-08-30 17:20:08 -07004569 * sets the layout parameters and puts the view in the list of children so that
4570 * it can be retrieved by calling {@link #getChildAt(int)}.
4571 * <p>
4572 * This method is intended to be lightweight and makes no assumptions about whether the
4573 * parent or child should be redrawn. Proper use of this method will include also making
4574 * any appropriate {@link #requestLayout()} or {@link #invalidate()} calls.
4575 * For example, callers can {@link #post(Runnable) post} a {@link Runnable}
4576 * which performs a {@link #requestLayout()} on the next frame, after all detach/attach
4577 * calls are finished, causing layout to be run prior to redrawing the view hierarchy.
4578 * <p>
4579 * This method should be called only for views which were detached from their parent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004580 *
4581 * @param child the child to attach
4582 * @param index the index at which the child should be attached
4583 * @param params the layout parameters of the child
4584 *
4585 * @see #removeDetachedView(View, boolean)
4586 * @see #detachAllViewsFromParent()
4587 * @see #detachViewFromParent(View)
4588 * @see #detachViewFromParent(int)
4589 */
4590 protected void attachViewToParent(View child, int index, LayoutParams params) {
4591 child.mLayoutParams = params;
4592
4593 if (index < 0) {
4594 index = mChildrenCount;
4595 }
4596
4597 addInArray(child, index);
4598
4599 child.mParent = this;
Dianne Hackborn4702a852012-08-17 15:18:29 -07004600 child.mPrivateFlags = (child.mPrivateFlags & ~PFLAG_DIRTY_MASK
4601 & ~PFLAG_DRAWING_CACHE_VALID)
4602 | PFLAG_DRAWN | PFLAG_INVALIDATED;
4603 this.mPrivateFlags |= PFLAG_INVALIDATED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004604
4605 if (child.hasFocus()) {
4606 requestChildFocus(child, child.findFocus());
4607 }
4608 }
4609
4610 /**
Chet Haaseca479d42012-08-30 17:20:08 -07004611 * Detaches a view from its parent. Detaching a view should be followed
4612 * either by a call to
4613 * {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
4614 * or a call to {@link #removeDetachedView(View, boolean)}. Detachment should only be
4615 * temporary; reattachment or removal should happen within the same drawing cycle as
4616 * detachment. When a view is detached, its parent is null and cannot be retrieved by a
4617 * call to {@link #getChildAt(int)}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004618 *
4619 * @param child the child to detach
4620 *
4621 * @see #detachViewFromParent(int)
4622 * @see #detachViewsFromParent(int, int)
4623 * @see #detachAllViewsFromParent()
4624 * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
4625 * @see #removeDetachedView(View, boolean)
4626 */
4627 protected void detachViewFromParent(View child) {
4628 removeFromArray(indexOfChild(child));
4629 }
4630
4631 /**
Chet Haaseca479d42012-08-30 17:20:08 -07004632 * Detaches a view from its parent. Detaching a view should be followed
4633 * either by a call to
4634 * {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
4635 * or a call to {@link #removeDetachedView(View, boolean)}. Detachment should only be
4636 * temporary; reattachment or removal should happen within the same drawing cycle as
4637 * detachment. When a view is detached, its parent is null and cannot be retrieved by a
4638 * call to {@link #getChildAt(int)}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004639 *
4640 * @param index the index of the child to detach
4641 *
4642 * @see #detachViewFromParent(View)
4643 * @see #detachAllViewsFromParent()
4644 * @see #detachViewsFromParent(int, int)
4645 * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
4646 * @see #removeDetachedView(View, boolean)
4647 */
4648 protected void detachViewFromParent(int index) {
4649 removeFromArray(index);
4650 }
4651
4652 /**
Chet Haaseca479d42012-08-30 17:20:08 -07004653 * Detaches a range of views from their parents. Detaching a view should be followed
4654 * either by a call to
4655 * {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
4656 * or a call to {@link #removeDetachedView(View, boolean)}. Detachment should only be
4657 * temporary; reattachment or removal should happen within the same drawing cycle as
4658 * detachment. When a view is detached, its parent is null and cannot be retrieved by a
4659 * call to {@link #getChildAt(int)}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004660 *
4661 * @param start the first index of the childrend range to detach
4662 * @param count the number of children to detach
4663 *
4664 * @see #detachViewFromParent(View)
4665 * @see #detachViewFromParent(int)
4666 * @see #detachAllViewsFromParent()
4667 * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
4668 * @see #removeDetachedView(View, boolean)
4669 */
4670 protected void detachViewsFromParent(int start, int count) {
4671 removeFromArray(start, count);
4672 }
4673
4674 /**
Chet Haaseca479d42012-08-30 17:20:08 -07004675 * Detaches all views from the parent. Detaching a view should be followed
4676 * either by a call to
4677 * {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
4678 * or a call to {@link #removeDetachedView(View, boolean)}. Detachment should only be
4679 * temporary; reattachment or removal should happen within the same drawing cycle as
4680 * detachment. When a view is detached, its parent is null and cannot be retrieved by a
4681 * call to {@link #getChildAt(int)}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004682 *
4683 * @see #detachViewFromParent(View)
4684 * @see #detachViewFromParent(int)
4685 * @see #detachViewsFromParent(int, int)
4686 * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
4687 * @see #removeDetachedView(View, boolean)
4688 */
4689 protected void detachAllViewsFromParent() {
4690 final int count = mChildrenCount;
4691 if (count <= 0) {
4692 return;
4693 }
4694
4695 final View[] children = mChildren;
4696 mChildrenCount = 0;
4697
4698 for (int i = count - 1; i >= 0; i--) {
4699 children[i].mParent = null;
4700 children[i] = null;
4701 }
4702 }
4703
4704 /**
4705 * Don't call or override this method. It is used for the implementation of
4706 * the view hierarchy.
4707 */
4708 public final void invalidateChild(View child, final Rect dirty) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004709 ViewParent parent = this;
4710
4711 final AttachInfo attachInfo = mAttachInfo;
4712 if (attachInfo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004713 // If the child is drawing an animation, we want to copy this flag onto
4714 // ourselves and the parent to make sure the invalidate request goes
4715 // through
Dianne Hackborn4702a852012-08-17 15:18:29 -07004716 final boolean drawAnimation = (child.mPrivateFlags & PFLAG_DRAW_ANIMATION)
4717 == PFLAG_DRAW_ANIMATION;
Romain Guy24443ea2009-05-11 11:56:30 -07004718
Romain Guyfe455af2012-02-15 16:40:20 -08004719 // Check whether the child that requests the invalidate is fully opaque
4720 // Views being animated or transformed are not considered opaque because we may
4721 // be invalidating their old position and need the parent to paint behind them.
4722 Matrix childMatrix = child.getMatrix();
4723 final boolean isOpaque = child.isOpaque() && !drawAnimation &&
4724 child.getAnimation() == null && childMatrix.isIdentity();
4725 // Mark the child as dirty, using the appropriate flag
4726 // Make sure we do not set both flags at the same time
Dianne Hackborn4702a852012-08-17 15:18:29 -07004727 int opaqueFlag = isOpaque ? PFLAG_DIRTY_OPAQUE : PFLAG_DIRTY;
Romain Guyfe455af2012-02-15 16:40:20 -08004728
John Reck96bb8ad2014-06-19 10:53:03 -07004729 if (child.mLayerType != LAYER_TYPE_NONE) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07004730 mPrivateFlags |= PFLAG_INVALIDATED;
4731 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
Romain Guyfe455af2012-02-15 16:40:20 -08004732 }
4733
4734 final int[] location = attachInfo.mInvalidateChildLocation;
4735 location[CHILD_LEFT_INDEX] = child.mLeft;
4736 location[CHILD_TOP_INDEX] = child.mTop;
Chet Haase599913d2012-07-23 16:22:05 -07004737 if (!childMatrix.isIdentity() ||
4738 (mGroupFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) {
Romain Guyfe455af2012-02-15 16:40:20 -08004739 RectF boundingRect = attachInfo.mTmpTransformRect;
4740 boundingRect.set(dirty);
Chet Haase599913d2012-07-23 16:22:05 -07004741 Matrix transformMatrix;
4742 if ((mGroupFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) {
4743 Transformation t = attachInfo.mTmpTransformation;
4744 boolean transformed = getChildStaticTransformation(child, t);
4745 if (transformed) {
4746 transformMatrix = attachInfo.mTmpMatrix;
4747 transformMatrix.set(t.getMatrix());
4748 if (!childMatrix.isIdentity()) {
4749 transformMatrix.preConcat(childMatrix);
4750 }
4751 } else {
4752 transformMatrix = childMatrix;
4753 }
4754 } else {
4755 transformMatrix = childMatrix;
4756 }
4757 transformMatrix.mapRect(boundingRect);
Romain Guyfe455af2012-02-15 16:40:20 -08004758 dirty.set((int) (boundingRect.left - 0.5f),
4759 (int) (boundingRect.top - 0.5f),
4760 (int) (boundingRect.right + 0.5f),
4761 (int) (boundingRect.bottom + 0.5f));
4762 }
4763
4764 do {
4765 View view = null;
4766 if (parent instanceof View) {
4767 view = (View) parent;
Romain Guyfe455af2012-02-15 16:40:20 -08004768 }
4769
4770 if (drawAnimation) {
4771 if (view != null) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07004772 view.mPrivateFlags |= PFLAG_DRAW_ANIMATION;
Romain Guyfe455af2012-02-15 16:40:20 -08004773 } else if (parent instanceof ViewRootImpl) {
4774 ((ViewRootImpl) parent).mIsAnimating = true;
4775 }
4776 }
4777
4778 // If the parent is dirty opaque or not dirty, mark it dirty with the opaque
4779 // flag coming from the child that initiated the invalidate
4780 if (view != null) {
4781 if ((view.mViewFlags & FADING_EDGE_MASK) != 0 &&
4782 view.getSolidColor() == 0) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07004783 opaqueFlag = PFLAG_DIRTY;
Romain Guyfe455af2012-02-15 16:40:20 -08004784 }
Dianne Hackborn4702a852012-08-17 15:18:29 -07004785 if ((view.mPrivateFlags & PFLAG_DIRTY_MASK) != PFLAG_DIRTY) {
4786 view.mPrivateFlags = (view.mPrivateFlags & ~PFLAG_DIRTY_MASK) | opaqueFlag;
Romain Guyfe455af2012-02-15 16:40:20 -08004787 }
4788 }
4789
4790 parent = parent.invalidateChildInParent(location, dirty);
4791 if (view != null) {
4792 // Account for transform on current parent
4793 Matrix m = view.getMatrix();
4794 if (!m.isIdentity()) {
4795 RectF boundingRect = attachInfo.mTmpTransformRect;
4796 boundingRect.set(dirty);
4797 m.mapRect(boundingRect);
Romain Guye8585b12012-02-17 18:28:47 -08004798 dirty.set((int) (boundingRect.left - 0.5f),
4799 (int) (boundingRect.top - 0.5f),
Romain Guyfe455af2012-02-15 16:40:20 -08004800 (int) (boundingRect.right + 0.5f),
4801 (int) (boundingRect.bottom + 0.5f));
4802 }
4803 }
4804 } while (parent != null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004805 }
4806 }
4807
4808 /**
4809 * Don't call or override this method. It is used for the implementation of
4810 * the view hierarchy.
4811 *
4812 * This implementation returns null if this ViewGroup does not have a parent,
4813 * if this ViewGroup is already fully invalidated or if the dirty rectangle
4814 * does not intersect with this ViewGroup's bounds.
4815 */
4816 public ViewParent invalidateChildInParent(final int[] location, final Rect dirty) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07004817 if ((mPrivateFlags & PFLAG_DRAWN) == PFLAG_DRAWN ||
4818 (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004819 if ((mGroupFlags & (FLAG_OPTIMIZE_INVALIDATE | FLAG_ANIMATION_DONE)) !=
4820 FLAG_OPTIMIZE_INVALIDATE) {
4821 dirty.offset(location[CHILD_LEFT_INDEX] - mScrollX,
4822 location[CHILD_TOP_INDEX] - mScrollY);
Chet Haasea4f14eb2013-04-22 11:11:39 -07004823 if ((mGroupFlags & FLAG_CLIP_CHILDREN) == 0) {
4824 dirty.union(0, 0, mRight - mLeft, mBottom - mTop);
4825 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004826
4827 final int left = mLeft;
4828 final int top = mTop;
4829
Chet Haase05e91ed2012-07-03 14:17:57 -07004830 if ((mGroupFlags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN) {
4831 if (!dirty.intersect(0, 0, mRight - left, mBottom - top)) {
4832 dirty.setEmpty();
Romain Guy3a3133d2011-02-01 22:59:58 -08004833 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004834 }
Dianne Hackborn4702a852012-08-17 15:18:29 -07004835 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
Chet Haase05e91ed2012-07-03 14:17:57 -07004836
4837 location[CHILD_LEFT_INDEX] = left;
4838 location[CHILD_TOP_INDEX] = top;
4839
John Reck96bb8ad2014-06-19 10:53:03 -07004840 if (mLayerType != LAYER_TYPE_NONE) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07004841 mPrivateFlags |= PFLAG_INVALIDATED;
Chet Haase05e91ed2012-07-03 14:17:57 -07004842 }
4843
4844 return mParent;
4845
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004846 } else {
Dianne Hackborn4702a852012-08-17 15:18:29 -07004847 mPrivateFlags &= ~PFLAG_DRAWN & ~PFLAG_DRAWING_CACHE_VALID;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004848
4849 location[CHILD_LEFT_INDEX] = mLeft;
4850 location[CHILD_TOP_INDEX] = mTop;
Chet Haasea3db8662011-07-19 10:36:05 -07004851 if ((mGroupFlags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN) {
4852 dirty.set(0, 0, mRight - mLeft, mBottom - mTop);
4853 } else {
4854 // in case the dirty rect extends outside the bounds of this container
4855 dirty.union(0, 0, mRight - mLeft, mBottom - mTop);
4856 }
Romain Guy3a3133d2011-02-01 22:59:58 -08004857
John Reck96bb8ad2014-06-19 10:53:03 -07004858 if (mLayerType != LAYER_TYPE_NONE) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07004859 mPrivateFlags |= PFLAG_INVALIDATED;
Romain Guy3a3133d2011-02-01 22:59:58 -08004860 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004861
4862 return mParent;
4863 }
4864 }
4865
4866 return null;
4867 }
4868
4869 /**
John Recke4267ea2014-06-03 15:53:15 -07004870 * Native-calculated damage path
4871 * Returns false if this path was unable to complete successfully. This means
4872 * it hit a ViewParent it doesn't recognize and needs to fall back to calculating
4873 * damage area
4874 * @hide
4875 */
4876 public boolean damageChildDeferred(View child) {
4877 ViewParent parent = getParent();
4878 while (parent != null) {
4879 if (parent instanceof ViewGroup) {
4880 parent = parent.getParent();
4881 } else if (parent instanceof ViewRootImpl) {
4882 ((ViewRootImpl) parent).invalidate();
4883 return true;
4884 } else {
4885 parent = null;
4886 }
4887 }
4888 return false;
4889 }
4890
4891 /**
Chet Haase9d1992d2012-03-13 11:03:25 -07004892 * Quick invalidation method called by View.invalidateViewProperty. This doesn't set the
4893 * DRAWN flags and doesn't handle the Animation logic that the default invalidation methods
4894 * do; all we want to do here is schedule a traversal with the appropriate dirty rect.
4895 *
4896 * @hide
4897 */
Chris Craik49e6c732014-03-31 12:34:11 -07004898 public void damageChild(View child, final Rect dirty) {
John Recke4267ea2014-06-03 15:53:15 -07004899 if (damageChildDeferred(child)) {
4900 return;
4901 }
4902
Chet Haase9d1992d2012-03-13 11:03:25 -07004903 ViewParent parent = this;
4904
4905 final AttachInfo attachInfo = mAttachInfo;
4906 if (attachInfo != null) {
Chet Haase9d1992d2012-03-13 11:03:25 -07004907 int left = child.mLeft;
4908 int top = child.mTop;
4909 if (!child.getMatrix().isIdentity()) {
4910 child.transformRect(dirty);
4911 }
4912
4913 do {
4914 if (parent instanceof ViewGroup) {
4915 ViewGroup parentVG = (ViewGroup) parent;
Chet Haaseb85967b2012-03-26 14:37:51 -07004916 if (parentVG.mLayerType != LAYER_TYPE_NONE) {
4917 // Layered parents should be recreated, not just re-issued
4918 parentVG.invalidate();
4919 parent = null;
4920 } else {
Chris Craik49e6c732014-03-31 12:34:11 -07004921 parent = parentVG.damageChildInParent(left, top, dirty);
Chet Haaseb85967b2012-03-26 14:37:51 -07004922 left = parentVG.mLeft;
4923 top = parentVG.mTop;
4924 }
Chet Haase9d1992d2012-03-13 11:03:25 -07004925 } else {
4926 // Reached the top; this calls into the usual invalidate method in
4927 // ViewRootImpl, which schedules a traversal
4928 final int[] location = attachInfo.mInvalidateChildLocation;
4929 location[0] = left;
4930 location[1] = top;
4931 parent = parent.invalidateChildInParent(location, dirty);
4932 }
4933 } while (parent != null);
4934 }
4935 }
4936
4937 /**
4938 * Quick invalidation method that simply transforms the dirty rect into the parent's
4939 * coordinate system, pruning the invalidation if the parent has already been invalidated.
Chet Haasee4a2d7c2013-06-21 17:49:36 -07004940 *
4941 * @hide
Chet Haase9d1992d2012-03-13 11:03:25 -07004942 */
Chris Craik49e6c732014-03-31 12:34:11 -07004943 protected ViewParent damageChildInParent(int left, int top, final Rect dirty) {
4944 if ((mPrivateFlags & PFLAG_DRAWN) != 0
4945 || (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) != 0) {
Chet Haase9d1992d2012-03-13 11:03:25 -07004946 dirty.offset(left - mScrollX, top - mScrollY);
Chet Haasea4f14eb2013-04-22 11:11:39 -07004947 if ((mGroupFlags & FLAG_CLIP_CHILDREN) == 0) {
4948 dirty.union(0, 0, mRight - mLeft, mBottom - mTop);
4949 }
Chet Haase9d1992d2012-03-13 11:03:25 -07004950
4951 if ((mGroupFlags & FLAG_CLIP_CHILDREN) == 0 ||
4952 dirty.intersect(0, 0, mRight - mLeft, mBottom - mTop)) {
4953
Chet Haase9d1992d2012-03-13 11:03:25 -07004954 if (!getMatrix().isIdentity()) {
4955 transformRect(dirty);
4956 }
4957
4958 return mParent;
4959 }
4960 }
4961
4962 return null;
4963 }
4964
4965 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004966 * Offset a rectangle that is in a descendant's coordinate
4967 * space into our coordinate space.
4968 * @param descendant A descendant of this view
4969 * @param rect A rectangle defined in descendant's coordinate space.
4970 */
4971 public final void offsetDescendantRectToMyCoords(View descendant, Rect rect) {
4972 offsetRectBetweenParentAndChild(descendant, rect, true, false);
4973 }
4974
4975 /**
4976 * Offset a rectangle that is in our coordinate space into an ancestor's
4977 * coordinate space.
4978 * @param descendant A descendant of this view
4979 * @param rect A rectangle defined in descendant's coordinate space.
4980 */
4981 public final void offsetRectIntoDescendantCoords(View descendant, Rect rect) {
4982 offsetRectBetweenParentAndChild(descendant, rect, false, false);
4983 }
4984
4985 /**
4986 * Helper method that offsets a rect either from parent to descendant or
4987 * descendant to parent.
4988 */
4989 void offsetRectBetweenParentAndChild(View descendant, Rect rect,
4990 boolean offsetFromChildToParent, boolean clipToBounds) {
4991
4992 // already in the same coord system :)
4993 if (descendant == this) {
4994 return;
4995 }
4996
4997 ViewParent theParent = descendant.mParent;
4998
4999 // search and offset up to the parent
5000 while ((theParent != null)
5001 && (theParent instanceof View)
5002 && (theParent != this)) {
5003
5004 if (offsetFromChildToParent) {
5005 rect.offset(descendant.mLeft - descendant.mScrollX,
5006 descendant.mTop - descendant.mScrollY);
5007 if (clipToBounds) {
5008 View p = (View) theParent;
5009 rect.intersect(0, 0, p.mRight - p.mLeft, p.mBottom - p.mTop);
5010 }
5011 } else {
5012 if (clipToBounds) {
5013 View p = (View) theParent;
5014 rect.intersect(0, 0, p.mRight - p.mLeft, p.mBottom - p.mTop);
5015 }
5016 rect.offset(descendant.mScrollX - descendant.mLeft,
5017 descendant.mScrollY - descendant.mTop);
5018 }
5019
5020 descendant = (View) theParent;
5021 theParent = descendant.mParent;
5022 }
5023
5024 // now that we are up to this view, need to offset one more time
5025 // to get into our coordinate space
5026 if (theParent == this) {
5027 if (offsetFromChildToParent) {
5028 rect.offset(descendant.mLeft - descendant.mScrollX,
5029 descendant.mTop - descendant.mScrollY);
5030 } else {
5031 rect.offset(descendant.mScrollX - descendant.mLeft,
5032 descendant.mScrollY - descendant.mTop);
5033 }
5034 } else {
5035 throw new IllegalArgumentException("parameter must be a descendant of this view");
5036 }
5037 }
5038
5039 /**
5040 * Offset the vertical location of all children of this view by the specified number of pixels.
5041 *
5042 * @param offset the number of pixels to offset
5043 *
5044 * @hide
5045 */
5046 public void offsetChildrenTopAndBottom(int offset) {
5047 final int count = mChildrenCount;
5048 final View[] children = mChildren;
Romain Guy5549cb52013-05-06 18:42:08 -07005049 boolean invalidate = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005050
5051 for (int i = 0; i < count; i++) {
5052 final View v = children[i];
5053 v.mTop += offset;
5054 v.mBottom += offset;
Chris Craik64a12e12014-03-28 18:12:12 -07005055 if (v.mRenderNode != null) {
Romain Guy5549cb52013-05-06 18:42:08 -07005056 invalidate = true;
Chris Craik64a12e12014-03-28 18:12:12 -07005057 v.mRenderNode.offsetTopAndBottom(offset);
Chet Haasea1cff502012-02-21 13:43:44 -08005058 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005059 }
Romain Guy5549cb52013-05-06 18:42:08 -07005060
5061 if (invalidate) {
5062 invalidateViewProperty(false, false);
5063 }
Guang Zhu84e25092014-05-01 21:12:55 -07005064 notifySubtreeAccessibilityStateChangedIfNeeded();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005065 }
5066
5067 /**
5068 * {@inheritDoc}
5069 */
5070 public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) {
Adam Powellf93bb6d2011-12-12 15:21:57 -08005071 // It doesn't make a whole lot of sense to call this on a view that isn't attached,
5072 // but for some simple tests it can be useful. If we don't have attach info this
5073 // will allocate memory.
5074 final RectF rect = mAttachInfo != null ? mAttachInfo.mTmpTransformRect : new RectF();
Gilles Debunnecea45132011-11-24 02:19:27 +01005075 rect.set(r);
5076
5077 if (!child.hasIdentityMatrix()) {
George Mount002d43d2014-11-11 12:54:43 -08005078 child.getMatrix().mapRect(rect);
Gilles Debunnecea45132011-11-24 02:19:27 +01005079 }
5080
Alan Viveretteab2cf6d2014-11-26 14:34:36 -08005081 final int dx = child.mLeft - mScrollX;
5082 final int dy = child.mTop - mScrollY;
Gilles Debunnecea45132011-11-24 02:19:27 +01005083
5084 rect.offset(dx, dy);
5085
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005086 if (offset != null) {
Gilles Debunnecea45132011-11-24 02:19:27 +01005087 if (!child.hasIdentityMatrix()) {
Adam Powellf93bb6d2011-12-12 15:21:57 -08005088 float[] position = mAttachInfo != null ? mAttachInfo.mTmpTransformLocation
5089 : new float[2];
Gilles Debunnecea45132011-11-24 02:19:27 +01005090 position[0] = offset.x;
5091 position[1] = offset.y;
5092 child.getMatrix().mapPoints(position);
5093 offset.x = (int) (position[0] + 0.5f);
5094 offset.y = (int) (position[1] + 0.5f);
5095 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005096 offset.x += dx;
5097 offset.y += dy;
5098 }
Gilles Debunnecea45132011-11-24 02:19:27 +01005099
Alan Viveretteab2cf6d2014-11-26 14:34:36 -08005100 final int width = mRight - mLeft;
5101 final int height = mBottom - mTop;
5102
George Mount002d43d2014-11-11 12:54:43 -08005103 boolean rectIsVisible = true;
Adam Powell35da41e2014-12-10 18:59:34 -08005104 if (mParent == null ||
5105 (mParent instanceof ViewGroup && ((ViewGroup) mParent).getClipChildren())) {
Alan Viveretteab2cf6d2014-11-26 14:34:36 -08005106 // Clip to bounds.
5107 rectIsVisible = rect.intersect(0, 0, width, height);
Gilles Debunnecea45132011-11-24 02:19:27 +01005108 }
5109
George Mount002d43d2014-11-11 12:54:43 -08005110 if (rectIsVisible && (mGroupFlags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK) {
Alan Viveretteab2cf6d2014-11-26 14:34:36 -08005111 // Clip to padding.
George Mount002d43d2014-11-11 12:54:43 -08005112 rectIsVisible = rect.intersect(mPaddingLeft, mPaddingTop,
Alan Viveretteab2cf6d2014-11-26 14:34:36 -08005113 width - mPaddingRight, height - mPaddingBottom);
George Mount002d43d2014-11-11 12:54:43 -08005114 }
5115
5116 if (rectIsVisible && mClipBounds != null) {
Alan Viveretteab2cf6d2014-11-26 14:34:36 -08005117 // Clip to clipBounds.
George Mount002d43d2014-11-11 12:54:43 -08005118 rectIsVisible = rect.intersect(mClipBounds.left, mClipBounds.top, mClipBounds.right,
5119 mClipBounds.bottom);
5120 }
5121 r.set((int) (rect.left + 0.5f), (int) (rect.top + 0.5f), (int) (rect.right + 0.5f),
5122 (int) (rect.bottom + 0.5f));
5123 if (rectIsVisible && mParent != null) {
5124 rectIsVisible = mParent.getChildVisibleRect(this, r, offset);
5125 }
5126 return rectIsVisible;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005127 }
5128
5129 /**
5130 * {@inheritDoc}
5131 */
5132 @Override
Chet Haase9c087442011-01-12 16:20:16 -08005133 public final void layout(int l, int t, int r, int b) {
Chet Haase430742f2013-04-12 11:18:36 -07005134 if (!mSuppressLayout && (mTransition == null || !mTransition.isChangingLayout())) {
Chet Haase7dd4a532012-04-16 13:35:09 -07005135 if (mTransition != null) {
5136 mTransition.layoutChange(this);
5137 }
Chet Haase9c087442011-01-12 16:20:16 -08005138 super.layout(l, t, r, b);
5139 } else {
5140 // record the fact that we noop'd it; request layout when transition finishes
Chet Haaseb9895022013-04-02 15:10:58 -07005141 mLayoutCalledWhileSuppressed = true;
Chet Haase9c087442011-01-12 16:20:16 -08005142 }
5143 }
5144
5145 /**
5146 * {@inheritDoc}
5147 */
5148 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005149 protected abstract void onLayout(boolean changed,
5150 int l, int t, int r, int b);
5151
5152 /**
5153 * Indicates whether the view group has the ability to animate its children
5154 * after the first layout.
5155 *
5156 * @return true if the children can be animated, false otherwise
5157 */
5158 protected boolean canAnimate() {
5159 return mLayoutAnimationController != null;
5160 }
5161
5162 /**
5163 * Runs the layout animation. Calling this method triggers a relayout of
5164 * this view group.
5165 */
5166 public void startLayoutAnimation() {
5167 if (mLayoutAnimationController != null) {
5168 mGroupFlags |= FLAG_RUN_ANIMATION;
5169 requestLayout();
5170 }
5171 }
5172
5173 /**
5174 * Schedules the layout animation to be played after the next layout pass
5175 * of this view group. This can be used to restart the layout animation
5176 * when the content of the view group changes or when the activity is
5177 * paused and resumed.
5178 */
5179 public void scheduleLayoutAnimation() {
5180 mGroupFlags |= FLAG_RUN_ANIMATION;
5181 }
5182
5183 /**
5184 * Sets the layout animation controller used to animate the group's
5185 * children after the first layout.
5186 *
5187 * @param controller the animation controller
5188 */
5189 public void setLayoutAnimation(LayoutAnimationController controller) {
5190 mLayoutAnimationController = controller;
5191 if (mLayoutAnimationController != null) {
5192 mGroupFlags |= FLAG_RUN_ANIMATION;
5193 }
5194 }
5195
5196 /**
5197 * Returns the layout animation controller used to animate the group's
5198 * children.
5199 *
5200 * @return the current animation controller
5201 */
5202 public LayoutAnimationController getLayoutAnimation() {
5203 return mLayoutAnimationController;
5204 }
5205
5206 /**
5207 * Indicates whether the children's drawing cache is used during a layout
5208 * animation. By default, the drawing cache is enabled but this will prevent
5209 * nested layout animations from working. To nest animations, you must disable
5210 * the cache.
5211 *
5212 * @return true if the animation cache is enabled, false otherwise
5213 *
5214 * @see #setAnimationCacheEnabled(boolean)
5215 * @see View#setDrawingCacheEnabled(boolean)
Chris Craik5a6bbae2015-04-10 17:41:34 -07005216 *
5217 * @deprecated As of {@link android.os.Build.VERSION_CODES#MNC}, this property is ignored.
5218 * Caching behavior of children may be controlled through {@link View#setLayerType(int, Paint)}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005219 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005220 public boolean isAnimationCacheEnabled() {
5221 return (mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE;
5222 }
5223
5224 /**
5225 * Enables or disables the children's drawing cache during a layout animation.
5226 * By default, the drawing cache is enabled but this will prevent nested
5227 * layout animations from working. To nest animations, you must disable the
5228 * cache.
5229 *
5230 * @param enabled true to enable the animation cache, false otherwise
5231 *
5232 * @see #isAnimationCacheEnabled()
5233 * @see View#setDrawingCacheEnabled(boolean)
Chris Craik5a6bbae2015-04-10 17:41:34 -07005234 *
5235 * @deprecated As of {@link android.os.Build.VERSION_CODES#MNC}, this property is ignored.
5236 * Caching behavior of children may be controlled through {@link View#setLayerType(int, Paint)}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005237 */
5238 public void setAnimationCacheEnabled(boolean enabled) {
5239 setBooleanFlag(FLAG_ANIMATION_CACHE, enabled);
5240 }
5241
5242 /**
5243 * Indicates whether this ViewGroup will always try to draw its children using their
5244 * drawing cache. By default this property is enabled.
5245 *
5246 * @return true if the animation cache is enabled, false otherwise
5247 *
5248 * @see #setAlwaysDrawnWithCacheEnabled(boolean)
5249 * @see #setChildrenDrawnWithCacheEnabled(boolean)
5250 * @see View#setDrawingCacheEnabled(boolean)
Chris Craik5a6bbae2015-04-10 17:41:34 -07005251 *
5252 * @deprecated As of {@link android.os.Build.VERSION_CODES#MNC}, this property is ignored.
5253 * Child views may no longer have their caching behavior disabled by parents.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005254 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005255 public boolean isAlwaysDrawnWithCacheEnabled() {
5256 return (mGroupFlags & FLAG_ALWAYS_DRAWN_WITH_CACHE) == FLAG_ALWAYS_DRAWN_WITH_CACHE;
5257 }
5258
5259 /**
5260 * Indicates whether this ViewGroup will always try to draw its children using their
5261 * drawing cache. This property can be set to true when the cache rendering is
5262 * slightly different from the children's normal rendering. Renderings can be different,
5263 * for instance, when the cache's quality is set to low.
5264 *
5265 * When this property is disabled, the ViewGroup will use the drawing cache of its
5266 * children only when asked to. It's usually the task of subclasses to tell ViewGroup
5267 * when to start using the drawing cache and when to stop using it.
5268 *
5269 * @param always true to always draw with the drawing cache, false otherwise
5270 *
5271 * @see #isAlwaysDrawnWithCacheEnabled()
5272 * @see #setChildrenDrawnWithCacheEnabled(boolean)
5273 * @see View#setDrawingCacheEnabled(boolean)
5274 * @see View#setDrawingCacheQuality(int)
Chris Craik5a6bbae2015-04-10 17:41:34 -07005275 *
5276 * @deprecated As of {@link android.os.Build.VERSION_CODES#MNC}, this property is ignored.
5277 * Child views may no longer have their caching behavior disabled by parents.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005278 */
5279 public void setAlwaysDrawnWithCacheEnabled(boolean always) {
5280 setBooleanFlag(FLAG_ALWAYS_DRAWN_WITH_CACHE, always);
5281 }
5282
5283 /**
5284 * Indicates whether the ViewGroup is currently drawing its children using
5285 * their drawing cache.
5286 *
5287 * @return true if children should be drawn with their cache, false otherwise
5288 *
5289 * @see #setAlwaysDrawnWithCacheEnabled(boolean)
5290 * @see #setChildrenDrawnWithCacheEnabled(boolean)
Chris Craik5a6bbae2015-04-10 17:41:34 -07005291 *
5292 * @deprecated As of {@link android.os.Build.VERSION_CODES#MNC}, this property is ignored.
5293 * Child views may no longer be forced to cache their rendering state by their parents.
5294 * Use {@link View#setLayerType(int, Paint)} on individual Views instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005295 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005296 protected boolean isChildrenDrawnWithCacheEnabled() {
5297 return (mGroupFlags & FLAG_CHILDREN_DRAWN_WITH_CACHE) == FLAG_CHILDREN_DRAWN_WITH_CACHE;
5298 }
5299
5300 /**
5301 * Tells the ViewGroup to draw its children using their drawing cache. This property
5302 * is ignored when {@link #isAlwaysDrawnWithCacheEnabled()} is true. A child's drawing cache
5303 * will be used only if it has been enabled.
5304 *
5305 * Subclasses should call this method to start and stop using the drawing cache when
5306 * they perform performance sensitive operations, like scrolling or animating.
5307 *
5308 * @param enabled true if children should be drawn with their cache, false otherwise
5309 *
5310 * @see #setAlwaysDrawnWithCacheEnabled(boolean)
5311 * @see #isChildrenDrawnWithCacheEnabled()
Chris Craik5a6bbae2015-04-10 17:41:34 -07005312 *
5313 * @deprecated As of {@link android.os.Build.VERSION_CODES#MNC}, this property is ignored.
5314 * Child views may no longer be forced to cache their rendering state by their parents.
5315 * Use {@link View#setLayerType(int, Paint)} on individual Views instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005316 */
5317 protected void setChildrenDrawnWithCacheEnabled(boolean enabled) {
5318 setBooleanFlag(FLAG_CHILDREN_DRAWN_WITH_CACHE, enabled);
5319 }
5320
Romain Guy293451e2009-11-04 13:59:48 -08005321 /**
5322 * Indicates whether the ViewGroup is drawing its children in the order defined by
5323 * {@link #getChildDrawingOrder(int, int)}.
5324 *
5325 * @return true if children drawing order is defined by {@link #getChildDrawingOrder(int, int)},
5326 * false otherwise
5327 *
5328 * @see #setChildrenDrawingOrderEnabled(boolean)
5329 * @see #getChildDrawingOrder(int, int)
5330 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07005331 @ViewDebug.ExportedProperty(category = "drawing")
Romain Guy293451e2009-11-04 13:59:48 -08005332 protected boolean isChildrenDrawingOrderEnabled() {
5333 return (mGroupFlags & FLAG_USE_CHILD_DRAWING_ORDER) == FLAG_USE_CHILD_DRAWING_ORDER;
5334 }
5335
5336 /**
5337 * Tells the ViewGroup whether to draw its children in the order defined by the method
5338 * {@link #getChildDrawingOrder(int, int)}.
Chris Craike83cbd42014-09-03 17:52:24 -07005339 * <p>
5340 * Note that {@link View#getZ() Z} reordering, done by {@link #dispatchDraw(Canvas)},
5341 * will override custom child ordering done via this method.
Romain Guy293451e2009-11-04 13:59:48 -08005342 *
5343 * @param enabled true if the order of the children when drawing is determined by
5344 * {@link #getChildDrawingOrder(int, int)}, false otherwise
5345 *
5346 * @see #isChildrenDrawingOrderEnabled()
5347 * @see #getChildDrawingOrder(int, int)
5348 */
5349 protected void setChildrenDrawingOrderEnabled(boolean enabled) {
5350 setBooleanFlag(FLAG_USE_CHILD_DRAWING_ORDER, enabled);
5351 }
5352
Svetoslav6254f482013-06-04 17:22:14 -07005353 private boolean hasBooleanFlag(int flag) {
Philip Milnef091b662013-02-27 11:15:21 -08005354 return (mGroupFlags & flag) == flag;
5355 }
5356
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005357 private void setBooleanFlag(int flag, boolean value) {
5358 if (value) {
5359 mGroupFlags |= flag;
5360 } else {
5361 mGroupFlags &= ~flag;
5362 }
5363 }
5364
5365 /**
5366 * Returns an integer indicating what types of drawing caches are kept in memory.
5367 *
5368 * @see #setPersistentDrawingCache(int)
5369 * @see #setAnimationCacheEnabled(boolean)
5370 *
5371 * @return one or a combination of {@link #PERSISTENT_NO_CACHE},
5372 * {@link #PERSISTENT_ANIMATION_CACHE}, {@link #PERSISTENT_SCROLLING_CACHE}
5373 * and {@link #PERSISTENT_ALL_CACHES}
5374 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07005375 @ViewDebug.ExportedProperty(category = "drawing", mapping = {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005376 @ViewDebug.IntToString(from = PERSISTENT_NO_CACHE, to = "NONE"),
Romain Guy203688c2010-05-12 15:41:32 -07005377 @ViewDebug.IntToString(from = PERSISTENT_ANIMATION_CACHE, to = "ANIMATION"),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005378 @ViewDebug.IntToString(from = PERSISTENT_SCROLLING_CACHE, to = "SCROLLING"),
5379 @ViewDebug.IntToString(from = PERSISTENT_ALL_CACHES, to = "ALL")
5380 })
5381 public int getPersistentDrawingCache() {
5382 return mPersistentDrawingCache;
5383 }
5384
5385 /**
5386 * Indicates what types of drawing caches should be kept in memory after
5387 * they have been created.
5388 *
5389 * @see #getPersistentDrawingCache()
5390 * @see #setAnimationCacheEnabled(boolean)
5391 *
5392 * @param drawingCacheToKeep one or a combination of {@link #PERSISTENT_NO_CACHE},
5393 * {@link #PERSISTENT_ANIMATION_CACHE}, {@link #PERSISTENT_SCROLLING_CACHE}
5394 * and {@link #PERSISTENT_ALL_CACHES}
5395 */
5396 public void setPersistentDrawingCache(int drawingCacheToKeep) {
5397 mPersistentDrawingCache = drawingCacheToKeep & PERSISTENT_ALL_CACHES;
5398 }
5399
Philip Milnef091b662013-02-27 11:15:21 -08005400 private void setLayoutMode(int layoutMode, boolean explicitly) {
5401 mLayoutMode = layoutMode;
5402 setBooleanFlag(FLAG_LAYOUT_MODE_WAS_EXPLICITLY_SET, explicitly);
5403 }
5404
5405 /**
5406 * Recursively traverse the view hierarchy, resetting the layoutMode of any
5407 * descendants that had inherited a different layoutMode from a previous parent.
5408 * Recursion terminates when a descendant's mode is:
5409 * <ul>
5410 * <li>Undefined</li>
5411 * <li>The same as the root node's</li>
5412 * <li>A mode that had been explicitly set</li>
5413 * <ul/>
5414 * The first two clauses are optimizations.
5415 * @param layoutModeOfRoot
5416 */
5417 @Override
5418 void invalidateInheritedLayoutMode(int layoutModeOfRoot) {
5419 if (mLayoutMode == LAYOUT_MODE_UNDEFINED ||
5420 mLayoutMode == layoutModeOfRoot ||
Svetoslav6254f482013-06-04 17:22:14 -07005421 hasBooleanFlag(FLAG_LAYOUT_MODE_WAS_EXPLICITLY_SET)) {
Philip Milnef091b662013-02-27 11:15:21 -08005422 return;
5423 }
5424 setLayoutMode(LAYOUT_MODE_UNDEFINED, false);
5425
5426 // apply recursively
5427 for (int i = 0, N = getChildCount(); i < N; i++) {
5428 getChildAt(i).invalidateInheritedLayoutMode(layoutModeOfRoot);
5429 }
5430 }
5431
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005432 /**
Philip Milnecfb631b2012-10-26 10:51:46 -07005433 * Returns the basis of alignment during layout operations on this ViewGroup:
Philip Milne7b757812012-09-19 18:13:44 -07005434 * either {@link #LAYOUT_MODE_CLIP_BOUNDS} or {@link #LAYOUT_MODE_OPTICAL_BOUNDS}.
Philip Milnecfb631b2012-10-26 10:51:46 -07005435 * <p>
5436 * If no layoutMode was explicitly set, either programmatically or in an XML resource,
5437 * the method returns the layoutMode of the view's parent ViewGroup if such a parent exists,
5438 * otherwise the method returns a default value of {@link #LAYOUT_MODE_CLIP_BOUNDS}.
Philip Milne1557fd72012-04-04 23:41:34 -07005439 *
Philip Milnefcc6a0f2012-04-16 16:12:19 -07005440 * @return the layout mode to use during layout operations
Philip Milne1557fd72012-04-04 23:41:34 -07005441 *
5442 * @see #setLayoutMode(int)
5443 */
5444 public int getLayoutMode() {
Philip Milnecfb631b2012-10-26 10:51:46 -07005445 if (mLayoutMode == LAYOUT_MODE_UNDEFINED) {
Philip Milnef091b662013-02-27 11:15:21 -08005446 int inheritedLayoutMode = (mParent instanceof ViewGroup) ?
5447 ((ViewGroup) mParent).getLayoutMode() : LAYOUT_MODE_DEFAULT;
5448 setLayoutMode(inheritedLayoutMode, false);
Philip Milnecfb631b2012-10-26 10:51:46 -07005449 }
Philip Milne1557fd72012-04-04 23:41:34 -07005450 return mLayoutMode;
5451 }
5452
5453 /**
Philip Milnecfb631b2012-10-26 10:51:46 -07005454 * Sets the basis of alignment during the layout of this ViewGroup.
Philip Milne7b757812012-09-19 18:13:44 -07005455 * Valid values are either {@link #LAYOUT_MODE_CLIP_BOUNDS} or
5456 * {@link #LAYOUT_MODE_OPTICAL_BOUNDS}.
Philip Milne1557fd72012-04-04 23:41:34 -07005457 *
Philip Milnefcc6a0f2012-04-16 16:12:19 -07005458 * @param layoutMode the layout mode to use during layout operations
Philip Milne1557fd72012-04-04 23:41:34 -07005459 *
5460 * @see #getLayoutMode()
Scott Main27a85082013-06-10 10:39:48 -07005461 * @attr ref android.R.styleable#ViewGroup_layoutMode
Philip Milne1557fd72012-04-04 23:41:34 -07005462 */
5463 public void setLayoutMode(int layoutMode) {
5464 if (mLayoutMode != layoutMode) {
Philip Milnef091b662013-02-27 11:15:21 -08005465 invalidateInheritedLayoutMode(layoutMode);
5466 setLayoutMode(layoutMode, layoutMode != LAYOUT_MODE_UNDEFINED);
Philip Milne1557fd72012-04-04 23:41:34 -07005467 requestLayout();
5468 }
5469 }
5470
5471 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005472 * Returns a new set of layout parameters based on the supplied attributes set.
5473 *
5474 * @param attrs the attributes to build the layout parameters from
5475 *
5476 * @return an instance of {@link android.view.ViewGroup.LayoutParams} or one
5477 * of its descendants
5478 */
5479 public LayoutParams generateLayoutParams(AttributeSet attrs) {
5480 return new LayoutParams(getContext(), attrs);
5481 }
5482
5483 /**
5484 * Returns a safe set of layout parameters based on the supplied layout params.
5485 * When a ViewGroup is passed a View whose layout params do not pass the test of
5486 * {@link #checkLayoutParams(android.view.ViewGroup.LayoutParams)}, this method
5487 * is invoked. This method should return a new set of layout params suitable for
5488 * this ViewGroup, possibly by copying the appropriate attributes from the
5489 * specified set of layout params.
5490 *
5491 * @param p The layout parameters to convert into a suitable set of layout parameters
5492 * for this ViewGroup.
5493 *
5494 * @return an instance of {@link android.view.ViewGroup.LayoutParams} or one
5495 * of its descendants
5496 */
5497 protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
5498 return p;
5499 }
5500
5501 /**
5502 * Returns a set of default layout parameters. These parameters are requested
5503 * when the View passed to {@link #addView(View)} has no layout parameters
5504 * already set. If null is returned, an exception is thrown from addView.
5505 *
5506 * @return a set of default layout parameters or null
5507 */
5508 protected LayoutParams generateDefaultLayoutParams() {
5509 return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
5510 }
5511
5512 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005513 * {@inheritDoc}
5514 */
5515 @Override
5516 protected void debug(int depth) {
5517 super.debug(depth);
5518 String output;
5519
5520 if (mFocused != null) {
5521 output = debugIndent(depth);
5522 output += "mFocused";
5523 Log.d(VIEW_LOG_TAG, output);
5524 }
5525 if (mChildrenCount != 0) {
5526 output = debugIndent(depth);
5527 output += "{";
5528 Log.d(VIEW_LOG_TAG, output);
5529 }
5530 int count = mChildrenCount;
5531 for (int i = 0; i < count; i++) {
5532 View child = mChildren[i];
5533 child.debug(depth + 1);
5534 }
5535
5536 if (mChildrenCount != 0) {
5537 output = debugIndent(depth);
5538 output += "}";
5539 Log.d(VIEW_LOG_TAG, output);
5540 }
5541 }
5542
5543 /**
5544 * Returns the position in the group of the specified child view.
5545 *
5546 * @param child the view for which to get the position
5547 * @return a positive integer representing the position of the view in the
5548 * group, or -1 if the view does not exist in the group
5549 */
5550 public int indexOfChild(View child) {
5551 final int count = mChildrenCount;
5552 final View[] children = mChildren;
5553 for (int i = 0; i < count; i++) {
5554 if (children[i] == child) {
5555 return i;
5556 }
5557 }
5558 return -1;
5559 }
5560
5561 /**
5562 * Returns the number of children in the group.
5563 *
5564 * @return a positive integer representing the number of children in
5565 * the group
5566 */
5567 public int getChildCount() {
5568 return mChildrenCount;
5569 }
5570
5571 /**
5572 * Returns the view at the specified position in the group.
5573 *
5574 * @param index the position at which to get the view from
5575 * @return the view at the specified position or null if the position
5576 * does not exist within the group
5577 */
5578 public View getChildAt(int index) {
Adam Powell3ba8f5d62011-03-07 15:36:33 -08005579 if (index < 0 || index >= mChildrenCount) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005580 return null;
5581 }
Adam Powell3ba8f5d62011-03-07 15:36:33 -08005582 return mChildren[index];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005583 }
5584
5585 /**
5586 * Ask all of the children of this view to measure themselves, taking into
5587 * account both the MeasureSpec requirements for this view and its padding.
5588 * We skip children that are in the GONE state The heavy lifting is done in
5589 * getChildMeasureSpec.
5590 *
5591 * @param widthMeasureSpec The width requirements for this view
5592 * @param heightMeasureSpec The height requirements for this view
5593 */
5594 protected void measureChildren(int widthMeasureSpec, int heightMeasureSpec) {
5595 final int size = mChildrenCount;
5596 final View[] children = mChildren;
5597 for (int i = 0; i < size; ++i) {
5598 final View child = children[i];
5599 if ((child.mViewFlags & VISIBILITY_MASK) != GONE) {
5600 measureChild(child, widthMeasureSpec, heightMeasureSpec);
5601 }
5602 }
5603 }
5604
5605 /**
5606 * Ask one of the children of this view to measure itself, taking into
5607 * account both the MeasureSpec requirements for this view and its padding.
5608 * The heavy lifting is done in getChildMeasureSpec.
5609 *
5610 * @param child The child to measure
5611 * @param parentWidthMeasureSpec The width requirements for this view
5612 * @param parentHeightMeasureSpec The height requirements for this view
5613 */
5614 protected void measureChild(View child, int parentWidthMeasureSpec,
5615 int parentHeightMeasureSpec) {
5616 final LayoutParams lp = child.getLayoutParams();
5617
5618 final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
5619 mPaddingLeft + mPaddingRight, lp.width);
5620 final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
5621 mPaddingTop + mPaddingBottom, lp.height);
5622
5623 child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
5624 }
5625
5626 /**
5627 * Ask one of the children of this view to measure itself, taking into
5628 * account both the MeasureSpec requirements for this view and its padding
5629 * and margins. The child must have MarginLayoutParams The heavy lifting is
5630 * done in getChildMeasureSpec.
5631 *
5632 * @param child The child to measure
5633 * @param parentWidthMeasureSpec The width requirements for this view
5634 * @param widthUsed Extra space that has been used up by the parent
5635 * horizontally (possibly by other children of the parent)
5636 * @param parentHeightMeasureSpec The height requirements for this view
5637 * @param heightUsed Extra space that has been used up by the parent
5638 * vertically (possibly by other children of the parent)
5639 */
5640 protected void measureChildWithMargins(View child,
5641 int parentWidthMeasureSpec, int widthUsed,
5642 int parentHeightMeasureSpec, int heightUsed) {
5643 final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
5644
5645 final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
5646 mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin
5647 + widthUsed, lp.width);
5648 final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
5649 mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin
5650 + heightUsed, lp.height);
5651
5652 child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
5653 }
5654
5655 /**
5656 * Does the hard part of measureChildren: figuring out the MeasureSpec to
5657 * pass to a particular child. This method figures out the right MeasureSpec
5658 * for one dimension (height or width) of one child view.
5659 *
5660 * The goal is to combine information from our MeasureSpec with the
5661 * LayoutParams of the child to get the best possible results. For example,
5662 * if the this view knows its size (because its MeasureSpec has a mode of
5663 * EXACTLY), and the child has indicated in its LayoutParams that it wants
5664 * to be the same size as the parent, the parent should ask the child to
5665 * layout given an exact size.
5666 *
5667 * @param spec The requirements for this view
5668 * @param padding The padding of this view for the current dimension and
5669 * margins, if applicable
5670 * @param childDimension How big the child wants to be in the current
5671 * dimension
5672 * @return a MeasureSpec integer for the child
5673 */
5674 public static int getChildMeasureSpec(int spec, int padding, int childDimension) {
5675 int specMode = MeasureSpec.getMode(spec);
5676 int specSize = MeasureSpec.getSize(spec);
5677
5678 int size = Math.max(0, specSize - padding);
5679
5680 int resultSize = 0;
5681 int resultMode = 0;
5682
5683 switch (specMode) {
5684 // Parent has imposed an exact size on us
5685 case MeasureSpec.EXACTLY:
5686 if (childDimension >= 0) {
5687 resultSize = childDimension;
5688 resultMode = MeasureSpec.EXACTLY;
Romain Guy980a9382010-01-08 15:06:28 -08005689 } else if (childDimension == LayoutParams.MATCH_PARENT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005690 // Child wants to be our size. So be it.
5691 resultSize = size;
5692 resultMode = MeasureSpec.EXACTLY;
5693 } else if (childDimension == LayoutParams.WRAP_CONTENT) {
5694 // Child wants to determine its own size. It can't be
5695 // bigger than us.
5696 resultSize = size;
5697 resultMode = MeasureSpec.AT_MOST;
5698 }
5699 break;
5700
5701 // Parent has imposed a maximum size on us
5702 case MeasureSpec.AT_MOST:
5703 if (childDimension >= 0) {
5704 // Child wants a specific size... so be it
5705 resultSize = childDimension;
5706 resultMode = MeasureSpec.EXACTLY;
Romain Guy980a9382010-01-08 15:06:28 -08005707 } else if (childDimension == LayoutParams.MATCH_PARENT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005708 // Child wants to be our size, but our size is not fixed.
5709 // Constrain child to not be bigger than us.
5710 resultSize = size;
5711 resultMode = MeasureSpec.AT_MOST;
5712 } else if (childDimension == LayoutParams.WRAP_CONTENT) {
5713 // Child wants to determine its own size. It can't be
5714 // bigger than us.
5715 resultSize = size;
5716 resultMode = MeasureSpec.AT_MOST;
5717 }
5718 break;
5719
5720 // Parent asked to see how big we want to be
5721 case MeasureSpec.UNSPECIFIED:
5722 if (childDimension >= 0) {
5723 // Child wants a specific size... let him have it
5724 resultSize = childDimension;
5725 resultMode = MeasureSpec.EXACTLY;
Romain Guy980a9382010-01-08 15:06:28 -08005726 } else if (childDimension == LayoutParams.MATCH_PARENT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005727 // Child wants to be our size... find out how big it should
5728 // be
Filip Gruszczynski415ab1a2015-03-11 16:42:00 -07005729 resultSize = size;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005730 resultMode = MeasureSpec.UNSPECIFIED;
5731 } else if (childDimension == LayoutParams.WRAP_CONTENT) {
5732 // Child wants to determine its own size.... find out how
5733 // big it should be
Filip Gruszczynski415ab1a2015-03-11 16:42:00 -07005734 resultSize = size;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005735 resultMode = MeasureSpec.UNSPECIFIED;
5736 }
5737 break;
5738 }
5739 return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
5740 }
5741
5742
5743 /**
5744 * Removes any pending animations for views that have been removed. Call
5745 * this if you don't want animations for exiting views to stack up.
5746 */
5747 public void clearDisappearingChildren() {
John Reckca7a9da2014-03-05 16:29:07 -08005748 final ArrayList<View> disappearingChildren = mDisappearingChildren;
5749 if (disappearingChildren != null) {
5750 final int count = disappearingChildren.size();
5751 for (int i = 0; i < count; i++) {
5752 final View view = disappearingChildren.get(i);
5753 if (view.mAttachInfo != null) {
5754 view.dispatchDetachedFromWindow();
5755 }
5756 view.clearAnimation();
5757 }
5758 disappearingChildren.clear();
Chet Haaseb85967b2012-03-26 14:37:51 -07005759 invalidate();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005760 }
5761 }
5762
5763 /**
5764 * Add a view which is removed from mChildren but still needs animation
5765 *
5766 * @param v View to add
5767 */
5768 private void addDisappearingView(View v) {
5769 ArrayList<View> disappearingChildren = mDisappearingChildren;
5770
5771 if (disappearingChildren == null) {
5772 disappearingChildren = mDisappearingChildren = new ArrayList<View>();
5773 }
5774
5775 disappearingChildren.add(v);
5776 }
5777
5778 /**
5779 * Cleanup a view when its animation is done. This may mean removing it from
5780 * the list of disappearing views.
5781 *
5782 * @param view The view whose animation has finished
5783 * @param animation The animation, cannot be null
5784 */
Chet Haase64a48c12012-02-13 16:33:29 -08005785 void finishAnimatingView(final View view, Animation animation) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005786 final ArrayList<View> disappearingChildren = mDisappearingChildren;
5787 if (disappearingChildren != null) {
5788 if (disappearingChildren.contains(view)) {
5789 disappearingChildren.remove(view);
5790
5791 if (view.mAttachInfo != null) {
5792 view.dispatchDetachedFromWindow();
5793 }
5794
5795 view.clearAnimation();
5796 mGroupFlags |= FLAG_INVALIDATE_REQUIRED;
5797 }
5798 }
5799
5800 if (animation != null && !animation.getFillAfter()) {
5801 view.clearAnimation();
5802 }
5803
Dianne Hackborn4702a852012-08-17 15:18:29 -07005804 if ((view.mPrivateFlags & PFLAG_ANIMATION_STARTED) == PFLAG_ANIMATION_STARTED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005805 view.onAnimationEnd();
5806 // Should be performed by onAnimationEnd() but this avoid an infinite loop,
5807 // so we'd rather be safe than sorry
Dianne Hackborn4702a852012-08-17 15:18:29 -07005808 view.mPrivateFlags &= ~PFLAG_ANIMATION_STARTED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005809 // Draw one more frame after the animation is done
5810 mGroupFlags |= FLAG_INVALIDATE_REQUIRED;
5811 }
5812 }
5813
Chet Haaseb20db3e2010-09-10 13:07:30 -07005814 /**
Chet Haaseaceafe62011-08-26 15:44:33 -07005815 * Utility function called by View during invalidation to determine whether a view that
5816 * is invisible or gone should still be invalidated because it is being transitioned (and
5817 * therefore still needs to be drawn).
5818 */
5819 boolean isViewTransitioning(View view) {
5820 return (mTransitioningViews != null && mTransitioningViews.contains(view));
5821 }
5822
5823 /**
Chet Haaseb20db3e2010-09-10 13:07:30 -07005824 * This method tells the ViewGroup that the given View object, which should have this
5825 * ViewGroup as its parent,
5826 * should be kept around (re-displayed when the ViewGroup draws its children) even if it
5827 * is removed from its parent. This allows animations, such as those used by
5828 * {@link android.app.Fragment} and {@link android.animation.LayoutTransition} to animate
5829 * the removal of views. A call to this method should always be accompanied by a later call
5830 * to {@link #endViewTransition(View)}, such as after an animation on the View has finished,
5831 * so that the View finally gets removed.
5832 *
5833 * @param view The View object to be kept visible even if it gets removed from its parent.
5834 */
5835 public void startViewTransition(View view) {
5836 if (view.mParent == this) {
5837 if (mTransitioningViews == null) {
5838 mTransitioningViews = new ArrayList<View>();
5839 }
5840 mTransitioningViews.add(view);
5841 }
5842 }
5843
5844 /**
5845 * This method should always be called following an earlier call to
5846 * {@link #startViewTransition(View)}. The given View is finally removed from its parent
5847 * and will no longer be displayed. Note that this method does not perform the functionality
5848 * of removing a view from its parent; it just discontinues the display of a View that
5849 * has previously been removed.
5850 *
5851 * @return view The View object that has been removed but is being kept around in the visible
5852 * hierarchy by an earlier call to {@link #startViewTransition(View)}.
5853 */
5854 public void endViewTransition(View view) {
5855 if (mTransitioningViews != null) {
5856 mTransitioningViews.remove(view);
5857 final ArrayList<View> disappearingChildren = mDisappearingChildren;
5858 if (disappearingChildren != null && disappearingChildren.contains(view)) {
5859 disappearingChildren.remove(view);
Chet Haase5e25c2c2010-09-16 11:15:56 -07005860 if (mVisibilityChangingChildren != null &&
5861 mVisibilityChangingChildren.contains(view)) {
5862 mVisibilityChangingChildren.remove(view);
5863 } else {
5864 if (view.mAttachInfo != null) {
5865 view.dispatchDetachedFromWindow();
5866 }
5867 if (view.mParent != null) {
5868 view.mParent = null;
5869 }
Chet Haaseb20db3e2010-09-10 13:07:30 -07005870 }
Chet Haaseb85967b2012-03-26 14:37:51 -07005871 invalidate();
Chet Haaseb20db3e2010-09-10 13:07:30 -07005872 }
5873 }
5874 }
5875
Chet Haase21cd1382010-09-01 17:42:29 -07005876 private LayoutTransition.TransitionListener mLayoutTransitionListener =
5877 new LayoutTransition.TransitionListener() {
5878 @Override
5879 public void startTransition(LayoutTransition transition, ViewGroup container,
5880 View view, int transitionType) {
5881 // We only care about disappearing items, since we need special logic to keep
5882 // those items visible after they've been 'removed'
5883 if (transitionType == LayoutTransition.DISAPPEARING) {
Chet Haaseb20db3e2010-09-10 13:07:30 -07005884 startViewTransition(view);
Chet Haase21cd1382010-09-01 17:42:29 -07005885 }
5886 }
5887
5888 @Override
5889 public void endTransition(LayoutTransition transition, ViewGroup container,
5890 View view, int transitionType) {
Chet Haaseb9895022013-04-02 15:10:58 -07005891 if (mLayoutCalledWhileSuppressed && !transition.isChangingLayout()) {
Chet Haase9c087442011-01-12 16:20:16 -08005892 requestLayout();
Chet Haaseb9895022013-04-02 15:10:58 -07005893 mLayoutCalledWhileSuppressed = false;
Chet Haase9c087442011-01-12 16:20:16 -08005894 }
Chet Haase21cd1382010-09-01 17:42:29 -07005895 if (transitionType == LayoutTransition.DISAPPEARING && mTransitioningViews != null) {
Chet Haaseb20db3e2010-09-10 13:07:30 -07005896 endViewTransition(view);
Chet Haase21cd1382010-09-01 17:42:29 -07005897 }
5898 }
5899 };
5900
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005901 /**
Chet Haaseb9895022013-04-02 15:10:58 -07005902 * Tells this ViewGroup to suppress all layout() calls until layout
5903 * suppression is disabled with a later call to suppressLayout(false).
5904 * When layout suppression is disabled, a requestLayout() call is sent
5905 * if layout() was attempted while layout was being suppressed.
5906 *
5907 * @hide
5908 */
5909 public void suppressLayout(boolean suppress) {
5910 mSuppressLayout = suppress;
5911 if (!suppress) {
5912 if (mLayoutCalledWhileSuppressed) {
5913 requestLayout();
5914 mLayoutCalledWhileSuppressed = false;
5915 }
5916 }
5917 }
5918
5919 /**
Chet Haase199acdf2013-07-24 18:40:55 -07005920 * Returns whether layout calls on this container are currently being
5921 * suppressed, due to an earlier call to {@link #suppressLayout(boolean)}.
5922 *
5923 * @return true if layout calls are currently suppressed, false otherwise.
5924 *
5925 * @hide
5926 */
5927 public boolean isLayoutSuppressed() {
5928 return mSuppressLayout;
5929 }
5930
5931 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005932 * {@inheritDoc}
5933 */
5934 @Override
5935 public boolean gatherTransparentRegion(Region region) {
5936 // If no transparent regions requested, we are always opaque.
Dianne Hackborn4702a852012-08-17 15:18:29 -07005937 final boolean meOpaque = (mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) == 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005938 if (meOpaque && region == null) {
5939 // The caller doesn't care about the region, so stop now.
5940 return true;
5941 }
5942 super.gatherTransparentRegion(region);
5943 final View[] children = mChildren;
5944 final int count = mChildrenCount;
5945 boolean noneOfTheChildrenAreTransparent = true;
5946 for (int i = 0; i < count; i++) {
5947 final View child = children[i];
Mathias Agopiane3381152010-12-02 15:19:36 -08005948 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005949 if (!child.gatherTransparentRegion(region)) {
5950 noneOfTheChildrenAreTransparent = false;
5951 }
5952 }
5953 }
5954 return meOpaque || noneOfTheChildrenAreTransparent;
5955 }
5956
5957 /**
5958 * {@inheritDoc}
5959 */
5960 public void requestTransparentRegion(View child) {
5961 if (child != null) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07005962 child.mPrivateFlags |= View.PFLAG_REQUEST_TRANSPARENT_REGIONS;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005963 if (mParent != null) {
5964 mParent.requestTransparentRegion(this);
5965 }
5966 }
5967 }
Romain Guy8506ab42009-06-11 17:35:47 -07005968
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005969 @Override
Adam Powell46e38fd2014-02-03 10:16:49 -08005970 public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) {
5971 insets = super.dispatchApplyWindowInsets(insets);
Adam Powell0d9fdba2014-06-11 15:33:08 -07005972 if (!insets.isConsumed()) {
Adam Powell46e38fd2014-02-03 10:16:49 -08005973 final int count = getChildCount();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005974 for (int i = 0; i < count; i++) {
Adam Powell46e38fd2014-02-03 10:16:49 -08005975 insets = getChildAt(i).dispatchApplyWindowInsets(insets);
Adam Powell0d9fdba2014-06-11 15:33:08 -07005976 if (insets.isConsumed()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005977 break;
5978 }
5979 }
5980 }
Adam Powell46e38fd2014-02-03 10:16:49 -08005981 return insets;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005982 }
5983
5984 /**
5985 * Returns the animation listener to which layout animation events are
5986 * sent.
5987 *
5988 * @return an {@link android.view.animation.Animation.AnimationListener}
5989 */
5990 public Animation.AnimationListener getLayoutAnimationListener() {
5991 return mAnimationListener;
5992 }
5993
5994 @Override
5995 protected void drawableStateChanged() {
5996 super.drawableStateChanged();
5997
5998 if ((mGroupFlags & FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE) != 0) {
5999 if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0) {
6000 throw new IllegalStateException("addStateFromChildren cannot be enabled if a"
6001 + " child has duplicateParentState set to true");
6002 }
6003
6004 final View[] children = mChildren;
6005 final int count = mChildrenCount;
6006
6007 for (int i = 0; i < count; i++) {
6008 final View child = children[i];
6009 if ((child.mViewFlags & DUPLICATE_PARENT_STATE) != 0) {
6010 child.refreshDrawableState();
6011 }
6012 }
6013 }
6014 }
6015
6016 @Override
Dianne Hackborne2136772010-11-04 15:08:59 -07006017 public void jumpDrawablesToCurrentState() {
6018 super.jumpDrawablesToCurrentState();
6019 final View[] children = mChildren;
6020 final int count = mChildrenCount;
6021 for (int i = 0; i < count; i++) {
6022 children[i].jumpDrawablesToCurrentState();
6023 }
6024 }
6025
6026 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006027 protected int[] onCreateDrawableState(int extraSpace) {
6028 if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) == 0) {
6029 return super.onCreateDrawableState(extraSpace);
6030 }
6031
6032 int need = 0;
6033 int n = getChildCount();
6034 for (int i = 0; i < n; i++) {
6035 int[] childState = getChildAt(i).getDrawableState();
6036
6037 if (childState != null) {
6038 need += childState.length;
6039 }
6040 }
6041
6042 int[] state = super.onCreateDrawableState(extraSpace + need);
6043
6044 for (int i = 0; i < n; i++) {
6045 int[] childState = getChildAt(i).getDrawableState();
6046
6047 if (childState != null) {
6048 state = mergeDrawableStates(state, childState);
6049 }
6050 }
6051
6052 return state;
6053 }
6054
6055 /**
6056 * Sets whether this ViewGroup's drawable states also include
6057 * its children's drawable states. This is used, for example, to
6058 * make a group appear to be focused when its child EditText or button
6059 * is focused.
6060 */
6061 public void setAddStatesFromChildren(boolean addsStates) {
6062 if (addsStates) {
6063 mGroupFlags |= FLAG_ADD_STATES_FROM_CHILDREN;
6064 } else {
6065 mGroupFlags &= ~FLAG_ADD_STATES_FROM_CHILDREN;
6066 }
6067
6068 refreshDrawableState();
6069 }
6070
6071 /**
6072 * Returns whether this ViewGroup's drawable states also include
6073 * its children's drawable states. This is used, for example, to
6074 * make a group appear to be focused when its child EditText or button
6075 * is focused.
6076 */
6077 public boolean addStatesFromChildren() {
6078 return (mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0;
6079 }
6080
6081 /**
Jeff Smitha45746e2012-07-19 14:19:24 -05006082 * If {@link #addStatesFromChildren} is true, refreshes this group's
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006083 * drawable state (to include the states from its children).
6084 */
6085 public void childDrawableStateChanged(View child) {
6086 if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0) {
6087 refreshDrawableState();
6088 }
6089 }
6090
6091 /**
6092 * Specifies the animation listener to which layout animation events must
6093 * be sent. Only
6094 * {@link android.view.animation.Animation.AnimationListener#onAnimationStart(Animation)}
6095 * and
6096 * {@link android.view.animation.Animation.AnimationListener#onAnimationEnd(Animation)}
6097 * are invoked.
6098 *
6099 * @param animationListener the layout animation listener
6100 */
6101 public void setLayoutAnimationListener(Animation.AnimationListener animationListener) {
6102 mAnimationListener = animationListener;
6103 }
6104
6105 /**
Chet Haasecca2c982011-05-20 14:34:18 -07006106 * This method is called by LayoutTransition when there are 'changing' animations that need
6107 * to start after the layout/setup phase. The request is forwarded to the ViewAncestor, who
6108 * starts all pending transitions prior to the drawing phase in the current traversal.
6109 *
6110 * @param transition The LayoutTransition to be started on the next traversal.
6111 *
6112 * @hide
6113 */
6114 public void requestTransitionStart(LayoutTransition transition) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006115 ViewRootImpl viewAncestor = getViewRootImpl();
Chet Haase1abf7fa2011-08-17 18:31:56 -07006116 if (viewAncestor != null) {
6117 viewAncestor.requestTransitionStart(transition);
6118 }
Chet Haasecca2c982011-05-20 14:34:18 -07006119 }
6120
Fabrice Di Meglio4457e852012-09-18 19:23:12 -07006121 /**
6122 * @hide
6123 */
Fabrice Di Meglio80dc53d2011-06-21 18:36:33 -07006124 @Override
Fabrice Di Meglio09ecb252013-05-03 16:51:55 -07006125 public boolean resolveRtlPropertiesIfNeeded() {
6126 final boolean result = super.resolveRtlPropertiesIfNeeded();
6127 // We dont need to resolve the children RTL properties if nothing has changed for the parent
6128 if (result) {
6129 int count = getChildCount();
6130 for (int i = 0; i < count; i++) {
6131 final View child = getChildAt(i);
6132 if (child.isLayoutDirectionInherited()) {
6133 child.resolveRtlPropertiesIfNeeded();
6134 }
Fabrice Di Meglio84ebb352012-10-11 16:27:37 -07006135 }
6136 }
Fabrice Di Meglio09ecb252013-05-03 16:51:55 -07006137 return result;
Fabrice Di Meglio84ebb352012-10-11 16:27:37 -07006138 }
6139
6140 /**
6141 * @hide
6142 */
6143 @Override
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07006144 public boolean resolveLayoutDirection() {
6145 final boolean result = super.resolveLayoutDirection();
6146 if (result) {
6147 int count = getChildCount();
6148 for (int i = 0; i < count; i++) {
6149 final View child = getChildAt(i);
6150 if (child.isLayoutDirectionInherited()) {
6151 child.resolveLayoutDirection();
6152 }
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07006153 }
6154 }
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07006155 return result;
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07006156 }
6157
6158 /**
6159 * @hide
6160 */
6161 @Override
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07006162 public boolean resolveTextDirection() {
6163 final boolean result = super.resolveTextDirection();
6164 if (result) {
6165 int count = getChildCount();
6166 for (int i = 0; i < count; i++) {
6167 final View child = getChildAt(i);
6168 if (child.isTextDirectionInherited()) {
6169 child.resolveTextDirection();
6170 }
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07006171 }
6172 }
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07006173 return result;
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07006174 }
6175
6176 /**
6177 * @hide
6178 */
6179 @Override
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07006180 public boolean resolveTextAlignment() {
6181 final boolean result = super.resolveTextAlignment();
6182 if (result) {
6183 int count = getChildCount();
6184 for (int i = 0; i < count; i++) {
6185 final View child = getChildAt(i);
6186 if (child.isTextAlignmentInherited()) {
6187 child.resolveTextAlignment();
6188 }
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07006189 }
6190 }
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07006191 return result;
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07006192 }
6193
6194 /**
6195 * @hide
6196 */
6197 @Override
Fabrice Di Meglio84ebb352012-10-11 16:27:37 -07006198 public void resolvePadding() {
6199 super.resolvePadding();
6200 int count = getChildCount();
6201 for (int i = 0; i < count; i++) {
6202 final View child = getChildAt(i);
Adam Powell05f35122014-11-10 17:47:37 -08006203 if (child.isLayoutDirectionInherited() && !child.isPaddingResolved()) {
Fabrice Di Meglio84ebb352012-10-11 16:27:37 -07006204 child.resolvePadding();
6205 }
6206 }
6207 }
6208
6209 /**
6210 * @hide
6211 */
6212 @Override
6213 protected void resolveDrawables() {
6214 super.resolveDrawables();
6215 int count = getChildCount();
6216 for (int i = 0; i < count; i++) {
6217 final View child = getChildAt(i);
Adam Powell05f35122014-11-10 17:47:37 -08006218 if (child.isLayoutDirectionInherited() && !child.areDrawablesResolved()) {
Fabrice Di Meglio84ebb352012-10-11 16:27:37 -07006219 child.resolveDrawables();
6220 }
6221 }
6222 }
6223
Fabrice Di Meglio1e0ed6b2012-10-18 16:06:52 -07006224 /**
6225 * @hide
6226 */
Fabrice Di Megliofcc33482012-10-18 11:11:51 -07006227 @Override
6228 public void resolveLayoutParams() {
6229 super.resolveLayoutParams();
6230 int count = getChildCount();
6231 for (int i = 0; i < count; i++) {
6232 final View child = getChildAt(i);
6233 child.resolveLayoutParams();
6234 }
6235 }
6236
Fabrice Di Meglio84ebb352012-10-11 16:27:37 -07006237 /**
6238 * @hide
6239 */
6240 @Override
Fabrice Di Meglio4457e852012-09-18 19:23:12 -07006241 public void resetResolvedLayoutDirection() {
6242 super.resetResolvedLayoutDirection();
6243
Fabrice Di Meglio4457e852012-09-18 19:23:12 -07006244 int count = getChildCount();
Fabrice Di Meglio80dc53d2011-06-21 18:36:33 -07006245 for (int i = 0; i < count; i++) {
6246 final View child = getChildAt(i);
Fabrice Di Meglioe56ffdc2012-09-23 14:51:16 -07006247 if (child.isLayoutDirectionInherited()) {
Fabrice Di Meglio7f86c802011-07-01 15:09:24 -07006248 child.resetResolvedLayoutDirection();
Fabrice Di Meglio80dc53d2011-06-21 18:36:33 -07006249 }
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07006250 }
6251 }
6252
6253 /**
6254 * @hide
6255 */
6256 @Override
6257 public void resetResolvedTextDirection() {
6258 super.resetResolvedTextDirection();
6259
6260 int count = getChildCount();
6261 for (int i = 0; i < count; i++) {
6262 final View child = getChildAt(i);
Fabrice Di Meglio97e146c2012-09-23 15:45:16 -07006263 if (child.isTextDirectionInherited()) {
Fabrice Di Meglio22268862011-06-27 18:13:18 -07006264 child.resetResolvedTextDirection();
6265 }
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07006266 }
6267 }
6268
6269 /**
6270 * @hide
6271 */
6272 @Override
6273 public void resetResolvedTextAlignment() {
6274 super.resetResolvedTextAlignment();
6275
6276 int count = getChildCount();
6277 for (int i = 0; i < count; i++) {
6278 final View child = getChildAt(i);
Fabrice Di Meglio1a7d4872012-09-23 16:19:58 -07006279 if (child.isTextAlignmentInherited()) {
Fabrice Di Meglio9da0f8a2012-03-13 19:37:57 -07006280 child.resetResolvedTextAlignment();
6281 }
6282 }
6283 }
6284
Fabrice Di Meglio22268862011-06-27 18:13:18 -07006285 /**
Fabrice Di Meglio84ebb352012-10-11 16:27:37 -07006286 * @hide
6287 */
6288 @Override
6289 public void resetResolvedPadding() {
6290 super.resetResolvedPadding();
6291
6292 int count = getChildCount();
6293 for (int i = 0; i < count; i++) {
6294 final View child = getChildAt(i);
6295 if (child.isLayoutDirectionInherited()) {
6296 child.resetResolvedPadding();
6297 }
6298 }
6299 }
6300
6301 /**
6302 * @hide
6303 */
6304 @Override
6305 protected void resetResolvedDrawables() {
6306 super.resetResolvedDrawables();
6307
6308 int count = getChildCount();
6309 for (int i = 0; i < count; i++) {
6310 final View child = getChildAt(i);
6311 if (child.isLayoutDirectionInherited()) {
6312 child.resetResolvedDrawables();
6313 }
6314 }
6315 }
6316
6317 /**
Patrick Dubroye0a799a2011-05-04 16:19:22 -07006318 * Return true if the pressed state should be delayed for children or descendants of this
6319 * ViewGroup. Generally, this should be done for containers that can scroll, such as a List.
6320 * This prevents the pressed state from appearing when the user is actually trying to scroll
6321 * the content.
6322 *
6323 * The default implementation returns true for compatibility reasons. Subclasses that do
6324 * not scroll should generally override this method and return false.
6325 */
6326 public boolean shouldDelayChildPressedState() {
6327 return true;
6328 }
6329
Adam Powell10ba2772014-04-15 09:46:51 -07006330 /**
6331 * @inheritDoc
6332 */
6333 @Override
6334 public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
6335 return false;
6336 }
6337
6338 /**
6339 * @inheritDoc
6340 */
6341 @Override
6342 public void onNestedScrollAccepted(View child, View target, int axes) {
6343 mNestedScrollAxes = axes;
6344 }
6345
6346 /**
6347 * @inheritDoc
6348 *
6349 * <p>The default implementation of onStopNestedScroll calls
6350 * {@link #stopNestedScroll()} to halt any recursive nested scrolling in progress.</p>
6351 */
6352 @Override
6353 public void onStopNestedScroll(View child) {
6354 // Stop any recursive nested scrolling.
6355 stopNestedScroll();
6356 }
6357
6358 /**
6359 * @inheritDoc
6360 */
6361 @Override
6362 public void onNestedScroll(View target, int dxConsumed, int dyConsumed,
6363 int dxUnconsumed, int dyUnconsumed) {
6364 // Do nothing
6365 }
6366
6367 /**
6368 * @inheritDoc
6369 */
6370 @Override
6371 public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
6372 // Do nothing
6373 }
6374
6375 /**
6376 * @inheritDoc
6377 */
6378 @Override
Adam Powellb36e4f92014-05-01 10:23:33 -07006379 public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
Adam Powell10ba2772014-04-15 09:46:51 -07006380 return false;
6381 }
6382
6383 /**
Adam Powellb72be592014-07-16 21:41:31 -07006384 * @inheritDoc
6385 */
6386 @Override
6387 public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
6388 return false;
6389 }
6390
6391 /**
Adam Powell10ba2772014-04-15 09:46:51 -07006392 * Return the current axes of nested scrolling for this ViewGroup.
6393 *
6394 * <p>A ViewGroup returning something other than {@link #SCROLL_AXIS_NONE} is currently
6395 * acting as a nested scrolling parent for one or more descendant views in the hierarchy.</p>
6396 *
6397 * @return Flags indicating the current axes of nested scrolling
6398 * @see #SCROLL_AXIS_HORIZONTAL
6399 * @see #SCROLL_AXIS_VERTICAL
6400 * @see #SCROLL_AXIS_NONE
6401 */
6402 public int getNestedScrollAxes() {
6403 return mNestedScrollAxes;
6404 }
6405
Philip Milned7dd8902012-01-26 16:55:30 -08006406 /** @hide */
6407 protected void onSetLayoutParams(View child, LayoutParams layoutParams) {
6408 }
6409
George Mounte1803372014-02-26 19:00:52 +00006410 /** @hide */
6411 @Override
6412 public void captureTransitioningViews(List<View> transitioningViews) {
6413 if (getVisibility() != View.VISIBLE) {
6414 return;
6415 }
6416 if (isTransitionGroup()) {
6417 transitioningViews.add(this);
6418 } else {
6419 int count = getChildCount();
6420 for (int i = 0; i < count; i++) {
6421 View child = getChildAt(i);
6422 child.captureTransitioningViews(transitioningViews);
6423 }
6424 }
6425 }
6426
6427 /** @hide */
6428 @Override
George Mountabb352a2014-05-09 10:27:20 -07006429 public void findNamedViews(Map<String, View> namedElements) {
George Mountfe361d22014-07-08 17:25:25 -07006430 if (getVisibility() != VISIBLE && mGhostView == null) {
George Mounte1803372014-02-26 19:00:52 +00006431 return;
6432 }
George Mountabb352a2014-05-09 10:27:20 -07006433 super.findNamedViews(namedElements);
George Mounte1803372014-02-26 19:00:52 +00006434 int count = getChildCount();
6435 for (int i = 0; i < count; i++) {
6436 View child = getChildAt(i);
George Mountabb352a2014-05-09 10:27:20 -07006437 child.findNamedViews(namedElements);
George Mounte1803372014-02-26 19:00:52 +00006438 }
6439 }
6440
Patrick Dubroye0a799a2011-05-04 16:19:22 -07006441 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006442 * LayoutParams are used by views to tell their parents how they want to be
6443 * laid out. See
6444 * {@link android.R.styleable#ViewGroup_Layout ViewGroup Layout Attributes}
6445 * for a list of all child view attributes that this class supports.
Romain Guy8506ab42009-06-11 17:35:47 -07006446 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006447 * <p>
6448 * The base LayoutParams class just describes how big the view wants to be
6449 * for both width and height. For each dimension, it can specify one of:
6450 * <ul>
Dirk Dougherty75c66da2010-03-25 16:33:33 -07006451 * <li>FILL_PARENT (renamed MATCH_PARENT in API Level 8 and higher), which
6452 * means that the view wants to be as big as its parent (minus padding)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006453 * <li> WRAP_CONTENT, which means that the view wants to be just big enough
6454 * to enclose its content (plus padding)
Dirk Dougherty75c66da2010-03-25 16:33:33 -07006455 * <li> an exact number
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006456 * </ul>
6457 * There are subclasses of LayoutParams for different subclasses of
6458 * ViewGroup. For example, AbsoluteLayout has its own subclass of
Joe Fernandez558459f2011-10-13 16:47:36 -07006459 * LayoutParams which adds an X and Y value.</p>
6460 *
6461 * <div class="special reference">
6462 * <h3>Developer Guides</h3>
6463 * <p>For more information about creating user interface layouts, read the
6464 * <a href="{@docRoot}guide/topics/ui/declaring-layout.html">XML Layouts</a> developer
6465 * guide.</p></div>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006466 *
6467 * @attr ref android.R.styleable#ViewGroup_Layout_layout_height
6468 * @attr ref android.R.styleable#ViewGroup_Layout_layout_width
6469 */
6470 public static class LayoutParams {
6471 /**
Dirk Dougherty75c66da2010-03-25 16:33:33 -07006472 * Special value for the height or width requested by a View.
6473 * FILL_PARENT means that the view wants to be as big as its parent,
6474 * minus the parent's padding, if any. This value is deprecated
6475 * starting in API Level 8 and replaced by {@link #MATCH_PARENT}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006476 */
Romain Guy980a9382010-01-08 15:06:28 -08006477 @SuppressWarnings({"UnusedDeclaration"})
6478 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006479 public static final int FILL_PARENT = -1;
6480
6481 /**
6482 * Special value for the height or width requested by a View.
Gilles Debunnef5c6eff2010-02-09 19:08:36 -08006483 * MATCH_PARENT means that the view wants to be as big as its parent,
Dirk Dougherty75c66da2010-03-25 16:33:33 -07006484 * minus the parent's padding, if any. Introduced in API Level 8.
Romain Guy980a9382010-01-08 15:06:28 -08006485 */
6486 public static final int MATCH_PARENT = -1;
6487
6488 /**
6489 * Special value for the height or width requested by a View.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006490 * WRAP_CONTENT means that the view wants to be just large enough to fit
6491 * its own internal content, taking its own padding into account.
6492 */
6493 public static final int WRAP_CONTENT = -2;
6494
6495 /**
Dirk Dougherty75c66da2010-03-25 16:33:33 -07006496 * Information about how wide the view wants to be. Can be one of the
Mark Dolinerd0646dc2014-08-27 16:04:02 -07006497 * constants FILL_PARENT (replaced by MATCH_PARENT
6498 * in API Level 8) or WRAP_CONTENT, or an exact size.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006499 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07006500 @ViewDebug.ExportedProperty(category = "layout", mapping = {
Romain Guy980a9382010-01-08 15:06:28 -08006501 @ViewDebug.IntToString(from = MATCH_PARENT, to = "MATCH_PARENT"),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006502 @ViewDebug.IntToString(from = WRAP_CONTENT, to = "WRAP_CONTENT")
6503 })
6504 public int width;
6505
6506 /**
Dirk Dougherty75c66da2010-03-25 16:33:33 -07006507 * Information about how tall the view wants to be. Can be one of the
Mark Dolinerd0646dc2014-08-27 16:04:02 -07006508 * constants FILL_PARENT (replaced by MATCH_PARENT
6509 * in API Level 8) or WRAP_CONTENT, or an exact size.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006510 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07006511 @ViewDebug.ExportedProperty(category = "layout", mapping = {
Romain Guy980a9382010-01-08 15:06:28 -08006512 @ViewDebug.IntToString(from = MATCH_PARENT, to = "MATCH_PARENT"),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006513 @ViewDebug.IntToString(from = WRAP_CONTENT, to = "WRAP_CONTENT")
6514 })
6515 public int height;
6516
6517 /**
6518 * Used to animate layouts.
6519 */
6520 public LayoutAnimationController.AnimationParameters layoutAnimationParameters;
6521
6522 /**
6523 * Creates a new set of layout parameters. The values are extracted from
6524 * the supplied attributes set and context. The XML attributes mapped
6525 * to this set of layout parameters are:
6526 *
6527 * <ul>
6528 * <li><code>layout_width</code>: the width, either an exact value,
Dirk Dougherty75c66da2010-03-25 16:33:33 -07006529 * {@link #WRAP_CONTENT}, or {@link #FILL_PARENT} (replaced by
6530 * {@link #MATCH_PARENT} in API Level 8)</li>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006531 * <li><code>layout_height</code>: the height, either an exact value,
Dirk Dougherty75c66da2010-03-25 16:33:33 -07006532 * {@link #WRAP_CONTENT}, or {@link #FILL_PARENT} (replaced by
6533 * {@link #MATCH_PARENT} in API Level 8)</li>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006534 * </ul>
6535 *
6536 * @param c the application environment
6537 * @param attrs the set of attributes from which to extract the layout
6538 * parameters' values
6539 */
6540 public LayoutParams(Context c, AttributeSet attrs) {
6541 TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.ViewGroup_Layout);
6542 setBaseAttributes(a,
6543 R.styleable.ViewGroup_Layout_layout_width,
6544 R.styleable.ViewGroup_Layout_layout_height);
6545 a.recycle();
6546 }
6547
6548 /**
6549 * Creates a new set of layout parameters with the specified width
6550 * and height.
6551 *
Dirk Dougherty75c66da2010-03-25 16:33:33 -07006552 * @param width the width, either {@link #WRAP_CONTENT},
6553 * {@link #FILL_PARENT} (replaced by {@link #MATCH_PARENT} in
6554 * API Level 8), or a fixed size in pixels
6555 * @param height the height, either {@link #WRAP_CONTENT},
6556 * {@link #FILL_PARENT} (replaced by {@link #MATCH_PARENT} in
6557 * API Level 8), or a fixed size in pixels
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006558 */
6559 public LayoutParams(int width, int height) {
6560 this.width = width;
6561 this.height = height;
6562 }
6563
6564 /**
6565 * Copy constructor. Clones the width and height values of the source.
6566 *
6567 * @param source The layout params to copy from.
6568 */
6569 public LayoutParams(LayoutParams source) {
6570 this.width = source.width;
6571 this.height = source.height;
6572 }
6573
6574 /**
6575 * Used internally by MarginLayoutParams.
6576 * @hide
6577 */
6578 LayoutParams() {
6579 }
6580
6581 /**
Dave Burke579e1402012-10-18 20:41:55 -07006582 * Extracts the layout parameters from the supplied attributes.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006583 *
6584 * @param a the style attributes to extract the parameters from
6585 * @param widthAttr the identifier of the width attribute
6586 * @param heightAttr the identifier of the height attribute
6587 */
6588 protected void setBaseAttributes(TypedArray a, int widthAttr, int heightAttr) {
Dave Burke579e1402012-10-18 20:41:55 -07006589 width = a.getLayoutDimension(widthAttr, "layout_width");
6590 height = a.getLayoutDimension(heightAttr, "layout_height");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006591 }
6592
6593 /**
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006594 * Resolve layout parameters depending on the layout direction. Subclasses that care about
6595 * layoutDirection changes should override this method. The default implementation does
6596 * nothing.
6597 *
6598 * @param layoutDirection the direction of the layout
6599 *
6600 * {@link View#LAYOUT_DIRECTION_LTR}
6601 * {@link View#LAYOUT_DIRECTION_RTL}
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006602 */
Fabrice Di Meglio2918ab62012-10-10 16:39:25 -07006603 public void resolveLayoutDirection(int layoutDirection) {
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006604 }
6605
6606 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006607 * Returns a String representation of this set of layout parameters.
6608 *
6609 * @param output the String to prepend to the internal representation
6610 * @return a String with the following format: output +
6611 * "ViewGroup.LayoutParams={ width=WIDTH, height=HEIGHT }"
Romain Guy8506ab42009-06-11 17:35:47 -07006612 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006613 * @hide
6614 */
6615 public String debug(String output) {
6616 return output + "ViewGroup.LayoutParams={ width="
6617 + sizeToString(width) + ", height=" + sizeToString(height) + " }";
6618 }
6619
6620 /**
Philip Milne10ca24a2012-04-23 15:38:27 -07006621 * Use {@code canvas} to draw suitable debugging annotations for these LayoutParameters.
6622 *
6623 * @param view the view that contains these layout parameters
6624 * @param canvas the canvas on which to draw
6625 *
6626 * @hide
6627 */
Philip Milne7b757812012-09-19 18:13:44 -07006628 public void onDebugDraw(View view, Canvas canvas, Paint paint) {
Philip Milne10ca24a2012-04-23 15:38:27 -07006629 }
6630
6631 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006632 * Converts the specified size to a readable String.
6633 *
6634 * @param size the size to convert
6635 * @return a String instance representing the supplied size
Romain Guy8506ab42009-06-11 17:35:47 -07006636 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006637 * @hide
6638 */
6639 protected static String sizeToString(int size) {
6640 if (size == WRAP_CONTENT) {
6641 return "wrap-content";
6642 }
Romain Guy980a9382010-01-08 15:06:28 -08006643 if (size == MATCH_PARENT) {
6644 return "match-parent";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006645 }
6646 return String.valueOf(size);
6647 }
6648 }
6649
6650 /**
6651 * Per-child layout information for layouts that support margins.
6652 * See
6653 * {@link android.R.styleable#ViewGroup_MarginLayout ViewGroup Margin Layout Attributes}
6654 * for a list of all child view attributes that this class supports.
6655 */
6656 public static class MarginLayoutParams extends ViewGroup.LayoutParams {
6657 /**
Adam Powella7a735f2014-10-09 12:54:52 -07006658 * The left margin in pixels of the child. Margin values should be positive.
Philip Milned7dd8902012-01-26 16:55:30 -08006659 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
6660 * to this field.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006661 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07006662 @ViewDebug.ExportedProperty(category = "layout")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006663 public int leftMargin;
6664
6665 /**
Adam Powella7a735f2014-10-09 12:54:52 -07006666 * The top margin in pixels of the child. Margin values should be positive.
Philip Milned7dd8902012-01-26 16:55:30 -08006667 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
6668 * to this field.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006669 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07006670 @ViewDebug.ExportedProperty(category = "layout")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006671 public int topMargin;
6672
6673 /**
Adam Powella7a735f2014-10-09 12:54:52 -07006674 * The right margin in pixels of the child. Margin values should be positive.
Philip Milned7dd8902012-01-26 16:55:30 -08006675 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
6676 * to this field.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006677 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07006678 @ViewDebug.ExportedProperty(category = "layout")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006679 public int rightMargin;
6680
6681 /**
Adam Powella7a735f2014-10-09 12:54:52 -07006682 * The bottom margin in pixels of the child. Margin values should be positive.
Philip Milned7dd8902012-01-26 16:55:30 -08006683 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
6684 * to this field.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006685 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07006686 @ViewDebug.ExportedProperty(category = "layout")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006687 public int bottomMargin;
6688
6689 /**
Adam Powella7a735f2014-10-09 12:54:52 -07006690 * The start margin in pixels of the child. Margin values should be positive.
Fabrice Di Meglio54546f22012-02-14 16:26:16 -08006691 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
6692 * to this field.
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006693 */
6694 @ViewDebug.ExportedProperty(category = "layout")
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006695 private int startMargin = DEFAULT_MARGIN_RELATIVE;
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006696
6697 /**
Adam Powella7a735f2014-10-09 12:54:52 -07006698 * The end margin in pixels of the child. Margin values should be positive.
Fabrice Di Meglio54546f22012-02-14 16:26:16 -08006699 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
6700 * to this field.
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006701 */
6702 @ViewDebug.ExportedProperty(category = "layout")
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006703 private int endMargin = DEFAULT_MARGIN_RELATIVE;
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006704
6705 /**
6706 * The default start and end margin.
Fabrice Di Megliof443f982012-07-13 20:24:03 -07006707 * @hide
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006708 */
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006709 public static final int DEFAULT_MARGIN_RELATIVE = Integer.MIN_VALUE;
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006710
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006711 /**
6712 * Bit 0: layout direction
6713 * Bit 1: layout direction
6714 * Bit 2: left margin undefined
6715 * Bit 3: right margin undefined
6716 * Bit 4: is RTL compatibility mode
6717 * Bit 5: need resolution
6718 *
6719 * Bit 6 to 7 not used
6720 *
6721 * @hide
6722 */
6723 @ViewDebug.ExportedProperty(category = "layout", flagMapping = {
6724 @ViewDebug.FlagToString(mask = LAYOUT_DIRECTION_MASK,
6725 equals = LAYOUT_DIRECTION_MASK, name = "LAYOUT_DIRECTION"),
6726 @ViewDebug.FlagToString(mask = LEFT_MARGIN_UNDEFINED_MASK,
6727 equals = LEFT_MARGIN_UNDEFINED_MASK, name = "LEFT_MARGIN_UNDEFINED_MASK"),
6728 @ViewDebug.FlagToString(mask = RIGHT_MARGIN_UNDEFINED_MASK,
6729 equals = RIGHT_MARGIN_UNDEFINED_MASK, name = "RIGHT_MARGIN_UNDEFINED_MASK"),
6730 @ViewDebug.FlagToString(mask = RTL_COMPATIBILITY_MODE_MASK,
6731 equals = RTL_COMPATIBILITY_MODE_MASK, name = "RTL_COMPATIBILITY_MODE_MASK"),
6732 @ViewDebug.FlagToString(mask = NEED_RESOLUTION_MASK,
6733 equals = NEED_RESOLUTION_MASK, name = "NEED_RESOLUTION_MASK")
Jon Miranda4597e982014-07-29 07:25:49 -07006734 }, formatToHexString = true)
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006735 byte mMarginFlags;
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07006736
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006737 private static final int LAYOUT_DIRECTION_MASK = 0x00000003;
6738 private static final int LEFT_MARGIN_UNDEFINED_MASK = 0x00000004;
6739 private static final int RIGHT_MARGIN_UNDEFINED_MASK = 0x00000008;
6740 private static final int RTL_COMPATIBILITY_MODE_MASK = 0x00000010;
6741 private static final int NEED_RESOLUTION_MASK = 0x00000020;
Fabrice Di Megliof443f982012-07-13 20:24:03 -07006742
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006743 private static final int DEFAULT_MARGIN_RESOLVED = 0;
6744 private static final int UNDEFINED_MARGIN = DEFAULT_MARGIN_RELATIVE;
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07006745
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006746 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006747 * Creates a new set of layout parameters. The values are extracted from
6748 * the supplied attributes set and context.
6749 *
6750 * @param c the application environment
6751 * @param attrs the set of attributes from which to extract the layout
6752 * parameters' values
6753 */
6754 public MarginLayoutParams(Context c, AttributeSet attrs) {
6755 super();
6756
6757 TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.ViewGroup_MarginLayout);
6758 setBaseAttributes(a,
6759 R.styleable.ViewGroup_MarginLayout_layout_width,
6760 R.styleable.ViewGroup_MarginLayout_layout_height);
6761
6762 int margin = a.getDimensionPixelSize(
6763 com.android.internal.R.styleable.ViewGroup_MarginLayout_layout_margin, -1);
6764 if (margin >= 0) {
6765 leftMargin = margin;
6766 topMargin = margin;
6767 rightMargin= margin;
6768 bottomMargin = margin;
6769 } else {
6770 leftMargin = a.getDimensionPixelSize(
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006771 R.styleable.ViewGroup_MarginLayout_layout_marginLeft,
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07006772 UNDEFINED_MARGIN);
6773 if (leftMargin == UNDEFINED_MARGIN) {
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006774 mMarginFlags |= LEFT_MARGIN_UNDEFINED_MASK;
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07006775 leftMargin = DEFAULT_MARGIN_RESOLVED;
6776 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006777 rightMargin = a.getDimensionPixelSize(
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006778 R.styleable.ViewGroup_MarginLayout_layout_marginRight,
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07006779 UNDEFINED_MARGIN);
6780 if (rightMargin == UNDEFINED_MARGIN) {
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006781 mMarginFlags |= RIGHT_MARGIN_UNDEFINED_MASK;
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07006782 rightMargin = DEFAULT_MARGIN_RESOLVED;
6783 }
6784
6785 topMargin = a.getDimensionPixelSize(
6786 R.styleable.ViewGroup_MarginLayout_layout_marginTop,
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006787 DEFAULT_MARGIN_RESOLVED);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006788 bottomMargin = a.getDimensionPixelSize(
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006789 R.styleable.ViewGroup_MarginLayout_layout_marginBottom,
6790 DEFAULT_MARGIN_RESOLVED);
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07006791
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006792 startMargin = a.getDimensionPixelSize(
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006793 R.styleable.ViewGroup_MarginLayout_layout_marginStart,
6794 DEFAULT_MARGIN_RELATIVE);
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006795 endMargin = a.getDimensionPixelSize(
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006796 R.styleable.ViewGroup_MarginLayout_layout_marginEnd,
6797 DEFAULT_MARGIN_RELATIVE);
6798
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006799 if (isMarginRelative()) {
6800 mMarginFlags |= NEED_RESOLUTION_MASK;
6801 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006802 }
6803
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006804 final boolean hasRtlSupport = c.getApplicationInfo().hasRtlSupport();
6805 final int targetSdkVersion = c.getApplicationInfo().targetSdkVersion;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006806 if (targetSdkVersion < JELLY_BEAN_MR1 || !hasRtlSupport) {
6807 mMarginFlags |= RTL_COMPATIBILITY_MODE_MASK;
6808 }
6809
6810 // Layout direction is LTR by default
6811 mMarginFlags |= LAYOUT_DIRECTION_LTR;
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07006812
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006813 a.recycle();
6814 }
6815
6816 /**
6817 * {@inheritDoc}
6818 */
6819 public MarginLayoutParams(int width, int height) {
6820 super(width, height);
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006821
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006822 mMarginFlags |= LEFT_MARGIN_UNDEFINED_MASK;
6823 mMarginFlags |= RIGHT_MARGIN_UNDEFINED_MASK;
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07006824
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006825 mMarginFlags &= ~NEED_RESOLUTION_MASK;
6826 mMarginFlags &= ~RTL_COMPATIBILITY_MODE_MASK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006827 }
6828
6829 /**
6830 * Copy constructor. Clones the width, height and margin values of the source.
6831 *
6832 * @param source The layout params to copy from.
6833 */
6834 public MarginLayoutParams(MarginLayoutParams source) {
6835 this.width = source.width;
6836 this.height = source.height;
6837
6838 this.leftMargin = source.leftMargin;
6839 this.topMargin = source.topMargin;
6840 this.rightMargin = source.rightMargin;
6841 this.bottomMargin = source.bottomMargin;
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006842 this.startMargin = source.startMargin;
6843 this.endMargin = source.endMargin;
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07006844
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006845 this.mMarginFlags = source.mMarginFlags;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006846 }
6847
6848 /**
6849 * {@inheritDoc}
6850 */
6851 public MarginLayoutParams(LayoutParams source) {
6852 super(source);
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006853
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006854 mMarginFlags |= LEFT_MARGIN_UNDEFINED_MASK;
6855 mMarginFlags |= RIGHT_MARGIN_UNDEFINED_MASK;
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07006856
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006857 mMarginFlags &= ~NEED_RESOLUTION_MASK;
6858 mMarginFlags &= ~RTL_COMPATIBILITY_MODE_MASK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006859 }
6860
6861 /**
Adam Powelld7600832014-07-01 15:22:50 -07006862 * @hide Used internally.
6863 */
6864 public final void copyMarginsFrom(MarginLayoutParams source) {
6865 this.leftMargin = source.leftMargin;
6866 this.topMargin = source.topMargin;
6867 this.rightMargin = source.rightMargin;
6868 this.bottomMargin = source.bottomMargin;
6869 this.startMargin = source.startMargin;
6870 this.endMargin = source.endMargin;
6871
6872 this.mMarginFlags = source.mMarginFlags;
6873 }
6874
6875 /**
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006876 * Sets the margins, in pixels. A call to {@link android.view.View#requestLayout()} needs
6877 * to be done so that the new margins are taken into account. Left and right margins may be
6878 * overriden by {@link android.view.View#requestLayout()} depending on layout direction.
Adam Powella7a735f2014-10-09 12:54:52 -07006879 * Margin values should be positive.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006880 *
6881 * @param left the left margin size
6882 * @param top the top margin size
6883 * @param right the right margin size
6884 * @param bottom the bottom margin size
6885 *
6886 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginLeft
6887 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginTop
6888 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginRight
6889 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginBottom
6890 */
6891 public void setMargins(int left, int top, int right, int bottom) {
6892 leftMargin = left;
6893 topMargin = top;
6894 rightMargin = right;
6895 bottomMargin = bottom;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006896 mMarginFlags &= ~LEFT_MARGIN_UNDEFINED_MASK;
6897 mMarginFlags &= ~RIGHT_MARGIN_UNDEFINED_MASK;
6898 if (isMarginRelative()) {
6899 mMarginFlags |= NEED_RESOLUTION_MASK;
6900 } else {
6901 mMarginFlags &= ~NEED_RESOLUTION_MASK;
6902 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006903 }
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006904
6905 /**
6906 * Sets the relative margins, in pixels. A call to {@link android.view.View#requestLayout()}
6907 * needs to be done so that the new relative margins are taken into account. Left and right
6908 * margins may be overriden by {@link android.view.View#requestLayout()} depending on layout
Adam Powella7a735f2014-10-09 12:54:52 -07006909 * direction. Margin values should be positive.
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006910 *
6911 * @param start the start margin size
6912 * @param top the top margin size
6913 * @param end the right margin size
6914 * @param bottom the bottom margin size
6915 *
6916 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart
6917 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginTop
6918 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd
6919 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginBottom
6920 *
6921 * @hide
6922 */
6923 public void setMarginsRelative(int start, int top, int end, int bottom) {
6924 startMargin = start;
6925 topMargin = top;
6926 endMargin = end;
6927 bottomMargin = bottom;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006928 mMarginFlags |= NEED_RESOLUTION_MASK;
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006929 }
6930
6931 /**
Adam Powella7a735f2014-10-09 12:54:52 -07006932 * Sets the relative start margin. Margin values should be positive.
Fabrice Di Meglioa40627d2012-09-11 16:47:21 -07006933 *
Fabrice Di Meglio61a21772012-09-12 16:33:13 -07006934 * @param start the start margin size
Fabrice Di Meglioa40627d2012-09-11 16:47:21 -07006935 *
6936 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart
6937 */
6938 public void setMarginStart(int start) {
6939 startMargin = start;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006940 mMarginFlags |= NEED_RESOLUTION_MASK;
Fabrice Di Meglioa40627d2012-09-11 16:47:21 -07006941 }
6942
6943 /**
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006944 * Returns the start margin in pixels.
6945 *
6946 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart
6947 *
6948 * @return the start margin in pixels.
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006949 */
6950 public int getMarginStart() {
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006951 if (startMargin != DEFAULT_MARGIN_RELATIVE) return startMargin;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006952 if ((mMarginFlags & NEED_RESOLUTION_MASK) == NEED_RESOLUTION_MASK) {
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006953 doResolveMargins();
6954 }
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006955 switch(mMarginFlags & LAYOUT_DIRECTION_MASK) {
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07006956 case View.LAYOUT_DIRECTION_RTL:
6957 return rightMargin;
6958 case View.LAYOUT_DIRECTION_LTR:
6959 default:
6960 return leftMargin;
6961 }
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006962 }
6963
6964 /**
Adam Powella7a735f2014-10-09 12:54:52 -07006965 * Sets the relative end margin. Margin values should be positive.
Fabrice Di Meglioa40627d2012-09-11 16:47:21 -07006966 *
Fabrice Di Meglio61a21772012-09-12 16:33:13 -07006967 * @param end the end margin size
Fabrice Di Meglioa40627d2012-09-11 16:47:21 -07006968 *
6969 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd
6970 */
6971 public void setMarginEnd(int end) {
6972 endMargin = end;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006973 mMarginFlags |= NEED_RESOLUTION_MASK;
Fabrice Di Meglioa40627d2012-09-11 16:47:21 -07006974 }
6975
6976 /**
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006977 * Returns the end margin in pixels.
6978 *
6979 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd
6980 *
6981 * @return the end margin in pixels.
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006982 */
6983 public int getMarginEnd() {
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006984 if (endMargin != DEFAULT_MARGIN_RELATIVE) return endMargin;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006985 if ((mMarginFlags & NEED_RESOLUTION_MASK) == NEED_RESOLUTION_MASK) {
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006986 doResolveMargins();
6987 }
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006988 switch(mMarginFlags & LAYOUT_DIRECTION_MASK) {
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07006989 case View.LAYOUT_DIRECTION_RTL:
6990 return leftMargin;
6991 case View.LAYOUT_DIRECTION_LTR:
6992 default:
6993 return rightMargin;
6994 }
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006995 }
6996
6997 /**
6998 * Check if margins are relative.
6999 *
7000 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart
7001 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd
7002 *
Fabrice Di Megliof443f982012-07-13 20:24:03 -07007003 * @return true if either marginStart or marginEnd has been set.
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007004 */
7005 public boolean isMarginRelative() {
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07007006 return (startMargin != DEFAULT_MARGIN_RELATIVE || endMargin != DEFAULT_MARGIN_RELATIVE);
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007007 }
7008
7009 /**
Fabrice Di Megliof443f982012-07-13 20:24:03 -07007010 * Set the layout direction
7011 * @param layoutDirection the layout direction.
7012 * Should be either {@link View#LAYOUT_DIRECTION_LTR}
7013 * or {@link View#LAYOUT_DIRECTION_RTL}.
7014 */
7015 public void setLayoutDirection(int layoutDirection) {
7016 if (layoutDirection != View.LAYOUT_DIRECTION_LTR &&
7017 layoutDirection != View.LAYOUT_DIRECTION_RTL) return;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007018 if (layoutDirection != (mMarginFlags & LAYOUT_DIRECTION_MASK)) {
7019 mMarginFlags &= ~LAYOUT_DIRECTION_MASK;
7020 mMarginFlags |= (layoutDirection & LAYOUT_DIRECTION_MASK);
7021 if (isMarginRelative()) {
7022 mMarginFlags |= NEED_RESOLUTION_MASK;
7023 } else {
7024 mMarginFlags &= ~NEED_RESOLUTION_MASK;
7025 }
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07007026 }
Fabrice Di Megliof443f982012-07-13 20:24:03 -07007027 }
7028
7029 /**
7030 * Retuns the layout direction. Can be either {@link View#LAYOUT_DIRECTION_LTR} or
7031 * {@link View#LAYOUT_DIRECTION_RTL}.
7032 *
7033 * @return the layout direction.
7034 */
7035 public int getLayoutDirection() {
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007036 return (mMarginFlags & LAYOUT_DIRECTION_MASK);
Fabrice Di Megliof443f982012-07-13 20:24:03 -07007037 }
7038
7039 /**
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007040 * This will be called by {@link android.view.View#requestLayout()}. Left and Right margins
Fabrice Di Meglio98aec1c2012-02-13 16:54:05 -08007041 * may be overridden depending on layout direction.
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007042 */
7043 @Override
Fabrice Di Meglio2918ab62012-10-10 16:39:25 -07007044 public void resolveLayoutDirection(int layoutDirection) {
Fabrice Di Megliof443f982012-07-13 20:24:03 -07007045 setLayoutDirection(layoutDirection);
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07007046
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07007047 // No relative margin or pre JB-MR1 case or no need to resolve, just dont do anything
7048 // Will use the left and right margins if no relative margin is defined.
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007049 if (!isMarginRelative() ||
7050 (mMarginFlags & NEED_RESOLUTION_MASK) != NEED_RESOLUTION_MASK) return;
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07007051
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07007052 // Proceed with resolution
7053 doResolveMargins();
7054 }
7055
7056 private void doResolveMargins() {
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007057 if ((mMarginFlags & RTL_COMPATIBILITY_MODE_MASK) == RTL_COMPATIBILITY_MODE_MASK) {
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07007058 // if left or right margins are not defined and if we have some start or end margin
7059 // defined then use those start and end margins.
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007060 if ((mMarginFlags & LEFT_MARGIN_UNDEFINED_MASK) == LEFT_MARGIN_UNDEFINED_MASK
7061 && startMargin > DEFAULT_MARGIN_RELATIVE) {
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07007062 leftMargin = startMargin;
7063 }
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007064 if ((mMarginFlags & RIGHT_MARGIN_UNDEFINED_MASK) == RIGHT_MARGIN_UNDEFINED_MASK
7065 && endMargin > DEFAULT_MARGIN_RELATIVE) {
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07007066 rightMargin = endMargin;
7067 }
7068 } else {
7069 // We have some relative margins (either the start one or the end one or both). So use
7070 // them and override what has been defined for left and right margins. If either start
7071 // or end margin is not defined, just set it to default "0".
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007072 switch(mMarginFlags & LAYOUT_DIRECTION_MASK) {
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07007073 case View.LAYOUT_DIRECTION_RTL:
7074 leftMargin = (endMargin > DEFAULT_MARGIN_RELATIVE) ?
7075 endMargin : DEFAULT_MARGIN_RESOLVED;
7076 rightMargin = (startMargin > DEFAULT_MARGIN_RELATIVE) ?
7077 startMargin : DEFAULT_MARGIN_RESOLVED;
7078 break;
7079 case View.LAYOUT_DIRECTION_LTR:
7080 default:
7081 leftMargin = (startMargin > DEFAULT_MARGIN_RELATIVE) ?
7082 startMargin : DEFAULT_MARGIN_RESOLVED;
7083 rightMargin = (endMargin > DEFAULT_MARGIN_RELATIVE) ?
7084 endMargin : DEFAULT_MARGIN_RESOLVED;
7085 break;
7086 }
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007087 }
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007088 mMarginFlags &= ~NEED_RESOLUTION_MASK;
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007089 }
Philip Milne10ca24a2012-04-23 15:38:27 -07007090
Fabrice Di Meglio03b8d3a2012-09-27 17:05:27 -07007091 /**
7092 * @hide
7093 */
7094 public boolean isLayoutRtl() {
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007095 return ((mMarginFlags & LAYOUT_DIRECTION_MASK) == View.LAYOUT_DIRECTION_RTL);
Fabrice Di Megliof443f982012-07-13 20:24:03 -07007096 }
7097
Philip Milne10ca24a2012-04-23 15:38:27 -07007098 /**
7099 * @hide
7100 */
7101 @Override
Philip Milne7b757812012-09-19 18:13:44 -07007102 public void onDebugDraw(View view, Canvas canvas, Paint paint) {
7103 Insets oi = isLayoutModeOptical(view.mParent) ? view.getOpticalInsets() : Insets.NONE;
7104
7105 fillDifference(canvas,
7106 view.getLeft() + oi.left,
7107 view.getTop() + oi.top,
7108 view.getRight() - oi.right,
7109 view.getBottom() - oi.bottom,
7110 leftMargin,
7111 topMargin,
7112 rightMargin,
7113 bottomMargin,
7114 paint);
Philip Milne10ca24a2012-04-23 15:38:27 -07007115 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007116 }
Adam Powell2b342f02010-08-18 18:14:13 -07007117
Jeff Brown20e987b2010-08-23 12:01:02 -07007118 /* Describes a touched view and the ids of the pointers that it has captured.
7119 *
7120 * This code assumes that pointer ids are always in the range 0..31 such that
7121 * it can use a bitfield to track which pointer ids are present.
7122 * As it happens, the lower layers of the input dispatch pipeline also use the
7123 * same trick so the assumption should be safe here...
7124 */
7125 private static final class TouchTarget {
7126 private static final int MAX_RECYCLED = 32;
Romain Guy6410c0a2013-06-17 11:21:58 -07007127 private static final Object sRecycleLock = new Object[0];
Jeff Brown20e987b2010-08-23 12:01:02 -07007128 private static TouchTarget sRecycleBin;
7129 private static int sRecycledCount;
Adam Powell2b342f02010-08-18 18:14:13 -07007130
Jeff Brown20e987b2010-08-23 12:01:02 -07007131 public static final int ALL_POINTER_IDS = -1; // all ones
Adam Powell2b342f02010-08-18 18:14:13 -07007132
Jeff Brown20e987b2010-08-23 12:01:02 -07007133 // The touched child view.
7134 public View child;
7135
7136 // The combined bit mask of pointer ids for all pointers captured by the target.
7137 public int pointerIdBits;
7138
7139 // The next target in the target list.
7140 public TouchTarget next;
7141
7142 private TouchTarget() {
Adam Powell2b342f02010-08-18 18:14:13 -07007143 }
7144
Jeff Brown20e987b2010-08-23 12:01:02 -07007145 public static TouchTarget obtain(View child, int pointerIdBits) {
7146 final TouchTarget target;
7147 synchronized (sRecycleLock) {
Adam Powell816c3be2010-08-23 18:00:05 -07007148 if (sRecycleBin == null) {
Jeff Brown20e987b2010-08-23 12:01:02 -07007149 target = new TouchTarget();
Adam Powell816c3be2010-08-23 18:00:05 -07007150 } else {
Jeff Brown20e987b2010-08-23 12:01:02 -07007151 target = sRecycleBin;
7152 sRecycleBin = target.next;
7153 sRecycledCount--;
7154 target.next = null;
Adam Powell816c3be2010-08-23 18:00:05 -07007155 }
Adam Powell816c3be2010-08-23 18:00:05 -07007156 }
Jeff Brown20e987b2010-08-23 12:01:02 -07007157 target.child = child;
7158 target.pointerIdBits = pointerIdBits;
7159 return target;
7160 }
Adam Powell816c3be2010-08-23 18:00:05 -07007161
Jeff Brown20e987b2010-08-23 12:01:02 -07007162 public void recycle() {
7163 synchronized (sRecycleLock) {
7164 if (sRecycledCount < MAX_RECYCLED) {
7165 next = sRecycleBin;
7166 sRecycleBin = this;
7167 sRecycledCount += 1;
Patrick Dubroyfb0547d22010-10-19 17:36:18 -07007168 } else {
7169 next = null;
Adam Powell816c3be2010-08-23 18:00:05 -07007170 }
Patrick Dubroyfb0547d22010-10-19 17:36:18 -07007171 child = null;
Adam Powell816c3be2010-08-23 18:00:05 -07007172 }
7173 }
Adam Powell2b342f02010-08-18 18:14:13 -07007174 }
Jeff Brown87b7f802011-06-21 18:35:45 -07007175
7176 /* Describes a hovered view. */
7177 private static final class HoverTarget {
7178 private static final int MAX_RECYCLED = 32;
Romain Guy6410c0a2013-06-17 11:21:58 -07007179 private static final Object sRecycleLock = new Object[0];
Jeff Brown87b7f802011-06-21 18:35:45 -07007180 private static HoverTarget sRecycleBin;
7181 private static int sRecycledCount;
7182
7183 // The hovered child view.
7184 public View child;
7185
7186 // The next target in the target list.
7187 public HoverTarget next;
7188
7189 private HoverTarget() {
7190 }
7191
7192 public static HoverTarget obtain(View child) {
7193 final HoverTarget target;
7194 synchronized (sRecycleLock) {
7195 if (sRecycleBin == null) {
7196 target = new HoverTarget();
7197 } else {
7198 target = sRecycleBin;
7199 sRecycleBin = target.next;
7200 sRecycledCount--;
7201 target.next = null;
7202 }
7203 }
7204 target.child = child;
7205 return target;
7206 }
7207
7208 public void recycle() {
7209 synchronized (sRecycleLock) {
7210 if (sRecycledCount < MAX_RECYCLED) {
7211 next = sRecycleBin;
7212 sRecycleBin = this;
7213 sRecycledCount += 1;
7214 } else {
7215 next = null;
7216 }
7217 child = null;
7218 }
7219 }
7220 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07007221
7222 /**
7223 * Pooled class that orderes the children of a ViewGroup from start
7224 * to end based on how they are laid out and the layout direction.
7225 */
7226 static class ChildListForAccessibility {
7227
7228 private static final int MAX_POOL_SIZE = 32;
7229
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08007230 private static final SynchronizedPool<ChildListForAccessibility> sPool =
7231 new SynchronizedPool<ChildListForAccessibility>(MAX_POOL_SIZE);
Svetoslav Ganov42138042012-03-20 11:51:39 -07007232
7233 private final ArrayList<View> mChildren = new ArrayList<View>();
7234
7235 private final ArrayList<ViewLocationHolder> mHolders = new ArrayList<ViewLocationHolder>();
7236
7237 public static ChildListForAccessibility obtain(ViewGroup parent, boolean sort) {
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08007238 ChildListForAccessibility list = sPool.acquire();
7239 if (list == null) {
7240 list = new ChildListForAccessibility();
Svetoslav Ganov42138042012-03-20 11:51:39 -07007241 }
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08007242 list.init(parent, sort);
7243 return list;
Svetoslav Ganov42138042012-03-20 11:51:39 -07007244 }
7245
7246 public void recycle() {
Svetoslav Ganov42138042012-03-20 11:51:39 -07007247 clear();
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08007248 sPool.release(this);
Svetoslav Ganov42138042012-03-20 11:51:39 -07007249 }
7250
7251 public int getChildCount() {
7252 return mChildren.size();
7253 }
7254
7255 public View getChildAt(int index) {
7256 return mChildren.get(index);
7257 }
7258
7259 public int getChildIndex(View child) {
7260 return mChildren.indexOf(child);
7261 }
7262
7263 private void init(ViewGroup parent, boolean sort) {
7264 ArrayList<View> children = mChildren;
7265 final int childCount = parent.getChildCount();
7266 for (int i = 0; i < childCount; i++) {
7267 View child = parent.getChildAt(i);
7268 children.add(child);
7269 }
7270 if (sort) {
7271 ArrayList<ViewLocationHolder> holders = mHolders;
7272 for (int i = 0; i < childCount; i++) {
7273 View child = children.get(i);
7274 ViewLocationHolder holder = ViewLocationHolder.obtain(parent, child);
7275 holders.add(holder);
7276 }
Svetoslav88e447b2014-10-09 15:49:02 -07007277 sort(holders);
Svetoslav Ganov42138042012-03-20 11:51:39 -07007278 for (int i = 0; i < childCount; i++) {
7279 ViewLocationHolder holder = holders.get(i);
7280 children.set(i, holder.mView);
7281 holder.recycle();
7282 }
7283 holders.clear();
7284 }
7285 }
7286
Svetoslav88e447b2014-10-09 15:49:02 -07007287 private void sort(ArrayList<ViewLocationHolder> holders) {
7288 // This is gross but the least risky solution. The current comparison
7289 // strategy breaks transitivity but produces very good results. Coming
7290 // up with a new strategy requires time which we do not have, so ...
7291 try {
7292 ViewLocationHolder.setComparisonStrategy(
7293 ViewLocationHolder.COMPARISON_STRATEGY_STRIPE);
7294 Collections.sort(holders);
7295 } catch (IllegalArgumentException iae) {
7296 // Note that in practice this occurs extremely rarely in a couple
7297 // of pathological cases.
7298 ViewLocationHolder.setComparisonStrategy(
7299 ViewLocationHolder.COMPARISON_STRATEGY_LOCATION);
7300 Collections.sort(holders);
7301 }
7302 }
7303
Svetoslav Ganov42138042012-03-20 11:51:39 -07007304 private void clear() {
7305 mChildren.clear();
7306 }
7307 }
7308
7309 /**
7310 * Pooled class that holds a View and its location with respect to
7311 * a specified root. This enables sorting of views based on their
7312 * coordinates without recomputing the position relative to the root
7313 * on every comparison.
7314 */
7315 static class ViewLocationHolder implements Comparable<ViewLocationHolder> {
7316
7317 private static final int MAX_POOL_SIZE = 32;
7318
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08007319 private static final SynchronizedPool<ViewLocationHolder> sPool =
7320 new SynchronizedPool<ViewLocationHolder>(MAX_POOL_SIZE);
Svetoslav Ganov42138042012-03-20 11:51:39 -07007321
Svetoslav88e447b2014-10-09 15:49:02 -07007322 public static final int COMPARISON_STRATEGY_STRIPE = 1;
7323
7324 public static final int COMPARISON_STRATEGY_LOCATION = 2;
7325
7326 private static int sComparisonStrategy = COMPARISON_STRATEGY_STRIPE;
7327
Svetoslav Ganov42138042012-03-20 11:51:39 -07007328 private final Rect mLocation = new Rect();
7329
7330 public View mView;
7331
7332 private int mLayoutDirection;
7333
7334 public static ViewLocationHolder obtain(ViewGroup root, View view) {
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08007335 ViewLocationHolder holder = sPool.acquire();
7336 if (holder == null) {
7337 holder = new ViewLocationHolder();
Svetoslav Ganov42138042012-03-20 11:51:39 -07007338 }
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08007339 holder.init(root, view);
7340 return holder;
Svetoslav Ganov42138042012-03-20 11:51:39 -07007341 }
7342
Svetoslav88e447b2014-10-09 15:49:02 -07007343 public static void setComparisonStrategy(int strategy) {
7344 sComparisonStrategy = strategy;
7345 }
7346
Svetoslav Ganov42138042012-03-20 11:51:39 -07007347 public void recycle() {
Svetoslav Ganov42138042012-03-20 11:51:39 -07007348 clear();
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08007349 sPool.release(this);
Svetoslav Ganov42138042012-03-20 11:51:39 -07007350 }
7351
7352 @Override
7353 public int compareTo(ViewLocationHolder another) {
7354 // This instance is greater than an invalid argument.
7355 if (another == null) {
7356 return 1;
7357 }
Svetoslav88e447b2014-10-09 15:49:02 -07007358
7359 if (sComparisonStrategy == COMPARISON_STRATEGY_STRIPE) {
7360 // First is above second.
7361 if (mLocation.bottom - another.mLocation.top <= 0) {
7362 return -1;
7363 }
7364 // First is below second.
7365 if (mLocation.top - another.mLocation.bottom >= 0) {
7366 return 1;
7367 }
7368 }
7369
Svetoslav04cab1b2014-08-25 18:35:57 -07007370 // We are ordering left-to-right, top-to-bottom.
Svetoslav Ganov42138042012-03-20 11:51:39 -07007371 if (mLayoutDirection == LAYOUT_DIRECTION_LTR) {
7372 final int leftDifference = mLocation.left - another.mLocation.left;
Svetoslav Ganov42138042012-03-20 11:51:39 -07007373 if (leftDifference != 0) {
7374 return leftDifference;
7375 }
7376 } else { // RTL
7377 final int rightDifference = mLocation.right - another.mLocation.right;
Svetoslav Ganov42138042012-03-20 11:51:39 -07007378 if (rightDifference != 0) {
7379 return -rightDifference;
7380 }
7381 }
Svetoslav04cab1b2014-08-25 18:35:57 -07007382 // We are ordering left-to-right, top-to-bottom.
7383 final int topDifference = mLocation.top - another.mLocation.top;
7384 if (topDifference != 0) {
7385 return topDifference;
7386 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07007387 // Break tie by height.
7388 final int heightDiference = mLocation.height() - another.mLocation.height();
7389 if (heightDiference != 0) {
7390 return -heightDiference;
7391 }
7392 // Break tie by width.
7393 final int widthDiference = mLocation.width() - another.mLocation.width();
7394 if (widthDiference != 0) {
7395 return -widthDiference;
7396 }
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07007397 // Just break the tie somehow. The accessibliity ids are unique
7398 // and stable, hence this is deterministic tie breaking.
7399 return mView.getAccessibilityViewId() - another.mView.getAccessibilityViewId();
Svetoslav Ganov42138042012-03-20 11:51:39 -07007400 }
7401
7402 private void init(ViewGroup root, View view) {
7403 Rect viewLocation = mLocation;
7404 view.getDrawingRect(viewLocation);
7405 root.offsetDescendantRectToMyCoords(view, viewLocation);
7406 mView = view;
Fabrice Di Meglioe56ffdc2012-09-23 14:51:16 -07007407 mLayoutDirection = root.getLayoutDirection();
Svetoslav Ganov42138042012-03-20 11:51:39 -07007408 }
7409
7410 private void clear() {
7411 mView = null;
7412 mLocation.set(0, 0, 0, 0);
7413 }
7414 }
Romain Guycbc67742012-04-27 16:12:57 -07007415
7416 private static Paint getDebugPaint() {
7417 if (sDebugPaint == null) {
7418 sDebugPaint = new Paint();
7419 sDebugPaint.setAntiAlias(false);
7420 }
7421 return sDebugPaint;
7422 }
7423
Romain Guy6410c0a2013-06-17 11:21:58 -07007424 private static void drawRect(Canvas canvas, Paint paint, int x1, int y1, int x2, int y2) {
Romain Guycbc67742012-04-27 16:12:57 -07007425 if (sDebugLines== null) {
Romain Guy6410c0a2013-06-17 11:21:58 -07007426 // TODO: This won't work with multiple UI threads in a single process
Romain Guycbc67742012-04-27 16:12:57 -07007427 sDebugLines = new float[16];
7428 }
7429
Romain Guycbc67742012-04-27 16:12:57 -07007430 sDebugLines[0] = x1;
7431 sDebugLines[1] = y1;
7432 sDebugLines[2] = x2;
7433 sDebugLines[3] = y1;
7434
7435 sDebugLines[4] = x2;
7436 sDebugLines[5] = y1;
7437 sDebugLines[6] = x2;
Philip Milne7b757812012-09-19 18:13:44 -07007438 sDebugLines[7] = y2;
Romain Guycbc67742012-04-27 16:12:57 -07007439
Philip Milne7b757812012-09-19 18:13:44 -07007440 sDebugLines[8] = x2;
Romain Guycbc67742012-04-27 16:12:57 -07007441 sDebugLines[9] = y2;
7442 sDebugLines[10] = x1;
7443 sDebugLines[11] = y2;
7444
Philip Milne7b757812012-09-19 18:13:44 -07007445 sDebugLines[12] = x1;
7446 sDebugLines[13] = y2;
Romain Guycbc67742012-04-27 16:12:57 -07007447 sDebugLines[14] = x1;
7448 sDebugLines[15] = y1;
7449
Philip Milne7b757812012-09-19 18:13:44 -07007450 canvas.drawLines(sDebugLines, paint);
Romain Guycbc67742012-04-27 16:12:57 -07007451 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007452}