blob: 854e6be5f84e2c054f017d61cb435042318dfbf1 [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;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080020import android.content.Context;
Adam Powellff0d2982014-07-10 20:34:14 -070021import android.content.pm.PackageManager;
Dianne Hackborne36d6e22010-02-17 19:46:25 -080022import android.content.res.Configuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080023import android.content.res.TypedArray;
24import android.graphics.Bitmap;
25import android.graphics.Canvas;
Philip Milne10ca24a2012-04-23 15:38:27 -070026import android.graphics.Color;
27import android.graphics.Insets;
Adam Powell6e346362010-07-23 10:18:23 -070028import android.graphics.Matrix;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080029import android.graphics.Paint;
Christopher Tatea53146c2010-09-07 11:57:52 -070030import android.graphics.PointF;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031import android.graphics.Rect;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032import android.graphics.RectF;
svetoslavganov75986cf2009-05-14 22:28:01 -070033import android.graphics.Region;
Jeff Brown995e7742010-12-22 16:59:36 -080034import android.os.Build;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080035import android.os.Parcelable;
36import android.os.SystemClock;
37import android.util.AttributeSet;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038import android.util.Log;
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -080039import android.util.Pools.SynchronizedPool;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040import android.util.SparseArray;
svetoslavganov75986cf2009-05-14 22:28:01 -070041import android.view.accessibility.AccessibilityEvent;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070042import android.view.accessibility.AccessibilityNodeInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043import android.view.animation.Animation;
44import android.view.animation.AnimationUtils;
45import android.view.animation.LayoutAnimationController;
46import android.view.animation.Transformation;
Doug Feltcb3791202011-07-07 11:57:48 -070047
Romain Guy0211a0a2011-02-14 16:34:59 -080048import com.android.internal.R;
49import com.android.internal.util.Predicate;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050
51import java.util.ArrayList;
Svetoslav Ganov42138042012-03-20 11:51:39 -070052import java.util.Collections;
Christopher Tate86cab1b2011-01-13 20:28:55 -080053import java.util.HashSet;
George Mounte1803372014-02-26 19:00:52 +000054import java.util.List;
55import java.util.Map;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056
Fabrice Di Meglio0072f642013-03-26 15:50:24 -070057import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
58
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080059/**
60 * <p>
61 * A <code>ViewGroup</code> is a special view that can contain other views
62 * (called children.) The view group is the base class for layouts and views
63 * containers. This class also defines the
64 * {@link android.view.ViewGroup.LayoutParams} class which serves as the base
65 * class for layouts parameters.
66 * </p>
67 *
68 * <p>
69 * Also see {@link LayoutParams} for layout attributes.
70 * </p>
Romain Guyd6a463a2009-05-21 23:10:10 -070071 *
Joe Fernandez558459f2011-10-13 16:47:36 -070072 * <div class="special reference">
73 * <h3>Developer Guides</h3>
74 * <p>For more information about creating user interface layouts, read the
75 * <a href="{@docRoot}guide/topics/ui/declaring-layout.html">XML Layouts</a> developer
76 * guide.</p></div>
77 *
Dianne Hackborn7caab0f2013-03-06 13:47:04 -080078 * <p>Here is a complete implementation of a custom ViewGroup that implements
79 * a simple {@link android.widget.FrameLayout} along with the ability to stack
80 * children in left and right gutters.</p>
81 *
82 * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/CustomLayout.java
83 * Complete}
84 *
85 * <p>If you are implementing XML layout attributes as shown in the example, this is the
86 * corresponding definition for them that would go in <code>res/values/attrs.xml</code>:</p>
87 *
88 * {@sample development/samples/ApiDemos/res/values/attrs.xml CustomLayout}
89 *
90 * <p>Finally the layout manager can be used in an XML layout like so:</p>
91 *
92 * {@sample development/samples/ApiDemos/res/layout/custom_layout.xml Complete}
93 *
Romain Guyd6a463a2009-05-21 23:10:10 -070094 * @attr ref android.R.styleable#ViewGroup_clipChildren
95 * @attr ref android.R.styleable#ViewGroup_clipToPadding
96 * @attr ref android.R.styleable#ViewGroup_layoutAnimation
97 * @attr ref android.R.styleable#ViewGroup_animationCache
98 * @attr ref android.R.styleable#ViewGroup_persistentDrawingCache
99 * @attr ref android.R.styleable#ViewGroup_alwaysDrawnWithCache
100 * @attr ref android.R.styleable#ViewGroup_addStatesFromChildren
101 * @attr ref android.R.styleable#ViewGroup_descendantFocusability
Chet Haase13cc1202010-09-03 15:39:20 -0700102 * @attr ref android.R.styleable#ViewGroup_animateLayoutChanges
Scott Main27a85082013-06-10 10:39:48 -0700103 * @attr ref android.R.styleable#ViewGroup_splitMotionEvents
104 * @attr ref android.R.styleable#ViewGroup_layoutMode
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800105 */
106public abstract class ViewGroup extends View implements ViewParent, ViewManager {
Adam Powell539ee872012-02-03 19:00:49 -0800107 private static final String TAG = "ViewGroup";
Chet Haase21cd1382010-09-01 17:42:29 -0700108
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800109 private static final boolean DBG = false;
Philip Milne7b757812012-09-19 18:13:44 -0700110 /** @hide */
111 public static boolean DEBUG_DRAW = false;
Gilles Debunnecea45132011-11-24 02:19:27 +0100112
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800113 /**
114 * Views which have been hidden or removed which need to be animated on
115 * their way out.
116 * This field should be made private, so it is hidden from the SDK.
117 * {@hide}
118 */
119 protected ArrayList<View> mDisappearingChildren;
120
121 /**
122 * Listener used to propagate events indicating when children are added
123 * and/or removed from a view group.
124 * This field should be made private, so it is hidden from the SDK.
125 * {@hide}
126 */
127 protected OnHierarchyChangeListener mOnHierarchyChangeListener;
128
129 // The view contained within this ViewGroup that has or contains focus.
130 private View mFocused;
131
Chet Haase48460322010-06-11 14:22:25 -0700132 /**
133 * A Transformation used when drawing children, to
134 * apply on the child being drawn.
135 */
Romain Guyf6991302013-06-05 17:19:01 -0700136 private Transformation mChildTransformation;
Chet Haase48460322010-06-11 14:22:25 -0700137
138 /**
139 * Used to track the current invalidation region.
140 */
Chet Haase64a48c12012-02-13 16:33:29 -0800141 RectF mInvalidateRegion;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800142
Chet Haase48460322010-06-11 14:22:25 -0700143 /**
144 * A Transformation used to calculate a correct
145 * invalidation area when the application is autoscaled.
146 */
Chet Haase64a48c12012-02-13 16:33:29 -0800147 Transformation mInvalidationTransformation;
Chet Haase48460322010-06-11 14:22:25 -0700148
Christopher Tatea53146c2010-09-07 11:57:52 -0700149 // View currently under an ongoing drag
150 private View mCurrentDragView;
151
Christopher Tate86cab1b2011-01-13 20:28:55 -0800152 // Metadata about the ongoing drag
153 private DragEvent mCurrentDrag;
154 private HashSet<View> mDragNotifiedChildren;
155
Christopher Tatea53146c2010-09-07 11:57:52 -0700156 // Does this group have a child that can accept the current drag payload?
157 private boolean mChildAcceptsDrag;
158
159 // Used during drag dispatch
Romain Guy6410c0a2013-06-17 11:21:58 -0700160 private PointF mLocalPoint;
Christopher Tatea53146c2010-09-07 11:57:52 -0700161
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800162 // Layout animation
163 private LayoutAnimationController mLayoutAnimationController;
164 private Animation.AnimationListener mAnimationListener;
165
Jeff Brown20e987b2010-08-23 12:01:02 -0700166 // First touch target in the linked list of touch targets.
167 private TouchTarget mFirstTouchTarget;
168
Joe Onorato03ab0c72011-01-06 15:46:27 -0800169 // For debugging only. You can see these in hierarchyviewer.
Romain Guye95003e2011-01-09 13:53:06 -0800170 @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"})
Joe Onorato03ab0c72011-01-06 15:46:27 -0800171 @ViewDebug.ExportedProperty(category = "events")
172 private long mLastTouchDownTime;
173 @ViewDebug.ExportedProperty(category = "events")
174 private int mLastTouchDownIndex = -1;
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 float mLastTouchDownX;
Romain Guye95003e2011-01-09 13:53:06 -0800178 @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"})
Joe Onorato03ab0c72011-01-06 15:46:27 -0800179 @ViewDebug.ExportedProperty(category = "events")
180 private float mLastTouchDownY;
181
Jeff Brown87b7f802011-06-21 18:35:45 -0700182 // First hover target in the linked list of hover targets.
183 // The hover targets are children which have received ACTION_HOVER_ENTER.
184 // They might not have actually handled the hover event, but we will
185 // continue sending hover events to them as long as the pointer remains over
186 // their bounds and the view group does not intercept hover.
187 private HoverTarget mFirstHoverTarget;
Jeff Browna032cc02011-03-07 16:56:21 -0800188
Jeff Brown10b62902011-06-20 16:40:37 -0700189 // True if the view group itself received a hover event.
190 // It might not have actually handled the hover event.
191 private boolean mHoveredSelf;
192
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800193 /**
194 * Internal flags.
Romain Guy8506ab42009-06-11 17:35:47 -0700195 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800196 * This field should be made private, so it is hidden from the SDK.
197 * {@hide}
198 */
Romain Guy2440e672012-08-07 14:43:43 -0700199 @ViewDebug.ExportedProperty(flagMapping = {
200 @ViewDebug.FlagToString(mask = FLAG_CLIP_CHILDREN, equals = FLAG_CLIP_CHILDREN,
201 name = "CLIP_CHILDREN"),
202 @ViewDebug.FlagToString(mask = FLAG_CLIP_TO_PADDING, equals = FLAG_CLIP_TO_PADDING,
203 name = "CLIP_TO_PADDING"),
204 @ViewDebug.FlagToString(mask = FLAG_PADDING_NOT_NULL, equals = FLAG_PADDING_NOT_NULL,
205 name = "PADDING_NOT_NULL")
Jon Miranda4597e982014-07-29 07:25:49 -0700206 }, formatToHexString = true)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800207 protected int mGroupFlags;
208
Philip Milne7b757812012-09-19 18:13:44 -0700209 /**
210 * Either {@link #LAYOUT_MODE_CLIP_BOUNDS} or {@link #LAYOUT_MODE_OPTICAL_BOUNDS}.
Philip Milne1557fd72012-04-04 23:41:34 -0700211 */
Philip Milnecfb631b2012-10-26 10:51:46 -0700212 private int mLayoutMode = LAYOUT_MODE_UNDEFINED;
Philip Milne1557fd72012-04-04 23:41:34 -0700213
Romain Guy33f6beb2012-02-16 19:24:51 -0800214 /**
215 * NOTE: If you change the flags below make sure to reflect the changes
216 * the DisplayList class
217 */
218
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800219 // When set, ViewGroup invalidates only the child's rectangle
220 // Set by default
Chet Haase64a48c12012-02-13 16:33:29 -0800221 static final int FLAG_CLIP_CHILDREN = 0x1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800222
223 // When set, ViewGroup excludes the padding area from the invalidate rectangle
224 // Set by default
225 private static final int FLAG_CLIP_TO_PADDING = 0x2;
226
227 // When set, dispatchDraw() will invoke invalidate(); this is set by drawChild() when
228 // a child needs to be invalidated and FLAG_OPTIMIZE_INVALIDATE is set
Chet Haase64a48c12012-02-13 16:33:29 -0800229 static final int FLAG_INVALIDATE_REQUIRED = 0x4;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800230
231 // When set, dispatchDraw() will run the layout animation and unset the flag
232 private static final int FLAG_RUN_ANIMATION = 0x8;
233
234 // When set, there is either no layout animation on the ViewGroup or the layout
235 // animation is over
236 // Set by default
Chet Haase64a48c12012-02-13 16:33:29 -0800237 static final int FLAG_ANIMATION_DONE = 0x10;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800238
239 // If set, this ViewGroup has padding; if unset there is no padding and we don't need
240 // to clip it, even if FLAG_CLIP_TO_PADDING is set
241 private static final int FLAG_PADDING_NOT_NULL = 0x20;
242
243 // When set, this ViewGroup caches its children in a Bitmap before starting a layout animation
244 // Set by default
245 private static final int FLAG_ANIMATION_CACHE = 0x40;
246
247 // When set, this ViewGroup converts calls to invalidate(Rect) to invalidate() during a
248 // layout animation; this avoid clobbering the hierarchy
249 // Automatically set when the layout animation starts, depending on the animation's
250 // characteristics
Chet Haase64a48c12012-02-13 16:33:29 -0800251 static final int FLAG_OPTIMIZE_INVALIDATE = 0x80;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800252
253 // When set, the next call to drawChild() will clear mChildTransformation's matrix
Chet Haase64a48c12012-02-13 16:33:29 -0800254 static final int FLAG_CLEAR_TRANSFORMATION = 0x100;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800255
256 // When set, this ViewGroup invokes mAnimationListener.onAnimationEnd() and removes
257 // the children's Bitmap caches if necessary
258 // This flag is set when the layout animation is over (after FLAG_ANIMATION_DONE is set)
259 private static final int FLAG_NOTIFY_ANIMATION_LISTENER = 0x200;
260
261 /**
262 * When set, the drawing method will call {@link #getChildDrawingOrder(int, int)}
263 * to get the index of the child to draw for that iteration.
Romain Guy293451e2009-11-04 13:59:48 -0800264 *
265 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800266 */
267 protected static final int FLAG_USE_CHILD_DRAWING_ORDER = 0x400;
Romain Guy8506ab42009-06-11 17:35:47 -0700268
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800269 /**
270 * When set, this ViewGroup supports static transformations on children; this causes
271 * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} to be
272 * invoked when a child is drawn.
273 *
274 * Any subclass overriding
275 * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} should
276 * set this flags in {@link #mGroupFlags}.
Romain Guy8506ab42009-06-11 17:35:47 -0700277 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800278 * {@hide}
279 */
280 protected static final int FLAG_SUPPORT_STATIC_TRANSFORMATIONS = 0x800;
281
John Reckfb5899d2014-08-15 18:51:27 -0700282 // UNUSED FLAG VALUE: 0x1000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800283
284 /**
285 * When set, this ViewGroup's drawable states also include those
286 * of its children.
287 */
288 private static final int FLAG_ADD_STATES_FROM_CHILDREN = 0x2000;
289
290 /**
291 * When set, this ViewGroup tries to always draw its children using their drawing cache.
292 */
Chet Haase64a48c12012-02-13 16:33:29 -0800293 static final int FLAG_ALWAYS_DRAWN_WITH_CACHE = 0x4000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800294
295 /**
296 * When set, and if FLAG_ALWAYS_DRAWN_WITH_CACHE is not set, this ViewGroup will try to
297 * draw its children with their drawing cache.
298 */
Chet Haase64a48c12012-02-13 16:33:29 -0800299 static final int FLAG_CHILDREN_DRAWN_WITH_CACHE = 0x8000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800300
301 /**
302 * When set, this group will go through its list of children to notify them of
303 * any drawable state change.
304 */
305 private static final int FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE = 0x10000;
306
307 private static final int FLAG_MASK_FOCUSABILITY = 0x60000;
308
309 /**
310 * This view will get focus before any of its descendants.
311 */
312 public static final int FOCUS_BEFORE_DESCENDANTS = 0x20000;
313
314 /**
315 * This view will get focus only if none of its descendants want it.
316 */
317 public static final int FOCUS_AFTER_DESCENDANTS = 0x40000;
318
319 /**
320 * This view will block any of its descendants from getting focus, even
321 * if they are focusable.
322 */
323 public static final int FOCUS_BLOCK_DESCENDANTS = 0x60000;
324
325 /**
326 * Used to map between enum in attrubutes and flag values.
327 */
328 private static final int[] DESCENDANT_FOCUSABILITY_FLAGS =
329 {FOCUS_BEFORE_DESCENDANTS, FOCUS_AFTER_DESCENDANTS,
330 FOCUS_BLOCK_DESCENDANTS};
331
332 /**
333 * When set, this ViewGroup should not intercept touch events.
Adam Powell110486f2010-06-22 17:14:44 -0700334 * {@hide}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800335 */
Adam Powell110486f2010-06-22 17:14:44 -0700336 protected static final int FLAG_DISALLOW_INTERCEPT = 0x80000;
Romain Guy8506ab42009-06-11 17:35:47 -0700337
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800338 /**
Adam Powell2b342f02010-08-18 18:14:13 -0700339 * When set, this ViewGroup will split MotionEvents to multiple child Views when appropriate.
340 */
Adam Powellf37df072010-09-17 16:22:49 -0700341 private static final int FLAG_SPLIT_MOTION_EVENTS = 0x200000;
Adam Powell2b342f02010-08-18 18:14:13 -0700342
343 /**
Adam Powell4b867882011-09-16 12:59:46 -0700344 * When set, this ViewGroup will not dispatch onAttachedToWindow calls
345 * to children when adding new views. This is used to prevent multiple
346 * onAttached calls when a ViewGroup adds children in its own onAttached method.
347 */
348 private static final int FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW = 0x400000;
349
350 /**
Philip Milnecfb631b2012-10-26 10:51:46 -0700351 * When true, indicates that a layoutMode has been explicitly set, either with
352 * an explicit call to {@link #setLayoutMode(int)} in code or from an XML resource.
353 * This distinguishes the situation in which a layout mode was inherited from
354 * one of the ViewGroup's ancestors and cached locally.
355 */
356 private static final int FLAG_LAYOUT_MODE_WAS_EXPLICITLY_SET = 0x800000;
357
Chris Craikb49f4462014-03-20 12:44:20 -0700358 static final int FLAG_IS_TRANSITION_GROUP = 0x1000000;
Chris Craikd863a102013-12-19 13:31:15 -0800359
Chris Craikb49f4462014-03-20 12:44:20 -0700360 static final int FLAG_IS_TRANSITION_GROUP_SET = 0x2000000;
George Mount0a778ed2013-12-13 13:35:36 -0800361
Chris Craikd863a102013-12-19 13:31:15 -0800362 /**
Adam Powellff0d2982014-07-10 20:34:14 -0700363 * When set, focus will not be permitted to enter this group if a touchscreen is present.
364 */
365 static final int FLAG_TOUCHSCREEN_BLOCKS_FOCUS = 0x4000000;
366
367 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800368 * Indicates which types of drawing caches are to be kept in memory.
369 * This field should be made private, so it is hidden from the SDK.
370 * {@hide}
371 */
372 protected int mPersistentDrawingCache;
373
374 /**
375 * Used to indicate that no drawing cache should be kept in memory.
376 */
377 public static final int PERSISTENT_NO_CACHE = 0x0;
378
379 /**
380 * Used to indicate that the animation drawing cache should be kept in memory.
381 */
382 public static final int PERSISTENT_ANIMATION_CACHE = 0x1;
383
384 /**
385 * Used to indicate that the scrolling drawing cache should be kept in memory.
386 */
387 public static final int PERSISTENT_SCROLLING_CACHE = 0x2;
388
389 /**
390 * Used to indicate that all drawing caches should be kept in memory.
391 */
392 public static final int PERSISTENT_ALL_CACHES = 0x3;
393
Philip Milne1557fd72012-04-04 23:41:34 -0700394 // Layout Modes
395
Philip Milnecfb631b2012-10-26 10:51:46 -0700396 private static final int LAYOUT_MODE_UNDEFINED = -1;
397
Philip Milne1557fd72012-04-04 23:41:34 -0700398 /**
399 * This constant is a {@link #setLayoutMode(int) layoutMode}.
Philip Milne7a23b492012-04-24 22:12:36 -0700400 * Clip bounds are the raw values of {@link #getLeft() left}, {@link #getTop() top},
Philip Milne1557fd72012-04-04 23:41:34 -0700401 * {@link #getRight() right} and {@link #getBottom() bottom}.
402 */
Philip Milne7b757812012-09-19 18:13:44 -0700403 public static final int LAYOUT_MODE_CLIP_BOUNDS = 0;
Philip Milne1557fd72012-04-04 23:41:34 -0700404
405 /**
406 * This constant is a {@link #setLayoutMode(int) layoutMode}.
Philip Milne7a23b492012-04-24 22:12:36 -0700407 * Optical bounds describe where a widget appears to be. They sit inside the clip
408 * bounds which need to cover a larger area to allow other effects,
409 * such as shadows and glows, to be drawn.
Philip Milne1557fd72012-04-04 23:41:34 -0700410 */
Philip Milne7b757812012-09-19 18:13:44 -0700411 public static final int LAYOUT_MODE_OPTICAL_BOUNDS = 1;
412
413 /** @hide */
Philip Milnecfb631b2012-10-26 10:51:46 -0700414 public static int LAYOUT_MODE_DEFAULT = LAYOUT_MODE_CLIP_BOUNDS;
Philip Milne1557fd72012-04-04 23:41:34 -0700415
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800416 /**
417 * We clip to padding when FLAG_CLIP_TO_PADDING and FLAG_PADDING_NOT_NULL
418 * are set at the same time.
419 */
420 protected static final int CLIP_TO_PADDING_MASK = FLAG_CLIP_TO_PADDING | FLAG_PADDING_NOT_NULL;
421
422 // Index of the child's left position in the mLocation array
423 private static final int CHILD_LEFT_INDEX = 0;
424 // Index of the child's top position in the mLocation array
425 private static final int CHILD_TOP_INDEX = 1;
426
427 // Child views of this ViewGroup
428 private View[] mChildren;
429 // Number of valid children in the mChildren array, the rest should be null or not
430 // considered as children
431 private int mChildrenCount;
432
Chet Haaseb9895022013-04-02 15:10:58 -0700433 // Whether layout calls are currently being suppressed, controlled by calls to
434 // suppressLayout()
435 boolean mSuppressLayout = false;
436
437 // Whether any layout calls have actually been suppressed while mSuppressLayout
438 // has been true. This tracks whether we need to issue a requestLayout() when
439 // layout is later re-enabled.
440 private boolean mLayoutCalledWhileSuppressed = false;
441
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800442 private static final int ARRAY_INITIAL_CAPACITY = 12;
443 private static final int ARRAY_CAPACITY_INCREMENT = 12;
444
Romain Guycbc67742012-04-27 16:12:57 -0700445 private static Paint sDebugPaint;
446 private static float[] sDebugLines;
Philip Milne604f4402012-04-24 19:27:11 -0700447
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800448 // Used to draw cached views
Chet Haase64a48c12012-02-13 16:33:29 -0800449 Paint mCachePaint;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800450
Chet Haase21cd1382010-09-01 17:42:29 -0700451 // Used to animate add/remove changes in layout
452 private LayoutTransition mTransition;
453
454 // The set of views that are currently being transitioned. This list is used to track views
455 // being removed that should not actually be removed from the parent yet because they are
456 // being animated.
457 private ArrayList<View> mTransitioningViews;
458
Chet Haase5e25c2c2010-09-16 11:15:56 -0700459 // List of children changing visibility. This is used to potentially keep rendering
460 // views during a transition when they otherwise would have become gone/invisible
461 private ArrayList<View> mVisibilityChangingChildren;
462
Chris Craikab008f02014-05-23 17:55:03 -0700463 // Temporary holder of presorted children, only used for
464 // input/software draw dispatch for correctly Z ordering.
465 private ArrayList<View> mPreSortedChildren;
466
Adam Powell539ee872012-02-03 19:00:49 -0800467 // Indicates how many of this container's child subtrees contain transient state
468 @ViewDebug.ExportedProperty(category = "layout")
469 private int mChildCountWithTransientState = 0;
470
Adam Powell10ba2772014-04-15 09:46:51 -0700471 /**
472 * Currently registered axes for nested scrolling. Flag set consisting of
473 * {@link #SCROLL_AXIS_HORIZONTAL} {@link #SCROLL_AXIS_VERTICAL} or {@link #SCROLL_AXIS_NONE}
474 * for null.
475 */
476 private int mNestedScrollAxes;
477
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800478 public ViewGroup(Context context) {
Alan Viveretted6479ec2013-09-10 17:03:02 -0700479 this(context, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800480 }
481
482 public ViewGroup(Context context, AttributeSet attrs) {
Alan Viveretted6479ec2013-09-10 17:03:02 -0700483 this(context, attrs, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800484 }
485
Alan Viverette617feb92013-09-09 18:09:13 -0700486 public ViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {
Alan Viveretted6479ec2013-09-10 17:03:02 -0700487 this(context, attrs, defStyleAttr, 0);
Alan Viverette617feb92013-09-09 18:09:13 -0700488 }
489
490 public ViewGroup(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
491 super(context, attrs, defStyleAttr, defStyleRes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800492 initViewGroup();
Alan Viveretted6479ec2013-09-10 17:03:02 -0700493 initFromAttributes(context, attrs, defStyleAttr, defStyleRes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800494 }
495
Philip Milne10ca24a2012-04-23 15:38:27 -0700496 private boolean debugDraw() {
Philip Milne7b757812012-09-19 18:13:44 -0700497 return DEBUG_DRAW || mAttachInfo != null && mAttachInfo.mDebugLayout;
Philip Milne10ca24a2012-04-23 15:38:27 -0700498 }
499
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800500 private void initViewGroup() {
501 // ViewGroup doesn't draw by default
Philip Milne10ca24a2012-04-23 15:38:27 -0700502 if (!debugDraw()) {
503 setFlags(WILL_NOT_DRAW, DRAW_MASK);
504 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800505 mGroupFlags |= FLAG_CLIP_CHILDREN;
506 mGroupFlags |= FLAG_CLIP_TO_PADDING;
507 mGroupFlags |= FLAG_ANIMATION_DONE;
508 mGroupFlags |= FLAG_ANIMATION_CACHE;
509 mGroupFlags |= FLAG_ALWAYS_DRAWN_WITH_CACHE;
510
Jeff Brown995e7742010-12-22 16:59:36 -0800511 if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB) {
512 mGroupFlags |= FLAG_SPLIT_MOTION_EVENTS;
513 }
514
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800515 setDescendantFocusability(FOCUS_BEFORE_DESCENDANTS);
516
517 mChildren = new View[ARRAY_INITIAL_CAPACITY];
518 mChildrenCount = 0;
519
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800520 mPersistentDrawingCache = PERSISTENT_SCROLLING_CACHE;
521 }
522
Alan Viveretted6479ec2013-09-10 17:03:02 -0700523 private void initFromAttributes(
524 Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
Filip Gruszczyńskib50cea02014-03-05 17:54:58 -0800525 final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ViewGroup, defStyleAttr,
526 defStyleRes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800527
528 final int N = a.getIndexCount();
529 for (int i = 0; i < N; i++) {
530 int attr = a.getIndex(i);
531 switch (attr) {
532 case R.styleable.ViewGroup_clipChildren:
533 setClipChildren(a.getBoolean(attr, true));
534 break;
535 case R.styleable.ViewGroup_clipToPadding:
536 setClipToPadding(a.getBoolean(attr, true));
537 break;
538 case R.styleable.ViewGroup_animationCache:
539 setAnimationCacheEnabled(a.getBoolean(attr, true));
540 break;
541 case R.styleable.ViewGroup_persistentDrawingCache:
542 setPersistentDrawingCache(a.getInt(attr, PERSISTENT_SCROLLING_CACHE));
543 break;
544 case R.styleable.ViewGroup_addStatesFromChildren:
545 setAddStatesFromChildren(a.getBoolean(attr, false));
546 break;
547 case R.styleable.ViewGroup_alwaysDrawnWithCache:
548 setAlwaysDrawnWithCacheEnabled(a.getBoolean(attr, true));
549 break;
550 case R.styleable.ViewGroup_layoutAnimation:
551 int id = a.getResourceId(attr, -1);
552 if (id > 0) {
553 setLayoutAnimation(AnimationUtils.loadLayoutAnimation(mContext, id));
554 }
555 break;
556 case R.styleable.ViewGroup_descendantFocusability:
557 setDescendantFocusability(DESCENDANT_FOCUSABILITY_FLAGS[a.getInt(attr, 0)]);
558 break;
Adam Powell2b342f02010-08-18 18:14:13 -0700559 case R.styleable.ViewGroup_splitMotionEvents:
560 setMotionEventSplittingEnabled(a.getBoolean(attr, false));
561 break;
Chet Haase13cc1202010-09-03 15:39:20 -0700562 case R.styleable.ViewGroup_animateLayoutChanges:
563 boolean animateLayoutChanges = a.getBoolean(attr, false);
564 if (animateLayoutChanges) {
565 setLayoutTransition(new LayoutTransition());
566 }
567 break;
Philip Milne7b757812012-09-19 18:13:44 -0700568 case R.styleable.ViewGroup_layoutMode:
Philip Milnecfb631b2012-10-26 10:51:46 -0700569 setLayoutMode(a.getInt(attr, LAYOUT_MODE_UNDEFINED));
Philip Milne7b757812012-09-19 18:13:44 -0700570 break;
George Mount0a778ed2013-12-13 13:35:36 -0800571 case R.styleable.ViewGroup_transitionGroup:
572 setTransitionGroup(a.getBoolean(attr, false));
573 break;
Adam Powellff0d2982014-07-10 20:34:14 -0700574 case R.styleable.ViewGroup_touchscreenBlocksFocus:
575 setTouchscreenBlocksFocus(a.getBoolean(attr, false));
576 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800577 }
578 }
579
580 a.recycle();
581 }
582
583 /**
584 * Gets the descendant focusability of this view group. The descendant
585 * focusability defines the relationship between this view group and its
586 * descendants when looking for a view to take focus in
587 * {@link #requestFocus(int, android.graphics.Rect)}.
588 *
589 * @return one of {@link #FOCUS_BEFORE_DESCENDANTS}, {@link #FOCUS_AFTER_DESCENDANTS},
590 * {@link #FOCUS_BLOCK_DESCENDANTS}.
591 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -0700592 @ViewDebug.ExportedProperty(category = "focus", mapping = {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800593 @ViewDebug.IntToString(from = FOCUS_BEFORE_DESCENDANTS, to = "FOCUS_BEFORE_DESCENDANTS"),
594 @ViewDebug.IntToString(from = FOCUS_AFTER_DESCENDANTS, to = "FOCUS_AFTER_DESCENDANTS"),
595 @ViewDebug.IntToString(from = FOCUS_BLOCK_DESCENDANTS, to = "FOCUS_BLOCK_DESCENDANTS")
596 })
597 public int getDescendantFocusability() {
598 return mGroupFlags & FLAG_MASK_FOCUSABILITY;
599 }
600
601 /**
602 * Set the descendant focusability of this view group. This defines the relationship
603 * between this view group and its descendants when looking for a view to
604 * take focus in {@link #requestFocus(int, android.graphics.Rect)}.
605 *
606 * @param focusability one of {@link #FOCUS_BEFORE_DESCENDANTS}, {@link #FOCUS_AFTER_DESCENDANTS},
607 * {@link #FOCUS_BLOCK_DESCENDANTS}.
608 */
609 public void setDescendantFocusability(int focusability) {
610 switch (focusability) {
611 case FOCUS_BEFORE_DESCENDANTS:
612 case FOCUS_AFTER_DESCENDANTS:
613 case FOCUS_BLOCK_DESCENDANTS:
614 break;
615 default:
616 throw new IllegalArgumentException("must be one of FOCUS_BEFORE_DESCENDANTS, "
617 + "FOCUS_AFTER_DESCENDANTS, FOCUS_BLOCK_DESCENDANTS");
618 }
619 mGroupFlags &= ~FLAG_MASK_FOCUSABILITY;
620 mGroupFlags |= (focusability & FLAG_MASK_FOCUSABILITY);
621 }
622
623 /**
624 * {@inheritDoc}
625 */
626 @Override
627 void handleFocusGainInternal(int direction, Rect previouslyFocusedRect) {
628 if (mFocused != null) {
Alan Viverette223622a2013-12-17 13:29:02 -0800629 mFocused.unFocus(this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800630 mFocused = null;
631 }
632 super.handleFocusGainInternal(direction, previouslyFocusedRect);
633 }
634
635 /**
636 * {@inheritDoc}
637 */
638 public void requestChildFocus(View child, View focused) {
639 if (DBG) {
640 System.out.println(this + " requestChildFocus()");
641 }
642 if (getDescendantFocusability() == FOCUS_BLOCK_DESCENDANTS) {
643 return;
644 }
645
646 // Unfocus us, if necessary
Alan Viverette223622a2013-12-17 13:29:02 -0800647 super.unFocus(focused);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800648
649 // We had a previous notion of who had focus. Clear it.
650 if (mFocused != child) {
651 if (mFocused != null) {
Alan Viverette223622a2013-12-17 13:29:02 -0800652 mFocused.unFocus(focused);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800653 }
654
655 mFocused = child;
656 }
657 if (mParent != null) {
658 mParent.requestChildFocus(this, focused);
659 }
660 }
661
662 /**
663 * {@inheritDoc}
664 */
665 public void focusableViewAvailable(View v) {
666 if (mParent != null
667 // shortcut: don't report a new focusable view if we block our descendants from
668 // getting focus
669 && (getDescendantFocusability() != FOCUS_BLOCK_DESCENDANTS)
Adam Powell88c11752014-07-21 17:19:16 -0700670 && (isFocusableInTouchMode() || !shouldBlockFocusForTouchscreen())
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800671 // shortcut: don't report a new focusable view if we already are focused
672 // (and we don't prefer our descendants)
673 //
674 // note: knowing that mFocused is non-null is not a good enough reason
675 // to break the traversal since in that case we'd actually have to find
676 // the focused view and make sure it wasn't FOCUS_AFTER_DESCENDANTS and
Joe Onoratoc6cc0f82011-04-12 11:53:13 -0700677 // an ancestor of v; this will get checked for at ViewAncestor
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800678 && !(isFocused() && getDescendantFocusability() != FOCUS_AFTER_DESCENDANTS)) {
679 mParent.focusableViewAvailable(v);
680 }
681 }
682
683 /**
684 * {@inheritDoc}
685 */
686 public boolean showContextMenuForChild(View originalView) {
687 return mParent != null && mParent.showContextMenuForChild(originalView);
688 }
689
690 /**
Adam Powell6e346362010-07-23 10:18:23 -0700691 * {@inheritDoc}
692 */
693 public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback) {
694 return mParent != null ? mParent.startActionModeForChild(originalView, callback) : null;
695 }
696
697 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800698 * Find the nearest view in the specified direction that wants to take
699 * focus.
700 *
701 * @param focused The view that currently has focus
702 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and
703 * FOCUS_RIGHT, or 0 for not applicable.
704 */
705 public View focusSearch(View focused, int direction) {
Svetoslav Ganov27e2da72012-07-02 18:12:00 -0700706 if (isRootNamespace()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800707 // root namespace means we should consider ourselves the top of the
708 // tree for focus searching; otherwise we could be focus searching
709 // into other tabs. see LocalActivityManager and TabHost for more info
710 return FocusFinder.getInstance().findNextFocus(this, focused, direction);
711 } else if (mParent != null) {
712 return mParent.focusSearch(focused, direction);
713 }
714 return null;
715 }
716
717 /**
718 * {@inheritDoc}
719 */
720 public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
721 return false;
722 }
723
724 /**
725 * {@inheritDoc}
726 */
Svetoslav Ganov42138042012-03-20 11:51:39 -0700727 @Override
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700728 public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event) {
Svetoslav Ganov42138042012-03-20 11:51:39 -0700729 ViewParent parent = mParent;
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700730 if (parent == null) {
731 return false;
732 }
733 final boolean propagate = onRequestSendAccessibilityEvent(child, event);
734 if (!propagate) {
735 return false;
736 }
737 return parent.requestSendAccessibilityEvent(this, event);
738 }
739
740 /**
741 * Called when a child has requested sending an {@link AccessibilityEvent} and
742 * gives an opportunity to its parent to augment the event.
Svetoslav Ganov031d9c12011-09-09 16:41:13 -0700743 * <p>
Adam Powell2fcbbd02011-09-28 18:56:43 -0700744 * If an {@link android.view.View.AccessibilityDelegate} has been specified via calling
745 * {@link android.view.View#setAccessibilityDelegate(android.view.View.AccessibilityDelegate)} its
746 * {@link android.view.View.AccessibilityDelegate#onRequestSendAccessibilityEvent(ViewGroup, View, AccessibilityEvent)}
Svetoslav Ganov031d9c12011-09-09 16:41:13 -0700747 * is responsible for handling this call.
748 * </p>
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700749 *
750 * @param child The child which requests sending the event.
751 * @param event The event to be sent.
752 * @return True if the event should be sent.
753 *
754 * @see #requestSendAccessibilityEvent(View, AccessibilityEvent)
755 */
756 public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
Svetoslav Ganov031d9c12011-09-09 16:41:13 -0700757 if (mAccessibilityDelegate != null) {
758 return mAccessibilityDelegate.onRequestSendAccessibilityEvent(this, child, event);
759 } else {
760 return onRequestSendAccessibilityEventInternal(child, event);
761 }
762 }
763
764 /**
765 * @see #onRequestSendAccessibilityEvent(View, AccessibilityEvent)
766 *
767 * Note: Called from the default {@link View.AccessibilityDelegate}.
768 */
769 boolean onRequestSendAccessibilityEventInternal(View child, AccessibilityEvent event) {
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700770 return true;
771 }
772
773 /**
Adam Powell539ee872012-02-03 19:00:49 -0800774 * Called when a child view has changed whether or not it is tracking transient state.
Adam Powell539ee872012-02-03 19:00:49 -0800775 */
776 public void childHasTransientStateChanged(View child, boolean childHasTransientState) {
777 final boolean oldHasTransientState = hasTransientState();
778 if (childHasTransientState) {
779 mChildCountWithTransientState++;
780 } else {
781 mChildCountWithTransientState--;
782 }
783
784 final boolean newHasTransientState = hasTransientState();
785 if (mParent != null && oldHasTransientState != newHasTransientState) {
786 try {
787 mParent.childHasTransientStateChanged(this, newHasTransientState);
788 } catch (AbstractMethodError e) {
789 Log.e(TAG, mParent.getClass().getSimpleName() +
790 " does not fully implement ViewParent", e);
791 }
792 }
793 }
794
Adam Powell539ee872012-02-03 19:00:49 -0800795 @Override
796 public boolean hasTransientState() {
797 return mChildCountWithTransientState > 0 || super.hasTransientState();
798 }
799
800 /**
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700801 * {@inheritDoc}
802 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800803 @Override
804 public boolean dispatchUnhandledMove(View focused, int direction) {
805 return mFocused != null &&
806 mFocused.dispatchUnhandledMove(focused, direction);
807 }
808
809 /**
810 * {@inheritDoc}
811 */
812 public void clearChildFocus(View child) {
813 if (DBG) {
814 System.out.println(this + " clearChildFocus()");
815 }
816
817 mFocused = null;
818 if (mParent != null) {
819 mParent.clearChildFocus(this);
820 }
821 }
822
823 /**
824 * {@inheritDoc}
825 */
826 @Override
827 public void clearFocus() {
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -0800828 if (DBG) {
829 System.out.println(this + " clearFocus()");
830 }
831 if (mFocused == null) {
832 super.clearFocus();
833 } else {
Svetoslav Ganovb552d892012-06-02 14:35:02 -0700834 View focused = mFocused;
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -0800835 mFocused = null;
Svetoslav Ganovb552d892012-06-02 14:35:02 -0700836 focused.clearFocus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800837 }
838 }
839
840 /**
841 * {@inheritDoc}
842 */
843 @Override
Alan Viverette223622a2013-12-17 13:29:02 -0800844 void unFocus(View focused) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800845 if (DBG) {
846 System.out.println(this + " unFocus()");
847 }
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -0800848 if (mFocused == null) {
Alan Viverette223622a2013-12-17 13:29:02 -0800849 super.unFocus(focused);
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -0800850 } else {
Alan Viverette223622a2013-12-17 13:29:02 -0800851 mFocused.unFocus(focused);
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -0800852 mFocused = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800853 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800854 }
855
856 /**
857 * Returns the focused child of this view, if any. The child may have focus
858 * or contain focus.
859 *
860 * @return the focused child or null.
861 */
862 public View getFocusedChild() {
863 return mFocused;
864 }
865
Adam Powell88c11752014-07-21 17:19:16 -0700866 View getDeepestFocusedChild() {
867 View v = this;
868 while (v != null) {
869 if (v.isFocused()) {
870 return v;
871 }
872 v = v instanceof ViewGroup ? ((ViewGroup) v).getFocusedChild() : null;
873 }
874 return null;
875 }
876
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800877 /**
878 * Returns true if this view has or contains focus
879 *
880 * @return true if this view has or contains focus
881 */
882 @Override
883 public boolean hasFocus() {
Dianne Hackborn4702a852012-08-17 15:18:29 -0700884 return (mPrivateFlags & PFLAG_FOCUSED) != 0 || mFocused != null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800885 }
886
887 /*
888 * (non-Javadoc)
889 *
890 * @see android.view.View#findFocus()
891 */
892 @Override
893 public View findFocus() {
894 if (DBG) {
895 System.out.println("Find focus in " + this + ": flags="
896 + isFocused() + ", child=" + mFocused);
897 }
898
899 if (isFocused()) {
900 return this;
901 }
902
903 if (mFocused != null) {
904 return mFocused.findFocus();
905 }
906 return null;
907 }
908
909 /**
910 * {@inheritDoc}
911 */
912 @Override
913 public boolean hasFocusable() {
914 if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) {
915 return false;
916 }
917
918 if (isFocusable()) {
919 return true;
920 }
921
922 final int descendantFocusability = getDescendantFocusability();
Adam Powell88c11752014-07-21 17:19:16 -0700923 if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800924 final int count = mChildrenCount;
925 final View[] children = mChildren;
926
927 for (int i = 0; i < count; i++) {
928 final View child = children[i];
929 if (child.hasFocusable()) {
930 return true;
931 }
932 }
933 }
934
935 return false;
936 }
937
938 /**
939 * {@inheritDoc}
940 */
941 @Override
svetoslavganov75986cf2009-05-14 22:28:01 -0700942 public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800943 final int focusableCount = views.size();
944
945 final int descendantFocusability = getDescendantFocusability();
946
Adam Powell88c11752014-07-21 17:19:16 -0700947 if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS) {
948 if (shouldBlockFocusForTouchscreen()) {
949 focusableMode |= FOCUSABLES_TOUCH_MODE;
950 }
951
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800952 final int count = mChildrenCount;
953 final View[] children = mChildren;
954
955 for (int i = 0; i < count; i++) {
956 final View child = children[i];
957 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
svetoslavganov75986cf2009-05-14 22:28:01 -0700958 child.addFocusables(views, direction, focusableMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800959 }
960 }
961 }
962
963 // we add ourselves (if focusable) in all cases except for when we are
964 // FOCUS_AFTER_DESCENDANTS and there are some descendants focusable. this is
965 // to avoid the focus search finding layouts when a more precise search
966 // among the focusable children would be more interesting.
Adam Powellff0d2982014-07-10 20:34:14 -0700967 if ((descendantFocusability != FOCUS_AFTER_DESCENDANTS
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800968 // No focusable descendants
Adam Powell88c11752014-07-21 17:19:16 -0700969 || (focusableCount == views.size())) &&
970 (isFocusableInTouchMode() || !shouldBlockFocusForTouchscreen())) {
svetoslavganov75986cf2009-05-14 22:28:01 -0700971 super.addFocusables(views, direction, focusableMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800972 }
973 }
974
Adam Powellff0d2982014-07-10 20:34:14 -0700975 /**
976 * Set whether this ViewGroup should ignore focus requests for itself and its children.
977 * If this option is enabled and the ViewGroup or a descendant currently has focus, focus
978 * will proceed forward.
979 *
980 * @param touchscreenBlocksFocus true to enable blocking focus in the presence of a touchscreen
981 */
982 public void setTouchscreenBlocksFocus(boolean touchscreenBlocksFocus) {
983 if (touchscreenBlocksFocus) {
984 mGroupFlags |= FLAG_TOUCHSCREEN_BLOCKS_FOCUS;
985 if (hasFocus()) {
Adam Powell88c11752014-07-21 17:19:16 -0700986 final View focusedChild = getDeepestFocusedChild();
987 if (!focusedChild.isFocusableInTouchMode()) {
988 final View newFocus = focusSearch(FOCUS_FORWARD);
989 if (newFocus != null) {
990 newFocus.requestFocus();
991 }
Adam Powellff0d2982014-07-10 20:34:14 -0700992 }
993 }
994 } else {
995 mGroupFlags &= ~FLAG_TOUCHSCREEN_BLOCKS_FOCUS;
996 }
997 }
998
999 /**
1000 * Check whether this ViewGroup should ignore focus requests for itself and its children.
1001 */
1002 public boolean getTouchscreenBlocksFocus() {
1003 return (mGroupFlags & FLAG_TOUCHSCREEN_BLOCKS_FOCUS) != 0;
1004 }
1005
1006 boolean shouldBlockFocusForTouchscreen() {
1007 return getTouchscreenBlocksFocus() &&
1008 mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN);
1009 }
1010
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001011 @Override
Svetoslav Ganovea515ae2011-09-14 18:15:32 -07001012 public void findViewsWithText(ArrayList<View> outViews, CharSequence text, int flags) {
1013 super.findViewsWithText(outViews, text, flags);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001014 final int childrenCount = mChildrenCount;
1015 final View[] children = mChildren;
1016 for (int i = 0; i < childrenCount; i++) {
1017 View child = children[i];
Svetoslav Ganovea515ae2011-09-14 18:15:32 -07001018 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE
Dianne Hackborn4702a852012-08-17 15:18:29 -07001019 && (child.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) {
Svetoslav Ganovea515ae2011-09-14 18:15:32 -07001020 child.findViewsWithText(outViews, text, flags);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001021 }
1022 }
1023 }
1024
Svetoslav5b578da2013-05-08 14:23:32 -07001025 /** @hide */
Svetoslav Ganov2cdedff2011-10-03 14:18:42 -07001026 @Override
Svetoslav5b578da2013-05-08 14:23:32 -07001027 public View findViewByAccessibilityIdTraversal(int accessibilityId) {
Svetoslav Ganov2cdedff2011-10-03 14:18:42 -07001028 View foundView = super.findViewByAccessibilityIdTraversal(accessibilityId);
1029 if (foundView != null) {
1030 return foundView;
1031 }
1032 final int childrenCount = mChildrenCount;
1033 final View[] children = mChildren;
1034 for (int i = 0; i < childrenCount; i++) {
1035 View child = children[i];
1036 foundView = child.findViewByAccessibilityIdTraversal(accessibilityId);
1037 if (foundView != null) {
1038 return foundView;
1039 }
1040 }
1041 return null;
1042 }
1043
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001044 /**
1045 * {@inheritDoc}
1046 */
1047 @Override
1048 public void dispatchWindowFocusChanged(boolean hasFocus) {
1049 super.dispatchWindowFocusChanged(hasFocus);
1050 final int count = mChildrenCount;
1051 final View[] children = mChildren;
1052 for (int i = 0; i < count; i++) {
1053 children[i].dispatchWindowFocusChanged(hasFocus);
1054 }
1055 }
1056
1057 /**
1058 * {@inheritDoc}
1059 */
1060 @Override
1061 public void addTouchables(ArrayList<View> views) {
1062 super.addTouchables(views);
1063
1064 final int count = mChildrenCount;
1065 final View[] children = mChildren;
1066
1067 for (int i = 0; i < count; i++) {
1068 final View child = children[i];
1069 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
1070 child.addTouchables(views);
1071 }
1072 }
1073 }
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001074
1075 /**
1076 * @hide
1077 */
1078 @Override
1079 public void makeOptionalFitsSystemWindows() {
1080 super.makeOptionalFitsSystemWindows();
1081 final int count = mChildrenCount;
1082 final View[] children = mChildren;
1083 for (int i = 0; i < count; i++) {
1084 children[i].makeOptionalFitsSystemWindows();
1085 }
1086 }
1087
Romain Guy43c9cdf2010-01-27 13:53:55 -08001088 /**
1089 * {@inheritDoc}
1090 */
1091 @Override
1092 public void dispatchDisplayHint(int hint) {
1093 super.dispatchDisplayHint(hint);
1094 final int count = mChildrenCount;
1095 final View[] children = mChildren;
1096 for (int i = 0; i < count; i++) {
1097 children[i].dispatchDisplayHint(hint);
1098 }
1099 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001100
1101 /**
Chet Haase0d299362012-01-26 10:51:48 -08001102 * Called when a view's visibility has changed. Notify the parent to take any appropriate
1103 * action.
1104 *
1105 * @param child The view whose visibility has changed
1106 * @param oldVisibility The previous visibility value (GONE, INVISIBLE, or VISIBLE).
1107 * @param newVisibility The new visibility value (GONE, INVISIBLE, or VISIBLE).
Chet Haase5e25c2c2010-09-16 11:15:56 -07001108 * @hide
Chet Haase5e25c2c2010-09-16 11:15:56 -07001109 */
Chet Haase0d299362012-01-26 10:51:48 -08001110 protected void onChildVisibilityChanged(View child, int oldVisibility, int newVisibility) {
Chet Haase5e25c2c2010-09-16 11:15:56 -07001111 if (mTransition != null) {
Chet Haase0d299362012-01-26 10:51:48 -08001112 if (newVisibility == VISIBLE) {
1113 mTransition.showChild(this, child, oldVisibility);
Chet Haase5e25c2c2010-09-16 11:15:56 -07001114 } else {
Chet Haase0d299362012-01-26 10:51:48 -08001115 mTransition.hideChild(this, child, newVisibility);
Chet Haase5e25c2c2010-09-16 11:15:56 -07001116 if (mTransitioningViews != null && mTransitioningViews.contains(child)) {
Chet Haaseddbb3462012-06-19 13:54:29 -07001117 // Only track this on disappearing views - appearing views are already visible
1118 // and don't need special handling during drawChild()
1119 if (mVisibilityChangingChildren == null) {
1120 mVisibilityChangingChildren = new ArrayList<View>();
1121 }
1122 mVisibilityChangingChildren.add(child);
Chet Haase5e25c2c2010-09-16 11:15:56 -07001123 addDisappearingView(child);
1124 }
1125 }
1126 }
Christopher Tate86cab1b2011-01-13 20:28:55 -08001127
1128 // in all cases, for drags
1129 if (mCurrentDrag != null) {
Chet Haase0d299362012-01-26 10:51:48 -08001130 if (newVisibility == VISIBLE) {
Christopher Tate86cab1b2011-01-13 20:28:55 -08001131 notifyChildOfDrag(child);
1132 }
1133 }
Chet Haase5e25c2c2010-09-16 11:15:56 -07001134 }
1135
1136 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001137 * {@inheritDoc}
1138 */
1139 @Override
Adam Powell326d8082009-12-09 15:10:07 -08001140 protected void dispatchVisibilityChanged(View changedView, int visibility) {
1141 super.dispatchVisibilityChanged(changedView, visibility);
1142 final int count = mChildrenCount;
1143 final View[] children = mChildren;
1144 for (int i = 0; i < count; i++) {
1145 children[i].dispatchVisibilityChanged(changedView, visibility);
1146 }
1147 }
1148
1149 /**
1150 * {@inheritDoc}
1151 */
1152 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001153 public void dispatchWindowVisibilityChanged(int visibility) {
1154 super.dispatchWindowVisibilityChanged(visibility);
1155 final int count = mChildrenCount;
1156 final View[] children = mChildren;
1157 for (int i = 0; i < count; i++) {
1158 children[i].dispatchWindowVisibilityChanged(visibility);
1159 }
1160 }
1161
1162 /**
1163 * {@inheritDoc}
1164 */
Dianne Hackborne36d6e22010-02-17 19:46:25 -08001165 @Override
1166 public void dispatchConfigurationChanged(Configuration newConfig) {
1167 super.dispatchConfigurationChanged(newConfig);
1168 final int count = mChildrenCount;
1169 final View[] children = mChildren;
1170 for (int i = 0; i < count; i++) {
1171 children[i].dispatchConfigurationChanged(newConfig);
1172 }
1173 }
1174
1175 /**
1176 * {@inheritDoc}
1177 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001178 public void recomputeViewAttributes(View child) {
Joe Onorato664644d2011-01-23 17:53:23 -08001179 if (mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) {
1180 ViewParent parent = mParent;
1181 if (parent != null) parent.recomputeViewAttributes(this);
1182 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001183 }
Romain Guy8506ab42009-06-11 17:35:47 -07001184
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001185 @Override
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001186 void dispatchCollectViewAttributes(AttachInfo attachInfo, int visibility) {
1187 if ((visibility & VISIBILITY_MASK) == VISIBLE) {
1188 super.dispatchCollectViewAttributes(attachInfo, visibility);
1189 final int count = mChildrenCount;
1190 final View[] children = mChildren;
1191 for (int i = 0; i < count; i++) {
1192 final View child = children[i];
1193 child.dispatchCollectViewAttributes(attachInfo,
1194 visibility | (child.mViewFlags&VISIBILITY_MASK));
1195 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001196 }
1197 }
1198
1199 /**
1200 * {@inheritDoc}
1201 */
1202 public void bringChildToFront(View child) {
1203 int index = indexOfChild(child);
1204 if (index >= 0) {
1205 removeFromArray(index);
1206 addInArray(child, mChildrenCount);
1207 child.mParent = this;
Chet Haasecb96db82013-09-04 10:21:46 -07001208 requestLayout();
1209 invalidate();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001210 }
1211 }
1212
Romain Guy6410c0a2013-06-17 11:21:58 -07001213 private PointF getLocalPoint() {
1214 if (mLocalPoint == null) mLocalPoint = new PointF();
1215 return mLocalPoint;
1216 }
1217
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001218 /**
1219 * {@inheritDoc}
Christopher Tatea53146c2010-09-07 11:57:52 -07001220 */
Steve Block8a7259b2012-03-01 11:24:41 +00001221 // TODO: Write real docs
Christopher Tatea53146c2010-09-07 11:57:52 -07001222 @Override
1223 public boolean dispatchDragEvent(DragEvent event) {
1224 boolean retval = false;
1225 final float tx = event.mX;
1226 final float ty = event.mY;
1227
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07001228 ViewRootImpl root = getViewRootImpl();
Christopher Tatea53146c2010-09-07 11:57:52 -07001229
1230 // Dispatch down the view hierarchy
Romain Guy6410c0a2013-06-17 11:21:58 -07001231 final PointF localPoint = getLocalPoint();
1232
Christopher Tatea53146c2010-09-07 11:57:52 -07001233 switch (event.mAction) {
1234 case DragEvent.ACTION_DRAG_STARTED: {
1235 // clear state to recalculate which views we drag over
Chris Tate9d1ab882010-11-02 15:55:39 -07001236 mCurrentDragView = null;
Christopher Tatea53146c2010-09-07 11:57:52 -07001237
Christopher Tate86cab1b2011-01-13 20:28:55 -08001238 // Set up our tracking of drag-started notifications
1239 mCurrentDrag = DragEvent.obtain(event);
1240 if (mDragNotifiedChildren == null) {
1241 mDragNotifiedChildren = new HashSet<View>();
1242 } else {
1243 mDragNotifiedChildren.clear();
1244 }
1245
Christopher Tatea53146c2010-09-07 11:57:52 -07001246 // Now dispatch down to our children, caching the responses
1247 mChildAcceptsDrag = false;
1248 final int count = mChildrenCount;
1249 final View[] children = mChildren;
1250 for (int i = 0; i < count; i++) {
Christopher Tate2c095f32010-10-04 14:13:40 -07001251 final View child = children[i];
Christopher Tate3d4bf172011-03-28 16:16:46 -07001252 child.mPrivateFlags2 &= ~View.DRAG_MASK;
Christopher Tate2c095f32010-10-04 14:13:40 -07001253 if (child.getVisibility() == VISIBLE) {
Christopher Tate86cab1b2011-01-13 20:28:55 -08001254 final boolean handled = notifyChildOfDrag(children[i]);
Christopher Tate2c095f32010-10-04 14:13:40 -07001255 if (handled) {
1256 mChildAcceptsDrag = true;
1257 }
Christopher Tatea53146c2010-09-07 11:57:52 -07001258 }
1259 }
1260
1261 // Return HANDLED if one of our children can accept the drag
1262 if (mChildAcceptsDrag) {
1263 retval = true;
1264 }
1265 } break;
1266
1267 case DragEvent.ACTION_DRAG_ENDED: {
Christopher Tate86cab1b2011-01-13 20:28:55 -08001268 // Release the bookkeeping now that the drag lifecycle has ended
Christopher Tate1fc014f2011-01-19 12:56:26 -08001269 if (mDragNotifiedChildren != null) {
1270 for (View child : mDragNotifiedChildren) {
1271 // If a child was notified about an ongoing drag, it's told that it's over
1272 child.dispatchDragEvent(event);
Christopher Tate3d4bf172011-03-28 16:16:46 -07001273 child.mPrivateFlags2 &= ~View.DRAG_MASK;
1274 child.refreshDrawableState();
Christopher Tate1fc014f2011-01-19 12:56:26 -08001275 }
1276
1277 mDragNotifiedChildren.clear();
Christopher Tatee9accff2013-03-04 12:57:23 -08001278 if (mCurrentDrag != null) {
1279 mCurrentDrag.recycle();
1280 mCurrentDrag = null;
1281 }
Christopher Tate1fc014f2011-01-19 12:56:26 -08001282 }
Christopher Tate86cab1b2011-01-13 20:28:55 -08001283
Christopher Tatea53146c2010-09-07 11:57:52 -07001284 // We consider drag-ended to have been handled if one of our children
1285 // had offered to handle the drag.
1286 if (mChildAcceptsDrag) {
1287 retval = true;
1288 }
1289 } break;
1290
1291 case DragEvent.ACTION_DRAG_LOCATION: {
1292 // Find the [possibly new] drag target
Romain Guy6410c0a2013-06-17 11:21:58 -07001293 final View target = findFrontmostDroppableChildAt(event.mX, event.mY, localPoint);
Christopher Tatea53146c2010-09-07 11:57:52 -07001294
1295 // If we've changed apparent drag target, tell the view root which view
Chris Tate9d1ab882010-11-02 15:55:39 -07001296 // we're over now [for purposes of the eventual drag-recipient-changed
1297 // notifications to the framework] and tell the new target that the drag
1298 // has entered its bounds. The root will see setDragFocus() calls all
1299 // the way down to the final leaf view that is handling the LOCATION event
1300 // before reporting the new potential recipient to the framework.
Christopher Tatea53146c2010-09-07 11:57:52 -07001301 if (mCurrentDragView != target) {
Chris Tate9d1ab882010-11-02 15:55:39 -07001302 root.setDragFocus(target);
1303
1304 final int action = event.mAction;
1305 // If we've dragged off of a child view, send it the EXITED message
1306 if (mCurrentDragView != null) {
Christopher Tate3d4bf172011-03-28 16:16:46 -07001307 final View view = mCurrentDragView;
Chris Tate9d1ab882010-11-02 15:55:39 -07001308 event.mAction = DragEvent.ACTION_DRAG_EXITED;
Christopher Tate3d4bf172011-03-28 16:16:46 -07001309 view.dispatchDragEvent(event);
Dianne Hackborn4702a852012-08-17 15:18:29 -07001310 view.mPrivateFlags2 &= ~View.PFLAG2_DRAG_HOVERED;
Christopher Tate3d4bf172011-03-28 16:16:46 -07001311 view.refreshDrawableState();
Chris Tate9d1ab882010-11-02 15:55:39 -07001312 }
Christopher Tatea53146c2010-09-07 11:57:52 -07001313 mCurrentDragView = target;
Chris Tate9d1ab882010-11-02 15:55:39 -07001314
1315 // If we've dragged over a new child view, send it the ENTERED message
1316 if (target != null) {
1317 event.mAction = DragEvent.ACTION_DRAG_ENTERED;
1318 target.dispatchDragEvent(event);
Dianne Hackborn4702a852012-08-17 15:18:29 -07001319 target.mPrivateFlags2 |= View.PFLAG2_DRAG_HOVERED;
Christopher Tate3d4bf172011-03-28 16:16:46 -07001320 target.refreshDrawableState();
Chris Tate9d1ab882010-11-02 15:55:39 -07001321 }
1322 event.mAction = action; // restore the event's original state
Christopher Tatea53146c2010-09-07 11:57:52 -07001323 }
Christopher Tate2c095f32010-10-04 14:13:40 -07001324
Christopher Tatea53146c2010-09-07 11:57:52 -07001325 // Dispatch the actual drag location notice, localized into its coordinates
1326 if (target != null) {
Romain Guy6410c0a2013-06-17 11:21:58 -07001327 event.mX = localPoint.x;
1328 event.mY = localPoint.y;
Christopher Tatea53146c2010-09-07 11:57:52 -07001329
1330 retval = target.dispatchDragEvent(event);
1331
1332 event.mX = tx;
1333 event.mY = ty;
1334 }
1335 } break;
1336
Chris Tate9d1ab882010-11-02 15:55:39 -07001337 /* Entered / exited dispatch
1338 *
1339 * DRAG_ENTERED is not dispatched downwards from ViewGroup. The reason for this is
1340 * that we're about to get the corresponding LOCATION event, which we will use to
1341 * determine which of our children is the new target; at that point we will
1342 * push a DRAG_ENTERED down to the new target child [which may itself be a ViewGroup].
1343 *
1344 * DRAG_EXITED *is* dispatched all the way down immediately: once we know the
1345 * drag has left this ViewGroup, we know by definition that every contained subview
1346 * is also no longer under the drag point.
1347 */
1348
1349 case DragEvent.ACTION_DRAG_EXITED: {
1350 if (mCurrentDragView != null) {
Christopher Tate3d4bf172011-03-28 16:16:46 -07001351 final View view = mCurrentDragView;
1352 view.dispatchDragEvent(event);
Dianne Hackborn4702a852012-08-17 15:18:29 -07001353 view.mPrivateFlags2 &= ~View.PFLAG2_DRAG_HOVERED;
Christopher Tate3d4bf172011-03-28 16:16:46 -07001354 view.refreshDrawableState();
1355
Chris Tate9d1ab882010-11-02 15:55:39 -07001356 mCurrentDragView = null;
1357 }
1358 } break;
1359
Christopher Tatea53146c2010-09-07 11:57:52 -07001360 case DragEvent.ACTION_DROP: {
Christopher Tate2c095f32010-10-04 14:13:40 -07001361 if (ViewDebug.DEBUG_DRAG) Log.d(View.VIEW_LOG_TAG, "Drop event: " + event);
Romain Guy6410c0a2013-06-17 11:21:58 -07001362 View target = findFrontmostDroppableChildAt(event.mX, event.mY, localPoint);
Christopher Tatea53146c2010-09-07 11:57:52 -07001363 if (target != null) {
Christopher Tate5ada6cb2010-10-05 14:15:29 -07001364 if (ViewDebug.DEBUG_DRAG) Log.d(View.VIEW_LOG_TAG, " dispatch drop to " + target);
Romain Guy6410c0a2013-06-17 11:21:58 -07001365 event.mX = localPoint.x;
1366 event.mY = localPoint.y;
Christopher Tatea53146c2010-09-07 11:57:52 -07001367 retval = target.dispatchDragEvent(event);
1368 event.mX = tx;
1369 event.mY = ty;
Christopher Tate5ada6cb2010-10-05 14:15:29 -07001370 } else {
1371 if (ViewDebug.DEBUG_DRAG) {
1372 Log.d(View.VIEW_LOG_TAG, " not dropped on an accepting view");
1373 }
Christopher Tatea53146c2010-09-07 11:57:52 -07001374 }
1375 } break;
1376 }
1377
1378 // If none of our children could handle the event, try here
1379 if (!retval) {
Chris Tate32affef2010-10-18 15:29:21 -07001380 // Call up to the View implementation that dispatches to installed listeners
1381 retval = super.dispatchDragEvent(event);
Christopher Tatea53146c2010-09-07 11:57:52 -07001382 }
1383 return retval;
1384 }
1385
1386 // Find the frontmost child view that lies under the given point, and calculate
1387 // the position within its own local coordinate system.
1388 View findFrontmostDroppableChildAt(float x, float y, PointF outLocalPoint) {
Christopher Tatea53146c2010-09-07 11:57:52 -07001389 final int count = mChildrenCount;
1390 final View[] children = mChildren;
1391 for (int i = count - 1; i >= 0; i--) {
1392 final View child = children[i];
Christopher Tate3d4bf172011-03-28 16:16:46 -07001393 if (!child.canAcceptDrag()) {
Christopher Tatea53146c2010-09-07 11:57:52 -07001394 continue;
1395 }
1396
Christopher Tate2c095f32010-10-04 14:13:40 -07001397 if (isTransformedTouchPointInView(x, y, child, outLocalPoint)) {
Christopher Tatea53146c2010-09-07 11:57:52 -07001398 return child;
1399 }
1400 }
1401 return null;
1402 }
1403
Christopher Tate86cab1b2011-01-13 20:28:55 -08001404 boolean notifyChildOfDrag(View child) {
1405 if (ViewDebug.DEBUG_DRAG) {
1406 Log.d(View.VIEW_LOG_TAG, "Sending drag-started to view: " + child);
1407 }
1408
Christopher Tate3d4bf172011-03-28 16:16:46 -07001409 boolean canAccept = false;
Christopher Tate86cab1b2011-01-13 20:28:55 -08001410 if (! mDragNotifiedChildren.contains(child)) {
1411 mDragNotifiedChildren.add(child);
Christopher Tate3d4bf172011-03-28 16:16:46 -07001412 canAccept = child.dispatchDragEvent(mCurrentDrag);
1413 if (canAccept && !child.canAcceptDrag()) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07001414 child.mPrivateFlags2 |= View.PFLAG2_DRAG_CAN_ACCEPT;
Christopher Tate3d4bf172011-03-28 16:16:46 -07001415 child.refreshDrawableState();
1416 }
Christopher Tate86cab1b2011-01-13 20:28:55 -08001417 }
Christopher Tate3d4bf172011-03-28 16:16:46 -07001418 return canAccept;
Christopher Tate86cab1b2011-01-13 20:28:55 -08001419 }
1420
Joe Onorato664644d2011-01-23 17:53:23 -08001421 @Override
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001422 public void dispatchWindowSystemUiVisiblityChanged(int visible) {
1423 super.dispatchWindowSystemUiVisiblityChanged(visible);
1424
1425 final int count = mChildrenCount;
1426 final View[] children = mChildren;
1427 for (int i=0; i <count; i++) {
1428 final View child = children[i];
1429 child.dispatchWindowSystemUiVisiblityChanged(visible);
1430 }
1431 }
1432
1433 @Override
Joe Onorato664644d2011-01-23 17:53:23 -08001434 public void dispatchSystemUiVisibilityChanged(int visible) {
1435 super.dispatchSystemUiVisibilityChanged(visible);
1436
1437 final int count = mChildrenCount;
1438 final View[] children = mChildren;
1439 for (int i=0; i <count; i++) {
1440 final View child = children[i];
1441 child.dispatchSystemUiVisibilityChanged(visible);
1442 }
1443 }
1444
Dianne Hackborn9a230e02011-10-06 11:51:27 -07001445 @Override
Dianne Hackborncf675782012-05-10 15:07:24 -07001446 boolean updateLocalSystemUiVisibility(int localValue, int localChanges) {
1447 boolean changed = super.updateLocalSystemUiVisibility(localValue, localChanges);
Dianne Hackborn9a230e02011-10-06 11:51:27 -07001448
1449 final int count = mChildrenCount;
1450 final View[] children = mChildren;
1451 for (int i=0; i <count; i++) {
1452 final View child = children[i];
Dianne Hackborncf675782012-05-10 15:07:24 -07001453 changed |= child.updateLocalSystemUiVisibility(localValue, localChanges);
Dianne Hackborn9a230e02011-10-06 11:51:27 -07001454 }
Dianne Hackborncf675782012-05-10 15:07:24 -07001455 return changed;
Dianne Hackborn9a230e02011-10-06 11:51:27 -07001456 }
1457
Christopher Tatea53146c2010-09-07 11:57:52 -07001458 /**
1459 * {@inheritDoc}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001460 */
1461 @Override
1462 public boolean dispatchKeyEventPreIme(KeyEvent event) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07001463 if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
1464 == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001465 return super.dispatchKeyEventPreIme(event);
Dianne Hackborn4702a852012-08-17 15:18:29 -07001466 } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
1467 == PFLAG_HAS_BOUNDS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001468 return mFocused.dispatchKeyEventPreIme(event);
1469 }
1470 return false;
1471 }
1472
1473 /**
1474 * {@inheritDoc}
1475 */
1476 @Override
1477 public boolean dispatchKeyEvent(KeyEvent event) {
Jeff Brown21bc5c92011-02-28 18:27:14 -08001478 if (mInputEventConsistencyVerifier != null) {
1479 mInputEventConsistencyVerifier.onKeyEvent(event, 1);
1480 }
1481
Dianne Hackborn4702a852012-08-17 15:18:29 -07001482 if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
1483 == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001484 if (super.dispatchKeyEvent(event)) {
1485 return true;
1486 }
Dianne Hackborn4702a852012-08-17 15:18:29 -07001487 } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
1488 == PFLAG_HAS_BOUNDS) {
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001489 if (mFocused.dispatchKeyEvent(event)) {
1490 return true;
1491 }
1492 }
1493
1494 if (mInputEventConsistencyVerifier != null) {
1495 mInputEventConsistencyVerifier.onUnhandledEvent(event, 1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001496 }
1497 return false;
1498 }
1499
1500 /**
1501 * {@inheritDoc}
1502 */
1503 @Override
1504 public boolean dispatchKeyShortcutEvent(KeyEvent event) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07001505 if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
1506 == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001507 return super.dispatchKeyShortcutEvent(event);
Dianne Hackborn4702a852012-08-17 15:18:29 -07001508 } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
1509 == PFLAG_HAS_BOUNDS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001510 return mFocused.dispatchKeyShortcutEvent(event);
1511 }
1512 return false;
1513 }
1514
1515 /**
1516 * {@inheritDoc}
1517 */
1518 @Override
1519 public boolean dispatchTrackballEvent(MotionEvent event) {
Jeff Brown21bc5c92011-02-28 18:27:14 -08001520 if (mInputEventConsistencyVerifier != null) {
1521 mInputEventConsistencyVerifier.onTrackballEvent(event, 1);
1522 }
1523
Dianne Hackborn4702a852012-08-17 15:18:29 -07001524 if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
1525 == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001526 if (super.dispatchTrackballEvent(event)) {
1527 return true;
1528 }
Dianne Hackborn4702a852012-08-17 15:18:29 -07001529 } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
1530 == PFLAG_HAS_BOUNDS) {
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001531 if (mFocused.dispatchTrackballEvent(event)) {
1532 return true;
1533 }
1534 }
1535
1536 if (mInputEventConsistencyVerifier != null) {
1537 mInputEventConsistencyVerifier.onUnhandledEvent(event, 1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001538 }
1539 return false;
1540 }
1541
Jeff Brown10b62902011-06-20 16:40:37 -07001542 /**
1543 * {@inheritDoc}
1544 */
Romain Guya9489272011-06-22 20:58:11 -07001545 @SuppressWarnings({"ConstantConditions"})
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001546 @Override
Jeff Browna032cc02011-03-07 16:56:21 -08001547 protected boolean dispatchHoverEvent(MotionEvent event) {
Jeff Browna032cc02011-03-07 16:56:21 -08001548 final int action = event.getAction();
Jeff Browna032cc02011-03-07 16:56:21 -08001549
Jeff Brown10b62902011-06-20 16:40:37 -07001550 // First check whether the view group wants to intercept the hover event.
1551 final boolean interceptHover = onInterceptHoverEvent(event);
1552 event.setAction(action); // restore action in case it was changed
1553
Jeff Brown87b7f802011-06-21 18:35:45 -07001554 MotionEvent eventNoHistory = event;
1555 boolean handled = false;
1556
1557 // Send events to the hovered children and build a new list of hover targets until
1558 // one is found that handles the event.
1559 HoverTarget firstOldHoverTarget = mFirstHoverTarget;
1560 mFirstHoverTarget = null;
Jeff Brown10b62902011-06-20 16:40:37 -07001561 if (!interceptHover && action != MotionEvent.ACTION_HOVER_EXIT) {
Jeff Browna032cc02011-03-07 16:56:21 -08001562 final float x = event.getX();
1563 final float y = event.getY();
Jeff Brown33bbfd22011-02-24 20:55:35 -08001564 final int childrenCount = mChildrenCount;
1565 if (childrenCount != 0) {
Chris Craikab008f02014-05-23 17:55:03 -07001566 final ArrayList<View> preorderedList = buildOrderedChildList();
1567 final boolean customOrder = preorderedList == null
1568 && isChildrenDrawingOrderEnabled();
Jeff Brown33bbfd22011-02-24 20:55:35 -08001569 final View[] children = mChildren;
Jeff Brown87b7f802011-06-21 18:35:45 -07001570 HoverTarget lastHoverTarget = null;
Jeff Brown33bbfd22011-02-24 20:55:35 -08001571 for (int i = childrenCount - 1; i >= 0; i--) {
Chris Craikab008f02014-05-23 17:55:03 -07001572 int childIndex = customOrder ? getChildDrawingOrder(childrenCount, i) : i;
1573 final View child = (preorderedList == null)
1574 ? children[childIndex] : preorderedList.get(childIndex);
Jeff Brown87b7f802011-06-21 18:35:45 -07001575 if (!canViewReceivePointerEvents(child)
1576 || !isTransformedTouchPointInView(x, y, child, null)) {
1577 continue;
1578 }
1579
1580 // Obtain a hover target for this child. Dequeue it from the
1581 // old hover target list if the child was previously hovered.
1582 HoverTarget hoverTarget = firstOldHoverTarget;
1583 final boolean wasHovered;
1584 for (HoverTarget predecessor = null; ;) {
1585 if (hoverTarget == null) {
1586 hoverTarget = HoverTarget.obtain(child);
1587 wasHovered = false;
1588 break;
1589 }
1590
1591 if (hoverTarget.child == child) {
1592 if (predecessor != null) {
1593 predecessor.next = hoverTarget.next;
1594 } else {
1595 firstOldHoverTarget = hoverTarget.next;
1596 }
1597 hoverTarget.next = null;
1598 wasHovered = true;
1599 break;
1600 }
1601
1602 predecessor = hoverTarget;
1603 hoverTarget = hoverTarget.next;
1604 }
1605
1606 // Enqueue the hover target onto the new hover target list.
1607 if (lastHoverTarget != null) {
1608 lastHoverTarget.next = hoverTarget;
1609 } else {
Jeff Brown87b7f802011-06-21 18:35:45 -07001610 mFirstHoverTarget = hoverTarget;
1611 }
Sangkyu Lee8725f362013-03-13 09:38:45 +09001612 lastHoverTarget = hoverTarget;
Jeff Brown87b7f802011-06-21 18:35:45 -07001613
1614 // Dispatch the event to the child.
1615 if (action == MotionEvent.ACTION_HOVER_ENTER) {
1616 if (!wasHovered) {
1617 // Send the enter as is.
1618 handled |= dispatchTransformedGenericPointerEvent(
1619 event, child); // enter
1620 }
1621 } else if (action == MotionEvent.ACTION_HOVER_MOVE) {
1622 if (!wasHovered) {
1623 // Synthesize an enter from a move.
1624 eventNoHistory = obtainMotionEventNoHistoryOrSelf(eventNoHistory);
1625 eventNoHistory.setAction(MotionEvent.ACTION_HOVER_ENTER);
1626 handled |= dispatchTransformedGenericPointerEvent(
1627 eventNoHistory, child); // enter
1628 eventNoHistory.setAction(action);
1629
1630 handled |= dispatchTransformedGenericPointerEvent(
1631 eventNoHistory, child); // move
1632 } else {
1633 // Send the move as is.
1634 handled |= dispatchTransformedGenericPointerEvent(event, child);
1635 }
1636 }
1637 if (handled) {
Jeff Brown10b62902011-06-20 16:40:37 -07001638 break;
Jeff Brown33bbfd22011-02-24 20:55:35 -08001639 }
Jeff Brown10b62902011-06-20 16:40:37 -07001640 }
Chris Craikab008f02014-05-23 17:55:03 -07001641 if (preorderedList != null) preorderedList.clear();
Jeff Brown10b62902011-06-20 16:40:37 -07001642 }
1643 }
Jeff Brown33bbfd22011-02-24 20:55:35 -08001644
Jeff Brown87b7f802011-06-21 18:35:45 -07001645 // Send exit events to all previously hovered children that are no longer hovered.
1646 while (firstOldHoverTarget != null) {
1647 final View child = firstOldHoverTarget.child;
Jeff Brown10b62902011-06-20 16:40:37 -07001648
Jeff Brown87b7f802011-06-21 18:35:45 -07001649 // Exit the old hovered child.
1650 if (action == MotionEvent.ACTION_HOVER_EXIT) {
1651 // Send the exit as is.
1652 handled |= dispatchTransformedGenericPointerEvent(
1653 event, child); // exit
1654 } else {
1655 // Synthesize an exit from a move or enter.
1656 // Ignore the result because hover focus has moved to a different view.
1657 if (action == MotionEvent.ACTION_HOVER_MOVE) {
Jeff Brown10b62902011-06-20 16:40:37 -07001658 dispatchTransformedGenericPointerEvent(
Jeff Brown87b7f802011-06-21 18:35:45 -07001659 event, child); // move
Jeff Brown10b62902011-06-20 16:40:37 -07001660 }
Jeff Brown87b7f802011-06-21 18:35:45 -07001661 eventNoHistory = obtainMotionEventNoHistoryOrSelf(eventNoHistory);
1662 eventNoHistory.setAction(MotionEvent.ACTION_HOVER_EXIT);
1663 dispatchTransformedGenericPointerEvent(
1664 eventNoHistory, child); // exit
1665 eventNoHistory.setAction(action);
Jeff Brown10b62902011-06-20 16:40:37 -07001666 }
1667
Jeff Brown87b7f802011-06-21 18:35:45 -07001668 final HoverTarget nextOldHoverTarget = firstOldHoverTarget.next;
1669 firstOldHoverTarget.recycle();
1670 firstOldHoverTarget = nextOldHoverTarget;
Jeff Brown10b62902011-06-20 16:40:37 -07001671 }
1672
Jeff Brown87b7f802011-06-21 18:35:45 -07001673 // Send events to the view group itself if no children have handled it.
Jeff Brown10b62902011-06-20 16:40:37 -07001674 boolean newHoveredSelf = !handled;
1675 if (newHoveredSelf == mHoveredSelf) {
1676 if (newHoveredSelf) {
1677 // Send event to the view group as before.
1678 handled |= super.dispatchHoverEvent(event);
1679 }
1680 } else {
1681 if (mHoveredSelf) {
1682 // Exit the view group.
1683 if (action == MotionEvent.ACTION_HOVER_EXIT) {
1684 // Send the exit as is.
1685 handled |= super.dispatchHoverEvent(event); // exit
1686 } else {
1687 // Synthesize an exit from a move or enter.
1688 // Ignore the result because hover focus is moving to a different view.
1689 if (action == MotionEvent.ACTION_HOVER_MOVE) {
1690 super.dispatchHoverEvent(event); // move
1691 }
1692 eventNoHistory = obtainMotionEventNoHistoryOrSelf(eventNoHistory);
1693 eventNoHistory.setAction(MotionEvent.ACTION_HOVER_EXIT);
1694 super.dispatchHoverEvent(eventNoHistory); // exit
1695 eventNoHistory.setAction(action);
1696 }
1697 mHoveredSelf = false;
1698 }
1699
1700 if (newHoveredSelf) {
1701 // Enter the view group.
1702 if (action == MotionEvent.ACTION_HOVER_ENTER) {
1703 // Send the enter as is.
1704 handled |= super.dispatchHoverEvent(event); // enter
1705 mHoveredSelf = true;
1706 } else if (action == MotionEvent.ACTION_HOVER_MOVE) {
1707 // Synthesize an enter from a move.
1708 eventNoHistory = obtainMotionEventNoHistoryOrSelf(eventNoHistory);
1709 eventNoHistory.setAction(MotionEvent.ACTION_HOVER_ENTER);
1710 handled |= super.dispatchHoverEvent(eventNoHistory); // enter
1711 eventNoHistory.setAction(action);
1712
1713 handled |= super.dispatchHoverEvent(eventNoHistory); // move
1714 mHoveredSelf = true;
Jeff Brown33bbfd22011-02-24 20:55:35 -08001715 }
1716 }
Jeff Brown33bbfd22011-02-24 20:55:35 -08001717 }
1718
Jeff Browna032cc02011-03-07 16:56:21 -08001719 // Recycle the copy of the event that we made.
1720 if (eventNoHistory != event) {
1721 eventNoHistory.recycle();
1722 }
1723
Jeff Browna032cc02011-03-07 16:56:21 -08001724 // Done.
1725 return handled;
1726 }
1727
Jeff Brown59a422e2012-04-19 15:19:19 -07001728 private void exitHoverTargets() {
1729 if (mHoveredSelf || mFirstHoverTarget != null) {
1730 final long now = SystemClock.uptimeMillis();
1731 MotionEvent event = MotionEvent.obtain(now, now,
1732 MotionEvent.ACTION_HOVER_EXIT, 0.0f, 0.0f, 0);
1733 event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
1734 dispatchHoverEvent(event);
1735 event.recycle();
1736 }
1737 }
1738
1739 private void cancelHoverTarget(View view) {
1740 HoverTarget predecessor = null;
1741 HoverTarget target = mFirstHoverTarget;
1742 while (target != null) {
1743 final HoverTarget next = target.next;
1744 if (target.child == view) {
1745 if (predecessor == null) {
1746 mFirstHoverTarget = next;
1747 } else {
1748 predecessor.next = next;
1749 }
1750 target.recycle();
1751
1752 final long now = SystemClock.uptimeMillis();
1753 MotionEvent event = MotionEvent.obtain(now, now,
1754 MotionEvent.ACTION_HOVER_EXIT, 0.0f, 0.0f, 0);
1755 event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
1756 view.dispatchHoverEvent(event);
1757 event.recycle();
1758 return;
1759 }
1760 predecessor = target;
1761 target = next;
1762 }
1763 }
1764
Jeff Brown87b7f802011-06-21 18:35:45 -07001765 /** @hide */
1766 @Override
1767 protected boolean hasHoveredChild() {
1768 return mFirstHoverTarget != null;
1769 }
1770
Svetoslav Ganov42138042012-03-20 11:51:39 -07001771 @Override
1772 public void addChildrenForAccessibility(ArrayList<View> childrenForAccessibility) {
Svetoslav Ganov76f287e2012-04-23 11:02:36 -07001773 ChildListForAccessibility children = ChildListForAccessibility.obtain(this, true);
1774 try {
1775 final int childrenCount = children.getChildCount();
1776 for (int i = 0; i < childrenCount; i++) {
1777 View child = children.getChildAt(i);
Svetoslav Ganovc406be92012-05-11 16:12:32 -07001778 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
Svetoslav Ganov76f287e2012-04-23 11:02:36 -07001779 if (child.includeForAccessibility()) {
1780 childrenForAccessibility.add(child);
1781 } else {
1782 child.addChildrenForAccessibility(childrenForAccessibility);
1783 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07001784 }
1785 }
Svetoslav Ganov76f287e2012-04-23 11:02:36 -07001786 } finally {
1787 children.recycle();
Svetoslav Ganov42138042012-03-20 11:51:39 -07001788 }
1789 }
1790
1791 /**
Jeff Brown10b62902011-06-20 16:40:37 -07001792 * Implement this method to intercept hover events before they are handled
1793 * by child views.
1794 * <p>
1795 * This method is called before dispatching a hover event to a child of
1796 * the view group or to the view group's own {@link #onHoverEvent} to allow
1797 * the view group a chance to intercept the hover event.
1798 * This method can also be used to watch all pointer motions that occur within
1799 * the bounds of the view group even when the pointer is hovering over
1800 * a child of the view group rather than over the view group itself.
1801 * </p><p>
1802 * The view group can prevent its children from receiving hover events by
1803 * implementing this method and returning <code>true</code> to indicate
1804 * that it would like to intercept hover events. The view group must
1805 * continuously return <code>true</code> from {@link #onInterceptHoverEvent}
1806 * for as long as it wishes to continue intercepting hover events from
1807 * its children.
1808 * </p><p>
1809 * Interception preserves the invariant that at most one view can be
1810 * hovered at a time by transferring hover focus from the currently hovered
1811 * child to the view group or vice-versa as needed.
1812 * </p><p>
1813 * If this method returns <code>true</code> and a child is already hovered, then the
1814 * child view will first receive a hover exit event and then the view group
1815 * itself will receive a hover enter event in {@link #onHoverEvent}.
1816 * Likewise, if this method had previously returned <code>true</code> to intercept hover
1817 * events and instead returns <code>false</code> while the pointer is hovering
1818 * within the bounds of one of a child, then the view group will first receive a
1819 * hover exit event in {@link #onHoverEvent} and then the hovered child will
1820 * receive a hover enter event.
1821 * </p><p>
1822 * The default implementation always returns false.
1823 * </p>
1824 *
1825 * @param event The motion event that describes the hover.
1826 * @return True if the view group would like to intercept the hover event
1827 * and prevent its children from receiving it.
1828 */
1829 public boolean onInterceptHoverEvent(MotionEvent event) {
Svetoslav Ganov736c2752011-04-22 18:30:36 -07001830 return false;
1831 }
1832
Jeff Browna032cc02011-03-07 16:56:21 -08001833 private static MotionEvent obtainMotionEventNoHistoryOrSelf(MotionEvent event) {
1834 if (event.getHistorySize() == 0) {
1835 return event;
1836 }
1837 return MotionEvent.obtainNoHistory(event);
1838 }
1839
Jeff Brown10b62902011-06-20 16:40:37 -07001840 /**
1841 * {@inheritDoc}
1842 */
Jeff Browna032cc02011-03-07 16:56:21 -08001843 @Override
1844 protected boolean dispatchGenericPointerEvent(MotionEvent event) {
1845 // Send the event to the child under the pointer.
1846 final int childrenCount = mChildrenCount;
1847 if (childrenCount != 0) {
Jeff Browna032cc02011-03-07 16:56:21 -08001848 final float x = event.getX();
1849 final float y = event.getY();
1850
Chris Craikab008f02014-05-23 17:55:03 -07001851 final ArrayList<View> preorderedList = buildOrderedChildList();
1852 final boolean customOrder = preorderedList == null
1853 && isChildrenDrawingOrderEnabled();
1854 final View[] children = mChildren;
Jeff Browna032cc02011-03-07 16:56:21 -08001855 for (int i = childrenCount - 1; i >= 0; i--) {
Chris Craikab008f02014-05-23 17:55:03 -07001856 int childIndex = customOrder ? getChildDrawingOrder(childrenCount, i) : i;
1857 final View child = (preorderedList == null)
1858 ? children[childIndex] : preorderedList.get(childIndex);
Jeff Browna032cc02011-03-07 16:56:21 -08001859 if (!canViewReceivePointerEvents(child)
1860 || !isTransformedTouchPointInView(x, y, child, null)) {
1861 continue;
1862 }
1863
1864 if (dispatchTransformedGenericPointerEvent(event, child)) {
Chris Craikab008f02014-05-23 17:55:03 -07001865 if (preorderedList != null) preorderedList.clear();
Jeff Browna032cc02011-03-07 16:56:21 -08001866 return true;
1867 }
1868 }
Chris Craikab008f02014-05-23 17:55:03 -07001869 if (preorderedList != null) preorderedList.clear();
Jeff Browna032cc02011-03-07 16:56:21 -08001870 }
1871
1872 // No child handled the event. Send it to this view group.
1873 return super.dispatchGenericPointerEvent(event);
1874 }
1875
Jeff Brown10b62902011-06-20 16:40:37 -07001876 /**
1877 * {@inheritDoc}
1878 */
Jeff Browna032cc02011-03-07 16:56:21 -08001879 @Override
1880 protected boolean dispatchGenericFocusedEvent(MotionEvent event) {
Jeff Brown33bbfd22011-02-24 20:55:35 -08001881 // Send the event to the focused child or to this view group if it has focus.
Dianne Hackborn4702a852012-08-17 15:18:29 -07001882 if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
1883 == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
Jeff Browna032cc02011-03-07 16:56:21 -08001884 return super.dispatchGenericFocusedEvent(event);
Dianne Hackborn4702a852012-08-17 15:18:29 -07001885 } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
1886 == PFLAG_HAS_BOUNDS) {
Jeff Browncb1404e2011-01-15 18:14:15 -08001887 return mFocused.dispatchGenericMotionEvent(event);
1888 }
1889 return false;
1890 }
1891
1892 /**
Jeff Browna032cc02011-03-07 16:56:21 -08001893 * Dispatches a generic pointer event to a child, taking into account
1894 * transformations that apply to the child.
1895 *
1896 * @param event The event to send.
1897 * @param child The view to send the event to.
1898 * @return {@code true} if the child handled the event.
1899 */
1900 private boolean dispatchTransformedGenericPointerEvent(MotionEvent event, View child) {
1901 final float offsetX = mScrollX - child.mLeft;
1902 final float offsetY = mScrollY - child.mTop;
1903
1904 boolean handled;
1905 if (!child.hasIdentityMatrix()) {
1906 MotionEvent transformedEvent = MotionEvent.obtain(event);
1907 transformedEvent.offsetLocation(offsetX, offsetY);
1908 transformedEvent.transform(child.getInverseMatrix());
1909 handled = child.dispatchGenericMotionEvent(transformedEvent);
1910 transformedEvent.recycle();
1911 } else {
1912 event.offsetLocation(offsetX, offsetY);
1913 handled = child.dispatchGenericMotionEvent(event);
1914 event.offsetLocation(-offsetX, -offsetY);
1915 }
1916 return handled;
1917 }
1918
1919 /**
Jeff Browncb1404e2011-01-15 18:14:15 -08001920 * {@inheritDoc}
1921 */
1922 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001923 public boolean dispatchTouchEvent(MotionEvent ev) {
Jeff Brown21bc5c92011-02-28 18:27:14 -08001924 if (mInputEventConsistencyVerifier != null) {
1925 mInputEventConsistencyVerifier.onTouchEvent(ev, 1);
1926 }
1927
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001928 boolean handled = false;
1929 if (onFilterTouchEventForSecurity(ev)) {
1930 final int action = ev.getAction();
1931 final int actionMasked = action & MotionEvent.ACTION_MASK;
Jeff Brown85a31762010-09-01 17:01:00 -07001932
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001933 // Handle an initial down.
1934 if (actionMasked == MotionEvent.ACTION_DOWN) {
1935 // Throw away all previous state when starting a new touch gesture.
1936 // The framework may have dropped the up or cancel event for the previous gesture
1937 // due to an app switch, ANR, or some other state change.
1938 cancelAndClearTouchTargets(ev);
1939 resetTouchState();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001940 }
Adam Powellb08013c2010-09-16 16:28:11 -07001941
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001942 // Check for interception.
1943 final boolean intercepted;
Jeff Brown20e987b2010-08-23 12:01:02 -07001944 if (actionMasked == MotionEvent.ACTION_DOWN
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001945 || mFirstTouchTarget != null) {
1946 final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
1947 if (!disallowIntercept) {
1948 intercepted = onInterceptTouchEvent(ev);
1949 ev.setAction(action); // restore action in case it was changed
1950 } else {
1951 intercepted = false;
1952 }
1953 } else {
1954 // There are no touch targets and this action is not an initial down
1955 // so this view group continues to intercept touches.
1956 intercepted = true;
1957 }
Jeff Brown20e987b2010-08-23 12:01:02 -07001958
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001959 // Check for cancelation.
1960 final boolean canceled = resetCancelNextUpFlag(this)
1961 || actionMasked == MotionEvent.ACTION_CANCEL;
Jeff Brown20e987b2010-08-23 12:01:02 -07001962
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001963 // Update list of touch targets for pointer down, if needed.
1964 final boolean split = (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) != 0;
1965 TouchTarget newTouchTarget = null;
1966 boolean alreadyDispatchedToNewTouchTarget = false;
1967 if (!canceled && !intercepted) {
1968 if (actionMasked == MotionEvent.ACTION_DOWN
1969 || (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN)
1970 || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
1971 final int actionIndex = ev.getActionIndex(); // always 0 for down
1972 final int idBitsToAssign = split ? 1 << ev.getPointerId(actionIndex)
1973 : TouchTarget.ALL_POINTER_IDS;
Jeff Brown20e987b2010-08-23 12:01:02 -07001974
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001975 // Clean up earlier touch targets for this pointer id in case they
1976 // have become out of sync.
1977 removePointersFromTouchTargets(idBitsToAssign);
1978
1979 final int childrenCount = mChildrenCount;
Chet Haase9c17fe62013-03-22 17:05:55 -07001980 if (newTouchTarget == null && childrenCount != 0) {
Chet Haaseedf6f4b2013-03-26 07:55:30 -07001981 final float x = ev.getX(actionIndex);
1982 final float y = ev.getY(actionIndex);
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001983 // Find a child that can receive the event.
1984 // Scan children from front to back.
Chris Craikab008f02014-05-23 17:55:03 -07001985 final ArrayList<View> preorderedList = buildOrderedChildList();
1986 final boolean customOrder = preorderedList == null
1987 && isChildrenDrawingOrderEnabled();
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001988 final View[] children = mChildren;
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001989 for (int i = childrenCount - 1; i >= 0; i--) {
Chris Craikab008f02014-05-23 17:55:03 -07001990 final int childIndex = customOrder
1991 ? getChildDrawingOrder(childrenCount, i) : i;
1992 final View child = (preorderedList == null)
1993 ? children[childIndex] : preorderedList.get(childIndex);
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001994 if (!canViewReceivePointerEvents(child)
1995 || !isTransformedTouchPointInView(x, y, child, null)) {
1996 continue;
1997 }
1998
1999 newTouchTarget = getTouchTarget(child);
2000 if (newTouchTarget != null) {
2001 // Child is already receiving touch within its bounds.
2002 // Give it the new pointer in addition to the ones it is handling.
2003 newTouchTarget.pointerIdBits |= idBitsToAssign;
2004 break;
2005 }
2006
2007 resetCancelNextUpFlag(child);
2008 if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
2009 // Child wants to receive touch within its bounds.
2010 mLastTouchDownTime = ev.getDownTime();
Chris Craikab008f02014-05-23 17:55:03 -07002011 if (preorderedList != null) {
2012 // childIndex points into presorted list, find original index
2013 for (int j = 0; j < childrenCount; j++) {
2014 if (children[childIndex] == mChildren[j]) {
2015 mLastTouchDownIndex = j;
2016 break;
2017 }
2018 }
2019 } else {
2020 mLastTouchDownIndex = childIndex;
2021 }
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002022 mLastTouchDownX = ev.getX();
2023 mLastTouchDownY = ev.getY();
2024 newTouchTarget = addTouchTarget(child, idBitsToAssign);
2025 alreadyDispatchedToNewTouchTarget = true;
2026 break;
2027 }
2028 }
Chris Craikab008f02014-05-23 17:55:03 -07002029 if (preorderedList != null) preorderedList.clear();
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002030 }
2031
2032 if (newTouchTarget == null && mFirstTouchTarget != null) {
2033 // Did not find a child to receive the event.
2034 // Assign the pointer to the least recently added target.
2035 newTouchTarget = mFirstTouchTarget;
2036 while (newTouchTarget.next != null) {
2037 newTouchTarget = newTouchTarget.next;
2038 }
2039 newTouchTarget.pointerIdBits |= idBitsToAssign;
2040 }
2041 }
2042 }
2043
2044 // Dispatch to touch targets.
2045 if (mFirstTouchTarget == null) {
2046 // No touch targets so treat this as an ordinary view.
2047 handled = dispatchTransformedTouchEvent(ev, canceled, null,
2048 TouchTarget.ALL_POINTER_IDS);
2049 } else {
2050 // Dispatch to touch targets, excluding the new touch target if we already
2051 // dispatched to it. Cancel touch targets if necessary.
2052 TouchTarget predecessor = null;
2053 TouchTarget target = mFirstTouchTarget;
2054 while (target != null) {
2055 final TouchTarget next = target.next;
2056 if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) {
2057 handled = true;
2058 } else {
2059 final boolean cancelChild = resetCancelNextUpFlag(target.child)
Chet Haase9c17fe62013-03-22 17:05:55 -07002060 || intercepted;
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002061 if (dispatchTransformedTouchEvent(ev, cancelChild,
2062 target.child, target.pointerIdBits)) {
2063 handled = true;
2064 }
2065 if (cancelChild) {
2066 if (predecessor == null) {
2067 mFirstTouchTarget = next;
2068 } else {
2069 predecessor.next = next;
2070 }
2071 target.recycle();
2072 target = next;
Jeff Brown20e987b2010-08-23 12:01:02 -07002073 continue;
2074 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002075 }
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002076 predecessor = target;
2077 target = next;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002078 }
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002079 }
Jeff Brown20e987b2010-08-23 12:01:02 -07002080
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002081 // Update list of touch targets for pointer up or cancel, if needed.
2082 if (canceled
2083 || actionMasked == MotionEvent.ACTION_UP
2084 || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
2085 resetTouchState();
2086 } else if (split && actionMasked == MotionEvent.ACTION_POINTER_UP) {
2087 final int actionIndex = ev.getActionIndex();
2088 final int idBitsToRemove = 1 << ev.getPointerId(actionIndex);
2089 removePointersFromTouchTargets(idBitsToRemove);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002090 }
2091 }
Romain Guy8506ab42009-06-11 17:35:47 -07002092
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002093 if (!handled && mInputEventConsistencyVerifier != null) {
2094 mInputEventConsistencyVerifier.onUnhandledEvent(ev, 1);
Jeff Brown20e987b2010-08-23 12:01:02 -07002095 }
Jeff Brown20e987b2010-08-23 12:01:02 -07002096 return handled;
2097 }
2098
Romain Guy469b1db2010-10-05 11:49:57 -07002099 /**
2100 * Resets all touch state in preparation for a new cycle.
2101 */
2102 private void resetTouchState() {
Jeff Brown20e987b2010-08-23 12:01:02 -07002103 clearTouchTargets();
2104 resetCancelNextUpFlag(this);
2105 mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
Adam Powell10ba2772014-04-15 09:46:51 -07002106 mNestedScrollAxes = SCROLL_AXIS_NONE;
Jeff Brown20e987b2010-08-23 12:01:02 -07002107 }
2108
Romain Guy469b1db2010-10-05 11:49:57 -07002109 /**
2110 * Resets the cancel next up flag.
2111 * Returns true if the flag was previously set.
2112 */
Romain Guya998dff2012-03-23 18:58:36 -07002113 private static boolean resetCancelNextUpFlag(View view) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07002114 if ((view.mPrivateFlags & PFLAG_CANCEL_NEXT_UP_EVENT) != 0) {
2115 view.mPrivateFlags &= ~PFLAG_CANCEL_NEXT_UP_EVENT;
Jeff Brown20e987b2010-08-23 12:01:02 -07002116 return true;
Adam Cohen9b073942010-08-19 16:49:52 -07002117 }
2118 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002119 }
2120
Romain Guy469b1db2010-10-05 11:49:57 -07002121 /**
2122 * Clears all touch targets.
2123 */
2124 private void clearTouchTargets() {
Jeff Brown20e987b2010-08-23 12:01:02 -07002125 TouchTarget target = mFirstTouchTarget;
2126 if (target != null) {
2127 do {
2128 TouchTarget next = target.next;
2129 target.recycle();
2130 target = next;
2131 } while (target != null);
2132 mFirstTouchTarget = null;
2133 }
2134 }
2135
Romain Guy469b1db2010-10-05 11:49:57 -07002136 /**
2137 * Cancels and clears all touch targets.
2138 */
2139 private void cancelAndClearTouchTargets(MotionEvent event) {
Jeff Brown20e987b2010-08-23 12:01:02 -07002140 if (mFirstTouchTarget != null) {
2141 boolean syntheticEvent = false;
2142 if (event == null) {
2143 final long now = SystemClock.uptimeMillis();
2144 event = MotionEvent.obtain(now, now,
2145 MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
Jeff Brown2fdbc5a2011-06-30 12:25:54 -07002146 event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
Jeff Brown20e987b2010-08-23 12:01:02 -07002147 syntheticEvent = true;
2148 }
2149
2150 for (TouchTarget target = mFirstTouchTarget; target != null; target = target.next) {
2151 resetCancelNextUpFlag(target.child);
2152 dispatchTransformedTouchEvent(event, true, target.child, target.pointerIdBits);
2153 }
2154 clearTouchTargets();
2155
2156 if (syntheticEvent) {
2157 event.recycle();
2158 }
2159 }
2160 }
2161
Romain Guy469b1db2010-10-05 11:49:57 -07002162 /**
2163 * Gets the touch target for specified child view.
2164 * Returns null if not found.
2165 */
2166 private TouchTarget getTouchTarget(View child) {
Jeff Brown20e987b2010-08-23 12:01:02 -07002167 for (TouchTarget target = mFirstTouchTarget; target != null; target = target.next) {
2168 if (target.child == child) {
2169 return target;
2170 }
2171 }
2172 return null;
2173 }
2174
Romain Guy469b1db2010-10-05 11:49:57 -07002175 /**
2176 * Adds a touch target for specified child to the beginning of the list.
2177 * Assumes the target child is not already present.
2178 */
2179 private TouchTarget addTouchTarget(View child, int pointerIdBits) {
Jeff Brown20e987b2010-08-23 12:01:02 -07002180 TouchTarget target = TouchTarget.obtain(child, pointerIdBits);
2181 target.next = mFirstTouchTarget;
2182 mFirstTouchTarget = target;
2183 return target;
2184 }
2185
Romain Guy469b1db2010-10-05 11:49:57 -07002186 /**
2187 * Removes the pointer ids from consideration.
2188 */
2189 private void removePointersFromTouchTargets(int pointerIdBits) {
Jeff Brown20e987b2010-08-23 12:01:02 -07002190 TouchTarget predecessor = null;
2191 TouchTarget target = mFirstTouchTarget;
2192 while (target != null) {
2193 final TouchTarget next = target.next;
2194 if ((target.pointerIdBits & pointerIdBits) != 0) {
2195 target.pointerIdBits &= ~pointerIdBits;
2196 if (target.pointerIdBits == 0) {
2197 if (predecessor == null) {
2198 mFirstTouchTarget = next;
2199 } else {
2200 predecessor.next = next;
2201 }
2202 target.recycle();
2203 target = next;
2204 continue;
2205 }
2206 }
2207 predecessor = target;
2208 target = next;
2209 }
2210 }
2211
Jeff Brown59a422e2012-04-19 15:19:19 -07002212 private void cancelTouchTarget(View view) {
2213 TouchTarget predecessor = null;
2214 TouchTarget target = mFirstTouchTarget;
2215 while (target != null) {
2216 final TouchTarget next = target.next;
2217 if (target.child == view) {
2218 if (predecessor == null) {
2219 mFirstTouchTarget = next;
2220 } else {
2221 predecessor.next = next;
2222 }
2223 target.recycle();
2224
2225 final long now = SystemClock.uptimeMillis();
2226 MotionEvent event = MotionEvent.obtain(now, now,
2227 MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
2228 event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
2229 view.dispatchTouchEvent(event);
2230 event.recycle();
2231 return;
2232 }
2233 predecessor = target;
2234 target = next;
2235 }
2236 }
2237
Romain Guy469b1db2010-10-05 11:49:57 -07002238 /**
Jeff Browna032cc02011-03-07 16:56:21 -08002239 * Returns true if a child view can receive pointer events.
2240 * @hide
2241 */
2242 private static boolean canViewReceivePointerEvents(View child) {
2243 return (child.mViewFlags & VISIBILITY_MASK) == VISIBLE
2244 || child.getAnimation() != null;
2245 }
2246
2247 /**
Romain Guy469b1db2010-10-05 11:49:57 -07002248 * Returns true if a child view contains the specified point when transformed
Jeff Brown20e987b2010-08-23 12:01:02 -07002249 * into its coordinate space.
Romain Guy469b1db2010-10-05 11:49:57 -07002250 * Child must not be null.
Adam Cohena32edd42010-10-26 10:35:01 -07002251 * @hide
Romain Guy469b1db2010-10-05 11:49:57 -07002252 */
Adam Cohena32edd42010-10-26 10:35:01 -07002253 protected boolean isTransformedTouchPointInView(float x, float y, View child,
Christopher Tate2c095f32010-10-04 14:13:40 -07002254 PointF outLocalPoint) {
Jeff Brown20e987b2010-08-23 12:01:02 -07002255 float localX = x + mScrollX - child.mLeft;
2256 float localY = y + mScrollY - child.mTop;
2257 if (! child.hasIdentityMatrix() && mAttachInfo != null) {
Adam Powell2b342f02010-08-18 18:14:13 -07002258 final float[] localXY = mAttachInfo.mTmpTransformLocation;
2259 localXY[0] = localX;
2260 localXY[1] = localY;
2261 child.getInverseMatrix().mapPoints(localXY);
2262 localX = localXY[0];
2263 localY = localXY[1];
2264 }
Christopher Tate2c095f32010-10-04 14:13:40 -07002265 final boolean isInView = child.pointInView(localX, localY);
2266 if (isInView && outLocalPoint != null) {
2267 outLocalPoint.set(localX, localY);
2268 }
2269 return isInView;
Adam Powell2b342f02010-08-18 18:14:13 -07002270 }
2271
Romain Guy469b1db2010-10-05 11:49:57 -07002272 /**
2273 * Transforms a motion event into the coordinate space of a particular child view,
Jeff Brown20e987b2010-08-23 12:01:02 -07002274 * filters out irrelevant pointer ids, and overrides its action if necessary.
Romain Guy469b1db2010-10-05 11:49:57 -07002275 * If child is null, assumes the MotionEvent will be sent to this ViewGroup instead.
2276 */
2277 private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,
Jeff Brown20e987b2010-08-23 12:01:02 -07002278 View child, int desiredPointerIdBits) {
2279 final boolean handled;
Adam Powell2b342f02010-08-18 18:14:13 -07002280
Jeff Brown20e987b2010-08-23 12:01:02 -07002281 // Canceling motions is a special case. We don't need to perform any transformations
2282 // or filtering. The important part is the action, not the contents.
2283 final int oldAction = event.getAction();
2284 if (cancel || oldAction == MotionEvent.ACTION_CANCEL) {
2285 event.setAction(MotionEvent.ACTION_CANCEL);
2286 if (child == null) {
2287 handled = super.dispatchTouchEvent(event);
2288 } else {
2289 handled = child.dispatchTouchEvent(event);
2290 }
2291 event.setAction(oldAction);
2292 return handled;
2293 }
Adam Powell2b342f02010-08-18 18:14:13 -07002294
Jeff Brown20e987b2010-08-23 12:01:02 -07002295 // Calculate the number of pointers to deliver.
Jeff Brownfe9f8ab2011-05-06 18:20:01 -07002296 final int oldPointerIdBits = event.getPointerIdBits();
2297 final int newPointerIdBits = oldPointerIdBits & desiredPointerIdBits;
Adam Powell2b342f02010-08-18 18:14:13 -07002298
Jeff Brown20e987b2010-08-23 12:01:02 -07002299 // If for some reason we ended up in an inconsistent state where it looks like we
2300 // might produce a motion event with no pointers in it, then drop the event.
Jeff Brownfe9f8ab2011-05-06 18:20:01 -07002301 if (newPointerIdBits == 0) {
Jeff Brown20e987b2010-08-23 12:01:02 -07002302 return false;
2303 }
Adam Powell2b342f02010-08-18 18:14:13 -07002304
Jeff Brown20e987b2010-08-23 12:01:02 -07002305 // If the number of pointers is the same and we don't need to perform any fancy
2306 // irreversible transformations, then we can reuse the motion event for this
2307 // dispatch as long as we are careful to revert any changes we make.
Jeff Brownfe9f8ab2011-05-06 18:20:01 -07002308 // Otherwise we need to make a copy.
2309 final MotionEvent transformedEvent;
2310 if (newPointerIdBits == oldPointerIdBits) {
2311 if (child == null || child.hasIdentityMatrix()) {
2312 if (child == null) {
2313 handled = super.dispatchTouchEvent(event);
2314 } else {
2315 final float offsetX = mScrollX - child.mLeft;
2316 final float offsetY = mScrollY - child.mTop;
2317 event.offsetLocation(offsetX, offsetY);
Adam Powell2b342f02010-08-18 18:14:13 -07002318
Jeff Brownfe9f8ab2011-05-06 18:20:01 -07002319 handled = child.dispatchTouchEvent(event);
Jeff Brown20e987b2010-08-23 12:01:02 -07002320
Jeff Brownfe9f8ab2011-05-06 18:20:01 -07002321 event.offsetLocation(-offsetX, -offsetY);
2322 }
2323 return handled;
Jeff Brown20e987b2010-08-23 12:01:02 -07002324 }
Jeff Brown20e987b2010-08-23 12:01:02 -07002325 transformedEvent = MotionEvent.obtain(event);
2326 } else {
Jeff Brownfe9f8ab2011-05-06 18:20:01 -07002327 transformedEvent = event.split(newPointerIdBits);
Adam Powell2b342f02010-08-18 18:14:13 -07002328 }
2329
Jeff Brown20e987b2010-08-23 12:01:02 -07002330 // Perform any necessary transformations and dispatch.
2331 if (child == null) {
2332 handled = super.dispatchTouchEvent(transformedEvent);
2333 } else {
2334 final float offsetX = mScrollX - child.mLeft;
2335 final float offsetY = mScrollY - child.mTop;
2336 transformedEvent.offsetLocation(offsetX, offsetY);
2337 if (! child.hasIdentityMatrix()) {
2338 transformedEvent.transform(child.getInverseMatrix());
Adam Powell2b342f02010-08-18 18:14:13 -07002339 }
2340
Jeff Brown20e987b2010-08-23 12:01:02 -07002341 handled = child.dispatchTouchEvent(transformedEvent);
Adam Powell2b342f02010-08-18 18:14:13 -07002342 }
2343
Jeff Brown20e987b2010-08-23 12:01:02 -07002344 // Done.
2345 transformedEvent.recycle();
Adam Powell2b342f02010-08-18 18:14:13 -07002346 return handled;
2347 }
2348
Romain Guy469b1db2010-10-05 11:49:57 -07002349 /**
Adam Powell2b342f02010-08-18 18:14:13 -07002350 * Enable or disable the splitting of MotionEvents to multiple children during touch event
Jeff Brown995e7742010-12-22 16:59:36 -08002351 * dispatch. This behavior is enabled by default for applications that target an
2352 * SDK version of {@link Build.VERSION_CODES#HONEYCOMB} or newer.
Adam Powell2b342f02010-08-18 18:14:13 -07002353 *
2354 * <p>When this option is enabled MotionEvents may be split and dispatched to different child
2355 * views depending on where each pointer initially went down. This allows for user interactions
2356 * such as scrolling two panes of content independently, chording of buttons, and performing
2357 * independent gestures on different pieces of content.
2358 *
2359 * @param split <code>true</code> to allow MotionEvents to be split and dispatched to multiple
2360 * child views. <code>false</code> to only allow one child view to be the target of
2361 * any MotionEvent received by this ViewGroup.
Scott Main27a85082013-06-10 10:39:48 -07002362 * @attr ref android.R.styleable#ViewGroup_splitMotionEvents
Adam Powell2b342f02010-08-18 18:14:13 -07002363 */
2364 public void setMotionEventSplittingEnabled(boolean split) {
2365 // TODO Applications really shouldn't change this setting mid-touch event,
2366 // but perhaps this should handle that case and send ACTION_CANCELs to any child views
2367 // with gestures in progress when this is changed.
2368 if (split) {
Adam Powell2b342f02010-08-18 18:14:13 -07002369 mGroupFlags |= FLAG_SPLIT_MOTION_EVENTS;
2370 } else {
2371 mGroupFlags &= ~FLAG_SPLIT_MOTION_EVENTS;
Adam Powell2b342f02010-08-18 18:14:13 -07002372 }
2373 }
2374
2375 /**
Jeff Brown995e7742010-12-22 16:59:36 -08002376 * Returns true if MotionEvents dispatched to this ViewGroup can be split to multiple children.
Adam Powell2b342f02010-08-18 18:14:13 -07002377 * @return true if MotionEvents dispatched to this ViewGroup can be split to multiple children.
2378 */
2379 public boolean isMotionEventSplittingEnabled() {
2380 return (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) == FLAG_SPLIT_MOTION_EVENTS;
2381 }
2382
2383 /**
George Mount0a778ed2013-12-13 13:35:36 -08002384 * Returns true if this ViewGroup should be considered as a single entity for removal
2385 * when executing an Activity transition. If this is false, child elements will move
2386 * individually during the transition.
2387 * @return True if the ViewGroup should be acted on together during an Activity transition.
2388 * The default value is false when the background is null and true when the background
George Mount0a2ae002014-06-23 14:57:27 +00002389 * is not null or if {@link #getTransitionName()} is not null.
George Mount0a778ed2013-12-13 13:35:36 -08002390 */
2391 public boolean isTransitionGroup() {
2392 if ((mGroupFlags & FLAG_IS_TRANSITION_GROUP_SET) != 0) {
2393 return ((mGroupFlags & FLAG_IS_TRANSITION_GROUP) != 0);
2394 } else {
George Mount0a2ae002014-06-23 14:57:27 +00002395 return getBackground() != null || getTransitionName() != null;
George Mount0a778ed2013-12-13 13:35:36 -08002396 }
2397 }
2398
2399 /**
2400 * Changes whether or not this ViewGroup should be treated as a single entity during
George Mount31a21722014-03-24 17:44:36 -07002401 * Activity Transitions.
George Mount0a778ed2013-12-13 13:35:36 -08002402 * @param isTransitionGroup Whether or not the ViewGroup should be treated as a unit
2403 * in Activity transitions. If false, the ViewGroup won't transition,
2404 * only its children. If true, the entire ViewGroup will transition
2405 * together.
George Mount62ab9b72014-05-02 13:51:17 -07002406 * @see android.app.ActivityOptions#makeSceneTransitionAnimation(android.app.Activity,
2407 * android.util.Pair[])
George Mount0a778ed2013-12-13 13:35:36 -08002408 */
2409 public void setTransitionGroup(boolean isTransitionGroup) {
2410 mGroupFlags |= FLAG_IS_TRANSITION_GROUP_SET;
2411 if (isTransitionGroup) {
2412 mGroupFlags |= FLAG_IS_TRANSITION_GROUP;
2413 } else {
2414 mGroupFlags &= ~FLAG_IS_TRANSITION_GROUP;
2415 }
2416 }
2417
2418 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002419 * {@inheritDoc}
2420 */
2421 public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
Romain Guy8506ab42009-06-11 17:35:47 -07002422
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002423 if (disallowIntercept == ((mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0)) {
2424 // We're already in this state, assume our ancestors are too
2425 return;
2426 }
Romain Guy8506ab42009-06-11 17:35:47 -07002427
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002428 if (disallowIntercept) {
2429 mGroupFlags |= FLAG_DISALLOW_INTERCEPT;
2430 } else {
2431 mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
2432 }
Romain Guy8506ab42009-06-11 17:35:47 -07002433
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002434 // Pass it up to our parent
2435 if (mParent != null) {
2436 mParent.requestDisallowInterceptTouchEvent(disallowIntercept);
2437 }
2438 }
2439
2440 /**
2441 * Implement this method to intercept all touch screen motion events. This
2442 * allows you to watch events as they are dispatched to your children, and
2443 * take ownership of the current gesture at any point.
2444 *
2445 * <p>Using this function takes some care, as it has a fairly complicated
2446 * interaction with {@link View#onTouchEvent(MotionEvent)
2447 * View.onTouchEvent(MotionEvent)}, and using it requires implementing
2448 * that method as well as this one in the correct way. Events will be
2449 * received in the following order:
2450 *
2451 * <ol>
2452 * <li> You will receive the down event here.
2453 * <li> The down event will be handled either by a child of this view
2454 * group, or given to your own onTouchEvent() method to handle; this means
2455 * you should implement onTouchEvent() to return true, so you will
2456 * continue to see the rest of the gesture (instead of looking for
2457 * a parent view to handle it). Also, by returning true from
2458 * onTouchEvent(), you will not receive any following
2459 * events in onInterceptTouchEvent() and all touch processing must
2460 * happen in onTouchEvent() like normal.
2461 * <li> For as long as you return false from this function, each following
2462 * event (up to and including the final up) will be delivered first here
2463 * and then to the target's onTouchEvent().
2464 * <li> If you return true from here, you will not receive any
2465 * following events: the target view will receive the same event but
2466 * with the action {@link MotionEvent#ACTION_CANCEL}, and all further
2467 * events will be delivered to your onTouchEvent() method and no longer
2468 * appear here.
2469 * </ol>
2470 *
2471 * @param ev The motion event being dispatched down the hierarchy.
2472 * @return Return true to steal motion events from the children and have
2473 * them dispatched to this ViewGroup through onTouchEvent().
2474 * The current target will receive an ACTION_CANCEL event, and no further
2475 * messages will be delivered here.
2476 */
2477 public boolean onInterceptTouchEvent(MotionEvent ev) {
2478 return false;
2479 }
2480
2481 /**
2482 * {@inheritDoc}
2483 *
2484 * Looks for a view to give focus to respecting the setting specified by
2485 * {@link #getDescendantFocusability()}.
2486 *
2487 * Uses {@link #onRequestFocusInDescendants(int, android.graphics.Rect)} to
2488 * find focus within the children of this group when appropriate.
2489 *
2490 * @see #FOCUS_BEFORE_DESCENDANTS
2491 * @see #FOCUS_AFTER_DESCENDANTS
2492 * @see #FOCUS_BLOCK_DESCENDANTS
Romain Guy02739a82011-05-16 11:43:18 -07002493 * @see #onRequestFocusInDescendants(int, android.graphics.Rect)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002494 */
2495 @Override
2496 public boolean requestFocus(int direction, Rect previouslyFocusedRect) {
2497 if (DBG) {
2498 System.out.println(this + " ViewGroup.requestFocus direction="
2499 + direction);
2500 }
2501 int descendantFocusability = getDescendantFocusability();
2502
2503 switch (descendantFocusability) {
2504 case FOCUS_BLOCK_DESCENDANTS:
2505 return super.requestFocus(direction, previouslyFocusedRect);
2506 case FOCUS_BEFORE_DESCENDANTS: {
2507 final boolean took = super.requestFocus(direction, previouslyFocusedRect);
2508 return took ? took : onRequestFocusInDescendants(direction, previouslyFocusedRect);
2509 }
2510 case FOCUS_AFTER_DESCENDANTS: {
2511 final boolean took = onRequestFocusInDescendants(direction, previouslyFocusedRect);
2512 return took ? took : super.requestFocus(direction, previouslyFocusedRect);
2513 }
2514 default:
2515 throw new IllegalStateException("descendant focusability must be "
2516 + "one of FOCUS_BEFORE_DESCENDANTS, FOCUS_AFTER_DESCENDANTS, FOCUS_BLOCK_DESCENDANTS "
2517 + "but is " + descendantFocusability);
2518 }
2519 }
2520
2521 /**
2522 * Look for a descendant to call {@link View#requestFocus} on.
2523 * Called by {@link ViewGroup#requestFocus(int, android.graphics.Rect)}
2524 * when it wants to request focus within its children. Override this to
2525 * customize how your {@link ViewGroup} requests focus within its children.
2526 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT
2527 * @param previouslyFocusedRect The rectangle (in this View's coordinate system)
2528 * to give a finer grained hint about where focus is coming from. May be null
2529 * if there is no hint.
2530 * @return Whether focus was taken.
2531 */
2532 @SuppressWarnings({"ConstantConditions"})
2533 protected boolean onRequestFocusInDescendants(int direction,
2534 Rect previouslyFocusedRect) {
2535 int index;
2536 int increment;
2537 int end;
2538 int count = mChildrenCount;
2539 if ((direction & FOCUS_FORWARD) != 0) {
2540 index = 0;
2541 increment = 1;
2542 end = count;
2543 } else {
2544 index = count - 1;
2545 increment = -1;
2546 end = -1;
2547 }
2548 final View[] children = mChildren;
2549 for (int i = index; i != end; i += increment) {
2550 View child = children[i];
2551 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
2552 if (child.requestFocus(direction, previouslyFocusedRect)) {
2553 return true;
2554 }
2555 }
2556 }
2557 return false;
2558 }
Chet Haase5c13d892010-10-08 08:37:55 -07002559
Romain Guya440b002010-02-24 15:57:54 -08002560 /**
2561 * {@inheritDoc}
Chet Haase5c13d892010-10-08 08:37:55 -07002562 *
Romain Guydcc490f2010-02-24 17:59:35 -08002563 * @hide
Romain Guya440b002010-02-24 15:57:54 -08002564 */
2565 @Override
2566 public void dispatchStartTemporaryDetach() {
2567 super.dispatchStartTemporaryDetach();
2568 final int count = mChildrenCount;
2569 final View[] children = mChildren;
2570 for (int i = 0; i < count; i++) {
2571 children[i].dispatchStartTemporaryDetach();
2572 }
2573 }
Chet Haase5c13d892010-10-08 08:37:55 -07002574
Romain Guya440b002010-02-24 15:57:54 -08002575 /**
2576 * {@inheritDoc}
Chet Haase5c13d892010-10-08 08:37:55 -07002577 *
Romain Guydcc490f2010-02-24 17:59:35 -08002578 * @hide
Romain Guya440b002010-02-24 15:57:54 -08002579 */
2580 @Override
2581 public void dispatchFinishTemporaryDetach() {
2582 super.dispatchFinishTemporaryDetach();
2583 final int count = mChildrenCount;
2584 final View[] children = mChildren;
2585 for (int i = 0; i < count; i++) {
2586 children[i].dispatchFinishTemporaryDetach();
2587 }
2588 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002589
2590 /**
2591 * {@inheritDoc}
2592 */
2593 @Override
2594 void dispatchAttachedToWindow(AttachInfo info, int visibility) {
Adam Powell4b867882011-09-16 12:59:46 -07002595 mGroupFlags |= FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002596 super.dispatchAttachedToWindow(info, visibility);
Adam Powell4b867882011-09-16 12:59:46 -07002597 mGroupFlags &= ~FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW;
2598
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002599 final int count = mChildrenCount;
2600 final View[] children = mChildren;
2601 for (int i = 0; i < count; i++) {
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07002602 final View child = children[i];
2603 child.dispatchAttachedToWindow(info,
Philip Milne7b757812012-09-19 18:13:44 -07002604 visibility | (child.mViewFlags & VISIBILITY_MASK));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002605 }
2606 }
2607
svetoslavganov75986cf2009-05-14 22:28:01 -07002608 @Override
Romain Guybb9908b2012-03-08 11:14:07 -08002609 void dispatchScreenStateChanged(int screenState) {
2610 super.dispatchScreenStateChanged(screenState);
2611
2612 final int count = mChildrenCount;
2613 final View[] children = mChildren;
2614 for (int i = 0; i < count; i++) {
2615 children[i].dispatchScreenStateChanged(screenState);
2616 }
2617 }
2618
2619 @Override
Svetoslav Ganov031d9c12011-09-09 16:41:13 -07002620 boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07002621 boolean handled = false;
2622 if (includeForAccessibility()) {
2623 handled = super.dispatchPopulateAccessibilityEventInternal(event);
2624 if (handled) {
2625 return handled;
2626 }
Svetoslav Ganovb84b94e2011-09-22 19:26:56 -07002627 }
Svetoslav Ganov736c2752011-04-22 18:30:36 -07002628 // Let our children have a shot in populating the event.
Svetoslav Ganov42138042012-03-20 11:51:39 -07002629 ChildListForAccessibility children = ChildListForAccessibility.obtain(this, true);
Svetoslav Ganov76f287e2012-04-23 11:02:36 -07002630 try {
2631 final int childCount = children.getChildCount();
2632 for (int i = 0; i < childCount; i++) {
2633 View child = children.getChildAt(i);
2634 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
2635 handled = child.dispatchPopulateAccessibilityEvent(event);
2636 if (handled) {
Svetoslav Ganov76f287e2012-04-23 11:02:36 -07002637 return handled;
2638 }
Svetoslav Ganov6179ea32011-06-28 01:12:41 -07002639 }
Svetoslav Ganov736c2752011-04-22 18:30:36 -07002640 }
Svetoslav Ganov76f287e2012-04-23 11:02:36 -07002641 } finally {
2642 children.recycle();
svetoslavganov75986cf2009-05-14 22:28:01 -07002643 }
Svetoslav Ganov736c2752011-04-22 18:30:36 -07002644 return false;
svetoslavganov75986cf2009-05-14 22:28:01 -07002645 }
2646
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002647 @Override
Svetoslav Ganov031d9c12011-09-09 16:41:13 -07002648 void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
2649 super.onInitializeAccessibilityNodeInfoInternal(info);
Svetoslav Ganov42138042012-03-20 11:51:39 -07002650 if (mAttachInfo != null) {
Alan Viverettef0aed092013-11-06 15:33:03 -08002651 final ArrayList<View> childrenForAccessibility = mAttachInfo.mTempArrayList;
Svetoslav Ganov42138042012-03-20 11:51:39 -07002652 childrenForAccessibility.clear();
2653 addChildrenForAccessibility(childrenForAccessibility);
2654 final int childrenForAccessibilityCount = childrenForAccessibility.size();
2655 for (int i = 0; i < childrenForAccessibilityCount; i++) {
Alan Viverettef0aed092013-11-06 15:33:03 -08002656 final View child = childrenForAccessibility.get(i);
2657 info.addChildUnchecked(child);
Svetoslav Ganovea1da3d2011-06-15 17:16:02 -07002658 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07002659 childrenForAccessibility.clear();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002660 }
2661 }
2662
Svetoslav Ganov8a78fd42012-01-17 14:36:46 -08002663 @Override
2664 void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
2665 super.onInitializeAccessibilityEventInternal(event);
2666 event.setClassName(ViewGroup.class.getName());
2667 }
2668
Svetoslav Ganov42138042012-03-20 11:51:39 -07002669 @Override
Alan Viverette77e9a282013-09-12 17:16:09 -07002670 public void notifySubtreeAccessibilityStateChanged(View child, View source, int changeType) {
2671 // If this is a live region, we should send a subtree change event
2672 // from this view. Otherwise, we can let it propagate up.
2673 if (getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE) {
2674 notifyViewAccessibilityStateChangedIfNeeded(changeType);
2675 } else if (mParent != null) {
Adam Powell504a10f2013-07-11 15:25:59 -07002676 try {
Alan Viverette77e9a282013-09-12 17:16:09 -07002677 mParent.notifySubtreeAccessibilityStateChanged(this, source, changeType);
Adam Powell504a10f2013-07-11 15:25:59 -07002678 } catch (AbstractMethodError e) {
2679 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() +
2680 " does not fully implement ViewParent", e);
2681 }
Svetoslav6254f482013-06-04 17:22:14 -07002682 }
2683 }
2684
2685 @Override
2686 void resetSubtreeAccessibilityStateChanged() {
2687 super.resetSubtreeAccessibilityStateChanged();
Svetoslav Ganov42138042012-03-20 11:51:39 -07002688 View[] children = mChildren;
2689 final int childCount = mChildrenCount;
2690 for (int i = 0; i < childCount; i++) {
Svetoslav6254f482013-06-04 17:22:14 -07002691 children[i].resetSubtreeAccessibilityStateChanged();
Svetoslav Ganov42138042012-03-20 11:51:39 -07002692 }
2693 }
2694
2695 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002696 * {@inheritDoc}
2697 */
2698 @Override
2699 void dispatchDetachedFromWindow() {
Jeff Brown20e987b2010-08-23 12:01:02 -07002700 // If we still have a touch target, we are still in the process of
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002701 // dispatching motion events to a child; we need to get rid of that
2702 // child to avoid dispatching events to it after the window is torn
2703 // down. To make sure we keep the child in a consistent state, we
2704 // first send it an ACTION_CANCEL motion event.
Jeff Brown20e987b2010-08-23 12:01:02 -07002705 cancelAndClearTouchTargets(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002706
Jeff Brown59a422e2012-04-19 15:19:19 -07002707 // Similarly, set ACTION_EXIT to all hover targets and clear them.
2708 exitHoverTargets();
2709
Chet Haase9c087442011-01-12 16:20:16 -08002710 // In case view is detached while transition is running
Chet Haaseb9895022013-04-02 15:10:58 -07002711 mLayoutCalledWhileSuppressed = false;
Chet Haase9c087442011-01-12 16:20:16 -08002712
Christopher Tate86cab1b2011-01-13 20:28:55 -08002713 // Tear down our drag tracking
2714 mDragNotifiedChildren = null;
2715 if (mCurrentDrag != null) {
2716 mCurrentDrag.recycle();
2717 mCurrentDrag = null;
2718 }
2719
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002720 final int count = mChildrenCount;
2721 final View[] children = mChildren;
2722 for (int i = 0; i < count; i++) {
2723 children[i].dispatchDetachedFromWindow();
2724 }
John Reckca7a9da2014-03-05 16:29:07 -08002725 clearDisappearingChildren();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002726 super.dispatchDetachedFromWindow();
2727 }
2728
Fabrice Di Meglio23c89fd2012-08-13 12:17:42 -07002729 /**
2730 * @hide
2731 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002732 @Override
Fabrice Di Meglio23c89fd2012-08-13 12:17:42 -07002733 protected void internalSetPadding(int left, int top, int right, int bottom) {
Romain Guy2440e672012-08-07 14:43:43 -07002734 super.internalSetPadding(left, top, right, bottom);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002735
Romain Guy13f35f32011-03-24 12:03:17 -07002736 if ((mPaddingLeft | mPaddingTop | mPaddingRight | mPaddingBottom) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002737 mGroupFlags |= FLAG_PADDING_NOT_NULL;
2738 } else {
2739 mGroupFlags &= ~FLAG_PADDING_NOT_NULL;
2740 }
2741 }
2742
2743 /**
2744 * {@inheritDoc}
2745 */
2746 @Override
2747 protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {
2748 super.dispatchSaveInstanceState(container);
2749 final int count = mChildrenCount;
2750 final View[] children = mChildren;
2751 for (int i = 0; i < count; i++) {
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07002752 View c = children[i];
2753 if ((c.mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED) {
2754 c.dispatchSaveInstanceState(container);
2755 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002756 }
2757 }
2758
2759 /**
Romain Guy9fc27812011-04-27 14:21:41 -07002760 * Perform dispatching of a {@link #saveHierarchyState(android.util.SparseArray)} freeze()}
2761 * to only this view, not to its children. For use when overriding
2762 * {@link #dispatchSaveInstanceState(android.util.SparseArray)} dispatchFreeze()} to allow
2763 * subclasses to freeze their own state but not the state of their children.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002764 *
2765 * @param container the container
2766 */
2767 protected void dispatchFreezeSelfOnly(SparseArray<Parcelable> container) {
2768 super.dispatchSaveInstanceState(container);
2769 }
2770
2771 /**
2772 * {@inheritDoc}
2773 */
2774 @Override
2775 protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {
2776 super.dispatchRestoreInstanceState(container);
2777 final int count = mChildrenCount;
2778 final View[] children = mChildren;
2779 for (int i = 0; i < count; i++) {
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07002780 View c = children[i];
2781 if ((c.mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED) {
2782 c.dispatchRestoreInstanceState(container);
2783 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002784 }
2785 }
2786
2787 /**
Romain Guy02739a82011-05-16 11:43:18 -07002788 * Perform dispatching of a {@link #restoreHierarchyState(android.util.SparseArray)}
2789 * to only this view, not to its children. For use when overriding
2790 * {@link #dispatchRestoreInstanceState(android.util.SparseArray)} to allow
2791 * subclasses to thaw their own state but not the state of their children.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002792 *
2793 * @param container the container
2794 */
2795 protected void dispatchThawSelfOnly(SparseArray<Parcelable> container) {
2796 super.dispatchRestoreInstanceState(container);
2797 }
2798
2799 /**
2800 * Enables or disables the drawing cache for each child of this view group.
2801 *
2802 * @param enabled true to enable the cache, false to dispose of it
2803 */
2804 protected void setChildrenDrawingCacheEnabled(boolean enabled) {
2805 if (enabled || (mPersistentDrawingCache & PERSISTENT_ALL_CACHES) != PERSISTENT_ALL_CACHES) {
2806 final View[] children = mChildren;
2807 final int count = mChildrenCount;
2808 for (int i = 0; i < count; i++) {
2809 children[i].setDrawingCacheEnabled(enabled);
2810 }
2811 }
2812 }
2813
2814 @Override
2815 protected void onAnimationStart() {
2816 super.onAnimationStart();
2817
2818 // When this ViewGroup's animation starts, build the cache for the children
2819 if ((mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE) {
2820 final int count = mChildrenCount;
2821 final View[] children = mChildren;
Romain Guy0d9275e2010-10-26 14:22:30 -07002822 final boolean buildCache = !isHardwareAccelerated();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002823
2824 for (int i = 0; i < count; i++) {
2825 final View child = children[i];
2826 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
2827 child.setDrawingCacheEnabled(true);
Romain Guy0d9275e2010-10-26 14:22:30 -07002828 if (buildCache) {
2829 child.buildDrawingCache(true);
2830 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002831 }
2832 }
2833
2834 mGroupFlags |= FLAG_CHILDREN_DRAWN_WITH_CACHE;
2835 }
2836 }
2837
2838 @Override
2839 protected void onAnimationEnd() {
2840 super.onAnimationEnd();
2841
2842 // When this ViewGroup's animation ends, destroy the cache of the children
2843 if ((mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE) {
2844 mGroupFlags &= ~FLAG_CHILDREN_DRAWN_WITH_CACHE;
2845
2846 if ((mPersistentDrawingCache & PERSISTENT_ANIMATION_CACHE) == 0) {
2847 setChildrenDrawingCacheEnabled(false);
2848 }
2849 }
2850 }
2851
Romain Guy223ff5c2010-03-02 17:07:47 -08002852 @Override
2853 Bitmap createSnapshot(Bitmap.Config quality, int backgroundColor, boolean skipChildren) {
Romain Guy65554f22010-03-22 18:58:21 -07002854 int count = mChildrenCount;
2855 int[] visibilities = null;
2856
Romain Guy223ff5c2010-03-02 17:07:47 -08002857 if (skipChildren) {
Romain Guy65554f22010-03-22 18:58:21 -07002858 visibilities = new int[count];
2859 for (int i = 0; i < count; i++) {
2860 View child = getChildAt(i);
2861 visibilities[i] = child.getVisibility();
2862 if (visibilities[i] == View.VISIBLE) {
2863 child.setVisibility(INVISIBLE);
2864 }
2865 }
Romain Guy223ff5c2010-03-02 17:07:47 -08002866 }
2867
2868 Bitmap b = super.createSnapshot(quality, backgroundColor, skipChildren);
Romain Guy65554f22010-03-22 18:58:21 -07002869
2870 if (skipChildren) {
2871 for (int i = 0; i < count; i++) {
2872 getChildAt(i).setVisibility(visibilities[i]);
Chet Haase5c13d892010-10-08 08:37:55 -07002873 }
Romain Guy65554f22010-03-22 18:58:21 -07002874 }
Romain Guy223ff5c2010-03-02 17:07:47 -08002875
2876 return b;
2877 }
2878
Philip Milne7b757812012-09-19 18:13:44 -07002879 /** Return true if this ViewGroup is laying out using optical bounds. */
2880 boolean isLayoutModeOptical() {
2881 return mLayoutMode == LAYOUT_MODE_OPTICAL_BOUNDS;
2882 }
Romain Guycbc67742012-04-27 16:12:57 -07002883
Philip Milne7b757812012-09-19 18:13:44 -07002884 Insets computeOpticalInsets() {
2885 if (isLayoutModeOptical()) {
2886 int left = 0;
2887 int top = 0;
2888 int right = 0;
2889 int bottom = 0;
2890 for (int i = 0; i < mChildrenCount; i++) {
2891 View child = getChildAt(i);
2892 if (child.getVisibility() == VISIBLE) {
2893 Insets insets = child.getOpticalInsets();
2894 left = Math.max(left, insets.left);
2895 top = Math.max(top, insets.top);
2896 right = Math.max(right, insets.right);
2897 bottom = Math.max(bottom, insets.bottom);
2898 }
2899 }
2900 return Insets.of(left, top, right, bottom);
2901 } else {
2902 return Insets.NONE;
2903 }
2904 }
2905
2906 private static void fillRect(Canvas canvas, Paint paint, int x1, int y1, int x2, int y2) {
2907 if (x1 != x2 && y1 != y2) {
2908 if (x1 > x2) {
2909 int tmp = x1; x1 = x2; x2 = tmp;
2910 }
2911 if (y1 > y2) {
2912 int tmp = y1; y1 = y2; y2 = tmp;
2913 }
2914 canvas.drawRect(x1, y1, x2, y2, paint);
2915 }
2916 }
2917
2918 private static int sign(int x) {
2919 return (x >= 0) ? 1 : -1;
2920 }
2921
2922 private static void drawCorner(Canvas c, Paint paint, int x1, int y1, int dx, int dy, int lw) {
2923 fillRect(c, paint, x1, y1, x1 + dx, y1 + lw * sign(dy));
2924 fillRect(c, paint, x1, y1, x1 + lw * sign(dx), y1 + dy);
2925 }
2926
2927 private int dipsToPixels(int dips) {
2928 float scale = getContext().getResources().getDisplayMetrics().density;
2929 return (int) (dips * scale + 0.5f);
2930 }
2931
Romain Guy6410c0a2013-06-17 11:21:58 -07002932 private static void drawRectCorners(Canvas canvas, int x1, int y1, int x2, int y2, Paint paint,
2933 int lineLength, int lineWidth) {
Philip Milne7b757812012-09-19 18:13:44 -07002934 drawCorner(canvas, paint, x1, y1, lineLength, lineLength, lineWidth);
2935 drawCorner(canvas, paint, x1, y2, lineLength, -lineLength, lineWidth);
2936 drawCorner(canvas, paint, x2, y1, -lineLength, lineLength, lineWidth);
2937 drawCorner(canvas, paint, x2, y2, -lineLength, -lineLength, lineWidth);
2938 }
2939
2940 private static void fillDifference(Canvas canvas,
2941 int x2, int y2, int x3, int y3,
2942 int dx1, int dy1, int dx2, int dy2, Paint paint) {
2943 int x1 = x2 - dx1;
2944 int y1 = y2 - dy1;
2945
2946 int x4 = x3 + dx2;
2947 int y4 = y3 + dy2;
2948
2949 fillRect(canvas, paint, x1, y1, x4, y2);
2950 fillRect(canvas, paint, x1, y2, x2, y3);
2951 fillRect(canvas, paint, x3, y2, x4, y3);
2952 fillRect(canvas, paint, x1, y3, x4, y4);
Philip Milne10ca24a2012-04-23 15:38:27 -07002953 }
2954
2955 /**
2956 * @hide
2957 */
Philip Milne7b757812012-09-19 18:13:44 -07002958 protected void onDebugDrawMargins(Canvas canvas, Paint paint) {
Philip Milne10ca24a2012-04-23 15:38:27 -07002959 for (int i = 0; i < getChildCount(); i++) {
2960 View c = getChildAt(i);
Philip Milne7b757812012-09-19 18:13:44 -07002961 c.getLayoutParams().onDebugDraw(c, canvas, paint);
Philip Milne10ca24a2012-04-23 15:38:27 -07002962 }
2963 }
2964
2965 /**
2966 * @hide
2967 */
2968 protected void onDebugDraw(Canvas canvas) {
Philip Milne7b757812012-09-19 18:13:44 -07002969 Paint paint = getDebugPaint();
2970
Philip Milne10ca24a2012-04-23 15:38:27 -07002971 // Draw optical bounds
Philip Milne7b757812012-09-19 18:13:44 -07002972 {
2973 paint.setColor(Color.RED);
2974 paint.setStyle(Paint.Style.STROKE);
Philip Milne7b757812012-09-19 18:13:44 -07002975
Philip Milne10ca24a2012-04-23 15:38:27 -07002976 for (int i = 0; i < getChildCount(); i++) {
2977 View c = getChildAt(i);
Philip Milne7a23b492012-04-24 22:12:36 -07002978 Insets insets = c.getOpticalInsets();
Philip Milne7b757812012-09-19 18:13:44 -07002979
2980 drawRect(canvas, paint,
2981 c.getLeft() + insets.left,
2982 c.getTop() + insets.top,
2983 c.getRight() - insets.right - 1,
2984 c.getBottom() - insets.bottom - 1);
Philip Milne10ca24a2012-04-23 15:38:27 -07002985 }
2986 }
2987
Philip Milne10ca24a2012-04-23 15:38:27 -07002988 // Draw margins
Philip Milne7b757812012-09-19 18:13:44 -07002989 {
2990 paint.setColor(Color.argb(63, 255, 0, 255));
2991 paint.setStyle(Paint.Style.FILL);
Philip Milne604f4402012-04-24 19:27:11 -07002992
Philip Milne7b757812012-09-19 18:13:44 -07002993 onDebugDrawMargins(canvas, paint);
2994 }
2995
2996 // Draw clip bounds
2997 {
2998 paint.setColor(Color.rgb(63, 127, 255));
2999 paint.setStyle(Paint.Style.FILL);
3000
3001 int lineLength = dipsToPixels(8);
3002 int lineWidth = dipsToPixels(1);
3003 for (int i = 0; i < getChildCount(); i++) {
3004 View c = getChildAt(i);
3005 drawRectCorners(canvas, c.getLeft(), c.getTop(), c.getRight(), c.getBottom(),
3006 paint, lineLength, lineWidth);
3007 }
Philip Milne604f4402012-04-24 19:27:11 -07003008 }
Philip Milne10ca24a2012-04-23 15:38:27 -07003009 }
3010
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003011 /**
3012 * {@inheritDoc}
3013 */
3014 @Override
3015 protected void dispatchDraw(Canvas canvas) {
Chris Craika753f4c2014-07-24 12:39:17 -07003016 boolean usingRenderNodeProperties = canvas.isRecordingFor(mRenderNode);
Chris Craikab008f02014-05-23 17:55:03 -07003017 final int childrenCount = mChildrenCount;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003018 final View[] children = mChildren;
3019 int flags = mGroupFlags;
3020
3021 if ((flags & FLAG_RUN_ANIMATION) != 0 && canAnimate()) {
3022 final boolean cache = (mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE;
3023
Romain Guy0d9275e2010-10-26 14:22:30 -07003024 final boolean buildCache = !isHardwareAccelerated();
Chris Craikab008f02014-05-23 17:55:03 -07003025 for (int i = 0; i < childrenCount; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003026 final View child = children[i];
3027 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
3028 final LayoutParams params = child.getLayoutParams();
Chris Craikab008f02014-05-23 17:55:03 -07003029 attachLayoutAnimationParameters(child, params, i, childrenCount);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003030 bindLayoutAnimation(child);
3031 if (cache) {
3032 child.setDrawingCacheEnabled(true);
Chris Craikab008f02014-05-23 17:55:03 -07003033 if (buildCache) {
Romain Guy0d9275e2010-10-26 14:22:30 -07003034 child.buildDrawingCache(true);
3035 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003036 }
3037 }
3038 }
3039
3040 final LayoutAnimationController controller = mLayoutAnimationController;
3041 if (controller.willOverlap()) {
3042 mGroupFlags |= FLAG_OPTIMIZE_INVALIDATE;
3043 }
3044
3045 controller.start();
3046
3047 mGroupFlags &= ~FLAG_RUN_ANIMATION;
3048 mGroupFlags &= ~FLAG_ANIMATION_DONE;
3049
3050 if (cache) {
3051 mGroupFlags |= FLAG_CHILDREN_DRAWN_WITH_CACHE;
3052 }
3053
3054 if (mAnimationListener != null) {
3055 mAnimationListener.onAnimationStart(controller.getAnimation());
3056 }
3057 }
3058
Selim Cinek19cadc22014-04-16 17:27:19 +02003059 int clipSaveCount = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003060 final boolean clipToPadding = (flags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK;
3061 if (clipToPadding) {
Chris Craike4cf1522014-08-04 17:55:22 -07003062 clipSaveCount = canvas.save();
Romain Guy8f2d94f2009-03-25 18:04:42 -07003063 canvas.clipRect(mScrollX + mPaddingLeft, mScrollY + mPaddingTop,
3064 mScrollX + mRight - mLeft - mPaddingRight,
3065 mScrollY + mBottom - mTop - mPaddingBottom);
Selim Cinek19cadc22014-04-16 17:27:19 +02003066 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003067
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003068 // We will draw our child's animation, let's reset the flag
Dianne Hackborn4702a852012-08-17 15:18:29 -07003069 mPrivateFlags &= ~PFLAG_DRAW_ANIMATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003070 mGroupFlags &= ~FLAG_INVALIDATE_REQUIRED;
3071
3072 boolean more = false;
3073 final long drawingTime = getDrawingTime();
3074
Chris Craik8afd0f22014-08-21 17:41:57 -07003075 if (usingRenderNodeProperties) canvas.insertReorderBarrier();
Chris Craikab008f02014-05-23 17:55:03 -07003076 // Only use the preordered list if not HW accelerated, since the HW pipeline will do the
3077 // draw reordering internally
Chris Craika753f4c2014-07-24 12:39:17 -07003078 final ArrayList<View> preorderedList = usingRenderNodeProperties
Chris Craikab008f02014-05-23 17:55:03 -07003079 ? null : buildOrderedChildList();
3080 final boolean customOrder = preorderedList == null
3081 && isChildrenDrawingOrderEnabled();
3082 for (int i = 0; i < childrenCount; i++) {
3083 int childIndex = customOrder ? getChildDrawingOrder(childrenCount, i) : i;
3084 final View child = (preorderedList == null)
3085 ? children[childIndex] : preorderedList.get(childIndex);
3086 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
3087 more |= drawChild(canvas, child, drawingTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003088 }
3089 }
Chris Craikab008f02014-05-23 17:55:03 -07003090 if (preorderedList != null) preorderedList.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003091
3092 // Draw any disappearing views that have animations
3093 if (mDisappearingChildren != null) {
3094 final ArrayList<View> disappearingChildren = mDisappearingChildren;
3095 final int disappearingCount = disappearingChildren.size() - 1;
3096 // Go backwards -- we may delete as animations finish
3097 for (int i = disappearingCount; i >= 0; i--) {
3098 final View child = disappearingChildren.get(i);
3099 more |= drawChild(canvas, child, drawingTime);
3100 }
3101 }
Chris Craik8afd0f22014-08-21 17:41:57 -07003102 if (usingRenderNodeProperties) canvas.insertInorderBarrier();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003103
Philip Milne10ca24a2012-04-23 15:38:27 -07003104 if (debugDraw()) {
3105 onDebugDraw(canvas);
3106 }
3107
Chris Craike4cf1522014-08-04 17:55:22 -07003108 if (clipToPadding) {
Selim Cinek19cadc22014-04-16 17:27:19 +02003109 canvas.restoreToCount(clipSaveCount);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003110 }
3111
3112 // mGroupFlags might have been updated by drawChild()
3113 flags = mGroupFlags;
3114
3115 if ((flags & FLAG_INVALIDATE_REQUIRED) == FLAG_INVALIDATE_REQUIRED) {
Romain Guy849d0a32011-02-01 17:20:48 -08003116 invalidate(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003117 }
3118
3119 if ((flags & FLAG_ANIMATION_DONE) == 0 && (flags & FLAG_NOTIFY_ANIMATION_LISTENER) == 0 &&
3120 mLayoutAnimationController.isDone() && !more) {
3121 // We want to erase the drawing cache and notify the listener after the
3122 // next frame is drawn because one extra invalidate() is caused by
3123 // drawChild() after the animation is over
3124 mGroupFlags |= FLAG_NOTIFY_ANIMATION_LISTENER;
3125 final Runnable end = new Runnable() {
3126 public void run() {
3127 notifyAnimationListener();
3128 }
3129 };
3130 post(end);
3131 }
3132 }
Romain Guy8506ab42009-06-11 17:35:47 -07003133
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003134 /**
Chet Haaseedf6f4b2013-03-26 07:55:30 -07003135 * Returns the ViewGroupOverlay for this view group, creating it if it does
3136 * not yet exist. In addition to {@link ViewOverlay}'s support for drawables,
3137 * {@link ViewGroupOverlay} allows views to be added to the overlay. These
3138 * views, like overlay drawables, are visual-only; they do not receive input
3139 * events and should not be used as anything other than a temporary
3140 * representation of a view in a parent container, such as might be used
3141 * by an animation effect.
3142 *
Chet Haase95399492013-04-08 14:30:31 -07003143 * <p>Note: Overlays do not currently work correctly with {@link
3144 * SurfaceView} or {@link TextureView}; contents in overlays for these
3145 * types of views may not display correctly.</p>
3146 *
Chet Haaseedf6f4b2013-03-26 07:55:30 -07003147 * @return The ViewGroupOverlay object for this view.
3148 * @see ViewGroupOverlay
3149 */
3150 @Override
3151 public ViewGroupOverlay getOverlay() {
3152 if (mOverlay == null) {
3153 mOverlay = new ViewGroupOverlay(mContext, this);
3154 }
3155 return (ViewGroupOverlay) mOverlay;
3156 }
3157
3158 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003159 * Returns the index of the child to draw for this iteration. Override this
3160 * if you want to change the drawing order of children. By default, it
3161 * returns i.
3162 * <p>
Romain Guy293451e2009-11-04 13:59:48 -08003163 * NOTE: In order for this method to be called, you must enable child ordering
3164 * first by calling {@link #setChildrenDrawingOrderEnabled(boolean)}.
Romain Guy8506ab42009-06-11 17:35:47 -07003165 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003166 * @param i The current iteration.
3167 * @return The index of the child to draw this iteration.
Chet Haase5c13d892010-10-08 08:37:55 -07003168 *
Romain Guy293451e2009-11-04 13:59:48 -08003169 * @see #setChildrenDrawingOrderEnabled(boolean)
3170 * @see #isChildrenDrawingOrderEnabled()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003171 */
3172 protected int getChildDrawingOrder(int childCount, int i) {
3173 return i;
3174 }
Romain Guy8506ab42009-06-11 17:35:47 -07003175
Chris Craikab008f02014-05-23 17:55:03 -07003176 private boolean hasChildWithZ() {
3177 for (int i = 0; i < mChildrenCount; i++) {
3178 if (mChildren[i].getZ() != 0) return true;
3179 }
3180 return false;
3181 }
3182
3183 /**
3184 * Populates (and returns) mPreSortedChildren with a pre-ordered list of the View's children,
3185 * sorted first by Z, then by child drawing order (if applicable).
3186 *
3187 * Uses a stable, insertion sort which is commonly O(n) for ViewGroups with very few elevated
3188 * children.
3189 */
3190 private ArrayList<View> buildOrderedChildList() {
3191 final int count = mChildrenCount;
3192 if (count <= 1 || !hasChildWithZ()) return null;
3193
3194 if (mPreSortedChildren == null) {
3195 mPreSortedChildren = new ArrayList<View>(count);
3196 } else {
3197 mPreSortedChildren.ensureCapacity(count);
3198 }
3199
3200 final boolean useCustomOrder = isChildrenDrawingOrderEnabled();
3201 for (int i = 0; i < mChildrenCount; i++) {
3202 // add next child (in child order) to end of list
3203 int childIndex = useCustomOrder ? getChildDrawingOrder(mChildrenCount, i) : i;
3204 View nextChild = mChildren[childIndex];
3205 float currentZ = nextChild.getZ();
3206
3207 // insert ahead of any Views with greater Z
3208 int insertIndex = i;
3209 while (insertIndex > 0 && mPreSortedChildren.get(insertIndex - 1).getZ() > currentZ) {
3210 insertIndex--;
3211 }
3212 mPreSortedChildren.add(insertIndex, nextChild);
3213 }
3214 return mPreSortedChildren;
3215 }
3216
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003217 private void notifyAnimationListener() {
3218 mGroupFlags &= ~FLAG_NOTIFY_ANIMATION_LISTENER;
3219 mGroupFlags |= FLAG_ANIMATION_DONE;
3220
3221 if (mAnimationListener != null) {
3222 final Runnable end = new Runnable() {
3223 public void run() {
3224 mAnimationListener.onAnimationEnd(mLayoutAnimationController.getAnimation());
3225 }
3226 };
3227 post(end);
3228 }
3229
3230 if ((mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE) {
3231 mGroupFlags &= ~FLAG_CHILDREN_DRAWN_WITH_CACHE;
3232 if ((mPersistentDrawingCache & PERSISTENT_ANIMATION_CACHE) == 0) {
3233 setChildrenDrawingCacheEnabled(false);
3234 }
3235 }
3236
Romain Guy849d0a32011-02-01 17:20:48 -08003237 invalidate(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003238 }
3239
3240 /**
Chet Haasedaf98e92011-01-10 14:10:36 -08003241 * This method is used to cause children of this ViewGroup to restore or recreate their
3242 * display lists. It is called by getDisplayList() when the parent ViewGroup does not need
3243 * to recreate its own display list, which would happen if it went through the normal
3244 * draw/dispatchDraw mechanisms.
3245 *
3246 * @hide
3247 */
3248 @Override
3249 protected void dispatchGetDisplayList() {
3250 final int count = mChildrenCount;
3251 final View[] children = mChildren;
3252 for (int i = 0; i < count; i++) {
3253 final View child = children[i];
Romain Guy59c7f802011-09-29 17:21:45 -07003254 if (((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) &&
3255 child.hasStaticLayer()) {
Chet Haase6c0665f2014-08-01 13:32:27 -07003256 recreateChildDisplayList(child);
Romain Guy2f57ba52011-02-03 18:03:29 -08003257 }
Chet Haasedaf98e92011-01-10 14:10:36 -08003258 }
Chet Haase91cedf12013-03-11 07:56:30 -07003259 if (mOverlay != null) {
Chet Haaseedf6f4b2013-03-26 07:55:30 -07003260 View overlayView = mOverlay.getOverlayView();
Chet Haase6c0665f2014-08-01 13:32:27 -07003261 recreateChildDisplayList(overlayView);
Chet Haase91cedf12013-03-11 07:56:30 -07003262 }
Chet Haase6c0665f2014-08-01 13:32:27 -07003263 if (mDisappearingChildren != null) {
3264 final ArrayList<View> disappearingChildren = mDisappearingChildren;
3265 final int disappearingCount = disappearingChildren.size();
3266 for (int i = 0; i < disappearingCount; ++i) {
3267 final View child = disappearingChildren.get(i);
3268 recreateChildDisplayList(child);
3269 }
3270 }
3271 }
3272
3273 private void recreateChildDisplayList(View child) {
3274 child.mRecreateDisplayList = (child.mPrivateFlags & PFLAG_INVALIDATED)
3275 == PFLAG_INVALIDATED;
3276 child.mPrivateFlags &= ~PFLAG_INVALIDATED;
3277 child.getDisplayList();
3278 child.mRecreateDisplayList = false;
Chet Haasedaf98e92011-01-10 14:10:36 -08003279 }
3280
3281 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003282 * Draw one child of this View Group. This method is responsible for getting
3283 * the canvas in the right state. This includes clipping, translating so
3284 * that the child's scrolled origin is at 0, 0, and applying any animation
3285 * transformations.
3286 *
3287 * @param canvas The canvas on which to draw the child
3288 * @param child Who to draw
Chet Haasebcca79a2012-02-14 08:45:14 -08003289 * @param drawingTime The time at which draw is occurring
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003290 * @return True if an invalidate() was issued
3291 */
3292 protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
Chet Haase64a48c12012-02-13 16:33:29 -08003293 return child.draw(canvas, this, drawingTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003294 }
3295
3296 /**
Chris Craikd863a102013-12-19 13:31:15 -08003297 * Returns whether this group's children are clipped to their bounds before drawing.
Chet Haase430742f2013-04-12 11:18:36 -07003298 * The default value is true.
3299 * @see #setClipChildren(boolean)
3300 *
3301 * @return True if the group's children will be clipped to their bounds,
3302 * false otherwise.
3303 */
3304 public boolean getClipChildren() {
3305 return ((mGroupFlags & FLAG_CLIP_CHILDREN) != 0);
3306 }
3307
3308 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003309 * By default, children are clipped to their bounds before drawing. This
3310 * allows view groups to override this behavior for animations, etc.
3311 *
3312 * @param clipChildren true to clip children to their bounds,
3313 * false otherwise
3314 * @attr ref android.R.styleable#ViewGroup_clipChildren
3315 */
3316 public void setClipChildren(boolean clipChildren) {
Chet Haasea1cff502012-02-21 13:43:44 -08003317 boolean previousValue = (mGroupFlags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN;
3318 if (clipChildren != previousValue) {
3319 setBooleanFlag(FLAG_CLIP_CHILDREN, clipChildren);
Chet Haase1271e2c2012-04-20 09:54:27 -07003320 for (int i = 0; i < mChildrenCount; ++i) {
3321 View child = getChildAt(i);
Chris Craik64a12e12014-03-28 18:12:12 -07003322 if (child.mRenderNode != null) {
3323 child.mRenderNode.setClipToBounds(clipChildren);
Chet Haasea1cff502012-02-21 13:43:44 -08003324 }
3325 }
John Reckaae9f3b2014-07-28 09:30:36 -07003326 invalidate(true);
Chet Haasea1cff502012-02-21 13:43:44 -08003327 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003328 }
3329
3330 /**
3331 * By default, children are clipped to the padding of the ViewGroup. This
3332 * allows view groups to override this behavior
3333 *
3334 * @param clipToPadding true to clip children to the padding of the
3335 * group, false otherwise
3336 * @attr ref android.R.styleable#ViewGroup_clipToPadding
3337 */
3338 public void setClipToPadding(boolean clipToPadding) {
John Reck9fa3a242014-06-27 15:57:19 -07003339 if (hasBooleanFlag(FLAG_CLIP_TO_PADDING) != clipToPadding) {
3340 setBooleanFlag(FLAG_CLIP_TO_PADDING, clipToPadding);
John Reckaae9f3b2014-07-28 09:30:36 -07003341 invalidate(true);
John Reck9fa3a242014-06-27 15:57:19 -07003342 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003343 }
3344
3345 /**
Adam Powell1c35b082014-07-11 15:37:15 -07003346 * Check if this ViewGroup is configured to clip child views to its padding.
3347 *
3348 * @return true if this ViewGroup clips children to its padding, false otherwise
3349 *
3350 * @attr ref android.R.styleable#ViewGroup_clipToPadding
3351 */
3352 public boolean getClipToPadding() {
3353 return hasBooleanFlag(FLAG_CLIP_TO_PADDING);
3354 }
3355
3356 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003357 * {@inheritDoc}
3358 */
3359 @Override
3360 public void dispatchSetSelected(boolean selected) {
3361 final View[] children = mChildren;
3362 final int count = mChildrenCount;
3363 for (int i = 0; i < count; i++) {
3364 children[i].setSelected(selected);
3365 }
3366 }
Romain Guy8506ab42009-06-11 17:35:47 -07003367
Dianne Hackbornd0fa3712010-09-14 18:57:14 -07003368 /**
3369 * {@inheritDoc}
3370 */
3371 @Override
3372 public void dispatchSetActivated(boolean activated) {
3373 final View[] children = mChildren;
3374 final int count = mChildrenCount;
3375 for (int i = 0; i < count; i++) {
Dianne Hackbornd0fa3712010-09-14 18:57:14 -07003376 children[i].setActivated(activated);
3377 }
3378 }
3379
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003380 @Override
3381 protected void dispatchSetPressed(boolean pressed) {
3382 final View[] children = mChildren;
3383 final int count = mChildrenCount;
3384 for (int i = 0; i < count; i++) {
Adam Powell035a1fc2012-02-27 15:23:50 -08003385 final View child = children[i];
3386 // Children that are clickable on their own should not
3387 // show a pressed state when their parent view does.
3388 // Clearing a pressed state always propagates.
3389 if (!pressed || (!child.isClickable() && !child.isLongClickable())) {
3390 child.setPressed(pressed);
3391 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003392 }
3393 }
3394
Adam Powell14874662013-07-18 19:42:41 -07003395 @Override
3396 void dispatchCancelPendingInputEvents() {
3397 super.dispatchCancelPendingInputEvents();
3398
3399 final View[] children = mChildren;
3400 final int count = mChildrenCount;
3401 for (int i = 0; i < count; i++) {
3402 children[i].dispatchCancelPendingInputEvents();
3403 }
3404 }
3405
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003406 /**
3407 * When this property is set to true, this ViewGroup supports static transformations on
3408 * children; this causes
3409 * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} to be
3410 * invoked when a child is drawn.
3411 *
3412 * Any subclass overriding
3413 * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} should
3414 * set this property to true.
3415 *
3416 * @param enabled True to enable static transformations on children, false otherwise.
3417 *
Chet Haase599913d2012-07-23 16:22:05 -07003418 * @see #getChildStaticTransformation(View, android.view.animation.Transformation)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003419 */
3420 protected void setStaticTransformationsEnabled(boolean enabled) {
3421 setBooleanFlag(FLAG_SUPPORT_STATIC_TRANSFORMATIONS, enabled);
3422 }
3423
3424 /**
Chet Haase2d46fcc2011-12-19 18:01:05 -08003425 * Sets <code>t</code> to be the static transformation of the child, if set, returning a
3426 * boolean to indicate whether a static transform was set. The default implementation
3427 * simply returns <code>false</code>; subclasses may override this method for different
Chet Haase599913d2012-07-23 16:22:05 -07003428 * behavior. {@link #setStaticTransformationsEnabled(boolean)} must be set to true
3429 * for this method to be called.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003430 *
Chet Haase2d46fcc2011-12-19 18:01:05 -08003431 * @param child The child view whose static transform is being requested
3432 * @param t The Transformation which will hold the result
3433 * @return true if the transformation was set, false otherwise
Romain Guy8506ab42009-06-11 17:35:47 -07003434 * @see #setStaticTransformationsEnabled(boolean)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003435 */
3436 protected boolean getChildStaticTransformation(View child, Transformation t) {
3437 return false;
3438 }
3439
Romain Guyf6991302013-06-05 17:19:01 -07003440 Transformation getChildTransformation() {
3441 if (mChildTransformation == null) {
3442 mChildTransformation = new Transformation();
3443 }
3444 return mChildTransformation;
3445 }
3446
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003447 /**
3448 * {@hide}
3449 */
3450 @Override
3451 protected View findViewTraversal(int id) {
3452 if (id == mID) {
3453 return this;
3454 }
3455
3456 final View[] where = mChildren;
3457 final int len = mChildrenCount;
3458
3459 for (int i = 0; i < len; i++) {
3460 View v = where[i];
3461
Dianne Hackborn4702a852012-08-17 15:18:29 -07003462 if ((v.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003463 v = v.findViewById(id);
3464
3465 if (v != null) {
3466 return v;
3467 }
3468 }
3469 }
3470
3471 return null;
3472 }
3473
3474 /**
3475 * {@hide}
3476 */
3477 @Override
3478 protected View findViewWithTagTraversal(Object tag) {
3479 if (tag != null && tag.equals(mTag)) {
3480 return this;
3481 }
3482
3483 final View[] where = mChildren;
3484 final int len = mChildrenCount;
3485
3486 for (int i = 0; i < len; i++) {
3487 View v = where[i];
3488
Dianne Hackborn4702a852012-08-17 15:18:29 -07003489 if ((v.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003490 v = v.findViewWithTag(tag);
3491
3492 if (v != null) {
3493 return v;
3494 }
3495 }
3496 }
3497
3498 return null;
3499 }
3500
3501 /**
Jeff Brown4e6319b2010-12-13 10:36:51 -08003502 * {@hide}
3503 */
3504 @Override
Jeff Brown4dfbec22011-08-15 14:55:37 -07003505 protected View findViewByPredicateTraversal(Predicate<View> predicate, View childToSkip) {
Jeff Brown4e6319b2010-12-13 10:36:51 -08003506 if (predicate.apply(this)) {
3507 return this;
3508 }
3509
3510 final View[] where = mChildren;
3511 final int len = mChildrenCount;
3512
3513 for (int i = 0; i < len; i++) {
3514 View v = where[i];
3515
Dianne Hackborn4702a852012-08-17 15:18:29 -07003516 if (v != childToSkip && (v.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) {
Jeff Brown4e6319b2010-12-13 10:36:51 -08003517 v = v.findViewByPredicate(predicate);
3518
3519 if (v != null) {
3520 return v;
3521 }
3522 }
3523 }
3524
3525 return null;
3526 }
3527
3528 /**
Romain Guy393a52c2012-05-22 20:21:08 -07003529 * <p>Adds a child view. If no layout parameters are already set on the child, the
3530 * default parameters for this ViewGroup are set on the child.</p>
3531 *
3532 * <p><strong>Note:</strong> do not invoke this method from
3533 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3534 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003535 *
3536 * @param child the child view to add
3537 *
3538 * @see #generateDefaultLayoutParams()
3539 */
3540 public void addView(View child) {
3541 addView(child, -1);
3542 }
3543
3544 /**
3545 * Adds a child view. If no layout parameters are already set on the child, the
3546 * default parameters for this ViewGroup are set on the child.
Romain Guy393a52c2012-05-22 20:21:08 -07003547 *
3548 * <p><strong>Note:</strong> do not invoke this method from
3549 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3550 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003551 *
3552 * @param child the child view to add
3553 * @param index the position at which to add the child
3554 *
3555 * @see #generateDefaultLayoutParams()
3556 */
3557 public void addView(View child, int index) {
3558 LayoutParams params = child.getLayoutParams();
3559 if (params == null) {
3560 params = generateDefaultLayoutParams();
3561 if (params == null) {
3562 throw new IllegalArgumentException("generateDefaultLayoutParams() cannot return null");
3563 }
3564 }
3565 addView(child, index, params);
3566 }
3567
3568 /**
3569 * Adds a child view with this ViewGroup's default layout parameters and the
3570 * specified width and height.
3571 *
Romain Guy393a52c2012-05-22 20:21:08 -07003572 * <p><strong>Note:</strong> do not invoke this method from
3573 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3574 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
3575 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003576 * @param child the child view to add
3577 */
3578 public void addView(View child, int width, int height) {
3579 final LayoutParams params = generateDefaultLayoutParams();
3580 params.width = width;
3581 params.height = height;
3582 addView(child, -1, params);
3583 }
3584
3585 /**
3586 * Adds a child view with the specified layout parameters.
3587 *
Romain Guy393a52c2012-05-22 20:21:08 -07003588 * <p><strong>Note:</strong> do not invoke this method from
3589 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3590 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
3591 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003592 * @param child the child view to add
3593 * @param params the layout parameters to set on the child
3594 */
3595 public void addView(View child, LayoutParams params) {
3596 addView(child, -1, params);
3597 }
3598
3599 /**
3600 * Adds a child view with the specified layout parameters.
3601 *
Romain Guy393a52c2012-05-22 20:21:08 -07003602 * <p><strong>Note:</strong> do not invoke this method from
3603 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3604 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
3605 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003606 * @param child the child view to add
3607 * @param index the position at which to add the child
3608 * @param params the layout parameters to set on the child
3609 */
3610 public void addView(View child, int index, LayoutParams params) {
3611 if (DBG) {
3612 System.out.println(this + " addView");
3613 }
3614
3615 // addViewInner() will call child.requestLayout() when setting the new LayoutParams
3616 // therefore, we call requestLayout() on ourselves before, so that the child's request
3617 // will be blocked at our level
3618 requestLayout();
Romain Guy849d0a32011-02-01 17:20:48 -08003619 invalidate(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003620 addViewInner(child, index, params, false);
3621 }
3622
3623 /**
3624 * {@inheritDoc}
3625 */
3626 public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
3627 if (!checkLayoutParams(params)) {
3628 throw new IllegalArgumentException("Invalid LayoutParams supplied to " + this);
3629 }
3630 if (view.mParent != this) {
3631 throw new IllegalArgumentException("Given view not a child of " + this);
3632 }
3633 view.setLayoutParams(params);
3634 }
3635
3636 /**
3637 * {@inheritDoc}
3638 */
3639 protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
3640 return p != null;
3641 }
3642
3643 /**
3644 * Interface definition for a callback to be invoked when the hierarchy
3645 * within this view changed. The hierarchy changes whenever a child is added
3646 * to or removed from this view.
3647 */
3648 public interface OnHierarchyChangeListener {
3649 /**
3650 * Called when a new child is added to a parent view.
3651 *
3652 * @param parent the view in which a child was added
3653 * @param child the new child view added in the hierarchy
3654 */
3655 void onChildViewAdded(View parent, View child);
3656
3657 /**
3658 * Called when a child is removed from a parent view.
3659 *
3660 * @param parent the view from which the child was removed
3661 * @param child the child removed from the hierarchy
3662 */
3663 void onChildViewRemoved(View parent, View child);
3664 }
3665
3666 /**
3667 * Register a callback to be invoked when a child is added to or removed
3668 * from this view.
3669 *
3670 * @param listener the callback to invoke on hierarchy change
3671 */
3672 public void setOnHierarchyChangeListener(OnHierarchyChangeListener listener) {
3673 mOnHierarchyChangeListener = listener;
3674 }
3675
3676 /**
Philip Milnef51d91c2011-07-18 16:12:19 -07003677 * @hide
3678 */
3679 protected void onViewAdded(View child) {
3680 if (mOnHierarchyChangeListener != null) {
3681 mOnHierarchyChangeListener.onChildViewAdded(this, child);
3682 }
3683 }
3684
3685 /**
3686 * @hide
3687 */
3688 protected void onViewRemoved(View child) {
3689 if (mOnHierarchyChangeListener != null) {
3690 mOnHierarchyChangeListener.onChildViewRemoved(this, child);
3691 }
3692 }
3693
Philip Milnecfb631b2012-10-26 10:51:46 -07003694 private void clearCachedLayoutMode() {
Svetoslav6254f482013-06-04 17:22:14 -07003695 if (!hasBooleanFlag(FLAG_LAYOUT_MODE_WAS_EXPLICITLY_SET)) {
Philip Milnecfb631b2012-10-26 10:51:46 -07003696 mLayoutMode = LAYOUT_MODE_UNDEFINED;
3697 }
3698 }
3699
3700 @Override
3701 protected void onAttachedToWindow() {
3702 super.onAttachedToWindow();
3703 clearCachedLayoutMode();
3704 }
3705
3706 @Override
3707 protected void onDetachedFromWindow() {
3708 super.onDetachedFromWindow();
3709 clearCachedLayoutMode();
3710 }
3711
Philip Milnef51d91c2011-07-18 16:12:19 -07003712 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003713 * Adds a view during layout. This is useful if in your onLayout() method,
3714 * you need to add more views (as does the list view for example).
3715 *
3716 * If index is negative, it means put it at the end of the list.
3717 *
3718 * @param child the view to add to the group
3719 * @param index the index at which the child must be added
3720 * @param params the layout parameters to associate with the child
3721 * @return true if the child was added, false otherwise
3722 */
3723 protected boolean addViewInLayout(View child, int index, LayoutParams params) {
3724 return addViewInLayout(child, index, params, false);
3725 }
3726
3727 /**
3728 * Adds a view during layout. This is useful if in your onLayout() method,
3729 * you need to add more views (as does the list view for example).
3730 *
3731 * If index is negative, it means put it at the end of the list.
3732 *
3733 * @param child the view to add to the group
3734 * @param index the index at which the child must be added
3735 * @param params the layout parameters to associate with the child
3736 * @param preventRequestLayout if true, calling this method will not trigger a
3737 * layout request on child
3738 * @return true if the child was added, false otherwise
3739 */
3740 protected boolean addViewInLayout(View child, int index, LayoutParams params,
3741 boolean preventRequestLayout) {
3742 child.mParent = null;
3743 addViewInner(child, index, params, preventRequestLayout);
Dianne Hackborn4702a852012-08-17 15:18:29 -07003744 child.mPrivateFlags = (child.mPrivateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003745 return true;
3746 }
3747
3748 /**
3749 * Prevents the specified child to be laid out during the next layout pass.
3750 *
3751 * @param child the child on which to perform the cleanup
3752 */
3753 protected void cleanupLayoutState(View child) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07003754 child.mPrivateFlags &= ~View.PFLAG_FORCE_LAYOUT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003755 }
3756
3757 private void addViewInner(View child, int index, LayoutParams params,
3758 boolean preventRequestLayout) {
3759
Chet Haasee8e45d32011-03-02 17:07:35 -08003760 if (mTransition != null) {
3761 // Don't prevent other add transitions from completing, but cancel remove
3762 // transitions to let them complete the process before we add to the container
3763 mTransition.cancel(LayoutTransition.DISAPPEARING);
Chet Haaseadd65772011-02-09 16:47:29 -08003764 }
3765
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003766 if (child.getParent() != null) {
3767 throw new IllegalStateException("The specified child already has a parent. " +
3768 "You must call removeView() on the child's parent first.");
3769 }
3770
Chet Haase21cd1382010-09-01 17:42:29 -07003771 if (mTransition != null) {
Chet Haase5e25c2c2010-09-16 11:15:56 -07003772 mTransition.addChild(this, child);
Chet Haase21cd1382010-09-01 17:42:29 -07003773 }
3774
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003775 if (!checkLayoutParams(params)) {
3776 params = generateLayoutParams(params);
3777 }
3778
3779 if (preventRequestLayout) {
3780 child.mLayoutParams = params;
3781 } else {
3782 child.setLayoutParams(params);
3783 }
3784
3785 if (index < 0) {
3786 index = mChildrenCount;
3787 }
3788
3789 addInArray(child, index);
3790
3791 // tell our children
3792 if (preventRequestLayout) {
3793 child.assignParent(this);
3794 } else {
3795 child.mParent = this;
3796 }
3797
3798 if (child.hasFocus()) {
3799 requestChildFocus(child, child.findFocus());
3800 }
Romain Guy8506ab42009-06-11 17:35:47 -07003801
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003802 AttachInfo ai = mAttachInfo;
Adam Powell4b867882011-09-16 12:59:46 -07003803 if (ai != null && (mGroupFlags & FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW) == 0) {
Romain Guy8506ab42009-06-11 17:35:47 -07003804 boolean lastKeepOn = ai.mKeepScreenOn;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003805 ai.mKeepScreenOn = false;
3806 child.dispatchAttachedToWindow(mAttachInfo, (mViewFlags&VISIBILITY_MASK));
3807 if (ai.mKeepScreenOn) {
3808 needGlobalAttributesUpdate(true);
3809 }
3810 ai.mKeepScreenOn = lastKeepOn;
3811 }
3812
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07003813 if (child.isLayoutDirectionInherited()) {
Fabrice Di Meglioa7e0bcd2012-10-16 19:55:01 -07003814 child.resetRtlProperties();
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07003815 }
3816
Philip Milnef51d91c2011-07-18 16:12:19 -07003817 onViewAdded(child);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003818
3819 if ((child.mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE) {
3820 mGroupFlags |= FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE;
3821 }
Adam Powell539ee872012-02-03 19:00:49 -08003822
3823 if (child.hasTransientState()) {
3824 childHasTransientStateChanged(child, true);
3825 }
Svetoslav6254f482013-06-04 17:22:14 -07003826
Svetoslav8e3feb12014-02-24 13:46:47 -08003827 if (child.getVisibility() != View.GONE) {
Svetoslav00dbe812013-06-10 12:51:09 -07003828 notifySubtreeAccessibilityStateChangedIfNeeded();
Svetoslav6254f482013-06-04 17:22:14 -07003829 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003830 }
3831
3832 private void addInArray(View child, int index) {
3833 View[] children = mChildren;
3834 final int count = mChildrenCount;
3835 final int size = children.length;
3836 if (index == count) {
3837 if (size == count) {
3838 mChildren = new View[size + ARRAY_CAPACITY_INCREMENT];
3839 System.arraycopy(children, 0, mChildren, 0, size);
3840 children = mChildren;
3841 }
3842 children[mChildrenCount++] = child;
3843 } else if (index < count) {
3844 if (size == count) {
3845 mChildren = new View[size + ARRAY_CAPACITY_INCREMENT];
3846 System.arraycopy(children, 0, mChildren, 0, index);
3847 System.arraycopy(children, index, mChildren, index + 1, count - index);
3848 children = mChildren;
3849 } else {
3850 System.arraycopy(children, index, children, index + 1, count - index);
3851 }
3852 children[index] = child;
3853 mChildrenCount++;
Joe Onorato03ab0c72011-01-06 15:46:27 -08003854 if (mLastTouchDownIndex >= index) {
3855 mLastTouchDownIndex++;
3856 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003857 } else {
3858 throw new IndexOutOfBoundsException("index=" + index + " count=" + count);
3859 }
3860 }
3861
3862 // This method also sets the child's mParent to null
3863 private void removeFromArray(int index) {
3864 final View[] children = mChildren;
Chet Haase21cd1382010-09-01 17:42:29 -07003865 if (!(mTransitioningViews != null && mTransitioningViews.contains(children[index]))) {
3866 children[index].mParent = null;
3867 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003868 final int count = mChildrenCount;
3869 if (index == count - 1) {
3870 children[--mChildrenCount] = null;
3871 } else if (index >= 0 && index < count) {
3872 System.arraycopy(children, index + 1, children, index, count - index - 1);
3873 children[--mChildrenCount] = null;
3874 } else {
3875 throw new IndexOutOfBoundsException();
3876 }
Joe Onorato03ab0c72011-01-06 15:46:27 -08003877 if (mLastTouchDownIndex == index) {
3878 mLastTouchDownTime = 0;
3879 mLastTouchDownIndex = -1;
3880 } else if (mLastTouchDownIndex > index) {
3881 mLastTouchDownIndex--;
3882 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003883 }
3884
3885 // This method also sets the children's mParent to null
3886 private void removeFromArray(int start, int count) {
3887 final View[] children = mChildren;
3888 final int childrenCount = mChildrenCount;
3889
3890 start = Math.max(0, start);
3891 final int end = Math.min(childrenCount, start + count);
3892
3893 if (start == end) {
3894 return;
3895 }
3896
3897 if (end == childrenCount) {
3898 for (int i = start; i < end; i++) {
3899 children[i].mParent = null;
3900 children[i] = null;
3901 }
3902 } else {
3903 for (int i = start; i < end; i++) {
3904 children[i].mParent = null;
3905 }
3906
3907 // Since we're looping above, we might as well do the copy, but is arraycopy()
3908 // faster than the extra 2 bounds checks we would do in the loop?
3909 System.arraycopy(children, end, children, start, childrenCount - end);
3910
3911 for (int i = childrenCount - (end - start); i < childrenCount; i++) {
3912 children[i] = null;
3913 }
3914 }
3915
3916 mChildrenCount -= (end - start);
3917 }
3918
3919 private void bindLayoutAnimation(View child) {
3920 Animation a = mLayoutAnimationController.getAnimationForView(child);
3921 child.setAnimation(a);
3922 }
3923
3924 /**
3925 * Subclasses should override this method to set layout animation
3926 * parameters on the supplied child.
3927 *
3928 * @param child the child to associate with animation parameters
3929 * @param params the child's layout parameters which hold the animation
3930 * parameters
3931 * @param index the index of the child in the view group
3932 * @param count the number of children in the view group
3933 */
3934 protected void attachLayoutAnimationParameters(View child,
3935 LayoutParams params, int index, int count) {
3936 LayoutAnimationController.AnimationParameters animationParams =
3937 params.layoutAnimationParameters;
3938 if (animationParams == null) {
3939 animationParams = new LayoutAnimationController.AnimationParameters();
3940 params.layoutAnimationParameters = animationParams;
3941 }
3942
3943 animationParams.count = count;
3944 animationParams.index = index;
3945 }
3946
3947 /**
3948 * {@inheritDoc}
Romain Guy393a52c2012-05-22 20:21:08 -07003949 *
3950 * <p><strong>Note:</strong> do not invoke this method from
3951 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3952 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003953 */
3954 public void removeView(View view) {
3955 removeViewInternal(view);
3956 requestLayout();
Romain Guy849d0a32011-02-01 17:20:48 -08003957 invalidate(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003958 }
3959
3960 /**
3961 * Removes a view during layout. This is useful if in your onLayout() method,
3962 * you need to remove more views.
3963 *
Romain Guy393a52c2012-05-22 20:21:08 -07003964 * <p><strong>Note:</strong> do not invoke this method from
3965 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3966 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
3967 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003968 * @param view the view to remove from the group
3969 */
3970 public void removeViewInLayout(View view) {
3971 removeViewInternal(view);
3972 }
3973
3974 /**
3975 * Removes a range of views during layout. This is useful if in your onLayout() method,
3976 * you need to remove more views.
3977 *
Romain Guy393a52c2012-05-22 20:21:08 -07003978 * <p><strong>Note:</strong> do not invoke this method from
3979 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3980 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
3981 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003982 * @param start the index of the first view to remove from the group
3983 * @param count the number of views to remove from the group
3984 */
3985 public void removeViewsInLayout(int start, int count) {
3986 removeViewsInternal(start, count);
3987 }
3988
3989 /**
3990 * Removes the view at the specified position in the group.
3991 *
Romain Guy393a52c2012-05-22 20:21:08 -07003992 * <p><strong>Note:</strong> do not invoke this method from
3993 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3994 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
3995 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003996 * @param index the position in the group of the view to remove
3997 */
3998 public void removeViewAt(int index) {
3999 removeViewInternal(index, getChildAt(index));
4000 requestLayout();
Romain Guy849d0a32011-02-01 17:20:48 -08004001 invalidate(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004002 }
4003
4004 /**
4005 * Removes the specified range of views from the group.
4006 *
Romain Guy393a52c2012-05-22 20:21:08 -07004007 * <p><strong>Note:</strong> do not invoke this method from
4008 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
4009 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
4010 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004011 * @param start the first position in the group of the range of views to remove
4012 * @param count the number of views to remove
4013 */
4014 public void removeViews(int start, int count) {
4015 removeViewsInternal(start, count);
4016 requestLayout();
Romain Guy849d0a32011-02-01 17:20:48 -08004017 invalidate(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004018 }
4019
4020 private void removeViewInternal(View view) {
4021 final int index = indexOfChild(view);
4022 if (index >= 0) {
4023 removeViewInternal(index, view);
4024 }
4025 }
4026
4027 private void removeViewInternal(int index, View view) {
Chet Haase21cd1382010-09-01 17:42:29 -07004028
4029 if (mTransition != null) {
Chet Haase5e25c2c2010-09-16 11:15:56 -07004030 mTransition.removeChild(this, view);
Chet Haase21cd1382010-09-01 17:42:29 -07004031 }
4032
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004033 boolean clearChildFocus = false;
4034 if (view == mFocused) {
Alan Viverette223622a2013-12-17 13:29:02 -08004035 view.unFocus(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004036 clearChildFocus = true;
4037 }
4038
Svetoslav Ganov149567f2013-01-08 15:23:34 -08004039 if (view.isAccessibilityFocused()) {
4040 view.clearAccessibilityFocus();
4041 }
Svetoslav Ganov961bf0e2012-05-08 09:40:03 -07004042
Jeff Brown59a422e2012-04-19 15:19:19 -07004043 cancelTouchTarget(view);
4044 cancelHoverTarget(view);
4045
Chet Haase21cd1382010-09-01 17:42:29 -07004046 if (view.getAnimation() != null ||
4047 (mTransitioningViews != null && mTransitioningViews.contains(view))) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004048 addDisappearingView(view);
4049 } else if (view.mAttachInfo != null) {
4050 view.dispatchDetachedFromWindow();
4051 }
4052
Adam Powell539ee872012-02-03 19:00:49 -08004053 if (view.hasTransientState()) {
4054 childHasTransientStateChanged(view, false);
4055 }
4056
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004057 needGlobalAttributesUpdate(false);
Romain Guy8506ab42009-06-11 17:35:47 -07004058
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004059 removeFromArray(index);
4060
4061 if (clearChildFocus) {
4062 clearChildFocus(view);
Svetoslav Ganov149567f2013-01-08 15:23:34 -08004063 if (!rootViewRequestFocus()) {
4064 notifyGlobalFocusCleared(this);
4065 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07004066 }
Romain Guy6fb05632012-11-29 10:50:33 -08004067
4068 onViewRemoved(view);
Svetoslav6254f482013-06-04 17:22:14 -07004069
Svetoslav8e3feb12014-02-24 13:46:47 -08004070 if (view.getVisibility() != View.GONE) {
Svetoslav00dbe812013-06-10 12:51:09 -07004071 notifySubtreeAccessibilityStateChangedIfNeeded();
Svetoslav6254f482013-06-04 17:22:14 -07004072 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004073 }
4074
Chet Haase21cd1382010-09-01 17:42:29 -07004075 /**
4076 * Sets the LayoutTransition object for this ViewGroup. If the LayoutTransition object is
4077 * not null, changes in layout which occur because of children being added to or removed from
4078 * the ViewGroup will be animated according to the animations defined in that LayoutTransition
4079 * object. By default, the transition object is null (so layout changes are not animated).
4080 *
Chet Haaseef3cbfd2013-08-21 14:01:02 -07004081 * <p>Replacing a non-null transition will cause that previous transition to be
4082 * canceled, if it is currently running, to restore this container to
4083 * its correct post-transition state.</p>
4084 *
Chet Haase21cd1382010-09-01 17:42:29 -07004085 * @param transition The LayoutTransition object that will animated changes in layout. A value
4086 * of <code>null</code> means no transition will run on layout changes.
Chet Haase13cc1202010-09-03 15:39:20 -07004087 * @attr ref android.R.styleable#ViewGroup_animateLayoutChanges
Chet Haase21cd1382010-09-01 17:42:29 -07004088 */
4089 public void setLayoutTransition(LayoutTransition transition) {
Chet Haaseb20db3e2010-09-10 13:07:30 -07004090 if (mTransition != null) {
Chet Haasefee6f2b2013-08-27 12:22:29 -07004091 LayoutTransition previousTransition = mTransition;
4092 previousTransition.cancel();
4093 previousTransition.removeTransitionListener(mLayoutTransitionListener);
Chet Haaseb20db3e2010-09-10 13:07:30 -07004094 }
Chet Haase21cd1382010-09-01 17:42:29 -07004095 mTransition = transition;
Chet Haase13cc1202010-09-03 15:39:20 -07004096 if (mTransition != null) {
4097 mTransition.addTransitionListener(mLayoutTransitionListener);
4098 }
4099 }
4100
4101 /**
4102 * Gets the LayoutTransition object for this ViewGroup. If the LayoutTransition object is
4103 * not null, changes in layout which occur because of children being added to or removed from
4104 * the ViewGroup will be animated according to the animations defined in that LayoutTransition
4105 * object. By default, the transition object is null (so layout changes are not animated).
4106 *
4107 * @return LayoutTranstion The LayoutTransition object that will animated changes in layout.
4108 * A value of <code>null</code> means no transition will run on layout changes.
4109 */
4110 public LayoutTransition getLayoutTransition() {
4111 return mTransition;
Chet Haase21cd1382010-09-01 17:42:29 -07004112 }
4113
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004114 private void removeViewsInternal(int start, int count) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004115 final View focused = mFocused;
4116 final boolean detach = mAttachInfo != null;
Svetoslav Ganov149567f2013-01-08 15:23:34 -08004117 boolean clearChildFocus = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004118
4119 final View[] children = mChildren;
4120 final int end = start + count;
4121
4122 for (int i = start; i < end; i++) {
4123 final View view = children[i];
4124
Chet Haase21cd1382010-09-01 17:42:29 -07004125 if (mTransition != null) {
Chet Haase5e25c2c2010-09-16 11:15:56 -07004126 mTransition.removeChild(this, view);
Chet Haase21cd1382010-09-01 17:42:29 -07004127 }
4128
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004129 if (view == focused) {
Alan Viverette223622a2013-12-17 13:29:02 -08004130 view.unFocus(null);
Svetoslav Ganov149567f2013-01-08 15:23:34 -08004131 clearChildFocus = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004132 }
4133
Svetoslav Ganov149567f2013-01-08 15:23:34 -08004134 if (view.isAccessibilityFocused()) {
4135 view.clearAccessibilityFocus();
4136 }
Svetoslav Ganov961bf0e2012-05-08 09:40:03 -07004137
Jeff Brown59a422e2012-04-19 15:19:19 -07004138 cancelTouchTarget(view);
4139 cancelHoverTarget(view);
4140
Chet Haase21cd1382010-09-01 17:42:29 -07004141 if (view.getAnimation() != null ||
4142 (mTransitioningViews != null && mTransitioningViews.contains(view))) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004143 addDisappearingView(view);
4144 } else if (detach) {
4145 view.dispatchDetachedFromWindow();
4146 }
4147
Adam Powell539ee872012-02-03 19:00:49 -08004148 if (view.hasTransientState()) {
4149 childHasTransientStateChanged(view, false);
4150 }
4151
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004152 needGlobalAttributesUpdate(false);
Romain Guy8506ab42009-06-11 17:35:47 -07004153
Philip Milnef51d91c2011-07-18 16:12:19 -07004154 onViewRemoved(view);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004155 }
4156
4157 removeFromArray(start, count);
4158
Svetoslav Ganov149567f2013-01-08 15:23:34 -08004159 if (clearChildFocus) {
4160 clearChildFocus(focused);
4161 if (!rootViewRequestFocus()) {
4162 notifyGlobalFocusCleared(focused);
4163 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004164 }
4165 }
4166
4167 /**
4168 * Call this method to remove all child views from the
4169 * ViewGroup.
Romain Guy393a52c2012-05-22 20:21:08 -07004170 *
4171 * <p><strong>Note:</strong> do not invoke this method from
4172 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
4173 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004174 */
4175 public void removeAllViews() {
4176 removeAllViewsInLayout();
4177 requestLayout();
Romain Guy849d0a32011-02-01 17:20:48 -08004178 invalidate(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004179 }
4180
4181 /**
4182 * Called by a ViewGroup subclass to remove child views from itself,
4183 * when it must first know its size on screen before it can calculate how many
4184 * child views it will render. An example is a Gallery or a ListView, which
4185 * may "have" 50 children, but actually only render the number of children
4186 * that can currently fit inside the object on screen. Do not call
4187 * this method unless you are extending ViewGroup and understand the
4188 * view measuring and layout pipeline.
Romain Guy393a52c2012-05-22 20:21:08 -07004189 *
4190 * <p><strong>Note:</strong> do not invoke this method from
4191 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
4192 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004193 */
4194 public void removeAllViewsInLayout() {
4195 final int count = mChildrenCount;
4196 if (count <= 0) {
4197 return;
4198 }
4199
4200 final View[] children = mChildren;
4201 mChildrenCount = 0;
4202
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004203 final View focused = mFocused;
4204 final boolean detach = mAttachInfo != null;
Svetoslav Ganov149567f2013-01-08 15:23:34 -08004205 boolean clearChildFocus = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004206
4207 needGlobalAttributesUpdate(false);
Romain Guy8506ab42009-06-11 17:35:47 -07004208
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004209 for (int i = count - 1; i >= 0; i--) {
4210 final View view = children[i];
4211
Chet Haase21cd1382010-09-01 17:42:29 -07004212 if (mTransition != null) {
Chet Haase5e25c2c2010-09-16 11:15:56 -07004213 mTransition.removeChild(this, view);
Chet Haase21cd1382010-09-01 17:42:29 -07004214 }
4215
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004216 if (view == focused) {
Alan Viverette223622a2013-12-17 13:29:02 -08004217 view.unFocus(null);
Svetoslav Ganov149567f2013-01-08 15:23:34 -08004218 clearChildFocus = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004219 }
4220
Svetoslav Ganov149567f2013-01-08 15:23:34 -08004221 if (view.isAccessibilityFocused()) {
4222 view.clearAccessibilityFocus();
4223 }
Svetoslav Ganov961bf0e2012-05-08 09:40:03 -07004224
Jeff Brown59a422e2012-04-19 15:19:19 -07004225 cancelTouchTarget(view);
4226 cancelHoverTarget(view);
4227
Chet Haase21cd1382010-09-01 17:42:29 -07004228 if (view.getAnimation() != null ||
4229 (mTransitioningViews != null && mTransitioningViews.contains(view))) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004230 addDisappearingView(view);
4231 } else if (detach) {
4232 view.dispatchDetachedFromWindow();
4233 }
4234
Adam Powell539ee872012-02-03 19:00:49 -08004235 if (view.hasTransientState()) {
4236 childHasTransientStateChanged(view, false);
4237 }
4238
Philip Milnef51d91c2011-07-18 16:12:19 -07004239 onViewRemoved(view);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004240
4241 view.mParent = null;
4242 children[i] = null;
4243 }
4244
Svetoslav Ganov149567f2013-01-08 15:23:34 -08004245 if (clearChildFocus) {
4246 clearChildFocus(focused);
4247 if (!rootViewRequestFocus()) {
4248 notifyGlobalFocusCleared(focused);
4249 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004250 }
4251 }
4252
4253 /**
4254 * Finishes the removal of a detached view. This method will dispatch the detached from
4255 * window event and notify the hierarchy change listener.
Chet Haaseca479d42012-08-30 17:20:08 -07004256 * <p>
4257 * This method is intended to be lightweight and makes no assumptions about whether the
4258 * parent or child should be redrawn. Proper use of this method will include also making
4259 * any appropriate {@link #requestLayout()} or {@link #invalidate()} calls.
4260 * For example, callers can {@link #post(Runnable) post} a {@link Runnable}
4261 * which performs a {@link #requestLayout()} on the next frame, after all detach/remove
4262 * calls are finished, causing layout to be run prior to redrawing the view hierarchy.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004263 *
4264 * @param child the child to be definitely removed from the view hierarchy
4265 * @param animate if true and the view has an animation, the view is placed in the
4266 * disappearing views list, otherwise, it is detached from the window
4267 *
4268 * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
4269 * @see #detachAllViewsFromParent()
4270 * @see #detachViewFromParent(View)
4271 * @see #detachViewFromParent(int)
4272 */
4273 protected void removeDetachedView(View child, boolean animate) {
Chet Haase21cd1382010-09-01 17:42:29 -07004274 if (mTransition != null) {
Chet Haase5e25c2c2010-09-16 11:15:56 -07004275 mTransition.removeChild(this, child);
Chet Haase21cd1382010-09-01 17:42:29 -07004276 }
4277
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004278 if (child == mFocused) {
4279 child.clearFocus();
4280 }
Romain Guy8506ab42009-06-11 17:35:47 -07004281
Svetoslav Ganov961bf0e2012-05-08 09:40:03 -07004282 child.clearAccessibilityFocus();
4283
Jeff Brown59a422e2012-04-19 15:19:19 -07004284 cancelTouchTarget(child);
4285 cancelHoverTarget(child);
4286
Chet Haase21cd1382010-09-01 17:42:29 -07004287 if ((animate && child.getAnimation() != null) ||
4288 (mTransitioningViews != null && mTransitioningViews.contains(child))) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004289 addDisappearingView(child);
4290 } else if (child.mAttachInfo != null) {
4291 child.dispatchDetachedFromWindow();
4292 }
4293
Adam Powell539ee872012-02-03 19:00:49 -08004294 if (child.hasTransientState()) {
4295 childHasTransientStateChanged(child, false);
4296 }
4297
Philip Milnef51d91c2011-07-18 16:12:19 -07004298 onViewRemoved(child);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004299 }
4300
4301 /**
4302 * Attaches a view to this view group. Attaching a view assigns this group as the parent,
Chet Haaseca479d42012-08-30 17:20:08 -07004303 * sets the layout parameters and puts the view in the list of children so that
4304 * it can be retrieved by calling {@link #getChildAt(int)}.
4305 * <p>
4306 * This method is intended to be lightweight and makes no assumptions about whether the
4307 * parent or child should be redrawn. Proper use of this method will include also making
4308 * any appropriate {@link #requestLayout()} or {@link #invalidate()} calls.
4309 * For example, callers can {@link #post(Runnable) post} a {@link Runnable}
4310 * which performs a {@link #requestLayout()} on the next frame, after all detach/attach
4311 * calls are finished, causing layout to be run prior to redrawing the view hierarchy.
4312 * <p>
4313 * This method should be called only for views which were detached from their parent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004314 *
4315 * @param child the child to attach
4316 * @param index the index at which the child should be attached
4317 * @param params the layout parameters of the child
4318 *
4319 * @see #removeDetachedView(View, boolean)
4320 * @see #detachAllViewsFromParent()
4321 * @see #detachViewFromParent(View)
4322 * @see #detachViewFromParent(int)
4323 */
4324 protected void attachViewToParent(View child, int index, LayoutParams params) {
4325 child.mLayoutParams = params;
4326
4327 if (index < 0) {
4328 index = mChildrenCount;
4329 }
4330
4331 addInArray(child, index);
4332
4333 child.mParent = this;
Dianne Hackborn4702a852012-08-17 15:18:29 -07004334 child.mPrivateFlags = (child.mPrivateFlags & ~PFLAG_DIRTY_MASK
4335 & ~PFLAG_DRAWING_CACHE_VALID)
4336 | PFLAG_DRAWN | PFLAG_INVALIDATED;
4337 this.mPrivateFlags |= PFLAG_INVALIDATED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004338
4339 if (child.hasFocus()) {
4340 requestChildFocus(child, child.findFocus());
4341 }
4342 }
4343
4344 /**
Chet Haaseca479d42012-08-30 17:20:08 -07004345 * Detaches a view from its parent. Detaching a view should be followed
4346 * either by a call to
4347 * {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
4348 * or a call to {@link #removeDetachedView(View, boolean)}. Detachment should only be
4349 * temporary; reattachment or removal should happen within the same drawing cycle as
4350 * detachment. When a view is detached, its parent is null and cannot be retrieved by a
4351 * call to {@link #getChildAt(int)}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004352 *
4353 * @param child the child to detach
4354 *
4355 * @see #detachViewFromParent(int)
4356 * @see #detachViewsFromParent(int, int)
4357 * @see #detachAllViewsFromParent()
4358 * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
4359 * @see #removeDetachedView(View, boolean)
4360 */
4361 protected void detachViewFromParent(View child) {
4362 removeFromArray(indexOfChild(child));
4363 }
4364
4365 /**
Chet Haaseca479d42012-08-30 17:20:08 -07004366 * Detaches a view from its parent. Detaching a view should be followed
4367 * either by a call to
4368 * {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
4369 * or a call to {@link #removeDetachedView(View, boolean)}. Detachment should only be
4370 * temporary; reattachment or removal should happen within the same drawing cycle as
4371 * detachment. When a view is detached, its parent is null and cannot be retrieved by a
4372 * call to {@link #getChildAt(int)}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004373 *
4374 * @param index the index of the child to detach
4375 *
4376 * @see #detachViewFromParent(View)
4377 * @see #detachAllViewsFromParent()
4378 * @see #detachViewsFromParent(int, int)
4379 * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
4380 * @see #removeDetachedView(View, boolean)
4381 */
4382 protected void detachViewFromParent(int index) {
4383 removeFromArray(index);
4384 }
4385
4386 /**
Chet Haaseca479d42012-08-30 17:20:08 -07004387 * Detaches a range of views from their parents. Detaching a view should be followed
4388 * either by a call to
4389 * {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
4390 * or a call to {@link #removeDetachedView(View, boolean)}. Detachment should only be
4391 * temporary; reattachment or removal should happen within the same drawing cycle as
4392 * detachment. When a view is detached, its parent is null and cannot be retrieved by a
4393 * call to {@link #getChildAt(int)}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004394 *
4395 * @param start the first index of the childrend range to detach
4396 * @param count the number of children to detach
4397 *
4398 * @see #detachViewFromParent(View)
4399 * @see #detachViewFromParent(int)
4400 * @see #detachAllViewsFromParent()
4401 * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
4402 * @see #removeDetachedView(View, boolean)
4403 */
4404 protected void detachViewsFromParent(int start, int count) {
4405 removeFromArray(start, count);
4406 }
4407
4408 /**
Chet Haaseca479d42012-08-30 17:20:08 -07004409 * Detaches all views from the parent. Detaching a view should be followed
4410 * either by a call to
4411 * {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
4412 * or a call to {@link #removeDetachedView(View, boolean)}. Detachment should only be
4413 * temporary; reattachment or removal should happen within the same drawing cycle as
4414 * detachment. When a view is detached, its parent is null and cannot be retrieved by a
4415 * call to {@link #getChildAt(int)}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004416 *
4417 * @see #detachViewFromParent(View)
4418 * @see #detachViewFromParent(int)
4419 * @see #detachViewsFromParent(int, int)
4420 * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
4421 * @see #removeDetachedView(View, boolean)
4422 */
4423 protected void detachAllViewsFromParent() {
4424 final int count = mChildrenCount;
4425 if (count <= 0) {
4426 return;
4427 }
4428
4429 final View[] children = mChildren;
4430 mChildrenCount = 0;
4431
4432 for (int i = count - 1; i >= 0; i--) {
4433 children[i].mParent = null;
4434 children[i] = null;
4435 }
4436 }
4437
4438 /**
4439 * Don't call or override this method. It is used for the implementation of
4440 * the view hierarchy.
4441 */
4442 public final void invalidateChild(View child, final Rect dirty) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004443 ViewParent parent = this;
4444
4445 final AttachInfo attachInfo = mAttachInfo;
4446 if (attachInfo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004447 // If the child is drawing an animation, we want to copy this flag onto
4448 // ourselves and the parent to make sure the invalidate request goes
4449 // through
Dianne Hackborn4702a852012-08-17 15:18:29 -07004450 final boolean drawAnimation = (child.mPrivateFlags & PFLAG_DRAW_ANIMATION)
4451 == PFLAG_DRAW_ANIMATION;
Romain Guy24443ea2009-05-11 11:56:30 -07004452
Romain Guyfe455af2012-02-15 16:40:20 -08004453 // Check whether the child that requests the invalidate is fully opaque
4454 // Views being animated or transformed are not considered opaque because we may
4455 // be invalidating their old position and need the parent to paint behind them.
4456 Matrix childMatrix = child.getMatrix();
4457 final boolean isOpaque = child.isOpaque() && !drawAnimation &&
4458 child.getAnimation() == null && childMatrix.isIdentity();
4459 // Mark the child as dirty, using the appropriate flag
4460 // Make sure we do not set both flags at the same time
Dianne Hackborn4702a852012-08-17 15:18:29 -07004461 int opaqueFlag = isOpaque ? PFLAG_DIRTY_OPAQUE : PFLAG_DIRTY;
Romain Guyfe455af2012-02-15 16:40:20 -08004462
John Reck96bb8ad2014-06-19 10:53:03 -07004463 if (child.mLayerType != LAYER_TYPE_NONE) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07004464 mPrivateFlags |= PFLAG_INVALIDATED;
4465 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
Romain Guyfe455af2012-02-15 16:40:20 -08004466 }
4467
4468 final int[] location = attachInfo.mInvalidateChildLocation;
4469 location[CHILD_LEFT_INDEX] = child.mLeft;
4470 location[CHILD_TOP_INDEX] = child.mTop;
Chet Haase599913d2012-07-23 16:22:05 -07004471 if (!childMatrix.isIdentity() ||
4472 (mGroupFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) {
Romain Guyfe455af2012-02-15 16:40:20 -08004473 RectF boundingRect = attachInfo.mTmpTransformRect;
4474 boundingRect.set(dirty);
Chet Haase599913d2012-07-23 16:22:05 -07004475 Matrix transformMatrix;
4476 if ((mGroupFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) {
4477 Transformation t = attachInfo.mTmpTransformation;
4478 boolean transformed = getChildStaticTransformation(child, t);
4479 if (transformed) {
4480 transformMatrix = attachInfo.mTmpMatrix;
4481 transformMatrix.set(t.getMatrix());
4482 if (!childMatrix.isIdentity()) {
4483 transformMatrix.preConcat(childMatrix);
4484 }
4485 } else {
4486 transformMatrix = childMatrix;
4487 }
4488 } else {
4489 transformMatrix = childMatrix;
4490 }
4491 transformMatrix.mapRect(boundingRect);
Romain Guyfe455af2012-02-15 16:40:20 -08004492 dirty.set((int) (boundingRect.left - 0.5f),
4493 (int) (boundingRect.top - 0.5f),
4494 (int) (boundingRect.right + 0.5f),
4495 (int) (boundingRect.bottom + 0.5f));
4496 }
4497
4498 do {
4499 View view = null;
4500 if (parent instanceof View) {
4501 view = (View) parent;
Romain Guyfe455af2012-02-15 16:40:20 -08004502 }
4503
4504 if (drawAnimation) {
4505 if (view != null) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07004506 view.mPrivateFlags |= PFLAG_DRAW_ANIMATION;
Romain Guyfe455af2012-02-15 16:40:20 -08004507 } else if (parent instanceof ViewRootImpl) {
4508 ((ViewRootImpl) parent).mIsAnimating = true;
4509 }
4510 }
4511
4512 // If the parent is dirty opaque or not dirty, mark it dirty with the opaque
4513 // flag coming from the child that initiated the invalidate
4514 if (view != null) {
4515 if ((view.mViewFlags & FADING_EDGE_MASK) != 0 &&
4516 view.getSolidColor() == 0) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07004517 opaqueFlag = PFLAG_DIRTY;
Romain Guyfe455af2012-02-15 16:40:20 -08004518 }
Dianne Hackborn4702a852012-08-17 15:18:29 -07004519 if ((view.mPrivateFlags & PFLAG_DIRTY_MASK) != PFLAG_DIRTY) {
4520 view.mPrivateFlags = (view.mPrivateFlags & ~PFLAG_DIRTY_MASK) | opaqueFlag;
Romain Guyfe455af2012-02-15 16:40:20 -08004521 }
4522 }
4523
4524 parent = parent.invalidateChildInParent(location, dirty);
4525 if (view != null) {
4526 // Account for transform on current parent
4527 Matrix m = view.getMatrix();
4528 if (!m.isIdentity()) {
4529 RectF boundingRect = attachInfo.mTmpTransformRect;
4530 boundingRect.set(dirty);
4531 m.mapRect(boundingRect);
Romain Guye8585b12012-02-17 18:28:47 -08004532 dirty.set((int) (boundingRect.left - 0.5f),
4533 (int) (boundingRect.top - 0.5f),
Romain Guyfe455af2012-02-15 16:40:20 -08004534 (int) (boundingRect.right + 0.5f),
4535 (int) (boundingRect.bottom + 0.5f));
4536 }
4537 }
4538 } while (parent != null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004539 }
4540 }
4541
4542 /**
4543 * Don't call or override this method. It is used for the implementation of
4544 * the view hierarchy.
4545 *
4546 * This implementation returns null if this ViewGroup does not have a parent,
4547 * if this ViewGroup is already fully invalidated or if the dirty rectangle
4548 * does not intersect with this ViewGroup's bounds.
4549 */
4550 public ViewParent invalidateChildInParent(final int[] location, final Rect dirty) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07004551 if ((mPrivateFlags & PFLAG_DRAWN) == PFLAG_DRAWN ||
4552 (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004553 if ((mGroupFlags & (FLAG_OPTIMIZE_INVALIDATE | FLAG_ANIMATION_DONE)) !=
4554 FLAG_OPTIMIZE_INVALIDATE) {
4555 dirty.offset(location[CHILD_LEFT_INDEX] - mScrollX,
4556 location[CHILD_TOP_INDEX] - mScrollY);
Chet Haasea4f14eb2013-04-22 11:11:39 -07004557 if ((mGroupFlags & FLAG_CLIP_CHILDREN) == 0) {
4558 dirty.union(0, 0, mRight - mLeft, mBottom - mTop);
4559 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004560
4561 final int left = mLeft;
4562 final int top = mTop;
4563
Chet Haase05e91ed2012-07-03 14:17:57 -07004564 if ((mGroupFlags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN) {
4565 if (!dirty.intersect(0, 0, mRight - left, mBottom - top)) {
4566 dirty.setEmpty();
Romain Guy3a3133d2011-02-01 22:59:58 -08004567 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004568 }
Dianne Hackborn4702a852012-08-17 15:18:29 -07004569 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
Chet Haase05e91ed2012-07-03 14:17:57 -07004570
4571 location[CHILD_LEFT_INDEX] = left;
4572 location[CHILD_TOP_INDEX] = top;
4573
John Reck96bb8ad2014-06-19 10:53:03 -07004574 if (mLayerType != LAYER_TYPE_NONE) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07004575 mPrivateFlags |= PFLAG_INVALIDATED;
Chet Haase05e91ed2012-07-03 14:17:57 -07004576 }
4577
4578 return mParent;
4579
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004580 } else {
Dianne Hackborn4702a852012-08-17 15:18:29 -07004581 mPrivateFlags &= ~PFLAG_DRAWN & ~PFLAG_DRAWING_CACHE_VALID;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004582
4583 location[CHILD_LEFT_INDEX] = mLeft;
4584 location[CHILD_TOP_INDEX] = mTop;
Chet Haasea3db8662011-07-19 10:36:05 -07004585 if ((mGroupFlags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN) {
4586 dirty.set(0, 0, mRight - mLeft, mBottom - mTop);
4587 } else {
4588 // in case the dirty rect extends outside the bounds of this container
4589 dirty.union(0, 0, mRight - mLeft, mBottom - mTop);
4590 }
Romain Guy3a3133d2011-02-01 22:59:58 -08004591
John Reck96bb8ad2014-06-19 10:53:03 -07004592 if (mLayerType != LAYER_TYPE_NONE) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07004593 mPrivateFlags |= PFLAG_INVALIDATED;
Romain Guy3a3133d2011-02-01 22:59:58 -08004594 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004595
4596 return mParent;
4597 }
4598 }
4599
4600 return null;
4601 }
4602
4603 /**
John Recke4267ea2014-06-03 15:53:15 -07004604 * Native-calculated damage path
4605 * Returns false if this path was unable to complete successfully. This means
4606 * it hit a ViewParent it doesn't recognize and needs to fall back to calculating
4607 * damage area
4608 * @hide
4609 */
4610 public boolean damageChildDeferred(View child) {
4611 ViewParent parent = getParent();
4612 while (parent != null) {
4613 if (parent instanceof ViewGroup) {
4614 parent = parent.getParent();
4615 } else if (parent instanceof ViewRootImpl) {
4616 ((ViewRootImpl) parent).invalidate();
4617 return true;
4618 } else {
4619 parent = null;
4620 }
4621 }
4622 return false;
4623 }
4624
4625 /**
Chet Haase9d1992d2012-03-13 11:03:25 -07004626 * Quick invalidation method called by View.invalidateViewProperty. This doesn't set the
4627 * DRAWN flags and doesn't handle the Animation logic that the default invalidation methods
4628 * do; all we want to do here is schedule a traversal with the appropriate dirty rect.
4629 *
4630 * @hide
4631 */
Chris Craik49e6c732014-03-31 12:34:11 -07004632 public void damageChild(View child, final Rect dirty) {
John Recke4267ea2014-06-03 15:53:15 -07004633 if (damageChildDeferred(child)) {
4634 return;
4635 }
4636
Chet Haase9d1992d2012-03-13 11:03:25 -07004637 ViewParent parent = this;
4638
4639 final AttachInfo attachInfo = mAttachInfo;
4640 if (attachInfo != null) {
Chet Haase9d1992d2012-03-13 11:03:25 -07004641 int left = child.mLeft;
4642 int top = child.mTop;
4643 if (!child.getMatrix().isIdentity()) {
4644 child.transformRect(dirty);
4645 }
4646
4647 do {
4648 if (parent instanceof ViewGroup) {
4649 ViewGroup parentVG = (ViewGroup) parent;
Chet Haaseb85967b2012-03-26 14:37:51 -07004650 if (parentVG.mLayerType != LAYER_TYPE_NONE) {
4651 // Layered parents should be recreated, not just re-issued
4652 parentVG.invalidate();
4653 parent = null;
4654 } else {
Chris Craik49e6c732014-03-31 12:34:11 -07004655 parent = parentVG.damageChildInParent(left, top, dirty);
Chet Haaseb85967b2012-03-26 14:37:51 -07004656 left = parentVG.mLeft;
4657 top = parentVG.mTop;
4658 }
Chet Haase9d1992d2012-03-13 11:03:25 -07004659 } else {
4660 // Reached the top; this calls into the usual invalidate method in
4661 // ViewRootImpl, which schedules a traversal
4662 final int[] location = attachInfo.mInvalidateChildLocation;
4663 location[0] = left;
4664 location[1] = top;
4665 parent = parent.invalidateChildInParent(location, dirty);
4666 }
4667 } while (parent != null);
4668 }
4669 }
4670
4671 /**
4672 * Quick invalidation method that simply transforms the dirty rect into the parent's
4673 * coordinate system, pruning the invalidation if the parent has already been invalidated.
Chet Haasee4a2d7c2013-06-21 17:49:36 -07004674 *
4675 * @hide
Chet Haase9d1992d2012-03-13 11:03:25 -07004676 */
Chris Craik49e6c732014-03-31 12:34:11 -07004677 protected ViewParent damageChildInParent(int left, int top, final Rect dirty) {
4678 if ((mPrivateFlags & PFLAG_DRAWN) != 0
4679 || (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) != 0) {
Chet Haase9d1992d2012-03-13 11:03:25 -07004680 dirty.offset(left - mScrollX, top - mScrollY);
Chet Haasea4f14eb2013-04-22 11:11:39 -07004681 if ((mGroupFlags & FLAG_CLIP_CHILDREN) == 0) {
4682 dirty.union(0, 0, mRight - mLeft, mBottom - mTop);
4683 }
Chet Haase9d1992d2012-03-13 11:03:25 -07004684
4685 if ((mGroupFlags & FLAG_CLIP_CHILDREN) == 0 ||
4686 dirty.intersect(0, 0, mRight - mLeft, mBottom - mTop)) {
4687
Chet Haase9d1992d2012-03-13 11:03:25 -07004688 if (!getMatrix().isIdentity()) {
4689 transformRect(dirty);
4690 }
4691
4692 return mParent;
4693 }
4694 }
4695
4696 return null;
4697 }
4698
4699 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004700 * Offset a rectangle that is in a descendant's coordinate
4701 * space into our coordinate space.
4702 * @param descendant A descendant of this view
4703 * @param rect A rectangle defined in descendant's coordinate space.
4704 */
4705 public final void offsetDescendantRectToMyCoords(View descendant, Rect rect) {
4706 offsetRectBetweenParentAndChild(descendant, rect, true, false);
4707 }
4708
4709 /**
4710 * Offset a rectangle that is in our coordinate space into an ancestor's
4711 * coordinate space.
4712 * @param descendant A descendant of this view
4713 * @param rect A rectangle defined in descendant's coordinate space.
4714 */
4715 public final void offsetRectIntoDescendantCoords(View descendant, Rect rect) {
4716 offsetRectBetweenParentAndChild(descendant, rect, false, false);
4717 }
4718
4719 /**
4720 * Helper method that offsets a rect either from parent to descendant or
4721 * descendant to parent.
4722 */
4723 void offsetRectBetweenParentAndChild(View descendant, Rect rect,
4724 boolean offsetFromChildToParent, boolean clipToBounds) {
4725
4726 // already in the same coord system :)
4727 if (descendant == this) {
4728 return;
4729 }
4730
4731 ViewParent theParent = descendant.mParent;
4732
4733 // search and offset up to the parent
4734 while ((theParent != null)
4735 && (theParent instanceof View)
4736 && (theParent != this)) {
4737
4738 if (offsetFromChildToParent) {
4739 rect.offset(descendant.mLeft - descendant.mScrollX,
4740 descendant.mTop - descendant.mScrollY);
4741 if (clipToBounds) {
4742 View p = (View) theParent;
4743 rect.intersect(0, 0, p.mRight - p.mLeft, p.mBottom - p.mTop);
4744 }
4745 } else {
4746 if (clipToBounds) {
4747 View p = (View) theParent;
4748 rect.intersect(0, 0, p.mRight - p.mLeft, p.mBottom - p.mTop);
4749 }
4750 rect.offset(descendant.mScrollX - descendant.mLeft,
4751 descendant.mScrollY - descendant.mTop);
4752 }
4753
4754 descendant = (View) theParent;
4755 theParent = descendant.mParent;
4756 }
4757
4758 // now that we are up to this view, need to offset one more time
4759 // to get into our coordinate space
4760 if (theParent == this) {
4761 if (offsetFromChildToParent) {
4762 rect.offset(descendant.mLeft - descendant.mScrollX,
4763 descendant.mTop - descendant.mScrollY);
4764 } else {
4765 rect.offset(descendant.mScrollX - descendant.mLeft,
4766 descendant.mScrollY - descendant.mTop);
4767 }
4768 } else {
4769 throw new IllegalArgumentException("parameter must be a descendant of this view");
4770 }
4771 }
4772
4773 /**
4774 * Offset the vertical location of all children of this view by the specified number of pixels.
4775 *
4776 * @param offset the number of pixels to offset
4777 *
4778 * @hide
4779 */
4780 public void offsetChildrenTopAndBottom(int offset) {
4781 final int count = mChildrenCount;
4782 final View[] children = mChildren;
Romain Guy5549cb52013-05-06 18:42:08 -07004783 boolean invalidate = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004784
4785 for (int i = 0; i < count; i++) {
4786 final View v = children[i];
4787 v.mTop += offset;
4788 v.mBottom += offset;
Chris Craik64a12e12014-03-28 18:12:12 -07004789 if (v.mRenderNode != null) {
Romain Guy5549cb52013-05-06 18:42:08 -07004790 invalidate = true;
Chris Craik64a12e12014-03-28 18:12:12 -07004791 v.mRenderNode.offsetTopAndBottom(offset);
Chet Haasea1cff502012-02-21 13:43:44 -08004792 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004793 }
Romain Guy5549cb52013-05-06 18:42:08 -07004794
4795 if (invalidate) {
4796 invalidateViewProperty(false, false);
4797 }
Guang Zhu84e25092014-05-01 21:12:55 -07004798 notifySubtreeAccessibilityStateChangedIfNeeded();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004799 }
4800
4801 /**
4802 * {@inheritDoc}
4803 */
4804 public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) {
Adam Powellf93bb6d2011-12-12 15:21:57 -08004805 // It doesn't make a whole lot of sense to call this on a view that isn't attached,
4806 // but for some simple tests it can be useful. If we don't have attach info this
4807 // will allocate memory.
4808 final RectF rect = mAttachInfo != null ? mAttachInfo.mTmpTransformRect : new RectF();
Gilles Debunnecea45132011-11-24 02:19:27 +01004809 rect.set(r);
4810
4811 if (!child.hasIdentityMatrix()) {
4812 child.getMatrix().mapRect(rect);
4813 }
4814
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004815 int dx = child.mLeft - mScrollX;
4816 int dy = child.mTop - mScrollY;
Gilles Debunnecea45132011-11-24 02:19:27 +01004817
4818 rect.offset(dx, dy);
4819
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004820 if (offset != null) {
Gilles Debunnecea45132011-11-24 02:19:27 +01004821 if (!child.hasIdentityMatrix()) {
Adam Powellf93bb6d2011-12-12 15:21:57 -08004822 float[] position = mAttachInfo != null ? mAttachInfo.mTmpTransformLocation
4823 : new float[2];
Gilles Debunnecea45132011-11-24 02:19:27 +01004824 position[0] = offset.x;
4825 position[1] = offset.y;
4826 child.getMatrix().mapPoints(position);
4827 offset.x = (int) (position[0] + 0.5f);
4828 offset.y = (int) (position[1] + 0.5f);
4829 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004830 offset.x += dx;
4831 offset.y += dy;
4832 }
Gilles Debunnecea45132011-11-24 02:19:27 +01004833
4834 if (rect.intersect(0, 0, mRight - mLeft, mBottom - mTop)) {
4835 if (mParent == null) return true;
4836 r.set((int) (rect.left + 0.5f), (int) (rect.top + 0.5f),
4837 (int) (rect.right + 0.5f), (int) (rect.bottom + 0.5f));
4838 return mParent.getChildVisibleRect(this, r, offset);
4839 }
4840
4841 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004842 }
4843
4844 /**
4845 * {@inheritDoc}
4846 */
4847 @Override
Chet Haase9c087442011-01-12 16:20:16 -08004848 public final void layout(int l, int t, int r, int b) {
Chet Haase430742f2013-04-12 11:18:36 -07004849 if (!mSuppressLayout && (mTransition == null || !mTransition.isChangingLayout())) {
Chet Haase7dd4a532012-04-16 13:35:09 -07004850 if (mTransition != null) {
4851 mTransition.layoutChange(this);
4852 }
Chet Haase9c087442011-01-12 16:20:16 -08004853 super.layout(l, t, r, b);
4854 } else {
4855 // record the fact that we noop'd it; request layout when transition finishes
Chet Haaseb9895022013-04-02 15:10:58 -07004856 mLayoutCalledWhileSuppressed = true;
Chet Haase9c087442011-01-12 16:20:16 -08004857 }
4858 }
4859
4860 /**
4861 * {@inheritDoc}
4862 */
4863 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004864 protected abstract void onLayout(boolean changed,
4865 int l, int t, int r, int b);
4866
4867 /**
4868 * Indicates whether the view group has the ability to animate its children
4869 * after the first layout.
4870 *
4871 * @return true if the children can be animated, false otherwise
4872 */
4873 protected boolean canAnimate() {
4874 return mLayoutAnimationController != null;
4875 }
4876
4877 /**
4878 * Runs the layout animation. Calling this method triggers a relayout of
4879 * this view group.
4880 */
4881 public void startLayoutAnimation() {
4882 if (mLayoutAnimationController != null) {
4883 mGroupFlags |= FLAG_RUN_ANIMATION;
4884 requestLayout();
4885 }
4886 }
4887
4888 /**
4889 * Schedules the layout animation to be played after the next layout pass
4890 * of this view group. This can be used to restart the layout animation
4891 * when the content of the view group changes or when the activity is
4892 * paused and resumed.
4893 */
4894 public void scheduleLayoutAnimation() {
4895 mGroupFlags |= FLAG_RUN_ANIMATION;
4896 }
4897
4898 /**
4899 * Sets the layout animation controller used to animate the group's
4900 * children after the first layout.
4901 *
4902 * @param controller the animation controller
4903 */
4904 public void setLayoutAnimation(LayoutAnimationController controller) {
4905 mLayoutAnimationController = controller;
4906 if (mLayoutAnimationController != null) {
4907 mGroupFlags |= FLAG_RUN_ANIMATION;
4908 }
4909 }
4910
4911 /**
4912 * Returns the layout animation controller used to animate the group's
4913 * children.
4914 *
4915 * @return the current animation controller
4916 */
4917 public LayoutAnimationController getLayoutAnimation() {
4918 return mLayoutAnimationController;
4919 }
4920
4921 /**
4922 * Indicates whether the children's drawing cache is used during a layout
4923 * animation. By default, the drawing cache is enabled but this will prevent
4924 * nested layout animations from working. To nest animations, you must disable
4925 * the cache.
4926 *
4927 * @return true if the animation cache is enabled, false otherwise
4928 *
4929 * @see #setAnimationCacheEnabled(boolean)
4930 * @see View#setDrawingCacheEnabled(boolean)
4931 */
4932 @ViewDebug.ExportedProperty
4933 public boolean isAnimationCacheEnabled() {
4934 return (mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE;
4935 }
4936
4937 /**
4938 * Enables or disables the children's drawing cache during a layout animation.
4939 * By default, the drawing cache is enabled but this will prevent nested
4940 * layout animations from working. To nest animations, you must disable the
4941 * cache.
4942 *
4943 * @param enabled true to enable the animation cache, false otherwise
4944 *
4945 * @see #isAnimationCacheEnabled()
4946 * @see View#setDrawingCacheEnabled(boolean)
4947 */
4948 public void setAnimationCacheEnabled(boolean enabled) {
4949 setBooleanFlag(FLAG_ANIMATION_CACHE, enabled);
4950 }
4951
4952 /**
4953 * Indicates whether this ViewGroup will always try to draw its children using their
4954 * drawing cache. By default this property is enabled.
4955 *
4956 * @return true if the animation cache is enabled, false otherwise
4957 *
4958 * @see #setAlwaysDrawnWithCacheEnabled(boolean)
4959 * @see #setChildrenDrawnWithCacheEnabled(boolean)
4960 * @see View#setDrawingCacheEnabled(boolean)
4961 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07004962 @ViewDebug.ExportedProperty(category = "drawing")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004963 public boolean isAlwaysDrawnWithCacheEnabled() {
4964 return (mGroupFlags & FLAG_ALWAYS_DRAWN_WITH_CACHE) == FLAG_ALWAYS_DRAWN_WITH_CACHE;
4965 }
4966
4967 /**
4968 * Indicates whether this ViewGroup will always try to draw its children using their
4969 * drawing cache. This property can be set to true when the cache rendering is
4970 * slightly different from the children's normal rendering. Renderings can be different,
4971 * for instance, when the cache's quality is set to low.
4972 *
4973 * When this property is disabled, the ViewGroup will use the drawing cache of its
4974 * children only when asked to. It's usually the task of subclasses to tell ViewGroup
4975 * when to start using the drawing cache and when to stop using it.
4976 *
4977 * @param always true to always draw with the drawing cache, false otherwise
4978 *
4979 * @see #isAlwaysDrawnWithCacheEnabled()
4980 * @see #setChildrenDrawnWithCacheEnabled(boolean)
4981 * @see View#setDrawingCacheEnabled(boolean)
4982 * @see View#setDrawingCacheQuality(int)
4983 */
4984 public void setAlwaysDrawnWithCacheEnabled(boolean always) {
4985 setBooleanFlag(FLAG_ALWAYS_DRAWN_WITH_CACHE, always);
4986 }
4987
4988 /**
4989 * Indicates whether the ViewGroup is currently drawing its children using
4990 * their drawing cache.
4991 *
4992 * @return true if children should be drawn with their cache, false otherwise
4993 *
4994 * @see #setAlwaysDrawnWithCacheEnabled(boolean)
4995 * @see #setChildrenDrawnWithCacheEnabled(boolean)
4996 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07004997 @ViewDebug.ExportedProperty(category = "drawing")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004998 protected boolean isChildrenDrawnWithCacheEnabled() {
4999 return (mGroupFlags & FLAG_CHILDREN_DRAWN_WITH_CACHE) == FLAG_CHILDREN_DRAWN_WITH_CACHE;
5000 }
5001
5002 /**
5003 * Tells the ViewGroup to draw its children using their drawing cache. This property
5004 * is ignored when {@link #isAlwaysDrawnWithCacheEnabled()} is true. A child's drawing cache
5005 * will be used only if it has been enabled.
5006 *
5007 * Subclasses should call this method to start and stop using the drawing cache when
5008 * they perform performance sensitive operations, like scrolling or animating.
5009 *
5010 * @param enabled true if children should be drawn with their cache, false otherwise
5011 *
5012 * @see #setAlwaysDrawnWithCacheEnabled(boolean)
5013 * @see #isChildrenDrawnWithCacheEnabled()
5014 */
5015 protected void setChildrenDrawnWithCacheEnabled(boolean enabled) {
5016 setBooleanFlag(FLAG_CHILDREN_DRAWN_WITH_CACHE, enabled);
5017 }
5018
Romain Guy293451e2009-11-04 13:59:48 -08005019 /**
5020 * Indicates whether the ViewGroup is drawing its children in the order defined by
5021 * {@link #getChildDrawingOrder(int, int)}.
5022 *
5023 * @return true if children drawing order is defined by {@link #getChildDrawingOrder(int, int)},
5024 * false otherwise
5025 *
5026 * @see #setChildrenDrawingOrderEnabled(boolean)
5027 * @see #getChildDrawingOrder(int, int)
5028 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07005029 @ViewDebug.ExportedProperty(category = "drawing")
Romain Guy293451e2009-11-04 13:59:48 -08005030 protected boolean isChildrenDrawingOrderEnabled() {
5031 return (mGroupFlags & FLAG_USE_CHILD_DRAWING_ORDER) == FLAG_USE_CHILD_DRAWING_ORDER;
5032 }
5033
5034 /**
5035 * Tells the ViewGroup whether to draw its children in the order defined by the method
5036 * {@link #getChildDrawingOrder(int, int)}.
5037 *
5038 * @param enabled true if the order of the children when drawing is determined by
5039 * {@link #getChildDrawingOrder(int, int)}, false otherwise
5040 *
5041 * @see #isChildrenDrawingOrderEnabled()
5042 * @see #getChildDrawingOrder(int, int)
5043 */
5044 protected void setChildrenDrawingOrderEnabled(boolean enabled) {
5045 setBooleanFlag(FLAG_USE_CHILD_DRAWING_ORDER, enabled);
5046 }
5047
Svetoslav6254f482013-06-04 17:22:14 -07005048 private boolean hasBooleanFlag(int flag) {
Philip Milnef091b662013-02-27 11:15:21 -08005049 return (mGroupFlags & flag) == flag;
5050 }
5051
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005052 private void setBooleanFlag(int flag, boolean value) {
5053 if (value) {
5054 mGroupFlags |= flag;
5055 } else {
5056 mGroupFlags &= ~flag;
5057 }
5058 }
5059
5060 /**
5061 * Returns an integer indicating what types of drawing caches are kept in memory.
5062 *
5063 * @see #setPersistentDrawingCache(int)
5064 * @see #setAnimationCacheEnabled(boolean)
5065 *
5066 * @return one or a combination of {@link #PERSISTENT_NO_CACHE},
5067 * {@link #PERSISTENT_ANIMATION_CACHE}, {@link #PERSISTENT_SCROLLING_CACHE}
5068 * and {@link #PERSISTENT_ALL_CACHES}
5069 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07005070 @ViewDebug.ExportedProperty(category = "drawing", mapping = {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005071 @ViewDebug.IntToString(from = PERSISTENT_NO_CACHE, to = "NONE"),
Romain Guy203688c2010-05-12 15:41:32 -07005072 @ViewDebug.IntToString(from = PERSISTENT_ANIMATION_CACHE, to = "ANIMATION"),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005073 @ViewDebug.IntToString(from = PERSISTENT_SCROLLING_CACHE, to = "SCROLLING"),
5074 @ViewDebug.IntToString(from = PERSISTENT_ALL_CACHES, to = "ALL")
5075 })
5076 public int getPersistentDrawingCache() {
5077 return mPersistentDrawingCache;
5078 }
5079
5080 /**
5081 * Indicates what types of drawing caches should be kept in memory after
5082 * they have been created.
5083 *
5084 * @see #getPersistentDrawingCache()
5085 * @see #setAnimationCacheEnabled(boolean)
5086 *
5087 * @param drawingCacheToKeep one or a combination of {@link #PERSISTENT_NO_CACHE},
5088 * {@link #PERSISTENT_ANIMATION_CACHE}, {@link #PERSISTENT_SCROLLING_CACHE}
5089 * and {@link #PERSISTENT_ALL_CACHES}
5090 */
5091 public void setPersistentDrawingCache(int drawingCacheToKeep) {
5092 mPersistentDrawingCache = drawingCacheToKeep & PERSISTENT_ALL_CACHES;
5093 }
5094
Philip Milnef091b662013-02-27 11:15:21 -08005095 private void setLayoutMode(int layoutMode, boolean explicitly) {
5096 mLayoutMode = layoutMode;
5097 setBooleanFlag(FLAG_LAYOUT_MODE_WAS_EXPLICITLY_SET, explicitly);
5098 }
5099
5100 /**
5101 * Recursively traverse the view hierarchy, resetting the layoutMode of any
5102 * descendants that had inherited a different layoutMode from a previous parent.
5103 * Recursion terminates when a descendant's mode is:
5104 * <ul>
5105 * <li>Undefined</li>
5106 * <li>The same as the root node's</li>
5107 * <li>A mode that had been explicitly set</li>
5108 * <ul/>
5109 * The first two clauses are optimizations.
5110 * @param layoutModeOfRoot
5111 */
5112 @Override
5113 void invalidateInheritedLayoutMode(int layoutModeOfRoot) {
5114 if (mLayoutMode == LAYOUT_MODE_UNDEFINED ||
5115 mLayoutMode == layoutModeOfRoot ||
Svetoslav6254f482013-06-04 17:22:14 -07005116 hasBooleanFlag(FLAG_LAYOUT_MODE_WAS_EXPLICITLY_SET)) {
Philip Milnef091b662013-02-27 11:15:21 -08005117 return;
5118 }
5119 setLayoutMode(LAYOUT_MODE_UNDEFINED, false);
5120
5121 // apply recursively
5122 for (int i = 0, N = getChildCount(); i < N; i++) {
5123 getChildAt(i).invalidateInheritedLayoutMode(layoutModeOfRoot);
5124 }
5125 }
5126
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005127 /**
Philip Milnecfb631b2012-10-26 10:51:46 -07005128 * Returns the basis of alignment during layout operations on this ViewGroup:
Philip Milne7b757812012-09-19 18:13:44 -07005129 * either {@link #LAYOUT_MODE_CLIP_BOUNDS} or {@link #LAYOUT_MODE_OPTICAL_BOUNDS}.
Philip Milnecfb631b2012-10-26 10:51:46 -07005130 * <p>
5131 * If no layoutMode was explicitly set, either programmatically or in an XML resource,
5132 * the method returns the layoutMode of the view's parent ViewGroup if such a parent exists,
5133 * otherwise the method returns a default value of {@link #LAYOUT_MODE_CLIP_BOUNDS}.
Philip Milne1557fd72012-04-04 23:41:34 -07005134 *
Philip Milnefcc6a0f2012-04-16 16:12:19 -07005135 * @return the layout mode to use during layout operations
Philip Milne1557fd72012-04-04 23:41:34 -07005136 *
5137 * @see #setLayoutMode(int)
5138 */
5139 public int getLayoutMode() {
Philip Milnecfb631b2012-10-26 10:51:46 -07005140 if (mLayoutMode == LAYOUT_MODE_UNDEFINED) {
Philip Milnef091b662013-02-27 11:15:21 -08005141 int inheritedLayoutMode = (mParent instanceof ViewGroup) ?
5142 ((ViewGroup) mParent).getLayoutMode() : LAYOUT_MODE_DEFAULT;
5143 setLayoutMode(inheritedLayoutMode, false);
Philip Milnecfb631b2012-10-26 10:51:46 -07005144 }
Philip Milne1557fd72012-04-04 23:41:34 -07005145 return mLayoutMode;
5146 }
5147
5148 /**
Philip Milnecfb631b2012-10-26 10:51:46 -07005149 * Sets the basis of alignment during the layout of this ViewGroup.
Philip Milne7b757812012-09-19 18:13:44 -07005150 * Valid values are either {@link #LAYOUT_MODE_CLIP_BOUNDS} or
5151 * {@link #LAYOUT_MODE_OPTICAL_BOUNDS}.
Philip Milne1557fd72012-04-04 23:41:34 -07005152 *
Philip Milnefcc6a0f2012-04-16 16:12:19 -07005153 * @param layoutMode the layout mode to use during layout operations
Philip Milne1557fd72012-04-04 23:41:34 -07005154 *
5155 * @see #getLayoutMode()
Scott Main27a85082013-06-10 10:39:48 -07005156 * @attr ref android.R.styleable#ViewGroup_layoutMode
Philip Milne1557fd72012-04-04 23:41:34 -07005157 */
5158 public void setLayoutMode(int layoutMode) {
5159 if (mLayoutMode != layoutMode) {
Philip Milnef091b662013-02-27 11:15:21 -08005160 invalidateInheritedLayoutMode(layoutMode);
5161 setLayoutMode(layoutMode, layoutMode != LAYOUT_MODE_UNDEFINED);
Philip Milne1557fd72012-04-04 23:41:34 -07005162 requestLayout();
5163 }
5164 }
5165
5166 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005167 * Returns a new set of layout parameters based on the supplied attributes set.
5168 *
5169 * @param attrs the attributes to build the layout parameters from
5170 *
5171 * @return an instance of {@link android.view.ViewGroup.LayoutParams} or one
5172 * of its descendants
5173 */
5174 public LayoutParams generateLayoutParams(AttributeSet attrs) {
5175 return new LayoutParams(getContext(), attrs);
5176 }
5177
5178 /**
5179 * Returns a safe set of layout parameters based on the supplied layout params.
5180 * When a ViewGroup is passed a View whose layout params do not pass the test of
5181 * {@link #checkLayoutParams(android.view.ViewGroup.LayoutParams)}, this method
5182 * is invoked. This method should return a new set of layout params suitable for
5183 * this ViewGroup, possibly by copying the appropriate attributes from the
5184 * specified set of layout params.
5185 *
5186 * @param p The layout parameters to convert into a suitable set of layout parameters
5187 * for this ViewGroup.
5188 *
5189 * @return an instance of {@link android.view.ViewGroup.LayoutParams} or one
5190 * of its descendants
5191 */
5192 protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
5193 return p;
5194 }
5195
5196 /**
5197 * Returns a set of default layout parameters. These parameters are requested
5198 * when the View passed to {@link #addView(View)} has no layout parameters
5199 * already set. If null is returned, an exception is thrown from addView.
5200 *
5201 * @return a set of default layout parameters or null
5202 */
5203 protected LayoutParams generateDefaultLayoutParams() {
5204 return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
5205 }
5206
5207 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005208 * {@inheritDoc}
5209 */
5210 @Override
5211 protected void debug(int depth) {
5212 super.debug(depth);
5213 String output;
5214
5215 if (mFocused != null) {
5216 output = debugIndent(depth);
5217 output += "mFocused";
5218 Log.d(VIEW_LOG_TAG, output);
5219 }
5220 if (mChildrenCount != 0) {
5221 output = debugIndent(depth);
5222 output += "{";
5223 Log.d(VIEW_LOG_TAG, output);
5224 }
5225 int count = mChildrenCount;
5226 for (int i = 0; i < count; i++) {
5227 View child = mChildren[i];
5228 child.debug(depth + 1);
5229 }
5230
5231 if (mChildrenCount != 0) {
5232 output = debugIndent(depth);
5233 output += "}";
5234 Log.d(VIEW_LOG_TAG, output);
5235 }
5236 }
5237
5238 /**
5239 * Returns the position in the group of the specified child view.
5240 *
5241 * @param child the view for which to get the position
5242 * @return a positive integer representing the position of the view in the
5243 * group, or -1 if the view does not exist in the group
5244 */
5245 public int indexOfChild(View child) {
5246 final int count = mChildrenCount;
5247 final View[] children = mChildren;
5248 for (int i = 0; i < count; i++) {
5249 if (children[i] == child) {
5250 return i;
5251 }
5252 }
5253 return -1;
5254 }
5255
5256 /**
5257 * Returns the number of children in the group.
5258 *
5259 * @return a positive integer representing the number of children in
5260 * the group
5261 */
5262 public int getChildCount() {
5263 return mChildrenCount;
5264 }
5265
5266 /**
5267 * Returns the view at the specified position in the group.
5268 *
5269 * @param index the position at which to get the view from
5270 * @return the view at the specified position or null if the position
5271 * does not exist within the group
5272 */
5273 public View getChildAt(int index) {
Adam Powell3ba8f5d62011-03-07 15:36:33 -08005274 if (index < 0 || index >= mChildrenCount) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005275 return null;
5276 }
Adam Powell3ba8f5d62011-03-07 15:36:33 -08005277 return mChildren[index];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005278 }
5279
5280 /**
5281 * Ask all of the children of this view to measure themselves, taking into
5282 * account both the MeasureSpec requirements for this view and its padding.
5283 * We skip children that are in the GONE state The heavy lifting is done in
5284 * getChildMeasureSpec.
5285 *
5286 * @param widthMeasureSpec The width requirements for this view
5287 * @param heightMeasureSpec The height requirements for this view
5288 */
5289 protected void measureChildren(int widthMeasureSpec, int heightMeasureSpec) {
5290 final int size = mChildrenCount;
5291 final View[] children = mChildren;
5292 for (int i = 0; i < size; ++i) {
5293 final View child = children[i];
5294 if ((child.mViewFlags & VISIBILITY_MASK) != GONE) {
5295 measureChild(child, widthMeasureSpec, heightMeasureSpec);
5296 }
5297 }
5298 }
5299
5300 /**
5301 * Ask one of the children of this view to measure itself, taking into
5302 * account both the MeasureSpec requirements for this view and its padding.
5303 * The heavy lifting is done in getChildMeasureSpec.
5304 *
5305 * @param child The child to measure
5306 * @param parentWidthMeasureSpec The width requirements for this view
5307 * @param parentHeightMeasureSpec The height requirements for this view
5308 */
5309 protected void measureChild(View child, int parentWidthMeasureSpec,
5310 int parentHeightMeasureSpec) {
5311 final LayoutParams lp = child.getLayoutParams();
5312
5313 final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
5314 mPaddingLeft + mPaddingRight, lp.width);
5315 final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
5316 mPaddingTop + mPaddingBottom, lp.height);
5317
5318 child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
5319 }
5320
5321 /**
5322 * Ask one of the children of this view to measure itself, taking into
5323 * account both the MeasureSpec requirements for this view and its padding
5324 * and margins. The child must have MarginLayoutParams The heavy lifting is
5325 * done in getChildMeasureSpec.
5326 *
5327 * @param child The child to measure
5328 * @param parentWidthMeasureSpec The width requirements for this view
5329 * @param widthUsed Extra space that has been used up by the parent
5330 * horizontally (possibly by other children of the parent)
5331 * @param parentHeightMeasureSpec The height requirements for this view
5332 * @param heightUsed Extra space that has been used up by the parent
5333 * vertically (possibly by other children of the parent)
5334 */
5335 protected void measureChildWithMargins(View child,
5336 int parentWidthMeasureSpec, int widthUsed,
5337 int parentHeightMeasureSpec, int heightUsed) {
5338 final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
5339
5340 final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
5341 mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin
5342 + widthUsed, lp.width);
5343 final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
5344 mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin
5345 + heightUsed, lp.height);
5346
5347 child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
5348 }
5349
5350 /**
5351 * Does the hard part of measureChildren: figuring out the MeasureSpec to
5352 * pass to a particular child. This method figures out the right MeasureSpec
5353 * for one dimension (height or width) of one child view.
5354 *
5355 * The goal is to combine information from our MeasureSpec with the
5356 * LayoutParams of the child to get the best possible results. For example,
5357 * if the this view knows its size (because its MeasureSpec has a mode of
5358 * EXACTLY), and the child has indicated in its LayoutParams that it wants
5359 * to be the same size as the parent, the parent should ask the child to
5360 * layout given an exact size.
5361 *
5362 * @param spec The requirements for this view
5363 * @param padding The padding of this view for the current dimension and
5364 * margins, if applicable
5365 * @param childDimension How big the child wants to be in the current
5366 * dimension
5367 * @return a MeasureSpec integer for the child
5368 */
5369 public static int getChildMeasureSpec(int spec, int padding, int childDimension) {
5370 int specMode = MeasureSpec.getMode(spec);
5371 int specSize = MeasureSpec.getSize(spec);
5372
5373 int size = Math.max(0, specSize - padding);
5374
5375 int resultSize = 0;
5376 int resultMode = 0;
5377
5378 switch (specMode) {
5379 // Parent has imposed an exact size on us
5380 case MeasureSpec.EXACTLY:
5381 if (childDimension >= 0) {
5382 resultSize = childDimension;
5383 resultMode = MeasureSpec.EXACTLY;
Romain Guy980a9382010-01-08 15:06:28 -08005384 } else if (childDimension == LayoutParams.MATCH_PARENT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005385 // Child wants to be our size. So be it.
5386 resultSize = size;
5387 resultMode = MeasureSpec.EXACTLY;
5388 } else if (childDimension == LayoutParams.WRAP_CONTENT) {
5389 // Child wants to determine its own size. It can't be
5390 // bigger than us.
5391 resultSize = size;
5392 resultMode = MeasureSpec.AT_MOST;
5393 }
5394 break;
5395
5396 // Parent has imposed a maximum size on us
5397 case MeasureSpec.AT_MOST:
5398 if (childDimension >= 0) {
5399 // Child wants a specific size... so be it
5400 resultSize = childDimension;
5401 resultMode = MeasureSpec.EXACTLY;
Romain Guy980a9382010-01-08 15:06:28 -08005402 } else if (childDimension == LayoutParams.MATCH_PARENT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005403 // Child wants to be our size, but our size is not fixed.
5404 // Constrain child to not be bigger than us.
5405 resultSize = size;
5406 resultMode = MeasureSpec.AT_MOST;
5407 } else if (childDimension == LayoutParams.WRAP_CONTENT) {
5408 // Child wants to determine its own size. It can't be
5409 // bigger than us.
5410 resultSize = size;
5411 resultMode = MeasureSpec.AT_MOST;
5412 }
5413 break;
5414
5415 // Parent asked to see how big we want to be
5416 case MeasureSpec.UNSPECIFIED:
5417 if (childDimension >= 0) {
5418 // Child wants a specific size... let him have it
5419 resultSize = childDimension;
5420 resultMode = MeasureSpec.EXACTLY;
Romain Guy980a9382010-01-08 15:06:28 -08005421 } else if (childDimension == LayoutParams.MATCH_PARENT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005422 // Child wants to be our size... find out how big it should
5423 // be
5424 resultSize = 0;
5425 resultMode = MeasureSpec.UNSPECIFIED;
5426 } else if (childDimension == LayoutParams.WRAP_CONTENT) {
5427 // Child wants to determine its own size.... find out how
5428 // big it should be
5429 resultSize = 0;
5430 resultMode = MeasureSpec.UNSPECIFIED;
5431 }
5432 break;
5433 }
5434 return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
5435 }
5436
5437
5438 /**
5439 * Removes any pending animations for views that have been removed. Call
5440 * this if you don't want animations for exiting views to stack up.
5441 */
5442 public void clearDisappearingChildren() {
John Reckca7a9da2014-03-05 16:29:07 -08005443 final ArrayList<View> disappearingChildren = mDisappearingChildren;
5444 if (disappearingChildren != null) {
5445 final int count = disappearingChildren.size();
5446 for (int i = 0; i < count; i++) {
5447 final View view = disappearingChildren.get(i);
5448 if (view.mAttachInfo != null) {
5449 view.dispatchDetachedFromWindow();
5450 }
5451 view.clearAnimation();
5452 }
5453 disappearingChildren.clear();
Chet Haaseb85967b2012-03-26 14:37:51 -07005454 invalidate();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005455 }
5456 }
5457
5458 /**
5459 * Add a view which is removed from mChildren but still needs animation
5460 *
5461 * @param v View to add
5462 */
5463 private void addDisappearingView(View v) {
5464 ArrayList<View> disappearingChildren = mDisappearingChildren;
5465
5466 if (disappearingChildren == null) {
5467 disappearingChildren = mDisappearingChildren = new ArrayList<View>();
5468 }
5469
5470 disappearingChildren.add(v);
5471 }
5472
5473 /**
5474 * Cleanup a view when its animation is done. This may mean removing it from
5475 * the list of disappearing views.
5476 *
5477 * @param view The view whose animation has finished
5478 * @param animation The animation, cannot be null
5479 */
Chet Haase64a48c12012-02-13 16:33:29 -08005480 void finishAnimatingView(final View view, Animation animation) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005481 final ArrayList<View> disappearingChildren = mDisappearingChildren;
5482 if (disappearingChildren != null) {
5483 if (disappearingChildren.contains(view)) {
5484 disappearingChildren.remove(view);
5485
5486 if (view.mAttachInfo != null) {
5487 view.dispatchDetachedFromWindow();
5488 }
5489
5490 view.clearAnimation();
5491 mGroupFlags |= FLAG_INVALIDATE_REQUIRED;
5492 }
5493 }
5494
5495 if (animation != null && !animation.getFillAfter()) {
5496 view.clearAnimation();
5497 }
5498
Dianne Hackborn4702a852012-08-17 15:18:29 -07005499 if ((view.mPrivateFlags & PFLAG_ANIMATION_STARTED) == PFLAG_ANIMATION_STARTED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005500 view.onAnimationEnd();
5501 // Should be performed by onAnimationEnd() but this avoid an infinite loop,
5502 // so we'd rather be safe than sorry
Dianne Hackborn4702a852012-08-17 15:18:29 -07005503 view.mPrivateFlags &= ~PFLAG_ANIMATION_STARTED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005504 // Draw one more frame after the animation is done
5505 mGroupFlags |= FLAG_INVALIDATE_REQUIRED;
5506 }
5507 }
5508
Chet Haaseb20db3e2010-09-10 13:07:30 -07005509 /**
Chet Haaseaceafe62011-08-26 15:44:33 -07005510 * Utility function called by View during invalidation to determine whether a view that
5511 * is invisible or gone should still be invalidated because it is being transitioned (and
5512 * therefore still needs to be drawn).
5513 */
5514 boolean isViewTransitioning(View view) {
5515 return (mTransitioningViews != null && mTransitioningViews.contains(view));
5516 }
5517
5518 /**
Chet Haaseb20db3e2010-09-10 13:07:30 -07005519 * This method tells the ViewGroup that the given View object, which should have this
5520 * ViewGroup as its parent,
5521 * should be kept around (re-displayed when the ViewGroup draws its children) even if it
5522 * is removed from its parent. This allows animations, such as those used by
5523 * {@link android.app.Fragment} and {@link android.animation.LayoutTransition} to animate
5524 * the removal of views. A call to this method should always be accompanied by a later call
5525 * to {@link #endViewTransition(View)}, such as after an animation on the View has finished,
5526 * so that the View finally gets removed.
5527 *
5528 * @param view The View object to be kept visible even if it gets removed from its parent.
5529 */
5530 public void startViewTransition(View view) {
5531 if (view.mParent == this) {
5532 if (mTransitioningViews == null) {
5533 mTransitioningViews = new ArrayList<View>();
5534 }
5535 mTransitioningViews.add(view);
5536 }
5537 }
5538
5539 /**
5540 * This method should always be called following an earlier call to
5541 * {@link #startViewTransition(View)}. The given View is finally removed from its parent
5542 * and will no longer be displayed. Note that this method does not perform the functionality
5543 * of removing a view from its parent; it just discontinues the display of a View that
5544 * has previously been removed.
5545 *
5546 * @return view The View object that has been removed but is being kept around in the visible
5547 * hierarchy by an earlier call to {@link #startViewTransition(View)}.
5548 */
5549 public void endViewTransition(View view) {
5550 if (mTransitioningViews != null) {
5551 mTransitioningViews.remove(view);
5552 final ArrayList<View> disappearingChildren = mDisappearingChildren;
5553 if (disappearingChildren != null && disappearingChildren.contains(view)) {
5554 disappearingChildren.remove(view);
Chet Haase5e25c2c2010-09-16 11:15:56 -07005555 if (mVisibilityChangingChildren != null &&
5556 mVisibilityChangingChildren.contains(view)) {
5557 mVisibilityChangingChildren.remove(view);
5558 } else {
5559 if (view.mAttachInfo != null) {
5560 view.dispatchDetachedFromWindow();
5561 }
5562 if (view.mParent != null) {
5563 view.mParent = null;
5564 }
Chet Haaseb20db3e2010-09-10 13:07:30 -07005565 }
Chet Haaseb85967b2012-03-26 14:37:51 -07005566 invalidate();
Chet Haaseb20db3e2010-09-10 13:07:30 -07005567 }
5568 }
5569 }
5570
Chet Haase21cd1382010-09-01 17:42:29 -07005571 private LayoutTransition.TransitionListener mLayoutTransitionListener =
5572 new LayoutTransition.TransitionListener() {
5573 @Override
5574 public void startTransition(LayoutTransition transition, ViewGroup container,
5575 View view, int transitionType) {
5576 // We only care about disappearing items, since we need special logic to keep
5577 // those items visible after they've been 'removed'
5578 if (transitionType == LayoutTransition.DISAPPEARING) {
Chet Haaseb20db3e2010-09-10 13:07:30 -07005579 startViewTransition(view);
Chet Haase21cd1382010-09-01 17:42:29 -07005580 }
5581 }
5582
5583 @Override
5584 public void endTransition(LayoutTransition transition, ViewGroup container,
5585 View view, int transitionType) {
Chet Haaseb9895022013-04-02 15:10:58 -07005586 if (mLayoutCalledWhileSuppressed && !transition.isChangingLayout()) {
Chet Haase9c087442011-01-12 16:20:16 -08005587 requestLayout();
Chet Haaseb9895022013-04-02 15:10:58 -07005588 mLayoutCalledWhileSuppressed = false;
Chet Haase9c087442011-01-12 16:20:16 -08005589 }
Chet Haase21cd1382010-09-01 17:42:29 -07005590 if (transitionType == LayoutTransition.DISAPPEARING && mTransitioningViews != null) {
Chet Haaseb20db3e2010-09-10 13:07:30 -07005591 endViewTransition(view);
Chet Haase21cd1382010-09-01 17:42:29 -07005592 }
5593 }
5594 };
5595
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005596 /**
Chet Haaseb9895022013-04-02 15:10:58 -07005597 * Tells this ViewGroup to suppress all layout() calls until layout
5598 * suppression is disabled with a later call to suppressLayout(false).
5599 * When layout suppression is disabled, a requestLayout() call is sent
5600 * if layout() was attempted while layout was being suppressed.
5601 *
5602 * @hide
5603 */
5604 public void suppressLayout(boolean suppress) {
5605 mSuppressLayout = suppress;
5606 if (!suppress) {
5607 if (mLayoutCalledWhileSuppressed) {
5608 requestLayout();
5609 mLayoutCalledWhileSuppressed = false;
5610 }
5611 }
5612 }
5613
5614 /**
Chet Haase199acdf2013-07-24 18:40:55 -07005615 * Returns whether layout calls on this container are currently being
5616 * suppressed, due to an earlier call to {@link #suppressLayout(boolean)}.
5617 *
5618 * @return true if layout calls are currently suppressed, false otherwise.
5619 *
5620 * @hide
5621 */
5622 public boolean isLayoutSuppressed() {
5623 return mSuppressLayout;
5624 }
5625
5626 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005627 * {@inheritDoc}
5628 */
5629 @Override
5630 public boolean gatherTransparentRegion(Region region) {
5631 // If no transparent regions requested, we are always opaque.
Dianne Hackborn4702a852012-08-17 15:18:29 -07005632 final boolean meOpaque = (mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) == 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005633 if (meOpaque && region == null) {
5634 // The caller doesn't care about the region, so stop now.
5635 return true;
5636 }
5637 super.gatherTransparentRegion(region);
5638 final View[] children = mChildren;
5639 final int count = mChildrenCount;
5640 boolean noneOfTheChildrenAreTransparent = true;
5641 for (int i = 0; i < count; i++) {
5642 final View child = children[i];
Mathias Agopiane3381152010-12-02 15:19:36 -08005643 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005644 if (!child.gatherTransparentRegion(region)) {
5645 noneOfTheChildrenAreTransparent = false;
5646 }
5647 }
5648 }
5649 return meOpaque || noneOfTheChildrenAreTransparent;
5650 }
5651
5652 /**
5653 * {@inheritDoc}
5654 */
5655 public void requestTransparentRegion(View child) {
5656 if (child != null) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07005657 child.mPrivateFlags |= View.PFLAG_REQUEST_TRANSPARENT_REGIONS;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005658 if (mParent != null) {
5659 mParent.requestTransparentRegion(this);
5660 }
5661 }
5662 }
Romain Guy8506ab42009-06-11 17:35:47 -07005663
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005664 @Override
Adam Powell46e38fd2014-02-03 10:16:49 -08005665 public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) {
5666 insets = super.dispatchApplyWindowInsets(insets);
Adam Powell0d9fdba2014-06-11 15:33:08 -07005667 if (!insets.isConsumed()) {
Adam Powell46e38fd2014-02-03 10:16:49 -08005668 final int count = getChildCount();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005669 for (int i = 0; i < count; i++) {
Adam Powell46e38fd2014-02-03 10:16:49 -08005670 insets = getChildAt(i).dispatchApplyWindowInsets(insets);
Adam Powell0d9fdba2014-06-11 15:33:08 -07005671 if (insets.isConsumed()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005672 break;
5673 }
5674 }
5675 }
Adam Powell46e38fd2014-02-03 10:16:49 -08005676 return insets;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005677 }
5678
5679 /**
5680 * Returns the animation listener to which layout animation events are
5681 * sent.
5682 *
5683 * @return an {@link android.view.animation.Animation.AnimationListener}
5684 */
5685 public Animation.AnimationListener getLayoutAnimationListener() {
5686 return mAnimationListener;
5687 }
5688
5689 @Override
5690 protected void drawableStateChanged() {
5691 super.drawableStateChanged();
5692
5693 if ((mGroupFlags & FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE) != 0) {
5694 if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0) {
5695 throw new IllegalStateException("addStateFromChildren cannot be enabled if a"
5696 + " child has duplicateParentState set to true");
5697 }
5698
5699 final View[] children = mChildren;
5700 final int count = mChildrenCount;
5701
5702 for (int i = 0; i < count; i++) {
5703 final View child = children[i];
5704 if ((child.mViewFlags & DUPLICATE_PARENT_STATE) != 0) {
5705 child.refreshDrawableState();
5706 }
5707 }
5708 }
5709 }
5710
5711 @Override
Dianne Hackborne2136772010-11-04 15:08:59 -07005712 public void jumpDrawablesToCurrentState() {
5713 super.jumpDrawablesToCurrentState();
5714 final View[] children = mChildren;
5715 final int count = mChildrenCount;
5716 for (int i = 0; i < count; i++) {
5717 children[i].jumpDrawablesToCurrentState();
5718 }
5719 }
5720
5721 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005722 protected int[] onCreateDrawableState(int extraSpace) {
5723 if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) == 0) {
5724 return super.onCreateDrawableState(extraSpace);
5725 }
5726
5727 int need = 0;
5728 int n = getChildCount();
5729 for (int i = 0; i < n; i++) {
5730 int[] childState = getChildAt(i).getDrawableState();
5731
5732 if (childState != null) {
5733 need += childState.length;
5734 }
5735 }
5736
5737 int[] state = super.onCreateDrawableState(extraSpace + need);
5738
5739 for (int i = 0; i < n; i++) {
5740 int[] childState = getChildAt(i).getDrawableState();
5741
5742 if (childState != null) {
5743 state = mergeDrawableStates(state, childState);
5744 }
5745 }
5746
5747 return state;
5748 }
5749
5750 /**
5751 * Sets whether this ViewGroup's drawable states also include
5752 * its children's drawable states. This is used, for example, to
5753 * make a group appear to be focused when its child EditText or button
5754 * is focused.
5755 */
5756 public void setAddStatesFromChildren(boolean addsStates) {
5757 if (addsStates) {
5758 mGroupFlags |= FLAG_ADD_STATES_FROM_CHILDREN;
5759 } else {
5760 mGroupFlags &= ~FLAG_ADD_STATES_FROM_CHILDREN;
5761 }
5762
5763 refreshDrawableState();
5764 }
5765
5766 /**
5767 * Returns whether this ViewGroup's drawable states also include
5768 * its children's drawable states. This is used, for example, to
5769 * make a group appear to be focused when its child EditText or button
5770 * is focused.
5771 */
5772 public boolean addStatesFromChildren() {
5773 return (mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0;
5774 }
5775
5776 /**
Jeff Smitha45746e2012-07-19 14:19:24 -05005777 * If {@link #addStatesFromChildren} is true, refreshes this group's
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005778 * drawable state (to include the states from its children).
5779 */
5780 public void childDrawableStateChanged(View child) {
5781 if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0) {
5782 refreshDrawableState();
5783 }
5784 }
5785
5786 /**
5787 * Specifies the animation listener to which layout animation events must
5788 * be sent. Only
5789 * {@link android.view.animation.Animation.AnimationListener#onAnimationStart(Animation)}
5790 * and
5791 * {@link android.view.animation.Animation.AnimationListener#onAnimationEnd(Animation)}
5792 * are invoked.
5793 *
5794 * @param animationListener the layout animation listener
5795 */
5796 public void setLayoutAnimationListener(Animation.AnimationListener animationListener) {
5797 mAnimationListener = animationListener;
5798 }
5799
5800 /**
Chet Haasecca2c982011-05-20 14:34:18 -07005801 * This method is called by LayoutTransition when there are 'changing' animations that need
5802 * to start after the layout/setup phase. The request is forwarded to the ViewAncestor, who
5803 * starts all pending transitions prior to the drawing phase in the current traversal.
5804 *
5805 * @param transition The LayoutTransition to be started on the next traversal.
5806 *
5807 * @hide
5808 */
5809 public void requestTransitionStart(LayoutTransition transition) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07005810 ViewRootImpl viewAncestor = getViewRootImpl();
Chet Haase1abf7fa2011-08-17 18:31:56 -07005811 if (viewAncestor != null) {
5812 viewAncestor.requestTransitionStart(transition);
5813 }
Chet Haasecca2c982011-05-20 14:34:18 -07005814 }
5815
Fabrice Di Meglio4457e852012-09-18 19:23:12 -07005816 /**
5817 * @hide
5818 */
Fabrice Di Meglio80dc53d2011-06-21 18:36:33 -07005819 @Override
Fabrice Di Meglio09ecb252013-05-03 16:51:55 -07005820 public boolean resolveRtlPropertiesIfNeeded() {
5821 final boolean result = super.resolveRtlPropertiesIfNeeded();
5822 // We dont need to resolve the children RTL properties if nothing has changed for the parent
5823 if (result) {
5824 int count = getChildCount();
5825 for (int i = 0; i < count; i++) {
5826 final View child = getChildAt(i);
5827 if (child.isLayoutDirectionInherited()) {
5828 child.resolveRtlPropertiesIfNeeded();
5829 }
Fabrice Di Meglio84ebb352012-10-11 16:27:37 -07005830 }
5831 }
Fabrice Di Meglio09ecb252013-05-03 16:51:55 -07005832 return result;
Fabrice Di Meglio84ebb352012-10-11 16:27:37 -07005833 }
5834
5835 /**
5836 * @hide
5837 */
5838 @Override
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07005839 public boolean resolveLayoutDirection() {
5840 final boolean result = super.resolveLayoutDirection();
5841 if (result) {
5842 int count = getChildCount();
5843 for (int i = 0; i < count; i++) {
5844 final View child = getChildAt(i);
5845 if (child.isLayoutDirectionInherited()) {
5846 child.resolveLayoutDirection();
5847 }
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07005848 }
5849 }
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07005850 return result;
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07005851 }
5852
5853 /**
5854 * @hide
5855 */
5856 @Override
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07005857 public boolean resolveTextDirection() {
5858 final boolean result = super.resolveTextDirection();
5859 if (result) {
5860 int count = getChildCount();
5861 for (int i = 0; i < count; i++) {
5862 final View child = getChildAt(i);
5863 if (child.isTextDirectionInherited()) {
5864 child.resolveTextDirection();
5865 }
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07005866 }
5867 }
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07005868 return result;
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07005869 }
5870
5871 /**
5872 * @hide
5873 */
5874 @Override
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07005875 public boolean resolveTextAlignment() {
5876 final boolean result = super.resolveTextAlignment();
5877 if (result) {
5878 int count = getChildCount();
5879 for (int i = 0; i < count; i++) {
5880 final View child = getChildAt(i);
5881 if (child.isTextAlignmentInherited()) {
5882 child.resolveTextAlignment();
5883 }
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07005884 }
5885 }
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07005886 return result;
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07005887 }
5888
5889 /**
5890 * @hide
5891 */
5892 @Override
Fabrice Di Meglio84ebb352012-10-11 16:27:37 -07005893 public void resolvePadding() {
5894 super.resolvePadding();
5895 int count = getChildCount();
5896 for (int i = 0; i < count; i++) {
5897 final View child = getChildAt(i);
5898 if (child.isLayoutDirectionInherited()) {
5899 child.resolvePadding();
5900 }
5901 }
5902 }
5903
5904 /**
5905 * @hide
5906 */
5907 @Override
5908 protected void resolveDrawables() {
5909 super.resolveDrawables();
5910 int count = getChildCount();
5911 for (int i = 0; i < count; i++) {
5912 final View child = getChildAt(i);
5913 if (child.isLayoutDirectionInherited()) {
5914 child.resolveDrawables();
5915 }
5916 }
5917 }
5918
Fabrice Di Meglio1e0ed6b2012-10-18 16:06:52 -07005919 /**
5920 * @hide
5921 */
Fabrice Di Megliofcc33482012-10-18 11:11:51 -07005922 @Override
5923 public void resolveLayoutParams() {
5924 super.resolveLayoutParams();
5925 int count = getChildCount();
5926 for (int i = 0; i < count; i++) {
5927 final View child = getChildAt(i);
5928 child.resolveLayoutParams();
5929 }
5930 }
5931
Fabrice Di Meglio84ebb352012-10-11 16:27:37 -07005932 /**
5933 * @hide
5934 */
5935 @Override
Fabrice Di Meglio4457e852012-09-18 19:23:12 -07005936 public void resetResolvedLayoutDirection() {
5937 super.resetResolvedLayoutDirection();
5938
Fabrice Di Meglio4457e852012-09-18 19:23:12 -07005939 int count = getChildCount();
Fabrice Di Meglio80dc53d2011-06-21 18:36:33 -07005940 for (int i = 0; i < count; i++) {
5941 final View child = getChildAt(i);
Fabrice Di Meglioe56ffdc2012-09-23 14:51:16 -07005942 if (child.isLayoutDirectionInherited()) {
Fabrice Di Meglio7f86c802011-07-01 15:09:24 -07005943 child.resetResolvedLayoutDirection();
Fabrice Di Meglio80dc53d2011-06-21 18:36:33 -07005944 }
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07005945 }
5946 }
5947
5948 /**
5949 * @hide
5950 */
5951 @Override
5952 public void resetResolvedTextDirection() {
5953 super.resetResolvedTextDirection();
5954
5955 int count = getChildCount();
5956 for (int i = 0; i < count; i++) {
5957 final View child = getChildAt(i);
Fabrice Di Meglio97e146c2012-09-23 15:45:16 -07005958 if (child.isTextDirectionInherited()) {
Fabrice Di Meglio22268862011-06-27 18:13:18 -07005959 child.resetResolvedTextDirection();
5960 }
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07005961 }
5962 }
5963
5964 /**
5965 * @hide
5966 */
5967 @Override
5968 public void resetResolvedTextAlignment() {
5969 super.resetResolvedTextAlignment();
5970
5971 int count = getChildCount();
5972 for (int i = 0; i < count; i++) {
5973 final View child = getChildAt(i);
Fabrice Di Meglio1a7d4872012-09-23 16:19:58 -07005974 if (child.isTextAlignmentInherited()) {
Fabrice Di Meglio9da0f8a2012-03-13 19:37:57 -07005975 child.resetResolvedTextAlignment();
5976 }
5977 }
5978 }
5979
Fabrice Di Meglio22268862011-06-27 18:13:18 -07005980 /**
Fabrice Di Meglio84ebb352012-10-11 16:27:37 -07005981 * @hide
5982 */
5983 @Override
5984 public void resetResolvedPadding() {
5985 super.resetResolvedPadding();
5986
5987 int count = getChildCount();
5988 for (int i = 0; i < count; i++) {
5989 final View child = getChildAt(i);
5990 if (child.isLayoutDirectionInherited()) {
5991 child.resetResolvedPadding();
5992 }
5993 }
5994 }
5995
5996 /**
5997 * @hide
5998 */
5999 @Override
6000 protected void resetResolvedDrawables() {
6001 super.resetResolvedDrawables();
6002
6003 int count = getChildCount();
6004 for (int i = 0; i < count; i++) {
6005 final View child = getChildAt(i);
6006 if (child.isLayoutDirectionInherited()) {
6007 child.resetResolvedDrawables();
6008 }
6009 }
6010 }
6011
6012 /**
Patrick Dubroye0a799a2011-05-04 16:19:22 -07006013 * Return true if the pressed state should be delayed for children or descendants of this
6014 * ViewGroup. Generally, this should be done for containers that can scroll, such as a List.
6015 * This prevents the pressed state from appearing when the user is actually trying to scroll
6016 * the content.
6017 *
6018 * The default implementation returns true for compatibility reasons. Subclasses that do
6019 * not scroll should generally override this method and return false.
6020 */
6021 public boolean shouldDelayChildPressedState() {
6022 return true;
6023 }
6024
Adam Powell10ba2772014-04-15 09:46:51 -07006025 /**
6026 * @inheritDoc
6027 */
6028 @Override
6029 public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
6030 return false;
6031 }
6032
6033 /**
6034 * @inheritDoc
6035 */
6036 @Override
6037 public void onNestedScrollAccepted(View child, View target, int axes) {
6038 mNestedScrollAxes = axes;
6039 }
6040
6041 /**
6042 * @inheritDoc
6043 *
6044 * <p>The default implementation of onStopNestedScroll calls
6045 * {@link #stopNestedScroll()} to halt any recursive nested scrolling in progress.</p>
6046 */
6047 @Override
6048 public void onStopNestedScroll(View child) {
6049 // Stop any recursive nested scrolling.
6050 stopNestedScroll();
6051 }
6052
6053 /**
6054 * @inheritDoc
6055 */
6056 @Override
6057 public void onNestedScroll(View target, int dxConsumed, int dyConsumed,
6058 int dxUnconsumed, int dyUnconsumed) {
6059 // Do nothing
6060 }
6061
6062 /**
6063 * @inheritDoc
6064 */
6065 @Override
6066 public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
6067 // Do nothing
6068 }
6069
6070 /**
6071 * @inheritDoc
6072 */
6073 @Override
Adam Powellb36e4f92014-05-01 10:23:33 -07006074 public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
Adam Powell10ba2772014-04-15 09:46:51 -07006075 return false;
6076 }
6077
6078 /**
Adam Powellb72be592014-07-16 21:41:31 -07006079 * @inheritDoc
6080 */
6081 @Override
6082 public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
6083 return false;
6084 }
6085
6086 /**
Adam Powell10ba2772014-04-15 09:46:51 -07006087 * Return the current axes of nested scrolling for this ViewGroup.
6088 *
6089 * <p>A ViewGroup returning something other than {@link #SCROLL_AXIS_NONE} is currently
6090 * acting as a nested scrolling parent for one or more descendant views in the hierarchy.</p>
6091 *
6092 * @return Flags indicating the current axes of nested scrolling
6093 * @see #SCROLL_AXIS_HORIZONTAL
6094 * @see #SCROLL_AXIS_VERTICAL
6095 * @see #SCROLL_AXIS_NONE
6096 */
6097 public int getNestedScrollAxes() {
6098 return mNestedScrollAxes;
6099 }
6100
Philip Milned7dd8902012-01-26 16:55:30 -08006101 /** @hide */
6102 protected void onSetLayoutParams(View child, LayoutParams layoutParams) {
6103 }
6104
George Mounte1803372014-02-26 19:00:52 +00006105 /** @hide */
6106 @Override
6107 public void captureTransitioningViews(List<View> transitioningViews) {
6108 if (getVisibility() != View.VISIBLE) {
6109 return;
6110 }
6111 if (isTransitionGroup()) {
6112 transitioningViews.add(this);
6113 } else {
6114 int count = getChildCount();
6115 for (int i = 0; i < count; i++) {
6116 View child = getChildAt(i);
6117 child.captureTransitioningViews(transitioningViews);
6118 }
6119 }
6120 }
6121
6122 /** @hide */
6123 @Override
George Mountabb352a2014-05-09 10:27:20 -07006124 public void findNamedViews(Map<String, View> namedElements) {
George Mountfe361d22014-07-08 17:25:25 -07006125 if (getVisibility() != VISIBLE && mGhostView == null) {
George Mounte1803372014-02-26 19:00:52 +00006126 return;
6127 }
George Mountabb352a2014-05-09 10:27:20 -07006128 super.findNamedViews(namedElements);
George Mounte1803372014-02-26 19:00:52 +00006129 int count = getChildCount();
6130 for (int i = 0; i < count; i++) {
6131 View child = getChildAt(i);
George Mountabb352a2014-05-09 10:27:20 -07006132 child.findNamedViews(namedElements);
George Mounte1803372014-02-26 19:00:52 +00006133 }
6134 }
6135
Patrick Dubroye0a799a2011-05-04 16:19:22 -07006136 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006137 * LayoutParams are used by views to tell their parents how they want to be
6138 * laid out. See
6139 * {@link android.R.styleable#ViewGroup_Layout ViewGroup Layout Attributes}
6140 * for a list of all child view attributes that this class supports.
Romain Guy8506ab42009-06-11 17:35:47 -07006141 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006142 * <p>
6143 * The base LayoutParams class just describes how big the view wants to be
6144 * for both width and height. For each dimension, it can specify one of:
6145 * <ul>
Dirk Dougherty75c66da2010-03-25 16:33:33 -07006146 * <li>FILL_PARENT (renamed MATCH_PARENT in API Level 8 and higher), which
6147 * means that the view wants to be as big as its parent (minus padding)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006148 * <li> WRAP_CONTENT, which means that the view wants to be just big enough
6149 * to enclose its content (plus padding)
Dirk Dougherty75c66da2010-03-25 16:33:33 -07006150 * <li> an exact number
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006151 * </ul>
6152 * There are subclasses of LayoutParams for different subclasses of
6153 * ViewGroup. For example, AbsoluteLayout has its own subclass of
Joe Fernandez558459f2011-10-13 16:47:36 -07006154 * LayoutParams which adds an X and Y value.</p>
6155 *
6156 * <div class="special reference">
6157 * <h3>Developer Guides</h3>
6158 * <p>For more information about creating user interface layouts, read the
6159 * <a href="{@docRoot}guide/topics/ui/declaring-layout.html">XML Layouts</a> developer
6160 * guide.</p></div>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006161 *
6162 * @attr ref android.R.styleable#ViewGroup_Layout_layout_height
6163 * @attr ref android.R.styleable#ViewGroup_Layout_layout_width
6164 */
6165 public static class LayoutParams {
6166 /**
Dirk Dougherty75c66da2010-03-25 16:33:33 -07006167 * Special value for the height or width requested by a View.
6168 * FILL_PARENT means that the view wants to be as big as its parent,
6169 * minus the parent's padding, if any. This value is deprecated
6170 * starting in API Level 8 and replaced by {@link #MATCH_PARENT}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006171 */
Romain Guy980a9382010-01-08 15:06:28 -08006172 @SuppressWarnings({"UnusedDeclaration"})
6173 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006174 public static final int FILL_PARENT = -1;
6175
6176 /**
6177 * Special value for the height or width requested by a View.
Gilles Debunnef5c6eff2010-02-09 19:08:36 -08006178 * MATCH_PARENT means that the view wants to be as big as its parent,
Dirk Dougherty75c66da2010-03-25 16:33:33 -07006179 * minus the parent's padding, if any. Introduced in API Level 8.
Romain Guy980a9382010-01-08 15:06:28 -08006180 */
6181 public static final int MATCH_PARENT = -1;
6182
6183 /**
6184 * Special value for the height or width requested by a View.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006185 * WRAP_CONTENT means that the view wants to be just large enough to fit
6186 * its own internal content, taking its own padding into account.
6187 */
6188 public static final int WRAP_CONTENT = -2;
6189
6190 /**
Dirk Dougherty75c66da2010-03-25 16:33:33 -07006191 * Information about how wide the view wants to be. Can be one of the
6192 * constants FILL_PARENT (replaced by MATCH_PARENT ,
6193 * in API Level 8) or WRAP_CONTENT. or an exact size.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006194 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07006195 @ViewDebug.ExportedProperty(category = "layout", mapping = {
Romain Guy980a9382010-01-08 15:06:28 -08006196 @ViewDebug.IntToString(from = MATCH_PARENT, to = "MATCH_PARENT"),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006197 @ViewDebug.IntToString(from = WRAP_CONTENT, to = "WRAP_CONTENT")
6198 })
6199 public int width;
6200
6201 /**
Dirk Dougherty75c66da2010-03-25 16:33:33 -07006202 * Information about how tall the view wants to be. Can be one of the
6203 * constants FILL_PARENT (replaced by MATCH_PARENT ,
6204 * in API Level 8) or WRAP_CONTENT. or an exact size.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006205 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07006206 @ViewDebug.ExportedProperty(category = "layout", mapping = {
Romain Guy980a9382010-01-08 15:06:28 -08006207 @ViewDebug.IntToString(from = MATCH_PARENT, to = "MATCH_PARENT"),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006208 @ViewDebug.IntToString(from = WRAP_CONTENT, to = "WRAP_CONTENT")
6209 })
6210 public int height;
6211
6212 /**
6213 * Used to animate layouts.
6214 */
6215 public LayoutAnimationController.AnimationParameters layoutAnimationParameters;
6216
6217 /**
6218 * Creates a new set of layout parameters. The values are extracted from
6219 * the supplied attributes set and context. The XML attributes mapped
6220 * to this set of layout parameters are:
6221 *
6222 * <ul>
6223 * <li><code>layout_width</code>: the width, either an exact value,
Dirk Dougherty75c66da2010-03-25 16:33:33 -07006224 * {@link #WRAP_CONTENT}, or {@link #FILL_PARENT} (replaced by
6225 * {@link #MATCH_PARENT} in API Level 8)</li>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006226 * <li><code>layout_height</code>: the height, either an exact value,
Dirk Dougherty75c66da2010-03-25 16:33:33 -07006227 * {@link #WRAP_CONTENT}, or {@link #FILL_PARENT} (replaced by
6228 * {@link #MATCH_PARENT} in API Level 8)</li>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006229 * </ul>
6230 *
6231 * @param c the application environment
6232 * @param attrs the set of attributes from which to extract the layout
6233 * parameters' values
6234 */
6235 public LayoutParams(Context c, AttributeSet attrs) {
6236 TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.ViewGroup_Layout);
6237 setBaseAttributes(a,
6238 R.styleable.ViewGroup_Layout_layout_width,
6239 R.styleable.ViewGroup_Layout_layout_height);
6240 a.recycle();
6241 }
6242
6243 /**
6244 * Creates a new set of layout parameters with the specified width
6245 * and height.
6246 *
Dirk Dougherty75c66da2010-03-25 16:33:33 -07006247 * @param width the width, either {@link #WRAP_CONTENT},
6248 * {@link #FILL_PARENT} (replaced by {@link #MATCH_PARENT} in
6249 * API Level 8), or a fixed size in pixels
6250 * @param height the height, either {@link #WRAP_CONTENT},
6251 * {@link #FILL_PARENT} (replaced by {@link #MATCH_PARENT} in
6252 * API Level 8), or a fixed size in pixels
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006253 */
6254 public LayoutParams(int width, int height) {
6255 this.width = width;
6256 this.height = height;
6257 }
6258
6259 /**
6260 * Copy constructor. Clones the width and height values of the source.
6261 *
6262 * @param source The layout params to copy from.
6263 */
6264 public LayoutParams(LayoutParams source) {
6265 this.width = source.width;
6266 this.height = source.height;
6267 }
6268
6269 /**
6270 * Used internally by MarginLayoutParams.
6271 * @hide
6272 */
6273 LayoutParams() {
6274 }
6275
6276 /**
Dave Burke579e1402012-10-18 20:41:55 -07006277 * Extracts the layout parameters from the supplied attributes.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006278 *
6279 * @param a the style attributes to extract the parameters from
6280 * @param widthAttr the identifier of the width attribute
6281 * @param heightAttr the identifier of the height attribute
6282 */
6283 protected void setBaseAttributes(TypedArray a, int widthAttr, int heightAttr) {
Dave Burke579e1402012-10-18 20:41:55 -07006284 width = a.getLayoutDimension(widthAttr, "layout_width");
6285 height = a.getLayoutDimension(heightAttr, "layout_height");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006286 }
6287
6288 /**
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006289 * Resolve layout parameters depending on the layout direction. Subclasses that care about
6290 * layoutDirection changes should override this method. The default implementation does
6291 * nothing.
6292 *
6293 * @param layoutDirection the direction of the layout
6294 *
6295 * {@link View#LAYOUT_DIRECTION_LTR}
6296 * {@link View#LAYOUT_DIRECTION_RTL}
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006297 */
Fabrice Di Meglio2918ab62012-10-10 16:39:25 -07006298 public void resolveLayoutDirection(int layoutDirection) {
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006299 }
6300
6301 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006302 * Returns a String representation of this set of layout parameters.
6303 *
6304 * @param output the String to prepend to the internal representation
6305 * @return a String with the following format: output +
6306 * "ViewGroup.LayoutParams={ width=WIDTH, height=HEIGHT }"
Romain Guy8506ab42009-06-11 17:35:47 -07006307 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006308 * @hide
6309 */
6310 public String debug(String output) {
6311 return output + "ViewGroup.LayoutParams={ width="
6312 + sizeToString(width) + ", height=" + sizeToString(height) + " }";
6313 }
6314
6315 /**
Philip Milne10ca24a2012-04-23 15:38:27 -07006316 * Use {@code canvas} to draw suitable debugging annotations for these LayoutParameters.
6317 *
6318 * @param view the view that contains these layout parameters
6319 * @param canvas the canvas on which to draw
6320 *
6321 * @hide
6322 */
Philip Milne7b757812012-09-19 18:13:44 -07006323 public void onDebugDraw(View view, Canvas canvas, Paint paint) {
Philip Milne10ca24a2012-04-23 15:38:27 -07006324 }
6325
6326 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006327 * Converts the specified size to a readable String.
6328 *
6329 * @param size the size to convert
6330 * @return a String instance representing the supplied size
Romain Guy8506ab42009-06-11 17:35:47 -07006331 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006332 * @hide
6333 */
6334 protected static String sizeToString(int size) {
6335 if (size == WRAP_CONTENT) {
6336 return "wrap-content";
6337 }
Romain Guy980a9382010-01-08 15:06:28 -08006338 if (size == MATCH_PARENT) {
6339 return "match-parent";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006340 }
6341 return String.valueOf(size);
6342 }
6343 }
6344
6345 /**
6346 * Per-child layout information for layouts that support margins.
6347 * See
6348 * {@link android.R.styleable#ViewGroup_MarginLayout ViewGroup Margin Layout Attributes}
6349 * for a list of all child view attributes that this class supports.
6350 */
6351 public static class MarginLayoutParams extends ViewGroup.LayoutParams {
6352 /**
Philip Milned7dd8902012-01-26 16:55:30 -08006353 * The left margin in pixels of the child.
6354 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
6355 * to this field.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006356 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07006357 @ViewDebug.ExportedProperty(category = "layout")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006358 public int leftMargin;
6359
6360 /**
Philip Milned7dd8902012-01-26 16:55:30 -08006361 * The top margin in pixels of the child.
6362 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
6363 * to this field.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006364 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07006365 @ViewDebug.ExportedProperty(category = "layout")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006366 public int topMargin;
6367
6368 /**
Philip Milned7dd8902012-01-26 16:55:30 -08006369 * The right margin in pixels of the child.
6370 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
6371 * to this field.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006372 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07006373 @ViewDebug.ExportedProperty(category = "layout")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006374 public int rightMargin;
6375
6376 /**
Philip Milned7dd8902012-01-26 16:55:30 -08006377 * The bottom margin in pixels of the child.
6378 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
6379 * to this field.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006380 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07006381 @ViewDebug.ExportedProperty(category = "layout")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006382 public int bottomMargin;
6383
6384 /**
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006385 * The start margin in pixels of the child.
Fabrice Di Meglio54546f22012-02-14 16:26:16 -08006386 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
6387 * to this field.
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006388 */
6389 @ViewDebug.ExportedProperty(category = "layout")
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006390 private int startMargin = DEFAULT_MARGIN_RELATIVE;
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006391
6392 /**
6393 * The end margin in pixels of the child.
Fabrice Di Meglio54546f22012-02-14 16:26:16 -08006394 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
6395 * to this field.
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006396 */
6397 @ViewDebug.ExportedProperty(category = "layout")
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006398 private int endMargin = DEFAULT_MARGIN_RELATIVE;
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006399
6400 /**
6401 * The default start and end margin.
Fabrice Di Megliof443f982012-07-13 20:24:03 -07006402 * @hide
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006403 */
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006404 public static final int DEFAULT_MARGIN_RELATIVE = Integer.MIN_VALUE;
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006405
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006406 /**
6407 * Bit 0: layout direction
6408 * Bit 1: layout direction
6409 * Bit 2: left margin undefined
6410 * Bit 3: right margin undefined
6411 * Bit 4: is RTL compatibility mode
6412 * Bit 5: need resolution
6413 *
6414 * Bit 6 to 7 not used
6415 *
6416 * @hide
6417 */
6418 @ViewDebug.ExportedProperty(category = "layout", flagMapping = {
6419 @ViewDebug.FlagToString(mask = LAYOUT_DIRECTION_MASK,
6420 equals = LAYOUT_DIRECTION_MASK, name = "LAYOUT_DIRECTION"),
6421 @ViewDebug.FlagToString(mask = LEFT_MARGIN_UNDEFINED_MASK,
6422 equals = LEFT_MARGIN_UNDEFINED_MASK, name = "LEFT_MARGIN_UNDEFINED_MASK"),
6423 @ViewDebug.FlagToString(mask = RIGHT_MARGIN_UNDEFINED_MASK,
6424 equals = RIGHT_MARGIN_UNDEFINED_MASK, name = "RIGHT_MARGIN_UNDEFINED_MASK"),
6425 @ViewDebug.FlagToString(mask = RTL_COMPATIBILITY_MODE_MASK,
6426 equals = RTL_COMPATIBILITY_MODE_MASK, name = "RTL_COMPATIBILITY_MODE_MASK"),
6427 @ViewDebug.FlagToString(mask = NEED_RESOLUTION_MASK,
6428 equals = NEED_RESOLUTION_MASK, name = "NEED_RESOLUTION_MASK")
Jon Miranda4597e982014-07-29 07:25:49 -07006429 }, formatToHexString = true)
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006430 byte mMarginFlags;
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07006431
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006432 private static final int LAYOUT_DIRECTION_MASK = 0x00000003;
6433 private static final int LEFT_MARGIN_UNDEFINED_MASK = 0x00000004;
6434 private static final int RIGHT_MARGIN_UNDEFINED_MASK = 0x00000008;
6435 private static final int RTL_COMPATIBILITY_MODE_MASK = 0x00000010;
6436 private static final int NEED_RESOLUTION_MASK = 0x00000020;
Fabrice Di Megliof443f982012-07-13 20:24:03 -07006437
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006438 private static final int DEFAULT_MARGIN_RESOLVED = 0;
6439 private static final int UNDEFINED_MARGIN = DEFAULT_MARGIN_RELATIVE;
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07006440
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006441 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006442 * Creates a new set of layout parameters. The values are extracted from
6443 * the supplied attributes set and context.
6444 *
6445 * @param c the application environment
6446 * @param attrs the set of attributes from which to extract the layout
6447 * parameters' values
6448 */
6449 public MarginLayoutParams(Context c, AttributeSet attrs) {
6450 super();
6451
6452 TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.ViewGroup_MarginLayout);
6453 setBaseAttributes(a,
6454 R.styleable.ViewGroup_MarginLayout_layout_width,
6455 R.styleable.ViewGroup_MarginLayout_layout_height);
6456
6457 int margin = a.getDimensionPixelSize(
6458 com.android.internal.R.styleable.ViewGroup_MarginLayout_layout_margin, -1);
6459 if (margin >= 0) {
6460 leftMargin = margin;
6461 topMargin = margin;
6462 rightMargin= margin;
6463 bottomMargin = margin;
6464 } else {
6465 leftMargin = a.getDimensionPixelSize(
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006466 R.styleable.ViewGroup_MarginLayout_layout_marginLeft,
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07006467 UNDEFINED_MARGIN);
6468 if (leftMargin == UNDEFINED_MARGIN) {
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006469 mMarginFlags |= LEFT_MARGIN_UNDEFINED_MASK;
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07006470 leftMargin = DEFAULT_MARGIN_RESOLVED;
6471 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006472 rightMargin = a.getDimensionPixelSize(
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006473 R.styleable.ViewGroup_MarginLayout_layout_marginRight,
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07006474 UNDEFINED_MARGIN);
6475 if (rightMargin == UNDEFINED_MARGIN) {
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006476 mMarginFlags |= RIGHT_MARGIN_UNDEFINED_MASK;
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07006477 rightMargin = DEFAULT_MARGIN_RESOLVED;
6478 }
6479
6480 topMargin = a.getDimensionPixelSize(
6481 R.styleable.ViewGroup_MarginLayout_layout_marginTop,
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006482 DEFAULT_MARGIN_RESOLVED);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006483 bottomMargin = a.getDimensionPixelSize(
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006484 R.styleable.ViewGroup_MarginLayout_layout_marginBottom,
6485 DEFAULT_MARGIN_RESOLVED);
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07006486
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006487 startMargin = a.getDimensionPixelSize(
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006488 R.styleable.ViewGroup_MarginLayout_layout_marginStart,
6489 DEFAULT_MARGIN_RELATIVE);
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006490 endMargin = a.getDimensionPixelSize(
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006491 R.styleable.ViewGroup_MarginLayout_layout_marginEnd,
6492 DEFAULT_MARGIN_RELATIVE);
6493
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006494 if (isMarginRelative()) {
6495 mMarginFlags |= NEED_RESOLUTION_MASK;
6496 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006497 }
6498
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006499 final boolean hasRtlSupport = c.getApplicationInfo().hasRtlSupport();
6500 final int targetSdkVersion = c.getApplicationInfo().targetSdkVersion;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006501 if (targetSdkVersion < JELLY_BEAN_MR1 || !hasRtlSupport) {
6502 mMarginFlags |= RTL_COMPATIBILITY_MODE_MASK;
6503 }
6504
6505 // Layout direction is LTR by default
6506 mMarginFlags |= LAYOUT_DIRECTION_LTR;
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07006507
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006508 a.recycle();
6509 }
6510
6511 /**
6512 * {@inheritDoc}
6513 */
6514 public MarginLayoutParams(int width, int height) {
6515 super(width, height);
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006516
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006517 mMarginFlags |= LEFT_MARGIN_UNDEFINED_MASK;
6518 mMarginFlags |= RIGHT_MARGIN_UNDEFINED_MASK;
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07006519
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006520 mMarginFlags &= ~NEED_RESOLUTION_MASK;
6521 mMarginFlags &= ~RTL_COMPATIBILITY_MODE_MASK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006522 }
6523
6524 /**
6525 * Copy constructor. Clones the width, height and margin values of the source.
6526 *
6527 * @param source The layout params to copy from.
6528 */
6529 public MarginLayoutParams(MarginLayoutParams source) {
6530 this.width = source.width;
6531 this.height = source.height;
6532
6533 this.leftMargin = source.leftMargin;
6534 this.topMargin = source.topMargin;
6535 this.rightMargin = source.rightMargin;
6536 this.bottomMargin = source.bottomMargin;
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006537 this.startMargin = source.startMargin;
6538 this.endMargin = source.endMargin;
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07006539
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006540 this.mMarginFlags = source.mMarginFlags;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006541 }
6542
6543 /**
6544 * {@inheritDoc}
6545 */
6546 public MarginLayoutParams(LayoutParams source) {
6547 super(source);
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006548
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006549 mMarginFlags |= LEFT_MARGIN_UNDEFINED_MASK;
6550 mMarginFlags |= RIGHT_MARGIN_UNDEFINED_MASK;
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07006551
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006552 mMarginFlags &= ~NEED_RESOLUTION_MASK;
6553 mMarginFlags &= ~RTL_COMPATIBILITY_MODE_MASK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006554 }
6555
6556 /**
Adam Powelld7600832014-07-01 15:22:50 -07006557 * @hide Used internally.
6558 */
6559 public final void copyMarginsFrom(MarginLayoutParams source) {
6560 this.leftMargin = source.leftMargin;
6561 this.topMargin = source.topMargin;
6562 this.rightMargin = source.rightMargin;
6563 this.bottomMargin = source.bottomMargin;
6564 this.startMargin = source.startMargin;
6565 this.endMargin = source.endMargin;
6566
6567 this.mMarginFlags = source.mMarginFlags;
6568 }
6569
6570 /**
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006571 * Sets the margins, in pixels. A call to {@link android.view.View#requestLayout()} needs
6572 * to be done so that the new margins are taken into account. Left and right margins may be
6573 * overriden by {@link android.view.View#requestLayout()} depending on layout direction.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006574 *
6575 * @param left the left margin size
6576 * @param top the top margin size
6577 * @param right the right margin size
6578 * @param bottom the bottom margin size
6579 *
6580 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginLeft
6581 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginTop
6582 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginRight
6583 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginBottom
6584 */
6585 public void setMargins(int left, int top, int right, int bottom) {
6586 leftMargin = left;
6587 topMargin = top;
6588 rightMargin = right;
6589 bottomMargin = bottom;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006590 mMarginFlags &= ~LEFT_MARGIN_UNDEFINED_MASK;
6591 mMarginFlags &= ~RIGHT_MARGIN_UNDEFINED_MASK;
6592 if (isMarginRelative()) {
6593 mMarginFlags |= NEED_RESOLUTION_MASK;
6594 } else {
6595 mMarginFlags &= ~NEED_RESOLUTION_MASK;
6596 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006597 }
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006598
6599 /**
6600 * Sets the relative margins, in pixels. A call to {@link android.view.View#requestLayout()}
6601 * needs to be done so that the new relative margins are taken into account. Left and right
6602 * margins may be overriden by {@link android.view.View#requestLayout()} depending on layout
6603 * direction.
6604 *
6605 * @param start the start margin size
6606 * @param top the top margin size
6607 * @param end the right margin size
6608 * @param bottom the bottom margin size
6609 *
6610 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart
6611 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginTop
6612 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd
6613 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginBottom
6614 *
6615 * @hide
6616 */
6617 public void setMarginsRelative(int start, int top, int end, int bottom) {
6618 startMargin = start;
6619 topMargin = top;
6620 endMargin = end;
6621 bottomMargin = bottom;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006622 mMarginFlags |= NEED_RESOLUTION_MASK;
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006623 }
6624
6625 /**
Fabrice Di Meglioa40627d2012-09-11 16:47:21 -07006626 * Sets the relative start margin.
6627 *
Fabrice Di Meglio61a21772012-09-12 16:33:13 -07006628 * @param start the start margin size
Fabrice Di Meglioa40627d2012-09-11 16:47:21 -07006629 *
6630 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart
6631 */
6632 public void setMarginStart(int start) {
6633 startMargin = start;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006634 mMarginFlags |= NEED_RESOLUTION_MASK;
Fabrice Di Meglioa40627d2012-09-11 16:47:21 -07006635 }
6636
6637 /**
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006638 * Returns the start margin in pixels.
6639 *
6640 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart
6641 *
6642 * @return the start margin in pixels.
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006643 */
6644 public int getMarginStart() {
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006645 if (startMargin != DEFAULT_MARGIN_RELATIVE) return startMargin;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006646 if ((mMarginFlags & NEED_RESOLUTION_MASK) == NEED_RESOLUTION_MASK) {
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006647 doResolveMargins();
6648 }
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006649 switch(mMarginFlags & LAYOUT_DIRECTION_MASK) {
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07006650 case View.LAYOUT_DIRECTION_RTL:
6651 return rightMargin;
6652 case View.LAYOUT_DIRECTION_LTR:
6653 default:
6654 return leftMargin;
6655 }
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006656 }
6657
6658 /**
Fabrice Di Meglioa40627d2012-09-11 16:47:21 -07006659 * Sets the relative end margin.
6660 *
Fabrice Di Meglio61a21772012-09-12 16:33:13 -07006661 * @param end the end margin size
Fabrice Di Meglioa40627d2012-09-11 16:47:21 -07006662 *
6663 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd
6664 */
6665 public void setMarginEnd(int end) {
6666 endMargin = end;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006667 mMarginFlags |= NEED_RESOLUTION_MASK;
Fabrice Di Meglioa40627d2012-09-11 16:47:21 -07006668 }
6669
6670 /**
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006671 * Returns the end margin in pixels.
6672 *
6673 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd
6674 *
6675 * @return the end margin in pixels.
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006676 */
6677 public int getMarginEnd() {
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006678 if (endMargin != DEFAULT_MARGIN_RELATIVE) return endMargin;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006679 if ((mMarginFlags & NEED_RESOLUTION_MASK) == NEED_RESOLUTION_MASK) {
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006680 doResolveMargins();
6681 }
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006682 switch(mMarginFlags & LAYOUT_DIRECTION_MASK) {
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07006683 case View.LAYOUT_DIRECTION_RTL:
6684 return leftMargin;
6685 case View.LAYOUT_DIRECTION_LTR:
6686 default:
6687 return rightMargin;
6688 }
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006689 }
6690
6691 /**
6692 * Check if margins are relative.
6693 *
6694 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart
6695 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd
6696 *
Fabrice Di Megliof443f982012-07-13 20:24:03 -07006697 * @return true if either marginStart or marginEnd has been set.
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006698 */
6699 public boolean isMarginRelative() {
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006700 return (startMargin != DEFAULT_MARGIN_RELATIVE || endMargin != DEFAULT_MARGIN_RELATIVE);
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006701 }
6702
6703 /**
Fabrice Di Megliof443f982012-07-13 20:24:03 -07006704 * Set the layout direction
6705 * @param layoutDirection the layout direction.
6706 * Should be either {@link View#LAYOUT_DIRECTION_LTR}
6707 * or {@link View#LAYOUT_DIRECTION_RTL}.
6708 */
6709 public void setLayoutDirection(int layoutDirection) {
6710 if (layoutDirection != View.LAYOUT_DIRECTION_LTR &&
6711 layoutDirection != View.LAYOUT_DIRECTION_RTL) return;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006712 if (layoutDirection != (mMarginFlags & LAYOUT_DIRECTION_MASK)) {
6713 mMarginFlags &= ~LAYOUT_DIRECTION_MASK;
6714 mMarginFlags |= (layoutDirection & LAYOUT_DIRECTION_MASK);
6715 if (isMarginRelative()) {
6716 mMarginFlags |= NEED_RESOLUTION_MASK;
6717 } else {
6718 mMarginFlags &= ~NEED_RESOLUTION_MASK;
6719 }
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006720 }
Fabrice Di Megliof443f982012-07-13 20:24:03 -07006721 }
6722
6723 /**
6724 * Retuns the layout direction. Can be either {@link View#LAYOUT_DIRECTION_LTR} or
6725 * {@link View#LAYOUT_DIRECTION_RTL}.
6726 *
6727 * @return the layout direction.
6728 */
6729 public int getLayoutDirection() {
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006730 return (mMarginFlags & LAYOUT_DIRECTION_MASK);
Fabrice Di Megliof443f982012-07-13 20:24:03 -07006731 }
6732
6733 /**
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006734 * This will be called by {@link android.view.View#requestLayout()}. Left and Right margins
Fabrice Di Meglio98aec1c2012-02-13 16:54:05 -08006735 * may be overridden depending on layout direction.
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006736 */
6737 @Override
Fabrice Di Meglio2918ab62012-10-10 16:39:25 -07006738 public void resolveLayoutDirection(int layoutDirection) {
Fabrice Di Megliof443f982012-07-13 20:24:03 -07006739 setLayoutDirection(layoutDirection);
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07006740
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006741 // No relative margin or pre JB-MR1 case or no need to resolve, just dont do anything
6742 // Will use the left and right margins if no relative margin is defined.
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006743 if (!isMarginRelative() ||
6744 (mMarginFlags & NEED_RESOLUTION_MASK) != NEED_RESOLUTION_MASK) return;
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07006745
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006746 // Proceed with resolution
6747 doResolveMargins();
6748 }
6749
6750 private void doResolveMargins() {
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006751 if ((mMarginFlags & RTL_COMPATIBILITY_MODE_MASK) == RTL_COMPATIBILITY_MODE_MASK) {
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07006752 // if left or right margins are not defined and if we have some start or end margin
6753 // defined then use those start and end margins.
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006754 if ((mMarginFlags & LEFT_MARGIN_UNDEFINED_MASK) == LEFT_MARGIN_UNDEFINED_MASK
6755 && startMargin > DEFAULT_MARGIN_RELATIVE) {
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07006756 leftMargin = startMargin;
6757 }
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006758 if ((mMarginFlags & RIGHT_MARGIN_UNDEFINED_MASK) == RIGHT_MARGIN_UNDEFINED_MASK
6759 && endMargin > DEFAULT_MARGIN_RELATIVE) {
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07006760 rightMargin = endMargin;
6761 }
6762 } else {
6763 // We have some relative margins (either the start one or the end one or both). So use
6764 // them and override what has been defined for left and right margins. If either start
6765 // or end margin is not defined, just set it to default "0".
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006766 switch(mMarginFlags & LAYOUT_DIRECTION_MASK) {
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07006767 case View.LAYOUT_DIRECTION_RTL:
6768 leftMargin = (endMargin > DEFAULT_MARGIN_RELATIVE) ?
6769 endMargin : DEFAULT_MARGIN_RESOLVED;
6770 rightMargin = (startMargin > DEFAULT_MARGIN_RELATIVE) ?
6771 startMargin : DEFAULT_MARGIN_RESOLVED;
6772 break;
6773 case View.LAYOUT_DIRECTION_LTR:
6774 default:
6775 leftMargin = (startMargin > DEFAULT_MARGIN_RELATIVE) ?
6776 startMargin : DEFAULT_MARGIN_RESOLVED;
6777 rightMargin = (endMargin > DEFAULT_MARGIN_RELATIVE) ?
6778 endMargin : DEFAULT_MARGIN_RESOLVED;
6779 break;
6780 }
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006781 }
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006782 mMarginFlags &= ~NEED_RESOLUTION_MASK;
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006783 }
Philip Milne10ca24a2012-04-23 15:38:27 -07006784
Fabrice Di Meglio03b8d3a2012-09-27 17:05:27 -07006785 /**
6786 * @hide
6787 */
6788 public boolean isLayoutRtl() {
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006789 return ((mMarginFlags & LAYOUT_DIRECTION_MASK) == View.LAYOUT_DIRECTION_RTL);
Fabrice Di Megliof443f982012-07-13 20:24:03 -07006790 }
6791
Philip Milne10ca24a2012-04-23 15:38:27 -07006792 /**
6793 * @hide
6794 */
6795 @Override
Philip Milne7b757812012-09-19 18:13:44 -07006796 public void onDebugDraw(View view, Canvas canvas, Paint paint) {
6797 Insets oi = isLayoutModeOptical(view.mParent) ? view.getOpticalInsets() : Insets.NONE;
6798
6799 fillDifference(canvas,
6800 view.getLeft() + oi.left,
6801 view.getTop() + oi.top,
6802 view.getRight() - oi.right,
6803 view.getBottom() - oi.bottom,
6804 leftMargin,
6805 topMargin,
6806 rightMargin,
6807 bottomMargin,
6808 paint);
Philip Milne10ca24a2012-04-23 15:38:27 -07006809 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006810 }
Adam Powell2b342f02010-08-18 18:14:13 -07006811
Jeff Brown20e987b2010-08-23 12:01:02 -07006812 /* Describes a touched view and the ids of the pointers that it has captured.
6813 *
6814 * This code assumes that pointer ids are always in the range 0..31 such that
6815 * it can use a bitfield to track which pointer ids are present.
6816 * As it happens, the lower layers of the input dispatch pipeline also use the
6817 * same trick so the assumption should be safe here...
6818 */
6819 private static final class TouchTarget {
6820 private static final int MAX_RECYCLED = 32;
Romain Guy6410c0a2013-06-17 11:21:58 -07006821 private static final Object sRecycleLock = new Object[0];
Jeff Brown20e987b2010-08-23 12:01:02 -07006822 private static TouchTarget sRecycleBin;
6823 private static int sRecycledCount;
Adam Powell2b342f02010-08-18 18:14:13 -07006824
Jeff Brown20e987b2010-08-23 12:01:02 -07006825 public static final int ALL_POINTER_IDS = -1; // all ones
Adam Powell2b342f02010-08-18 18:14:13 -07006826
Jeff Brown20e987b2010-08-23 12:01:02 -07006827 // The touched child view.
6828 public View child;
6829
6830 // The combined bit mask of pointer ids for all pointers captured by the target.
6831 public int pointerIdBits;
6832
6833 // The next target in the target list.
6834 public TouchTarget next;
6835
6836 private TouchTarget() {
Adam Powell2b342f02010-08-18 18:14:13 -07006837 }
6838
Jeff Brown20e987b2010-08-23 12:01:02 -07006839 public static TouchTarget obtain(View child, int pointerIdBits) {
6840 final TouchTarget target;
6841 synchronized (sRecycleLock) {
Adam Powell816c3be2010-08-23 18:00:05 -07006842 if (sRecycleBin == null) {
Jeff Brown20e987b2010-08-23 12:01:02 -07006843 target = new TouchTarget();
Adam Powell816c3be2010-08-23 18:00:05 -07006844 } else {
Jeff Brown20e987b2010-08-23 12:01:02 -07006845 target = sRecycleBin;
6846 sRecycleBin = target.next;
6847 sRecycledCount--;
6848 target.next = null;
Adam Powell816c3be2010-08-23 18:00:05 -07006849 }
Adam Powell816c3be2010-08-23 18:00:05 -07006850 }
Jeff Brown20e987b2010-08-23 12:01:02 -07006851 target.child = child;
6852 target.pointerIdBits = pointerIdBits;
6853 return target;
6854 }
Adam Powell816c3be2010-08-23 18:00:05 -07006855
Jeff Brown20e987b2010-08-23 12:01:02 -07006856 public void recycle() {
6857 synchronized (sRecycleLock) {
6858 if (sRecycledCount < MAX_RECYCLED) {
6859 next = sRecycleBin;
6860 sRecycleBin = this;
6861 sRecycledCount += 1;
Patrick Dubroyfb0547d22010-10-19 17:36:18 -07006862 } else {
6863 next = null;
Adam Powell816c3be2010-08-23 18:00:05 -07006864 }
Patrick Dubroyfb0547d22010-10-19 17:36:18 -07006865 child = null;
Adam Powell816c3be2010-08-23 18:00:05 -07006866 }
6867 }
Adam Powell2b342f02010-08-18 18:14:13 -07006868 }
Jeff Brown87b7f802011-06-21 18:35:45 -07006869
6870 /* Describes a hovered view. */
6871 private static final class HoverTarget {
6872 private static final int MAX_RECYCLED = 32;
Romain Guy6410c0a2013-06-17 11:21:58 -07006873 private static final Object sRecycleLock = new Object[0];
Jeff Brown87b7f802011-06-21 18:35:45 -07006874 private static HoverTarget sRecycleBin;
6875 private static int sRecycledCount;
6876
6877 // The hovered child view.
6878 public View child;
6879
6880 // The next target in the target list.
6881 public HoverTarget next;
6882
6883 private HoverTarget() {
6884 }
6885
6886 public static HoverTarget obtain(View child) {
6887 final HoverTarget target;
6888 synchronized (sRecycleLock) {
6889 if (sRecycleBin == null) {
6890 target = new HoverTarget();
6891 } else {
6892 target = sRecycleBin;
6893 sRecycleBin = target.next;
6894 sRecycledCount--;
6895 target.next = null;
6896 }
6897 }
6898 target.child = child;
6899 return target;
6900 }
6901
6902 public void recycle() {
6903 synchronized (sRecycleLock) {
6904 if (sRecycledCount < MAX_RECYCLED) {
6905 next = sRecycleBin;
6906 sRecycleBin = this;
6907 sRecycledCount += 1;
6908 } else {
6909 next = null;
6910 }
6911 child = null;
6912 }
6913 }
6914 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07006915
6916 /**
6917 * Pooled class that orderes the children of a ViewGroup from start
6918 * to end based on how they are laid out and the layout direction.
6919 */
6920 static class ChildListForAccessibility {
6921
6922 private static final int MAX_POOL_SIZE = 32;
6923
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08006924 private static final SynchronizedPool<ChildListForAccessibility> sPool =
6925 new SynchronizedPool<ChildListForAccessibility>(MAX_POOL_SIZE);
Svetoslav Ganov42138042012-03-20 11:51:39 -07006926
6927 private final ArrayList<View> mChildren = new ArrayList<View>();
6928
6929 private final ArrayList<ViewLocationHolder> mHolders = new ArrayList<ViewLocationHolder>();
6930
6931 public static ChildListForAccessibility obtain(ViewGroup parent, boolean sort) {
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08006932 ChildListForAccessibility list = sPool.acquire();
6933 if (list == null) {
6934 list = new ChildListForAccessibility();
Svetoslav Ganov42138042012-03-20 11:51:39 -07006935 }
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08006936 list.init(parent, sort);
6937 return list;
Svetoslav Ganov42138042012-03-20 11:51:39 -07006938 }
6939
6940 public void recycle() {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006941 clear();
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08006942 sPool.release(this);
Svetoslav Ganov42138042012-03-20 11:51:39 -07006943 }
6944
6945 public int getChildCount() {
6946 return mChildren.size();
6947 }
6948
6949 public View getChildAt(int index) {
6950 return mChildren.get(index);
6951 }
6952
6953 public int getChildIndex(View child) {
6954 return mChildren.indexOf(child);
6955 }
6956
6957 private void init(ViewGroup parent, boolean sort) {
6958 ArrayList<View> children = mChildren;
6959 final int childCount = parent.getChildCount();
6960 for (int i = 0; i < childCount; i++) {
6961 View child = parent.getChildAt(i);
6962 children.add(child);
6963 }
6964 if (sort) {
6965 ArrayList<ViewLocationHolder> holders = mHolders;
6966 for (int i = 0; i < childCount; i++) {
6967 View child = children.get(i);
6968 ViewLocationHolder holder = ViewLocationHolder.obtain(parent, child);
6969 holders.add(holder);
6970 }
6971 Collections.sort(holders);
6972 for (int i = 0; i < childCount; i++) {
6973 ViewLocationHolder holder = holders.get(i);
6974 children.set(i, holder.mView);
6975 holder.recycle();
6976 }
6977 holders.clear();
6978 }
6979 }
6980
6981 private void clear() {
6982 mChildren.clear();
6983 }
6984 }
6985
6986 /**
6987 * Pooled class that holds a View and its location with respect to
6988 * a specified root. This enables sorting of views based on their
6989 * coordinates without recomputing the position relative to the root
6990 * on every comparison.
6991 */
6992 static class ViewLocationHolder implements Comparable<ViewLocationHolder> {
6993
6994 private static final int MAX_POOL_SIZE = 32;
6995
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08006996 private static final SynchronizedPool<ViewLocationHolder> sPool =
6997 new SynchronizedPool<ViewLocationHolder>(MAX_POOL_SIZE);
Svetoslav Ganov42138042012-03-20 11:51:39 -07006998
6999 private final Rect mLocation = new Rect();
7000
7001 public View mView;
7002
7003 private int mLayoutDirection;
7004
7005 public static ViewLocationHolder obtain(ViewGroup root, View view) {
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08007006 ViewLocationHolder holder = sPool.acquire();
7007 if (holder == null) {
7008 holder = new ViewLocationHolder();
Svetoslav Ganov42138042012-03-20 11:51:39 -07007009 }
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08007010 holder.init(root, view);
7011 return holder;
Svetoslav Ganov42138042012-03-20 11:51:39 -07007012 }
7013
7014 public void recycle() {
Svetoslav Ganov42138042012-03-20 11:51:39 -07007015 clear();
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08007016 sPool.release(this);
Svetoslav Ganov42138042012-03-20 11:51:39 -07007017 }
7018
7019 @Override
7020 public int compareTo(ViewLocationHolder another) {
7021 // This instance is greater than an invalid argument.
7022 if (another == null) {
7023 return 1;
7024 }
7025 if (getClass() != another.getClass()) {
7026 return 1;
7027 }
Kristian Monsen2c35d032014-06-04 18:30:39 -07007028 final int topDiference = mLocation.top - another.mLocation.top;
7029 if (topDiference != 0) {
7030 return topDiference;
Svetoslav Ganov42138042012-03-20 11:51:39 -07007031 }
7032 // LTR
7033 if (mLayoutDirection == LAYOUT_DIRECTION_LTR) {
7034 final int leftDifference = mLocation.left - another.mLocation.left;
7035 // First more to the left than second.
7036 if (leftDifference != 0) {
7037 return leftDifference;
7038 }
7039 } else { // RTL
7040 final int rightDifference = mLocation.right - another.mLocation.right;
7041 // First more to the right than second.
7042 if (rightDifference != 0) {
7043 return -rightDifference;
7044 }
7045 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07007046 // Break tie by height.
7047 final int heightDiference = mLocation.height() - another.mLocation.height();
7048 if (heightDiference != 0) {
7049 return -heightDiference;
7050 }
7051 // Break tie by width.
7052 final int widthDiference = mLocation.width() - another.mLocation.width();
7053 if (widthDiference != 0) {
7054 return -widthDiference;
7055 }
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07007056 // Just break the tie somehow. The accessibliity ids are unique
7057 // and stable, hence this is deterministic tie breaking.
7058 return mView.getAccessibilityViewId() - another.mView.getAccessibilityViewId();
Svetoslav Ganov42138042012-03-20 11:51:39 -07007059 }
7060
7061 private void init(ViewGroup root, View view) {
7062 Rect viewLocation = mLocation;
7063 view.getDrawingRect(viewLocation);
7064 root.offsetDescendantRectToMyCoords(view, viewLocation);
7065 mView = view;
Fabrice Di Meglioe56ffdc2012-09-23 14:51:16 -07007066 mLayoutDirection = root.getLayoutDirection();
Svetoslav Ganov42138042012-03-20 11:51:39 -07007067 }
7068
7069 private void clear() {
7070 mView = null;
7071 mLocation.set(0, 0, 0, 0);
7072 }
7073 }
Romain Guycbc67742012-04-27 16:12:57 -07007074
7075 private static Paint getDebugPaint() {
7076 if (sDebugPaint == null) {
7077 sDebugPaint = new Paint();
7078 sDebugPaint.setAntiAlias(false);
7079 }
7080 return sDebugPaint;
7081 }
7082
Romain Guy6410c0a2013-06-17 11:21:58 -07007083 private static void drawRect(Canvas canvas, Paint paint, int x1, int y1, int x2, int y2) {
Romain Guycbc67742012-04-27 16:12:57 -07007084 if (sDebugLines== null) {
Romain Guy6410c0a2013-06-17 11:21:58 -07007085 // TODO: This won't work with multiple UI threads in a single process
Romain Guycbc67742012-04-27 16:12:57 -07007086 sDebugLines = new float[16];
7087 }
7088
Romain Guycbc67742012-04-27 16:12:57 -07007089 sDebugLines[0] = x1;
7090 sDebugLines[1] = y1;
7091 sDebugLines[2] = x2;
7092 sDebugLines[3] = y1;
7093
7094 sDebugLines[4] = x2;
7095 sDebugLines[5] = y1;
7096 sDebugLines[6] = x2;
Philip Milne7b757812012-09-19 18:13:44 -07007097 sDebugLines[7] = y2;
Romain Guycbc67742012-04-27 16:12:57 -07007098
Philip Milne7b757812012-09-19 18:13:44 -07007099 sDebugLines[8] = x2;
Romain Guycbc67742012-04-27 16:12:57 -07007100 sDebugLines[9] = y2;
7101 sDebugLines[10] = x1;
7102 sDebugLines[11] = y2;
7103
Philip Milne7b757812012-09-19 18:13:44 -07007104 sDebugLines[12] = x1;
7105 sDebugLines[13] = y2;
Romain Guycbc67742012-04-27 16:12:57 -07007106 sDebugLines[14] = x1;
7107 sDebugLines[15] = y1;
7108
Philip Milne7b757812012-09-19 18:13:44 -07007109 canvas.drawLines(sDebugLines, paint);
Romain Guycbc67742012-04-27 16:12:57 -07007110 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007111}