blob: 8f2be990e460f259703da91e5b05f1cb53e05cc3 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.view;
18
Chet Haase21cd1382010-09-01 17:42:29 -070019import android.animation.LayoutTransition;
Tor Norbye7b9c9122013-05-30 16:48:33 -070020import android.annotation.IdRes;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021import android.content.Context;
Clara Bayarrid5bf3ed2015-03-27 17:32:45 +000022import android.content.Intent;
Adam Powellff0d2982014-07-10 20:34:14 -070023import android.content.pm.PackageManager;
Dianne Hackborne36d6e22010-02-17 19:46:25 -080024import android.content.res.Configuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025import android.content.res.TypedArray;
26import android.graphics.Bitmap;
27import android.graphics.Canvas;
Philip Milne10ca24a2012-04-23 15:38:27 -070028import android.graphics.Color;
29import android.graphics.Insets;
Adam Powell6e346362010-07-23 10:18:23 -070030import android.graphics.Matrix;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031import android.graphics.Paint;
Christopher Tatea53146c2010-09-07 11:57:52 -070032import android.graphics.PointF;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080033import android.graphics.Rect;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034import android.graphics.RectF;
svetoslavganov75986cf2009-05-14 22:28:01 -070035import android.graphics.Region;
Jeff Brown995e7742010-12-22 16:59:36 -080036import android.os.Build;
Adam Powellb6ab0982015-01-07 17:00:12 -080037import android.os.Bundle;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038import android.os.Parcelable;
39import android.os.SystemClock;
40import android.util.AttributeSet;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041import android.util.Log;
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -080042import android.util.Pools.SynchronizedPool;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043import android.util.SparseArray;
svetoslavganov75986cf2009-05-14 22:28:01 -070044import android.view.accessibility.AccessibilityEvent;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070045import android.view.accessibility.AccessibilityNodeInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046import android.view.animation.Animation;
47import android.view.animation.AnimationUtils;
48import android.view.animation.LayoutAnimationController;
49import android.view.animation.Transformation;
Doug Feltcb3791202011-07-07 11:57:48 -070050
Romain Guy0211a0a2011-02-14 16:34:59 -080051import com.android.internal.R;
52import com.android.internal.util.Predicate;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053
54import java.util.ArrayList;
Svetoslav Ganov42138042012-03-20 11:51:39 -070055import java.util.Collections;
Christopher Tate86cab1b2011-01-13 20:28:55 -080056import java.util.HashSet;
George Mounte1803372014-02-26 19:00:52 +000057import java.util.List;
58import java.util.Map;
Fabrice Di Meglio0072f642013-03-26 15:50:24 -070059import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
60
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080061/**
62 * <p>
63 * A <code>ViewGroup</code> is a special view that can contain other views
64 * (called children.) The view group is the base class for layouts and views
65 * containers. This class also defines the
66 * {@link android.view.ViewGroup.LayoutParams} class which serves as the base
67 * class for layouts parameters.
68 * </p>
69 *
70 * <p>
71 * Also see {@link LayoutParams} for layout attributes.
72 * </p>
Romain Guyd6a463a2009-05-21 23:10:10 -070073 *
Joe Fernandez558459f2011-10-13 16:47:36 -070074 * <div class="special reference">
75 * <h3>Developer Guides</h3>
76 * <p>For more information about creating user interface layouts, read the
77 * <a href="{@docRoot}guide/topics/ui/declaring-layout.html">XML Layouts</a> developer
78 * guide.</p></div>
79 *
Dianne Hackborn7caab0f2013-03-06 13:47:04 -080080 * <p>Here is a complete implementation of a custom ViewGroup that implements
81 * a simple {@link android.widget.FrameLayout} along with the ability to stack
82 * children in left and right gutters.</p>
83 *
84 * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/CustomLayout.java
85 * Complete}
86 *
87 * <p>If you are implementing XML layout attributes as shown in the example, this is the
88 * corresponding definition for them that would go in <code>res/values/attrs.xml</code>:</p>
89 *
90 * {@sample development/samples/ApiDemos/res/values/attrs.xml CustomLayout}
91 *
92 * <p>Finally the layout manager can be used in an XML layout like so:</p>
93 *
94 * {@sample development/samples/ApiDemos/res/layout/custom_layout.xml Complete}
95 *
Romain Guyd6a463a2009-05-21 23:10:10 -070096 * @attr ref android.R.styleable#ViewGroup_clipChildren
97 * @attr ref android.R.styleable#ViewGroup_clipToPadding
98 * @attr ref android.R.styleable#ViewGroup_layoutAnimation
99 * @attr ref android.R.styleable#ViewGroup_animationCache
100 * @attr ref android.R.styleable#ViewGroup_persistentDrawingCache
101 * @attr ref android.R.styleable#ViewGroup_alwaysDrawnWithCache
102 * @attr ref android.R.styleable#ViewGroup_addStatesFromChildren
103 * @attr ref android.R.styleable#ViewGroup_descendantFocusability
Chet Haase13cc1202010-09-03 15:39:20 -0700104 * @attr ref android.R.styleable#ViewGroup_animateLayoutChanges
Scott Main27a85082013-06-10 10:39:48 -0700105 * @attr ref android.R.styleable#ViewGroup_splitMotionEvents
106 * @attr ref android.R.styleable#ViewGroup_layoutMode
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800107 */
108public abstract class ViewGroup extends View implements ViewParent, ViewManager {
Adam Powell539ee872012-02-03 19:00:49 -0800109 private static final String TAG = "ViewGroup";
Chet Haase21cd1382010-09-01 17:42:29 -0700110
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800111 private static final boolean DBG = false;
Philip Milne7b757812012-09-19 18:13:44 -0700112 /** @hide */
113 public static boolean DEBUG_DRAW = false;
Gilles Debunnecea45132011-11-24 02:19:27 +0100114
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800115 /**
116 * Views which have been hidden or removed which need to be animated on
117 * their way out.
118 * This field should be made private, so it is hidden from the SDK.
119 * {@hide}
120 */
121 protected ArrayList<View> mDisappearingChildren;
122
123 /**
124 * Listener used to propagate events indicating when children are added
125 * and/or removed from a view group.
126 * This field should be made private, so it is hidden from the SDK.
127 * {@hide}
128 */
129 protected OnHierarchyChangeListener mOnHierarchyChangeListener;
130
131 // The view contained within this ViewGroup that has or contains focus.
132 private View mFocused;
133
Chet Haase48460322010-06-11 14:22:25 -0700134 /**
135 * A Transformation used when drawing children, to
136 * apply on the child being drawn.
137 */
Romain Guyf6991302013-06-05 17:19:01 -0700138 private Transformation mChildTransformation;
Chet Haase48460322010-06-11 14:22:25 -0700139
140 /**
141 * Used to track the current invalidation region.
142 */
Chet Haase64a48c12012-02-13 16:33:29 -0800143 RectF mInvalidateRegion;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800144
Chet Haase48460322010-06-11 14:22:25 -0700145 /**
146 * A Transformation used to calculate a correct
147 * invalidation area when the application is autoscaled.
148 */
Chet Haase64a48c12012-02-13 16:33:29 -0800149 Transformation mInvalidationTransformation;
Chet Haase48460322010-06-11 14:22:25 -0700150
Christopher Tatea53146c2010-09-07 11:57:52 -0700151 // View currently under an ongoing drag
152 private View mCurrentDragView;
153
Christopher Tate86cab1b2011-01-13 20:28:55 -0800154 // Metadata about the ongoing drag
155 private DragEvent mCurrentDrag;
156 private HashSet<View> mDragNotifiedChildren;
157
Christopher Tatea53146c2010-09-07 11:57:52 -0700158 // Does this group have a child that can accept the current drag payload?
159 private boolean mChildAcceptsDrag;
160
161 // Used during drag dispatch
Romain Guy6410c0a2013-06-17 11:21:58 -0700162 private PointF mLocalPoint;
Christopher Tatea53146c2010-09-07 11:57:52 -0700163
Alan Viveretteb942b6f2014-12-08 10:37:39 -0800164 // Lazily-created holder for point computations.
165 private float[] mTempPoint;
166
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800167 // Layout animation
168 private LayoutAnimationController mLayoutAnimationController;
169 private Animation.AnimationListener mAnimationListener;
170
Jeff Brown20e987b2010-08-23 12:01:02 -0700171 // First touch target in the linked list of touch targets.
172 private TouchTarget mFirstTouchTarget;
173
Joe Onorato03ab0c72011-01-06 15:46:27 -0800174 // For debugging only. You can see these in hierarchyviewer.
Romain Guye95003e2011-01-09 13:53:06 -0800175 @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"})
Joe Onorato03ab0c72011-01-06 15:46:27 -0800176 @ViewDebug.ExportedProperty(category = "events")
177 private long mLastTouchDownTime;
178 @ViewDebug.ExportedProperty(category = "events")
179 private int mLastTouchDownIndex = -1;
Romain Guye95003e2011-01-09 13:53:06 -0800180 @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"})
Joe Onorato03ab0c72011-01-06 15:46:27 -0800181 @ViewDebug.ExportedProperty(category = "events")
182 private float mLastTouchDownX;
Romain Guye95003e2011-01-09 13:53:06 -0800183 @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"})
Joe Onorato03ab0c72011-01-06 15:46:27 -0800184 @ViewDebug.ExportedProperty(category = "events")
185 private float mLastTouchDownY;
186
Jeff Brown87b7f802011-06-21 18:35:45 -0700187 // First hover target in the linked list of hover targets.
188 // The hover targets are children which have received ACTION_HOVER_ENTER.
189 // They might not have actually handled the hover event, but we will
190 // continue sending hover events to them as long as the pointer remains over
191 // their bounds and the view group does not intercept hover.
192 private HoverTarget mFirstHoverTarget;
Jeff Browna032cc02011-03-07 16:56:21 -0800193
Jeff Brown10b62902011-06-20 16:40:37 -0700194 // True if the view group itself received a hover event.
195 // It might not have actually handled the hover event.
196 private boolean mHoveredSelf;
197
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800198 /**
199 * Internal flags.
Romain Guy8506ab42009-06-11 17:35:47 -0700200 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800201 * This field should be made private, so it is hidden from the SDK.
202 * {@hide}
203 */
Romain Guy2440e672012-08-07 14:43:43 -0700204 @ViewDebug.ExportedProperty(flagMapping = {
205 @ViewDebug.FlagToString(mask = FLAG_CLIP_CHILDREN, equals = FLAG_CLIP_CHILDREN,
206 name = "CLIP_CHILDREN"),
207 @ViewDebug.FlagToString(mask = FLAG_CLIP_TO_PADDING, equals = FLAG_CLIP_TO_PADDING,
208 name = "CLIP_TO_PADDING"),
209 @ViewDebug.FlagToString(mask = FLAG_PADDING_NOT_NULL, equals = FLAG_PADDING_NOT_NULL,
210 name = "PADDING_NOT_NULL")
Jon Miranda4597e982014-07-29 07:25:49 -0700211 }, formatToHexString = true)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800212 protected int mGroupFlags;
213
Philip Milne7b757812012-09-19 18:13:44 -0700214 /**
215 * Either {@link #LAYOUT_MODE_CLIP_BOUNDS} or {@link #LAYOUT_MODE_OPTICAL_BOUNDS}.
Philip Milne1557fd72012-04-04 23:41:34 -0700216 */
Philip Milnecfb631b2012-10-26 10:51:46 -0700217 private int mLayoutMode = LAYOUT_MODE_UNDEFINED;
Philip Milne1557fd72012-04-04 23:41:34 -0700218
Romain Guy33f6beb2012-02-16 19:24:51 -0800219 /**
220 * NOTE: If you change the flags below make sure to reflect the changes
221 * the DisplayList class
222 */
223
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800224 // When set, ViewGroup invalidates only the child's rectangle
225 // Set by default
Chet Haase64a48c12012-02-13 16:33:29 -0800226 static final int FLAG_CLIP_CHILDREN = 0x1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800227
228 // When set, ViewGroup excludes the padding area from the invalidate rectangle
229 // Set by default
230 private static final int FLAG_CLIP_TO_PADDING = 0x2;
231
232 // When set, dispatchDraw() will invoke invalidate(); this is set by drawChild() when
233 // a child needs to be invalidated and FLAG_OPTIMIZE_INVALIDATE is set
Chet Haase64a48c12012-02-13 16:33:29 -0800234 static final int FLAG_INVALIDATE_REQUIRED = 0x4;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800235
236 // When set, dispatchDraw() will run the layout animation and unset the flag
237 private static final int FLAG_RUN_ANIMATION = 0x8;
238
239 // When set, there is either no layout animation on the ViewGroup or the layout
240 // animation is over
241 // Set by default
Chet Haase64a48c12012-02-13 16:33:29 -0800242 static final int FLAG_ANIMATION_DONE = 0x10;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800243
244 // If set, this ViewGroup has padding; if unset there is no padding and we don't need
245 // to clip it, even if FLAG_CLIP_TO_PADDING is set
246 private static final int FLAG_PADDING_NOT_NULL = 0x20;
247
Chris Craik5a6bbae2015-04-10 17:41:34 -0700248 /** @deprecated - functionality removed */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800249 private static final int FLAG_ANIMATION_CACHE = 0x40;
250
251 // When set, this ViewGroup converts calls to invalidate(Rect) to invalidate() during a
252 // layout animation; this avoid clobbering the hierarchy
253 // Automatically set when the layout animation starts, depending on the animation's
254 // characteristics
Chet Haase64a48c12012-02-13 16:33:29 -0800255 static final int FLAG_OPTIMIZE_INVALIDATE = 0x80;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800256
257 // When set, the next call to drawChild() will clear mChildTransformation's matrix
Chet Haase64a48c12012-02-13 16:33:29 -0800258 static final int FLAG_CLEAR_TRANSFORMATION = 0x100;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800259
260 // When set, this ViewGroup invokes mAnimationListener.onAnimationEnd() and removes
261 // the children's Bitmap caches if necessary
262 // This flag is set when the layout animation is over (after FLAG_ANIMATION_DONE is set)
263 private static final int FLAG_NOTIFY_ANIMATION_LISTENER = 0x200;
264
265 /**
266 * When set, the drawing method will call {@link #getChildDrawingOrder(int, int)}
267 * to get the index of the child to draw for that iteration.
Romain Guy293451e2009-11-04 13:59:48 -0800268 *
269 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800270 */
271 protected static final int FLAG_USE_CHILD_DRAWING_ORDER = 0x400;
Romain Guy8506ab42009-06-11 17:35:47 -0700272
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800273 /**
274 * When set, this ViewGroup supports static transformations on children; this causes
275 * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} to be
276 * invoked when a child is drawn.
277 *
278 * Any subclass overriding
279 * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} should
280 * set this flags in {@link #mGroupFlags}.
Romain Guy8506ab42009-06-11 17:35:47 -0700281 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800282 * {@hide}
283 */
284 protected static final int FLAG_SUPPORT_STATIC_TRANSFORMATIONS = 0x800;
285
John Reckfb5899d2014-08-15 18:51:27 -0700286 // UNUSED FLAG VALUE: 0x1000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800287
288 /**
289 * When set, this ViewGroup's drawable states also include those
290 * of its children.
291 */
292 private static final int FLAG_ADD_STATES_FROM_CHILDREN = 0x2000;
293
Chris Craik5a6bbae2015-04-10 17:41:34 -0700294 /** @deprecated functionality removed */
295 private static final int FLAG_ALWAYS_DRAWN_WITH_CACHE = 0x4000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800296
Chris Craik5a6bbae2015-04-10 17:41:34 -0700297 /** @deprecated functionality removed */
298 private static final int FLAG_CHILDREN_DRAWN_WITH_CACHE = 0x8000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800299
300 /**
301 * When set, this group will go through its list of children to notify them of
302 * any drawable state change.
303 */
304 private static final int FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE = 0x10000;
305
306 private static final int FLAG_MASK_FOCUSABILITY = 0x60000;
307
308 /**
309 * This view will get focus before any of its descendants.
310 */
311 public static final int FOCUS_BEFORE_DESCENDANTS = 0x20000;
312
313 /**
314 * This view will get focus only if none of its descendants want it.
315 */
316 public static final int FOCUS_AFTER_DESCENDANTS = 0x40000;
317
318 /**
319 * This view will block any of its descendants from getting focus, even
320 * if they are focusable.
321 */
322 public static final int FOCUS_BLOCK_DESCENDANTS = 0x60000;
323
324 /**
325 * Used to map between enum in attrubutes and flag values.
326 */
327 private static final int[] DESCENDANT_FOCUSABILITY_FLAGS =
328 {FOCUS_BEFORE_DESCENDANTS, FOCUS_AFTER_DESCENDANTS,
329 FOCUS_BLOCK_DESCENDANTS};
330
331 /**
332 * When set, this ViewGroup should not intercept touch events.
Adam Powell110486f2010-06-22 17:14:44 -0700333 * {@hide}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800334 */
Adam Powell110486f2010-06-22 17:14:44 -0700335 protected static final int FLAG_DISALLOW_INTERCEPT = 0x80000;
Romain Guy8506ab42009-06-11 17:35:47 -0700336
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800337 /**
Adam Powell2b342f02010-08-18 18:14:13 -0700338 * When set, this ViewGroup will split MotionEvents to multiple child Views when appropriate.
339 */
Adam Powellf37df072010-09-17 16:22:49 -0700340 private static final int FLAG_SPLIT_MOTION_EVENTS = 0x200000;
Adam Powell2b342f02010-08-18 18:14:13 -0700341
342 /**
Adam Powell4b867882011-09-16 12:59:46 -0700343 * When set, this ViewGroup will not dispatch onAttachedToWindow calls
344 * to children when adding new views. This is used to prevent multiple
345 * onAttached calls when a ViewGroup adds children in its own onAttached method.
346 */
347 private static final int FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW = 0x400000;
348
349 /**
Philip Milnecfb631b2012-10-26 10:51:46 -0700350 * When true, indicates that a layoutMode has been explicitly set, either with
351 * an explicit call to {@link #setLayoutMode(int)} in code or from an XML resource.
352 * This distinguishes the situation in which a layout mode was inherited from
353 * one of the ViewGroup's ancestors and cached locally.
354 */
355 private static final int FLAG_LAYOUT_MODE_WAS_EXPLICITLY_SET = 0x800000;
356
Chris Craikb49f4462014-03-20 12:44:20 -0700357 static final int FLAG_IS_TRANSITION_GROUP = 0x1000000;
Chris Craikd863a102013-12-19 13:31:15 -0800358
Chris Craikb49f4462014-03-20 12:44:20 -0700359 static final int FLAG_IS_TRANSITION_GROUP_SET = 0x2000000;
George Mount0a778ed2013-12-13 13:35:36 -0800360
Chris Craikd863a102013-12-19 13:31:15 -0800361 /**
Adam Powellff0d2982014-07-10 20:34:14 -0700362 * When set, focus will not be permitted to enter this group if a touchscreen is present.
363 */
364 static final int FLAG_TOUCHSCREEN_BLOCKS_FOCUS = 0x4000000;
365
366 /**
Clara Bayarri4423d912015-03-02 19:42:48 +0000367 * When true, indicates that a call to startActionModeForChild was made with the type parameter
368 * and should not be ignored. This helps in backwards compatibility with the existing method
369 * without a type.
370 *
371 * @see #startActionModeForChild(View, android.view.ActionMode.Callback)
372 * @see #startActionModeForChild(View, android.view.ActionMode.Callback, int)
373 */
374 private static final int FLAG_START_ACTION_MODE_FOR_CHILD_IS_TYPED = 0x8000000;
375
376 /**
377 * When true, indicates that a call to startActionModeForChild was made without the type
378 * parameter. This helps in backwards compatibility with the existing method
379 * without a type.
380 *
381 * @see #startActionModeForChild(View, android.view.ActionMode.Callback)
382 * @see #startActionModeForChild(View, android.view.ActionMode.Callback, int)
383 */
384 private static final int FLAG_START_ACTION_MODE_FOR_CHILD_IS_NOT_TYPED = 0x10000000;
385
386 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800387 * Indicates which types of drawing caches are to be kept in memory.
388 * This field should be made private, so it is hidden from the SDK.
389 * {@hide}
390 */
391 protected int mPersistentDrawingCache;
392
393 /**
394 * Used to indicate that no drawing cache should be kept in memory.
395 */
396 public static final int PERSISTENT_NO_CACHE = 0x0;
397
398 /**
399 * Used to indicate that the animation drawing cache should be kept in memory.
400 */
401 public static final int PERSISTENT_ANIMATION_CACHE = 0x1;
402
403 /**
404 * Used to indicate that the scrolling drawing cache should be kept in memory.
405 */
406 public static final int PERSISTENT_SCROLLING_CACHE = 0x2;
407
408 /**
409 * Used to indicate that all drawing caches should be kept in memory.
410 */
411 public static final int PERSISTENT_ALL_CACHES = 0x3;
412
Philip Milne1557fd72012-04-04 23:41:34 -0700413 // Layout Modes
414
Philip Milnecfb631b2012-10-26 10:51:46 -0700415 private static final int LAYOUT_MODE_UNDEFINED = -1;
416
Philip Milne1557fd72012-04-04 23:41:34 -0700417 /**
418 * This constant is a {@link #setLayoutMode(int) layoutMode}.
Philip Milne7a23b492012-04-24 22:12:36 -0700419 * Clip bounds are the raw values of {@link #getLeft() left}, {@link #getTop() top},
Philip Milne1557fd72012-04-04 23:41:34 -0700420 * {@link #getRight() right} and {@link #getBottom() bottom}.
421 */
Philip Milne7b757812012-09-19 18:13:44 -0700422 public static final int LAYOUT_MODE_CLIP_BOUNDS = 0;
Philip Milne1557fd72012-04-04 23:41:34 -0700423
424 /**
425 * This constant is a {@link #setLayoutMode(int) layoutMode}.
Philip Milne7a23b492012-04-24 22:12:36 -0700426 * Optical bounds describe where a widget appears to be. They sit inside the clip
427 * bounds which need to cover a larger area to allow other effects,
428 * such as shadows and glows, to be drawn.
Philip Milne1557fd72012-04-04 23:41:34 -0700429 */
Philip Milne7b757812012-09-19 18:13:44 -0700430 public static final int LAYOUT_MODE_OPTICAL_BOUNDS = 1;
431
432 /** @hide */
Philip Milnecfb631b2012-10-26 10:51:46 -0700433 public static int LAYOUT_MODE_DEFAULT = LAYOUT_MODE_CLIP_BOUNDS;
Philip Milne1557fd72012-04-04 23:41:34 -0700434
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800435 /**
436 * We clip to padding when FLAG_CLIP_TO_PADDING and FLAG_PADDING_NOT_NULL
437 * are set at the same time.
438 */
439 protected static final int CLIP_TO_PADDING_MASK = FLAG_CLIP_TO_PADDING | FLAG_PADDING_NOT_NULL;
440
441 // Index of the child's left position in the mLocation array
442 private static final int CHILD_LEFT_INDEX = 0;
443 // Index of the child's top position in the mLocation array
444 private static final int CHILD_TOP_INDEX = 1;
445
446 // Child views of this ViewGroup
447 private View[] mChildren;
448 // Number of valid children in the mChildren array, the rest should be null or not
449 // considered as children
450 private int mChildrenCount;
451
Chet Haaseb9895022013-04-02 15:10:58 -0700452 // Whether layout calls are currently being suppressed, controlled by calls to
453 // suppressLayout()
454 boolean mSuppressLayout = false;
455
456 // Whether any layout calls have actually been suppressed while mSuppressLayout
457 // has been true. This tracks whether we need to issue a requestLayout() when
458 // layout is later re-enabled.
459 private boolean mLayoutCalledWhileSuppressed = false;
460
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800461 private static final int ARRAY_INITIAL_CAPACITY = 12;
462 private static final int ARRAY_CAPACITY_INCREMENT = 12;
463
Romain Guycbc67742012-04-27 16:12:57 -0700464 private static Paint sDebugPaint;
465 private static float[] sDebugLines;
Philip Milne604f4402012-04-24 19:27:11 -0700466
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800467 // Used to draw cached views
Chet Haase64a48c12012-02-13 16:33:29 -0800468 Paint mCachePaint;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800469
Chet Haase21cd1382010-09-01 17:42:29 -0700470 // Used to animate add/remove changes in layout
471 private LayoutTransition mTransition;
472
473 // The set of views that are currently being transitioned. This list is used to track views
474 // being removed that should not actually be removed from the parent yet because they are
475 // being animated.
476 private ArrayList<View> mTransitioningViews;
477
Chet Haase5e25c2c2010-09-16 11:15:56 -0700478 // List of children changing visibility. This is used to potentially keep rendering
479 // views during a transition when they otherwise would have become gone/invisible
480 private ArrayList<View> mVisibilityChangingChildren;
481
Chris Craikab008f02014-05-23 17:55:03 -0700482 // Temporary holder of presorted children, only used for
483 // input/software draw dispatch for correctly Z ordering.
484 private ArrayList<View> mPreSortedChildren;
485
Adam Powell539ee872012-02-03 19:00:49 -0800486 // Indicates how many of this container's child subtrees contain transient state
487 @ViewDebug.ExportedProperty(category = "layout")
488 private int mChildCountWithTransientState = 0;
489
Adam Powell10ba2772014-04-15 09:46:51 -0700490 /**
491 * Currently registered axes for nested scrolling. Flag set consisting of
492 * {@link #SCROLL_AXIS_HORIZONTAL} {@link #SCROLL_AXIS_VERTICAL} or {@link #SCROLL_AXIS_NONE}
493 * for null.
494 */
495 private int mNestedScrollAxes;
496
Chet Haasec633d2f2015-04-07 10:29:39 -0700497 // Used to manage the list of transient views, added by addTransientView()
498 private List<Integer> mTransientIndices = null;
499 private List<View> mTransientViews = null;
500
501
Clara Bayarri4423d912015-03-02 19:42:48 +0000502 /**
503 * Empty ActionMode used as a sentinel in recursive entries to startActionModeForChild.
504 *
505 * @see #startActionModeForChild(View, android.view.ActionMode.Callback)
506 * @see #startActionModeForChild(View, android.view.ActionMode.Callback, int)
507 */
508 private static final ActionMode SENTINEL_ACTION_MODE = new ActionMode() {
509 @Override
510 public void setTitle(CharSequence title) {}
511
512 @Override
513 public void setTitle(int resId) {}
514
515 @Override
516 public void setSubtitle(CharSequence subtitle) {}
517
518 @Override
519 public void setSubtitle(int resId) {}
520
521 @Override
522 public void setCustomView(View view) {}
523
524 @Override
525 public void invalidate() {}
526
527 @Override
528 public void finish() {}
529
530 @Override
531 public Menu getMenu() {
532 return null;
533 }
534
535 @Override
536 public CharSequence getTitle() {
537 return null;
538 }
539
540 @Override
541 public CharSequence getSubtitle() {
542 return null;
543 }
544
545 @Override
546 public View getCustomView() {
547 return null;
548 }
549
550 @Override
551 public MenuInflater getMenuInflater() {
552 return null;
553 }
554 };
555
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800556 public ViewGroup(Context context) {
Alan Viveretted6479ec2013-09-10 17:03:02 -0700557 this(context, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800558 }
559
560 public ViewGroup(Context context, AttributeSet attrs) {
Alan Viveretted6479ec2013-09-10 17:03:02 -0700561 this(context, attrs, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800562 }
563
Alan Viverette617feb92013-09-09 18:09:13 -0700564 public ViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {
Alan Viveretted6479ec2013-09-10 17:03:02 -0700565 this(context, attrs, defStyleAttr, 0);
Alan Viverette617feb92013-09-09 18:09:13 -0700566 }
567
568 public ViewGroup(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
569 super(context, attrs, defStyleAttr, defStyleRes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800570 initViewGroup();
Alan Viveretted6479ec2013-09-10 17:03:02 -0700571 initFromAttributes(context, attrs, defStyleAttr, defStyleRes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800572 }
573
Philip Milne10ca24a2012-04-23 15:38:27 -0700574 private boolean debugDraw() {
Philip Milne7b757812012-09-19 18:13:44 -0700575 return DEBUG_DRAW || mAttachInfo != null && mAttachInfo.mDebugLayout;
Philip Milne10ca24a2012-04-23 15:38:27 -0700576 }
577
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800578 private void initViewGroup() {
579 // ViewGroup doesn't draw by default
Philip Milne10ca24a2012-04-23 15:38:27 -0700580 if (!debugDraw()) {
581 setFlags(WILL_NOT_DRAW, DRAW_MASK);
582 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800583 mGroupFlags |= FLAG_CLIP_CHILDREN;
584 mGroupFlags |= FLAG_CLIP_TO_PADDING;
585 mGroupFlags |= FLAG_ANIMATION_DONE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800586
Jeff Brown995e7742010-12-22 16:59:36 -0800587 if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB) {
588 mGroupFlags |= FLAG_SPLIT_MOTION_EVENTS;
589 }
590
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800591 setDescendantFocusability(FOCUS_BEFORE_DESCENDANTS);
592
593 mChildren = new View[ARRAY_INITIAL_CAPACITY];
594 mChildrenCount = 0;
595
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800596 mPersistentDrawingCache = PERSISTENT_SCROLLING_CACHE;
597 }
598
Alan Viveretted6479ec2013-09-10 17:03:02 -0700599 private void initFromAttributes(
600 Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
Filip Gruszczyńskib50cea02014-03-05 17:54:58 -0800601 final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ViewGroup, defStyleAttr,
602 defStyleRes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800603
604 final int N = a.getIndexCount();
605 for (int i = 0; i < N; i++) {
606 int attr = a.getIndex(i);
607 switch (attr) {
608 case R.styleable.ViewGroup_clipChildren:
609 setClipChildren(a.getBoolean(attr, true));
610 break;
611 case R.styleable.ViewGroup_clipToPadding:
612 setClipToPadding(a.getBoolean(attr, true));
613 break;
614 case R.styleable.ViewGroup_animationCache:
615 setAnimationCacheEnabled(a.getBoolean(attr, true));
616 break;
617 case R.styleable.ViewGroup_persistentDrawingCache:
618 setPersistentDrawingCache(a.getInt(attr, PERSISTENT_SCROLLING_CACHE));
619 break;
620 case R.styleable.ViewGroup_addStatesFromChildren:
621 setAddStatesFromChildren(a.getBoolean(attr, false));
622 break;
623 case R.styleable.ViewGroup_alwaysDrawnWithCache:
624 setAlwaysDrawnWithCacheEnabled(a.getBoolean(attr, true));
625 break;
626 case R.styleable.ViewGroup_layoutAnimation:
627 int id = a.getResourceId(attr, -1);
628 if (id > 0) {
629 setLayoutAnimation(AnimationUtils.loadLayoutAnimation(mContext, id));
630 }
631 break;
632 case R.styleable.ViewGroup_descendantFocusability:
633 setDescendantFocusability(DESCENDANT_FOCUSABILITY_FLAGS[a.getInt(attr, 0)]);
634 break;
Adam Powell2b342f02010-08-18 18:14:13 -0700635 case R.styleable.ViewGroup_splitMotionEvents:
636 setMotionEventSplittingEnabled(a.getBoolean(attr, false));
637 break;
Chet Haase13cc1202010-09-03 15:39:20 -0700638 case R.styleable.ViewGroup_animateLayoutChanges:
639 boolean animateLayoutChanges = a.getBoolean(attr, false);
640 if (animateLayoutChanges) {
641 setLayoutTransition(new LayoutTransition());
642 }
643 break;
Philip Milne7b757812012-09-19 18:13:44 -0700644 case R.styleable.ViewGroup_layoutMode:
Philip Milnecfb631b2012-10-26 10:51:46 -0700645 setLayoutMode(a.getInt(attr, LAYOUT_MODE_UNDEFINED));
Philip Milne7b757812012-09-19 18:13:44 -0700646 break;
George Mount0a778ed2013-12-13 13:35:36 -0800647 case R.styleable.ViewGroup_transitionGroup:
648 setTransitionGroup(a.getBoolean(attr, false));
649 break;
Adam Powellff0d2982014-07-10 20:34:14 -0700650 case R.styleable.ViewGroup_touchscreenBlocksFocus:
651 setTouchscreenBlocksFocus(a.getBoolean(attr, false));
652 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800653 }
654 }
655
656 a.recycle();
657 }
658
659 /**
660 * Gets the descendant focusability of this view group. The descendant
661 * focusability defines the relationship between this view group and its
662 * descendants when looking for a view to take focus in
663 * {@link #requestFocus(int, android.graphics.Rect)}.
664 *
665 * @return one of {@link #FOCUS_BEFORE_DESCENDANTS}, {@link #FOCUS_AFTER_DESCENDANTS},
666 * {@link #FOCUS_BLOCK_DESCENDANTS}.
667 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -0700668 @ViewDebug.ExportedProperty(category = "focus", mapping = {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800669 @ViewDebug.IntToString(from = FOCUS_BEFORE_DESCENDANTS, to = "FOCUS_BEFORE_DESCENDANTS"),
670 @ViewDebug.IntToString(from = FOCUS_AFTER_DESCENDANTS, to = "FOCUS_AFTER_DESCENDANTS"),
671 @ViewDebug.IntToString(from = FOCUS_BLOCK_DESCENDANTS, to = "FOCUS_BLOCK_DESCENDANTS")
672 })
673 public int getDescendantFocusability() {
674 return mGroupFlags & FLAG_MASK_FOCUSABILITY;
675 }
676
677 /**
678 * Set the descendant focusability of this view group. This defines the relationship
679 * between this view group and its descendants when looking for a view to
680 * take focus in {@link #requestFocus(int, android.graphics.Rect)}.
681 *
682 * @param focusability one of {@link #FOCUS_BEFORE_DESCENDANTS}, {@link #FOCUS_AFTER_DESCENDANTS},
683 * {@link #FOCUS_BLOCK_DESCENDANTS}.
684 */
685 public void setDescendantFocusability(int focusability) {
686 switch (focusability) {
687 case FOCUS_BEFORE_DESCENDANTS:
688 case FOCUS_AFTER_DESCENDANTS:
689 case FOCUS_BLOCK_DESCENDANTS:
690 break;
691 default:
692 throw new IllegalArgumentException("must be one of FOCUS_BEFORE_DESCENDANTS, "
693 + "FOCUS_AFTER_DESCENDANTS, FOCUS_BLOCK_DESCENDANTS");
694 }
695 mGroupFlags &= ~FLAG_MASK_FOCUSABILITY;
696 mGroupFlags |= (focusability & FLAG_MASK_FOCUSABILITY);
697 }
698
699 /**
700 * {@inheritDoc}
701 */
702 @Override
703 void handleFocusGainInternal(int direction, Rect previouslyFocusedRect) {
704 if (mFocused != null) {
Alan Viverette223622a2013-12-17 13:29:02 -0800705 mFocused.unFocus(this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800706 mFocused = null;
707 }
708 super.handleFocusGainInternal(direction, previouslyFocusedRect);
709 }
710
711 /**
712 * {@inheritDoc}
713 */
714 public void requestChildFocus(View child, View focused) {
715 if (DBG) {
716 System.out.println(this + " requestChildFocus()");
717 }
718 if (getDescendantFocusability() == FOCUS_BLOCK_DESCENDANTS) {
719 return;
720 }
721
722 // Unfocus us, if necessary
Alan Viverette223622a2013-12-17 13:29:02 -0800723 super.unFocus(focused);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800724
725 // We had a previous notion of who had focus. Clear it.
726 if (mFocused != child) {
727 if (mFocused != null) {
Alan Viverette223622a2013-12-17 13:29:02 -0800728 mFocused.unFocus(focused);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800729 }
730
731 mFocused = child;
732 }
733 if (mParent != null) {
734 mParent.requestChildFocus(this, focused);
735 }
736 }
737
738 /**
739 * {@inheritDoc}
740 */
741 public void focusableViewAvailable(View v) {
742 if (mParent != null
743 // shortcut: don't report a new focusable view if we block our descendants from
744 // getting focus
745 && (getDescendantFocusability() != FOCUS_BLOCK_DESCENDANTS)
Adam Powell88c11752014-07-21 17:19:16 -0700746 && (isFocusableInTouchMode() || !shouldBlockFocusForTouchscreen())
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800747 // shortcut: don't report a new focusable view if we already are focused
748 // (and we don't prefer our descendants)
749 //
750 // note: knowing that mFocused is non-null is not a good enough reason
751 // to break the traversal since in that case we'd actually have to find
752 // the focused view and make sure it wasn't FOCUS_AFTER_DESCENDANTS and
Joe Onoratoc6cc0f82011-04-12 11:53:13 -0700753 // an ancestor of v; this will get checked for at ViewAncestor
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800754 && !(isFocused() && getDescendantFocusability() != FOCUS_AFTER_DESCENDANTS)) {
755 mParent.focusableViewAvailable(v);
756 }
757 }
758
759 /**
760 * {@inheritDoc}
761 */
762 public boolean showContextMenuForChild(View originalView) {
763 return mParent != null && mParent.showContextMenuForChild(originalView);
764 }
765
766 /**
Adam Powell6e346362010-07-23 10:18:23 -0700767 * {@inheritDoc}
768 */
Clara Bayarri4423d912015-03-02 19:42:48 +0000769 @Override
Adam Powell6e346362010-07-23 10:18:23 -0700770 public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback) {
Clara Bayarri4423d912015-03-02 19:42:48 +0000771 if ((mGroupFlags & FLAG_START_ACTION_MODE_FOR_CHILD_IS_TYPED) == 0) {
772 // This is the original call.
773 try {
774 mGroupFlags |= FLAG_START_ACTION_MODE_FOR_CHILD_IS_NOT_TYPED;
775 return startActionModeForChild(originalView, callback, ActionMode.TYPE_PRIMARY);
776 } finally {
777 mGroupFlags &= ~FLAG_START_ACTION_MODE_FOR_CHILD_IS_NOT_TYPED;
778 }
779 } else {
780 // We are being called from the new method with type.
781 return SENTINEL_ACTION_MODE;
782 }
783 }
784
785 /**
786 * {@inheritDoc}
787 */
788 @Override
789 public ActionMode startActionModeForChild(
790 View originalView, ActionMode.Callback callback, int type) {
791 if ((mGroupFlags & FLAG_START_ACTION_MODE_FOR_CHILD_IS_NOT_TYPED) == 0) {
792 ActionMode mode;
793 try {
794 mGroupFlags |= FLAG_START_ACTION_MODE_FOR_CHILD_IS_TYPED;
795 mode = startActionModeForChild(originalView, callback);
796 } finally {
797 mGroupFlags &= ~FLAG_START_ACTION_MODE_FOR_CHILD_IS_TYPED;
798 }
799 if (mode != SENTINEL_ACTION_MODE) {
800 return mode;
801 }
802 }
803 if (mParent != null) {
804 try {
805 return mParent.startActionModeForChild(originalView, callback, type);
806 } catch (AbstractMethodError ame) {
807 // Custom view parents might not implement this method.
808 return mParent.startActionModeForChild(originalView, callback);
809 }
810 }
811 return null;
Adam Powell6e346362010-07-23 10:18:23 -0700812 }
813
814 /**
Clara Bayarrid5bf3ed2015-03-27 17:32:45 +0000815 * @hide
816 */
817 @Override
818 public boolean dispatchActivityResult(
819 String who, int requestCode, int resultCode, Intent data) {
820 if (super.dispatchActivityResult(who, requestCode, resultCode, data)) {
821 return true;
822 }
823 int childCount = getChildCount();
824 for (int i = 0; i < childCount; i++) {
825 View child = getChildAt(i);
826 if (child.dispatchActivityResult(who, requestCode, resultCode, data)) {
827 return true;
828 }
829 }
830 return false;
831 }
832
833 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800834 * Find the nearest view in the specified direction that wants to take
835 * focus.
836 *
837 * @param focused The view that currently has focus
838 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and
839 * FOCUS_RIGHT, or 0 for not applicable.
840 */
841 public View focusSearch(View focused, int direction) {
Svetoslav Ganov27e2da72012-07-02 18:12:00 -0700842 if (isRootNamespace()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800843 // root namespace means we should consider ourselves the top of the
844 // tree for focus searching; otherwise we could be focus searching
845 // into other tabs. see LocalActivityManager and TabHost for more info
846 return FocusFinder.getInstance().findNextFocus(this, focused, direction);
847 } else if (mParent != null) {
848 return mParent.focusSearch(focused, direction);
849 }
850 return null;
851 }
852
853 /**
854 * {@inheritDoc}
855 */
856 public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
857 return false;
858 }
859
860 /**
861 * {@inheritDoc}
862 */
Svetoslav Ganov42138042012-03-20 11:51:39 -0700863 @Override
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700864 public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event) {
Svetoslav Ganov42138042012-03-20 11:51:39 -0700865 ViewParent parent = mParent;
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700866 if (parent == null) {
867 return false;
868 }
869 final boolean propagate = onRequestSendAccessibilityEvent(child, event);
870 if (!propagate) {
871 return false;
872 }
873 return parent.requestSendAccessibilityEvent(this, event);
874 }
875
876 /**
877 * Called when a child has requested sending an {@link AccessibilityEvent} and
878 * gives an opportunity to its parent to augment the event.
Svetoslav Ganov031d9c12011-09-09 16:41:13 -0700879 * <p>
Adam Powell2fcbbd02011-09-28 18:56:43 -0700880 * If an {@link android.view.View.AccessibilityDelegate} has been specified via calling
881 * {@link android.view.View#setAccessibilityDelegate(android.view.View.AccessibilityDelegate)} its
882 * {@link android.view.View.AccessibilityDelegate#onRequestSendAccessibilityEvent(ViewGroup, View, AccessibilityEvent)}
Svetoslav Ganov031d9c12011-09-09 16:41:13 -0700883 * is responsible for handling this call.
884 * </p>
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700885 *
886 * @param child The child which requests sending the event.
887 * @param event The event to be sent.
888 * @return True if the event should be sent.
889 *
890 * @see #requestSendAccessibilityEvent(View, AccessibilityEvent)
891 */
892 public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
Svetoslav Ganov031d9c12011-09-09 16:41:13 -0700893 if (mAccessibilityDelegate != null) {
894 return mAccessibilityDelegate.onRequestSendAccessibilityEvent(this, child, event);
895 } else {
896 return onRequestSendAccessibilityEventInternal(child, event);
897 }
898 }
899
900 /**
901 * @see #onRequestSendAccessibilityEvent(View, AccessibilityEvent)
902 *
903 * Note: Called from the default {@link View.AccessibilityDelegate}.
Alan Viverettea54956a2015-01-07 16:05:02 -0800904 *
905 * @hide
Svetoslav Ganov031d9c12011-09-09 16:41:13 -0700906 */
Alan Viverettea54956a2015-01-07 16:05:02 -0800907 public boolean onRequestSendAccessibilityEventInternal(View child, AccessibilityEvent event) {
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700908 return true;
909 }
910
911 /**
Adam Powell539ee872012-02-03 19:00:49 -0800912 * Called when a child view has changed whether or not it is tracking transient state.
Adam Powell539ee872012-02-03 19:00:49 -0800913 */
914 public void childHasTransientStateChanged(View child, boolean childHasTransientState) {
915 final boolean oldHasTransientState = hasTransientState();
916 if (childHasTransientState) {
917 mChildCountWithTransientState++;
918 } else {
919 mChildCountWithTransientState--;
920 }
921
922 final boolean newHasTransientState = hasTransientState();
923 if (mParent != null && oldHasTransientState != newHasTransientState) {
924 try {
925 mParent.childHasTransientStateChanged(this, newHasTransientState);
926 } catch (AbstractMethodError e) {
927 Log.e(TAG, mParent.getClass().getSimpleName() +
928 " does not fully implement ViewParent", e);
929 }
930 }
931 }
932
Adam Powell539ee872012-02-03 19:00:49 -0800933 @Override
934 public boolean hasTransientState() {
935 return mChildCountWithTransientState > 0 || super.hasTransientState();
936 }
937
938 /**
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700939 * {@inheritDoc}
940 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800941 @Override
942 public boolean dispatchUnhandledMove(View focused, int direction) {
943 return mFocused != null &&
944 mFocused.dispatchUnhandledMove(focused, direction);
945 }
946
947 /**
948 * {@inheritDoc}
949 */
950 public void clearChildFocus(View child) {
951 if (DBG) {
952 System.out.println(this + " clearChildFocus()");
953 }
954
955 mFocused = null;
956 if (mParent != null) {
957 mParent.clearChildFocus(this);
958 }
959 }
960
961 /**
962 * {@inheritDoc}
963 */
964 @Override
965 public void clearFocus() {
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -0800966 if (DBG) {
967 System.out.println(this + " clearFocus()");
968 }
969 if (mFocused == null) {
970 super.clearFocus();
971 } else {
Svetoslav Ganovb552d892012-06-02 14:35:02 -0700972 View focused = mFocused;
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -0800973 mFocused = null;
Svetoslav Ganovb552d892012-06-02 14:35:02 -0700974 focused.clearFocus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800975 }
976 }
977
978 /**
979 * {@inheritDoc}
980 */
981 @Override
Alan Viverette223622a2013-12-17 13:29:02 -0800982 void unFocus(View focused) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800983 if (DBG) {
984 System.out.println(this + " unFocus()");
985 }
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -0800986 if (mFocused == null) {
Alan Viverette223622a2013-12-17 13:29:02 -0800987 super.unFocus(focused);
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -0800988 } else {
Alan Viverette223622a2013-12-17 13:29:02 -0800989 mFocused.unFocus(focused);
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -0800990 mFocused = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800991 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800992 }
993
994 /**
995 * Returns the focused child of this view, if any. The child may have focus
996 * or contain focus.
997 *
998 * @return the focused child or null.
999 */
1000 public View getFocusedChild() {
1001 return mFocused;
1002 }
1003
Adam Powell88c11752014-07-21 17:19:16 -07001004 View getDeepestFocusedChild() {
1005 View v = this;
1006 while (v != null) {
1007 if (v.isFocused()) {
1008 return v;
1009 }
1010 v = v instanceof ViewGroup ? ((ViewGroup) v).getFocusedChild() : null;
1011 }
1012 return null;
1013 }
1014
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001015 /**
1016 * Returns true if this view has or contains focus
1017 *
1018 * @return true if this view has or contains focus
1019 */
1020 @Override
1021 public boolean hasFocus() {
Dianne Hackborn4702a852012-08-17 15:18:29 -07001022 return (mPrivateFlags & PFLAG_FOCUSED) != 0 || mFocused != null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001023 }
1024
1025 /*
1026 * (non-Javadoc)
1027 *
1028 * @see android.view.View#findFocus()
1029 */
1030 @Override
1031 public View findFocus() {
1032 if (DBG) {
1033 System.out.println("Find focus in " + this + ": flags="
1034 + isFocused() + ", child=" + mFocused);
1035 }
1036
1037 if (isFocused()) {
1038 return this;
1039 }
1040
1041 if (mFocused != null) {
1042 return mFocused.findFocus();
1043 }
1044 return null;
1045 }
1046
1047 /**
1048 * {@inheritDoc}
1049 */
1050 @Override
1051 public boolean hasFocusable() {
1052 if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) {
1053 return false;
1054 }
1055
1056 if (isFocusable()) {
1057 return true;
1058 }
1059
1060 final int descendantFocusability = getDescendantFocusability();
Adam Powell88c11752014-07-21 17:19:16 -07001061 if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001062 final int count = mChildrenCount;
1063 final View[] children = mChildren;
1064
1065 for (int i = 0; i < count; i++) {
1066 final View child = children[i];
1067 if (child.hasFocusable()) {
1068 return true;
1069 }
1070 }
1071 }
1072
1073 return false;
1074 }
1075
1076 /**
1077 * {@inheritDoc}
1078 */
1079 @Override
svetoslavganov75986cf2009-05-14 22:28:01 -07001080 public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001081 final int focusableCount = views.size();
1082
1083 final int descendantFocusability = getDescendantFocusability();
1084
Adam Powell88c11752014-07-21 17:19:16 -07001085 if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS) {
1086 if (shouldBlockFocusForTouchscreen()) {
1087 focusableMode |= FOCUSABLES_TOUCH_MODE;
1088 }
1089
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001090 final int count = mChildrenCount;
1091 final View[] children = mChildren;
1092
1093 for (int i = 0; i < count; i++) {
1094 final View child = children[i];
1095 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
svetoslavganov75986cf2009-05-14 22:28:01 -07001096 child.addFocusables(views, direction, focusableMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001097 }
1098 }
1099 }
1100
1101 // we add ourselves (if focusable) in all cases except for when we are
1102 // FOCUS_AFTER_DESCENDANTS and there are some descendants focusable. this is
1103 // to avoid the focus search finding layouts when a more precise search
1104 // among the focusable children would be more interesting.
Adam Powellff0d2982014-07-10 20:34:14 -07001105 if ((descendantFocusability != FOCUS_AFTER_DESCENDANTS
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001106 // No focusable descendants
Adam Powell88c11752014-07-21 17:19:16 -07001107 || (focusableCount == views.size())) &&
1108 (isFocusableInTouchMode() || !shouldBlockFocusForTouchscreen())) {
svetoslavganov75986cf2009-05-14 22:28:01 -07001109 super.addFocusables(views, direction, focusableMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001110 }
1111 }
1112
Adam Powellff0d2982014-07-10 20:34:14 -07001113 /**
1114 * Set whether this ViewGroup should ignore focus requests for itself and its children.
1115 * If this option is enabled and the ViewGroup or a descendant currently has focus, focus
1116 * will proceed forward.
1117 *
1118 * @param touchscreenBlocksFocus true to enable blocking focus in the presence of a touchscreen
1119 */
1120 public void setTouchscreenBlocksFocus(boolean touchscreenBlocksFocus) {
1121 if (touchscreenBlocksFocus) {
1122 mGroupFlags |= FLAG_TOUCHSCREEN_BLOCKS_FOCUS;
1123 if (hasFocus()) {
Adam Powell88c11752014-07-21 17:19:16 -07001124 final View focusedChild = getDeepestFocusedChild();
1125 if (!focusedChild.isFocusableInTouchMode()) {
1126 final View newFocus = focusSearch(FOCUS_FORWARD);
1127 if (newFocus != null) {
1128 newFocus.requestFocus();
1129 }
Adam Powellff0d2982014-07-10 20:34:14 -07001130 }
1131 }
1132 } else {
1133 mGroupFlags &= ~FLAG_TOUCHSCREEN_BLOCKS_FOCUS;
1134 }
1135 }
1136
1137 /**
1138 * Check whether this ViewGroup should ignore focus requests for itself and its children.
1139 */
1140 public boolean getTouchscreenBlocksFocus() {
1141 return (mGroupFlags & FLAG_TOUCHSCREEN_BLOCKS_FOCUS) != 0;
1142 }
1143
1144 boolean shouldBlockFocusForTouchscreen() {
1145 return getTouchscreenBlocksFocus() &&
1146 mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN);
1147 }
1148
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001149 @Override
Svetoslav Ganovea515ae2011-09-14 18:15:32 -07001150 public void findViewsWithText(ArrayList<View> outViews, CharSequence text, int flags) {
1151 super.findViewsWithText(outViews, text, flags);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001152 final int childrenCount = mChildrenCount;
1153 final View[] children = mChildren;
1154 for (int i = 0; i < childrenCount; i++) {
1155 View child = children[i];
Svetoslav Ganovea515ae2011-09-14 18:15:32 -07001156 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE
Dianne Hackborn4702a852012-08-17 15:18:29 -07001157 && (child.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) {
Svetoslav Ganovea515ae2011-09-14 18:15:32 -07001158 child.findViewsWithText(outViews, text, flags);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07001159 }
1160 }
1161 }
1162
Svetoslav5b578da2013-05-08 14:23:32 -07001163 /** @hide */
Svetoslav Ganov2cdedff2011-10-03 14:18:42 -07001164 @Override
Svetoslav5b578da2013-05-08 14:23:32 -07001165 public View findViewByAccessibilityIdTraversal(int accessibilityId) {
Svetoslav Ganov2cdedff2011-10-03 14:18:42 -07001166 View foundView = super.findViewByAccessibilityIdTraversal(accessibilityId);
1167 if (foundView != null) {
1168 return foundView;
1169 }
1170 final int childrenCount = mChildrenCount;
1171 final View[] children = mChildren;
1172 for (int i = 0; i < childrenCount; i++) {
1173 View child = children[i];
1174 foundView = child.findViewByAccessibilityIdTraversal(accessibilityId);
1175 if (foundView != null) {
1176 return foundView;
1177 }
1178 }
1179 return null;
1180 }
1181
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001182 /**
1183 * {@inheritDoc}
1184 */
1185 @Override
1186 public void dispatchWindowFocusChanged(boolean hasFocus) {
1187 super.dispatchWindowFocusChanged(hasFocus);
1188 final int count = mChildrenCount;
1189 final View[] children = mChildren;
1190 for (int i = 0; i < count; i++) {
1191 children[i].dispatchWindowFocusChanged(hasFocus);
1192 }
1193 }
1194
1195 /**
1196 * {@inheritDoc}
1197 */
1198 @Override
1199 public void addTouchables(ArrayList<View> views) {
1200 super.addTouchables(views);
1201
1202 final int count = mChildrenCount;
1203 final View[] children = mChildren;
1204
1205 for (int i = 0; i < count; i++) {
1206 final View child = children[i];
1207 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
1208 child.addTouchables(views);
1209 }
1210 }
1211 }
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001212
1213 /**
1214 * @hide
1215 */
1216 @Override
1217 public void makeOptionalFitsSystemWindows() {
1218 super.makeOptionalFitsSystemWindows();
1219 final int count = mChildrenCount;
1220 final View[] children = mChildren;
1221 for (int i = 0; i < count; i++) {
1222 children[i].makeOptionalFitsSystemWindows();
1223 }
1224 }
1225
Romain Guy43c9cdf2010-01-27 13:53:55 -08001226 /**
1227 * {@inheritDoc}
1228 */
1229 @Override
1230 public void dispatchDisplayHint(int hint) {
1231 super.dispatchDisplayHint(hint);
1232 final int count = mChildrenCount;
1233 final View[] children = mChildren;
1234 for (int i = 0; i < count; i++) {
1235 children[i].dispatchDisplayHint(hint);
1236 }
1237 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001238
1239 /**
Chet Haase0d299362012-01-26 10:51:48 -08001240 * Called when a view's visibility has changed. Notify the parent to take any appropriate
1241 * action.
1242 *
1243 * @param child The view whose visibility has changed
1244 * @param oldVisibility The previous visibility value (GONE, INVISIBLE, or VISIBLE).
1245 * @param newVisibility The new visibility value (GONE, INVISIBLE, or VISIBLE).
Chet Haase5e25c2c2010-09-16 11:15:56 -07001246 * @hide
Chet Haase5e25c2c2010-09-16 11:15:56 -07001247 */
Chet Haase0d299362012-01-26 10:51:48 -08001248 protected void onChildVisibilityChanged(View child, int oldVisibility, int newVisibility) {
Chet Haase5e25c2c2010-09-16 11:15:56 -07001249 if (mTransition != null) {
Chet Haase0d299362012-01-26 10:51:48 -08001250 if (newVisibility == VISIBLE) {
1251 mTransition.showChild(this, child, oldVisibility);
Chet Haase5e25c2c2010-09-16 11:15:56 -07001252 } else {
Chet Haase0d299362012-01-26 10:51:48 -08001253 mTransition.hideChild(this, child, newVisibility);
Chet Haase5e25c2c2010-09-16 11:15:56 -07001254 if (mTransitioningViews != null && mTransitioningViews.contains(child)) {
Chet Haaseddbb3462012-06-19 13:54:29 -07001255 // Only track this on disappearing views - appearing views are already visible
1256 // and don't need special handling during drawChild()
1257 if (mVisibilityChangingChildren == null) {
1258 mVisibilityChangingChildren = new ArrayList<View>();
1259 }
1260 mVisibilityChangingChildren.add(child);
Chet Haase5e25c2c2010-09-16 11:15:56 -07001261 addDisappearingView(child);
1262 }
1263 }
1264 }
Christopher Tate86cab1b2011-01-13 20:28:55 -08001265
1266 // in all cases, for drags
1267 if (mCurrentDrag != null) {
Chet Haase0d299362012-01-26 10:51:48 -08001268 if (newVisibility == VISIBLE) {
Christopher Tate86cab1b2011-01-13 20:28:55 -08001269 notifyChildOfDrag(child);
1270 }
1271 }
Chet Haase5e25c2c2010-09-16 11:15:56 -07001272 }
1273
1274 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001275 * {@inheritDoc}
1276 */
1277 @Override
Adam Powell326d8082009-12-09 15:10:07 -08001278 protected void dispatchVisibilityChanged(View changedView, int visibility) {
1279 super.dispatchVisibilityChanged(changedView, visibility);
1280 final int count = mChildrenCount;
1281 final View[] children = mChildren;
1282 for (int i = 0; i < count; i++) {
1283 children[i].dispatchVisibilityChanged(changedView, visibility);
1284 }
1285 }
1286
1287 /**
1288 * {@inheritDoc}
1289 */
1290 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001291 public void dispatchWindowVisibilityChanged(int visibility) {
1292 super.dispatchWindowVisibilityChanged(visibility);
1293 final int count = mChildrenCount;
1294 final View[] children = mChildren;
1295 for (int i = 0; i < count; i++) {
1296 children[i].dispatchWindowVisibilityChanged(visibility);
1297 }
1298 }
1299
1300 /**
1301 * {@inheritDoc}
1302 */
Dianne Hackborne36d6e22010-02-17 19:46:25 -08001303 @Override
1304 public void dispatchConfigurationChanged(Configuration newConfig) {
1305 super.dispatchConfigurationChanged(newConfig);
1306 final int count = mChildrenCount;
1307 final View[] children = mChildren;
1308 for (int i = 0; i < count; i++) {
1309 children[i].dispatchConfigurationChanged(newConfig);
1310 }
1311 }
1312
1313 /**
1314 * {@inheritDoc}
1315 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001316 public void recomputeViewAttributes(View child) {
Joe Onorato664644d2011-01-23 17:53:23 -08001317 if (mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) {
1318 ViewParent parent = mParent;
1319 if (parent != null) parent.recomputeViewAttributes(this);
1320 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001321 }
Romain Guy8506ab42009-06-11 17:35:47 -07001322
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001323 @Override
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001324 void dispatchCollectViewAttributes(AttachInfo attachInfo, int visibility) {
1325 if ((visibility & VISIBILITY_MASK) == VISIBLE) {
1326 super.dispatchCollectViewAttributes(attachInfo, visibility);
1327 final int count = mChildrenCount;
1328 final View[] children = mChildren;
1329 for (int i = 0; i < count; i++) {
1330 final View child = children[i];
1331 child.dispatchCollectViewAttributes(attachInfo,
1332 visibility | (child.mViewFlags&VISIBILITY_MASK));
1333 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001334 }
1335 }
1336
1337 /**
1338 * {@inheritDoc}
1339 */
1340 public void bringChildToFront(View child) {
Alan Viverette77bb6f12015-02-11 17:24:33 -08001341 final int index = indexOfChild(child);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001342 if (index >= 0) {
1343 removeFromArray(index);
1344 addInArray(child, mChildrenCount);
1345 child.mParent = this;
Chet Haasecb96db82013-09-04 10:21:46 -07001346 requestLayout();
1347 invalidate();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001348 }
1349 }
1350
Romain Guy6410c0a2013-06-17 11:21:58 -07001351 private PointF getLocalPoint() {
1352 if (mLocalPoint == null) mLocalPoint = new PointF();
1353 return mLocalPoint;
1354 }
1355
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001356 /**
1357 * {@inheritDoc}
Christopher Tatea53146c2010-09-07 11:57:52 -07001358 */
Steve Block8a7259b2012-03-01 11:24:41 +00001359 // TODO: Write real docs
Christopher Tatea53146c2010-09-07 11:57:52 -07001360 @Override
1361 public boolean dispatchDragEvent(DragEvent event) {
1362 boolean retval = false;
1363 final float tx = event.mX;
1364 final float ty = event.mY;
1365
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07001366 ViewRootImpl root = getViewRootImpl();
Christopher Tatea53146c2010-09-07 11:57:52 -07001367
1368 // Dispatch down the view hierarchy
Romain Guy6410c0a2013-06-17 11:21:58 -07001369 final PointF localPoint = getLocalPoint();
1370
Christopher Tatea53146c2010-09-07 11:57:52 -07001371 switch (event.mAction) {
1372 case DragEvent.ACTION_DRAG_STARTED: {
1373 // clear state to recalculate which views we drag over
Chris Tate9d1ab882010-11-02 15:55:39 -07001374 mCurrentDragView = null;
Christopher Tatea53146c2010-09-07 11:57:52 -07001375
Christopher Tate86cab1b2011-01-13 20:28:55 -08001376 // Set up our tracking of drag-started notifications
1377 mCurrentDrag = DragEvent.obtain(event);
1378 if (mDragNotifiedChildren == null) {
1379 mDragNotifiedChildren = new HashSet<View>();
1380 } else {
1381 mDragNotifiedChildren.clear();
1382 }
1383
Christopher Tatea53146c2010-09-07 11:57:52 -07001384 // Now dispatch down to our children, caching the responses
1385 mChildAcceptsDrag = false;
1386 final int count = mChildrenCount;
1387 final View[] children = mChildren;
1388 for (int i = 0; i < count; i++) {
Christopher Tate2c095f32010-10-04 14:13:40 -07001389 final View child = children[i];
Christopher Tate3d4bf172011-03-28 16:16:46 -07001390 child.mPrivateFlags2 &= ~View.DRAG_MASK;
Christopher Tate2c095f32010-10-04 14:13:40 -07001391 if (child.getVisibility() == VISIBLE) {
Christopher Tate86cab1b2011-01-13 20:28:55 -08001392 final boolean handled = notifyChildOfDrag(children[i]);
Christopher Tate2c095f32010-10-04 14:13:40 -07001393 if (handled) {
1394 mChildAcceptsDrag = true;
1395 }
Christopher Tatea53146c2010-09-07 11:57:52 -07001396 }
1397 }
1398
1399 // Return HANDLED if one of our children can accept the drag
1400 if (mChildAcceptsDrag) {
1401 retval = true;
1402 }
1403 } break;
1404
1405 case DragEvent.ACTION_DRAG_ENDED: {
Christopher Tate86cab1b2011-01-13 20:28:55 -08001406 // Release the bookkeeping now that the drag lifecycle has ended
Christopher Tate1fc014f2011-01-19 12:56:26 -08001407 if (mDragNotifiedChildren != null) {
1408 for (View child : mDragNotifiedChildren) {
1409 // If a child was notified about an ongoing drag, it's told that it's over
1410 child.dispatchDragEvent(event);
Christopher Tate3d4bf172011-03-28 16:16:46 -07001411 child.mPrivateFlags2 &= ~View.DRAG_MASK;
1412 child.refreshDrawableState();
Christopher Tate1fc014f2011-01-19 12:56:26 -08001413 }
1414
1415 mDragNotifiedChildren.clear();
Christopher Tatee9accff2013-03-04 12:57:23 -08001416 if (mCurrentDrag != null) {
1417 mCurrentDrag.recycle();
1418 mCurrentDrag = null;
1419 }
Christopher Tate1fc014f2011-01-19 12:56:26 -08001420 }
Christopher Tate86cab1b2011-01-13 20:28:55 -08001421
Christopher Tatea53146c2010-09-07 11:57:52 -07001422 // We consider drag-ended to have been handled if one of our children
1423 // had offered to handle the drag.
1424 if (mChildAcceptsDrag) {
1425 retval = true;
1426 }
1427 } break;
1428
1429 case DragEvent.ACTION_DRAG_LOCATION: {
1430 // Find the [possibly new] drag target
Romain Guy6410c0a2013-06-17 11:21:58 -07001431 final View target = findFrontmostDroppableChildAt(event.mX, event.mY, localPoint);
Christopher Tatea53146c2010-09-07 11:57:52 -07001432
1433 // If we've changed apparent drag target, tell the view root which view
Chris Tate9d1ab882010-11-02 15:55:39 -07001434 // we're over now [for purposes of the eventual drag-recipient-changed
1435 // notifications to the framework] and tell the new target that the drag
1436 // has entered its bounds. The root will see setDragFocus() calls all
1437 // the way down to the final leaf view that is handling the LOCATION event
1438 // before reporting the new potential recipient to the framework.
Christopher Tatea53146c2010-09-07 11:57:52 -07001439 if (mCurrentDragView != target) {
Chris Tate9d1ab882010-11-02 15:55:39 -07001440 root.setDragFocus(target);
1441
1442 final int action = event.mAction;
1443 // If we've dragged off of a child view, send it the EXITED message
1444 if (mCurrentDragView != null) {
Christopher Tate3d4bf172011-03-28 16:16:46 -07001445 final View view = mCurrentDragView;
Chris Tate9d1ab882010-11-02 15:55:39 -07001446 event.mAction = DragEvent.ACTION_DRAG_EXITED;
Christopher Tate3d4bf172011-03-28 16:16:46 -07001447 view.dispatchDragEvent(event);
Dianne Hackborn4702a852012-08-17 15:18:29 -07001448 view.mPrivateFlags2 &= ~View.PFLAG2_DRAG_HOVERED;
Christopher Tate3d4bf172011-03-28 16:16:46 -07001449 view.refreshDrawableState();
Chris Tate9d1ab882010-11-02 15:55:39 -07001450 }
Christopher Tatea53146c2010-09-07 11:57:52 -07001451 mCurrentDragView = target;
Chris Tate9d1ab882010-11-02 15:55:39 -07001452
1453 // If we've dragged over a new child view, send it the ENTERED message
1454 if (target != null) {
1455 event.mAction = DragEvent.ACTION_DRAG_ENTERED;
1456 target.dispatchDragEvent(event);
Dianne Hackborn4702a852012-08-17 15:18:29 -07001457 target.mPrivateFlags2 |= View.PFLAG2_DRAG_HOVERED;
Christopher Tate3d4bf172011-03-28 16:16:46 -07001458 target.refreshDrawableState();
Chris Tate9d1ab882010-11-02 15:55:39 -07001459 }
1460 event.mAction = action; // restore the event's original state
Christopher Tatea53146c2010-09-07 11:57:52 -07001461 }
Christopher Tate2c095f32010-10-04 14:13:40 -07001462
Christopher Tatea53146c2010-09-07 11:57:52 -07001463 // Dispatch the actual drag location notice, localized into its coordinates
1464 if (target != null) {
Romain Guy6410c0a2013-06-17 11:21:58 -07001465 event.mX = localPoint.x;
1466 event.mY = localPoint.y;
Christopher Tatea53146c2010-09-07 11:57:52 -07001467
1468 retval = target.dispatchDragEvent(event);
1469
1470 event.mX = tx;
1471 event.mY = ty;
1472 }
1473 } break;
1474
Chris Tate9d1ab882010-11-02 15:55:39 -07001475 /* Entered / exited dispatch
1476 *
1477 * DRAG_ENTERED is not dispatched downwards from ViewGroup. The reason for this is
1478 * that we're about to get the corresponding LOCATION event, which we will use to
1479 * determine which of our children is the new target; at that point we will
1480 * push a DRAG_ENTERED down to the new target child [which may itself be a ViewGroup].
1481 *
1482 * DRAG_EXITED *is* dispatched all the way down immediately: once we know the
1483 * drag has left this ViewGroup, we know by definition that every contained subview
1484 * is also no longer under the drag point.
1485 */
1486
1487 case DragEvent.ACTION_DRAG_EXITED: {
1488 if (mCurrentDragView != null) {
Christopher Tate3d4bf172011-03-28 16:16:46 -07001489 final View view = mCurrentDragView;
1490 view.dispatchDragEvent(event);
Dianne Hackborn4702a852012-08-17 15:18:29 -07001491 view.mPrivateFlags2 &= ~View.PFLAG2_DRAG_HOVERED;
Christopher Tate3d4bf172011-03-28 16:16:46 -07001492 view.refreshDrawableState();
1493
Chris Tate9d1ab882010-11-02 15:55:39 -07001494 mCurrentDragView = null;
1495 }
1496 } break;
1497
Christopher Tatea53146c2010-09-07 11:57:52 -07001498 case DragEvent.ACTION_DROP: {
Christopher Tate2c095f32010-10-04 14:13:40 -07001499 if (ViewDebug.DEBUG_DRAG) Log.d(View.VIEW_LOG_TAG, "Drop event: " + event);
Romain Guy6410c0a2013-06-17 11:21:58 -07001500 View target = findFrontmostDroppableChildAt(event.mX, event.mY, localPoint);
Christopher Tatea53146c2010-09-07 11:57:52 -07001501 if (target != null) {
Christopher Tate5ada6cb2010-10-05 14:15:29 -07001502 if (ViewDebug.DEBUG_DRAG) Log.d(View.VIEW_LOG_TAG, " dispatch drop to " + target);
Romain Guy6410c0a2013-06-17 11:21:58 -07001503 event.mX = localPoint.x;
1504 event.mY = localPoint.y;
Christopher Tatea53146c2010-09-07 11:57:52 -07001505 retval = target.dispatchDragEvent(event);
1506 event.mX = tx;
1507 event.mY = ty;
Christopher Tate5ada6cb2010-10-05 14:15:29 -07001508 } else {
1509 if (ViewDebug.DEBUG_DRAG) {
1510 Log.d(View.VIEW_LOG_TAG, " not dropped on an accepting view");
1511 }
Christopher Tatea53146c2010-09-07 11:57:52 -07001512 }
1513 } break;
1514 }
1515
1516 // If none of our children could handle the event, try here
1517 if (!retval) {
Chris Tate32affef2010-10-18 15:29:21 -07001518 // Call up to the View implementation that dispatches to installed listeners
1519 retval = super.dispatchDragEvent(event);
Christopher Tatea53146c2010-09-07 11:57:52 -07001520 }
1521 return retval;
1522 }
1523
1524 // Find the frontmost child view that lies under the given point, and calculate
1525 // the position within its own local coordinate system.
1526 View findFrontmostDroppableChildAt(float x, float y, PointF outLocalPoint) {
Christopher Tatea53146c2010-09-07 11:57:52 -07001527 final int count = mChildrenCount;
1528 final View[] children = mChildren;
1529 for (int i = count - 1; i >= 0; i--) {
1530 final View child = children[i];
Christopher Tate3d4bf172011-03-28 16:16:46 -07001531 if (!child.canAcceptDrag()) {
Christopher Tatea53146c2010-09-07 11:57:52 -07001532 continue;
1533 }
1534
Christopher Tate2c095f32010-10-04 14:13:40 -07001535 if (isTransformedTouchPointInView(x, y, child, outLocalPoint)) {
Christopher Tatea53146c2010-09-07 11:57:52 -07001536 return child;
1537 }
1538 }
1539 return null;
1540 }
1541
Christopher Tate86cab1b2011-01-13 20:28:55 -08001542 boolean notifyChildOfDrag(View child) {
1543 if (ViewDebug.DEBUG_DRAG) {
1544 Log.d(View.VIEW_LOG_TAG, "Sending drag-started to view: " + child);
1545 }
1546
Christopher Tate3d4bf172011-03-28 16:16:46 -07001547 boolean canAccept = false;
Christopher Tate86cab1b2011-01-13 20:28:55 -08001548 if (! mDragNotifiedChildren.contains(child)) {
1549 mDragNotifiedChildren.add(child);
Christopher Tate3d4bf172011-03-28 16:16:46 -07001550 canAccept = child.dispatchDragEvent(mCurrentDrag);
1551 if (canAccept && !child.canAcceptDrag()) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07001552 child.mPrivateFlags2 |= View.PFLAG2_DRAG_CAN_ACCEPT;
Christopher Tate3d4bf172011-03-28 16:16:46 -07001553 child.refreshDrawableState();
1554 }
Christopher Tate86cab1b2011-01-13 20:28:55 -08001555 }
Christopher Tate3d4bf172011-03-28 16:16:46 -07001556 return canAccept;
Christopher Tate86cab1b2011-01-13 20:28:55 -08001557 }
1558
Joe Onorato664644d2011-01-23 17:53:23 -08001559 @Override
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001560 public void dispatchWindowSystemUiVisiblityChanged(int visible) {
1561 super.dispatchWindowSystemUiVisiblityChanged(visible);
1562
1563 final int count = mChildrenCount;
1564 final View[] children = mChildren;
1565 for (int i=0; i <count; i++) {
1566 final View child = children[i];
1567 child.dispatchWindowSystemUiVisiblityChanged(visible);
1568 }
1569 }
1570
1571 @Override
Joe Onorato664644d2011-01-23 17:53:23 -08001572 public void dispatchSystemUiVisibilityChanged(int visible) {
1573 super.dispatchSystemUiVisibilityChanged(visible);
1574
1575 final int count = mChildrenCount;
1576 final View[] children = mChildren;
1577 for (int i=0; i <count; i++) {
1578 final View child = children[i];
1579 child.dispatchSystemUiVisibilityChanged(visible);
1580 }
1581 }
1582
Dianne Hackborn9a230e02011-10-06 11:51:27 -07001583 @Override
Dianne Hackborncf675782012-05-10 15:07:24 -07001584 boolean updateLocalSystemUiVisibility(int localValue, int localChanges) {
1585 boolean changed = super.updateLocalSystemUiVisibility(localValue, localChanges);
Dianne Hackborn9a230e02011-10-06 11:51:27 -07001586
1587 final int count = mChildrenCount;
1588 final View[] children = mChildren;
1589 for (int i=0; i <count; i++) {
1590 final View child = children[i];
Dianne Hackborncf675782012-05-10 15:07:24 -07001591 changed |= child.updateLocalSystemUiVisibility(localValue, localChanges);
Dianne Hackborn9a230e02011-10-06 11:51:27 -07001592 }
Dianne Hackborncf675782012-05-10 15:07:24 -07001593 return changed;
Dianne Hackborn9a230e02011-10-06 11:51:27 -07001594 }
1595
Christopher Tatea53146c2010-09-07 11:57:52 -07001596 /**
1597 * {@inheritDoc}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001598 */
1599 @Override
1600 public boolean dispatchKeyEventPreIme(KeyEvent event) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07001601 if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
1602 == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001603 return super.dispatchKeyEventPreIme(event);
Dianne Hackborn4702a852012-08-17 15:18:29 -07001604 } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
1605 == PFLAG_HAS_BOUNDS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001606 return mFocused.dispatchKeyEventPreIme(event);
1607 }
1608 return false;
1609 }
1610
1611 /**
1612 * {@inheritDoc}
1613 */
1614 @Override
1615 public boolean dispatchKeyEvent(KeyEvent event) {
Jeff Brown21bc5c92011-02-28 18:27:14 -08001616 if (mInputEventConsistencyVerifier != null) {
1617 mInputEventConsistencyVerifier.onKeyEvent(event, 1);
1618 }
1619
Dianne Hackborn4702a852012-08-17 15:18:29 -07001620 if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
1621 == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001622 if (super.dispatchKeyEvent(event)) {
1623 return true;
1624 }
Dianne Hackborn4702a852012-08-17 15:18:29 -07001625 } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
1626 == PFLAG_HAS_BOUNDS) {
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001627 if (mFocused.dispatchKeyEvent(event)) {
1628 return true;
1629 }
1630 }
1631
1632 if (mInputEventConsistencyVerifier != null) {
1633 mInputEventConsistencyVerifier.onUnhandledEvent(event, 1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001634 }
1635 return false;
1636 }
1637
1638 /**
1639 * {@inheritDoc}
1640 */
1641 @Override
1642 public boolean dispatchKeyShortcutEvent(KeyEvent event) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07001643 if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
1644 == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001645 return super.dispatchKeyShortcutEvent(event);
Dianne Hackborn4702a852012-08-17 15:18:29 -07001646 } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
1647 == PFLAG_HAS_BOUNDS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001648 return mFocused.dispatchKeyShortcutEvent(event);
1649 }
1650 return false;
1651 }
1652
1653 /**
1654 * {@inheritDoc}
1655 */
1656 @Override
1657 public boolean dispatchTrackballEvent(MotionEvent event) {
Jeff Brown21bc5c92011-02-28 18:27:14 -08001658 if (mInputEventConsistencyVerifier != null) {
1659 mInputEventConsistencyVerifier.onTrackballEvent(event, 1);
1660 }
1661
Dianne Hackborn4702a852012-08-17 15:18:29 -07001662 if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
1663 == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001664 if (super.dispatchTrackballEvent(event)) {
1665 return true;
1666 }
Dianne Hackborn4702a852012-08-17 15:18:29 -07001667 } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
1668 == PFLAG_HAS_BOUNDS) {
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001669 if (mFocused.dispatchTrackballEvent(event)) {
1670 return true;
1671 }
1672 }
1673
1674 if (mInputEventConsistencyVerifier != null) {
1675 mInputEventConsistencyVerifier.onUnhandledEvent(event, 1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001676 }
1677 return false;
1678 }
1679
Jeff Brown10b62902011-06-20 16:40:37 -07001680 /**
1681 * {@inheritDoc}
1682 */
Romain Guya9489272011-06-22 20:58:11 -07001683 @SuppressWarnings({"ConstantConditions"})
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001684 @Override
Jeff Browna032cc02011-03-07 16:56:21 -08001685 protected boolean dispatchHoverEvent(MotionEvent event) {
Jeff Browna032cc02011-03-07 16:56:21 -08001686 final int action = event.getAction();
Jeff Browna032cc02011-03-07 16:56:21 -08001687
Jeff Brown10b62902011-06-20 16:40:37 -07001688 // First check whether the view group wants to intercept the hover event.
1689 final boolean interceptHover = onInterceptHoverEvent(event);
1690 event.setAction(action); // restore action in case it was changed
1691
Jeff Brown87b7f802011-06-21 18:35:45 -07001692 MotionEvent eventNoHistory = event;
1693 boolean handled = false;
1694
1695 // Send events to the hovered children and build a new list of hover targets until
1696 // one is found that handles the event.
1697 HoverTarget firstOldHoverTarget = mFirstHoverTarget;
1698 mFirstHoverTarget = null;
Jeff Brown10b62902011-06-20 16:40:37 -07001699 if (!interceptHover && action != MotionEvent.ACTION_HOVER_EXIT) {
Jeff Browna032cc02011-03-07 16:56:21 -08001700 final float x = event.getX();
1701 final float y = event.getY();
Jeff Brown33bbfd22011-02-24 20:55:35 -08001702 final int childrenCount = mChildrenCount;
1703 if (childrenCount != 0) {
Chris Craikab008f02014-05-23 17:55:03 -07001704 final ArrayList<View> preorderedList = buildOrderedChildList();
1705 final boolean customOrder = preorderedList == null
1706 && isChildrenDrawingOrderEnabled();
Jeff Brown33bbfd22011-02-24 20:55:35 -08001707 final View[] children = mChildren;
Jeff Brown87b7f802011-06-21 18:35:45 -07001708 HoverTarget lastHoverTarget = null;
Jeff Brown33bbfd22011-02-24 20:55:35 -08001709 for (int i = childrenCount - 1; i >= 0; i--) {
Chris Craikab008f02014-05-23 17:55:03 -07001710 int childIndex = customOrder ? getChildDrawingOrder(childrenCount, i) : i;
1711 final View child = (preorderedList == null)
1712 ? children[childIndex] : preorderedList.get(childIndex);
Jeff Brown87b7f802011-06-21 18:35:45 -07001713 if (!canViewReceivePointerEvents(child)
1714 || !isTransformedTouchPointInView(x, y, child, null)) {
1715 continue;
1716 }
1717
1718 // Obtain a hover target for this child. Dequeue it from the
1719 // old hover target list if the child was previously hovered.
1720 HoverTarget hoverTarget = firstOldHoverTarget;
1721 final boolean wasHovered;
1722 for (HoverTarget predecessor = null; ;) {
1723 if (hoverTarget == null) {
1724 hoverTarget = HoverTarget.obtain(child);
1725 wasHovered = false;
1726 break;
1727 }
1728
1729 if (hoverTarget.child == child) {
1730 if (predecessor != null) {
1731 predecessor.next = hoverTarget.next;
1732 } else {
1733 firstOldHoverTarget = hoverTarget.next;
1734 }
1735 hoverTarget.next = null;
1736 wasHovered = true;
1737 break;
1738 }
1739
1740 predecessor = hoverTarget;
1741 hoverTarget = hoverTarget.next;
1742 }
1743
1744 // Enqueue the hover target onto the new hover target list.
1745 if (lastHoverTarget != null) {
1746 lastHoverTarget.next = hoverTarget;
1747 } else {
Jeff Brown87b7f802011-06-21 18:35:45 -07001748 mFirstHoverTarget = hoverTarget;
1749 }
Sangkyu Lee8725f362013-03-13 09:38:45 +09001750 lastHoverTarget = hoverTarget;
Jeff Brown87b7f802011-06-21 18:35:45 -07001751
1752 // Dispatch the event to the child.
1753 if (action == MotionEvent.ACTION_HOVER_ENTER) {
1754 if (!wasHovered) {
1755 // Send the enter as is.
1756 handled |= dispatchTransformedGenericPointerEvent(
1757 event, child); // enter
1758 }
1759 } else if (action == MotionEvent.ACTION_HOVER_MOVE) {
1760 if (!wasHovered) {
1761 // Synthesize an enter from a move.
1762 eventNoHistory = obtainMotionEventNoHistoryOrSelf(eventNoHistory);
1763 eventNoHistory.setAction(MotionEvent.ACTION_HOVER_ENTER);
1764 handled |= dispatchTransformedGenericPointerEvent(
1765 eventNoHistory, child); // enter
1766 eventNoHistory.setAction(action);
1767
1768 handled |= dispatchTransformedGenericPointerEvent(
1769 eventNoHistory, child); // move
1770 } else {
1771 // Send the move as is.
1772 handled |= dispatchTransformedGenericPointerEvent(event, child);
1773 }
1774 }
1775 if (handled) {
Jeff Brown10b62902011-06-20 16:40:37 -07001776 break;
Jeff Brown33bbfd22011-02-24 20:55:35 -08001777 }
Jeff Brown10b62902011-06-20 16:40:37 -07001778 }
Chris Craikab008f02014-05-23 17:55:03 -07001779 if (preorderedList != null) preorderedList.clear();
Jeff Brown10b62902011-06-20 16:40:37 -07001780 }
1781 }
Jeff Brown33bbfd22011-02-24 20:55:35 -08001782
Jeff Brown87b7f802011-06-21 18:35:45 -07001783 // Send exit events to all previously hovered children that are no longer hovered.
1784 while (firstOldHoverTarget != null) {
1785 final View child = firstOldHoverTarget.child;
Jeff Brown10b62902011-06-20 16:40:37 -07001786
Jeff Brown87b7f802011-06-21 18:35:45 -07001787 // Exit the old hovered child.
1788 if (action == MotionEvent.ACTION_HOVER_EXIT) {
1789 // Send the exit as is.
1790 handled |= dispatchTransformedGenericPointerEvent(
1791 event, child); // exit
1792 } else {
1793 // Synthesize an exit from a move or enter.
1794 // Ignore the result because hover focus has moved to a different view.
1795 if (action == MotionEvent.ACTION_HOVER_MOVE) {
Jeff Brown10b62902011-06-20 16:40:37 -07001796 dispatchTransformedGenericPointerEvent(
Jeff Brown87b7f802011-06-21 18:35:45 -07001797 event, child); // move
Jeff Brown10b62902011-06-20 16:40:37 -07001798 }
Jeff Brown87b7f802011-06-21 18:35:45 -07001799 eventNoHistory = obtainMotionEventNoHistoryOrSelf(eventNoHistory);
1800 eventNoHistory.setAction(MotionEvent.ACTION_HOVER_EXIT);
1801 dispatchTransformedGenericPointerEvent(
1802 eventNoHistory, child); // exit
1803 eventNoHistory.setAction(action);
Jeff Brown10b62902011-06-20 16:40:37 -07001804 }
1805
Jeff Brown87b7f802011-06-21 18:35:45 -07001806 final HoverTarget nextOldHoverTarget = firstOldHoverTarget.next;
1807 firstOldHoverTarget.recycle();
1808 firstOldHoverTarget = nextOldHoverTarget;
Jeff Brown10b62902011-06-20 16:40:37 -07001809 }
1810
Jeff Brown87b7f802011-06-21 18:35:45 -07001811 // Send events to the view group itself if no children have handled it.
Jeff Brown10b62902011-06-20 16:40:37 -07001812 boolean newHoveredSelf = !handled;
1813 if (newHoveredSelf == mHoveredSelf) {
1814 if (newHoveredSelf) {
1815 // Send event to the view group as before.
1816 handled |= super.dispatchHoverEvent(event);
1817 }
1818 } else {
1819 if (mHoveredSelf) {
1820 // Exit the view group.
1821 if (action == MotionEvent.ACTION_HOVER_EXIT) {
1822 // Send the exit as is.
1823 handled |= super.dispatchHoverEvent(event); // exit
1824 } else {
1825 // Synthesize an exit from a move or enter.
1826 // Ignore the result because hover focus is moving to a different view.
1827 if (action == MotionEvent.ACTION_HOVER_MOVE) {
1828 super.dispatchHoverEvent(event); // move
1829 }
1830 eventNoHistory = obtainMotionEventNoHistoryOrSelf(eventNoHistory);
1831 eventNoHistory.setAction(MotionEvent.ACTION_HOVER_EXIT);
1832 super.dispatchHoverEvent(eventNoHistory); // exit
1833 eventNoHistory.setAction(action);
1834 }
1835 mHoveredSelf = false;
1836 }
1837
1838 if (newHoveredSelf) {
1839 // Enter the view group.
1840 if (action == MotionEvent.ACTION_HOVER_ENTER) {
1841 // Send the enter as is.
1842 handled |= super.dispatchHoverEvent(event); // enter
1843 mHoveredSelf = true;
1844 } else if (action == MotionEvent.ACTION_HOVER_MOVE) {
1845 // Synthesize an enter from a move.
1846 eventNoHistory = obtainMotionEventNoHistoryOrSelf(eventNoHistory);
1847 eventNoHistory.setAction(MotionEvent.ACTION_HOVER_ENTER);
1848 handled |= super.dispatchHoverEvent(eventNoHistory); // enter
1849 eventNoHistory.setAction(action);
1850
1851 handled |= super.dispatchHoverEvent(eventNoHistory); // move
1852 mHoveredSelf = true;
Jeff Brown33bbfd22011-02-24 20:55:35 -08001853 }
1854 }
Jeff Brown33bbfd22011-02-24 20:55:35 -08001855 }
1856
Jeff Browna032cc02011-03-07 16:56:21 -08001857 // Recycle the copy of the event that we made.
1858 if (eventNoHistory != event) {
1859 eventNoHistory.recycle();
1860 }
1861
Jeff Browna032cc02011-03-07 16:56:21 -08001862 // Done.
1863 return handled;
1864 }
1865
Jeff Brown59a422e2012-04-19 15:19:19 -07001866 private void exitHoverTargets() {
1867 if (mHoveredSelf || mFirstHoverTarget != null) {
1868 final long now = SystemClock.uptimeMillis();
1869 MotionEvent event = MotionEvent.obtain(now, now,
1870 MotionEvent.ACTION_HOVER_EXIT, 0.0f, 0.0f, 0);
1871 event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
1872 dispatchHoverEvent(event);
1873 event.recycle();
1874 }
1875 }
1876
1877 private void cancelHoverTarget(View view) {
1878 HoverTarget predecessor = null;
1879 HoverTarget target = mFirstHoverTarget;
1880 while (target != null) {
1881 final HoverTarget next = target.next;
1882 if (target.child == view) {
1883 if (predecessor == null) {
1884 mFirstHoverTarget = next;
1885 } else {
1886 predecessor.next = next;
1887 }
1888 target.recycle();
1889
1890 final long now = SystemClock.uptimeMillis();
1891 MotionEvent event = MotionEvent.obtain(now, now,
1892 MotionEvent.ACTION_HOVER_EXIT, 0.0f, 0.0f, 0);
1893 event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
1894 view.dispatchHoverEvent(event);
1895 event.recycle();
1896 return;
1897 }
1898 predecessor = target;
1899 target = next;
1900 }
1901 }
1902
Jeff Brown87b7f802011-06-21 18:35:45 -07001903 /** @hide */
1904 @Override
1905 protected boolean hasHoveredChild() {
1906 return mFirstHoverTarget != null;
1907 }
1908
Svetoslav Ganov42138042012-03-20 11:51:39 -07001909 @Override
1910 public void addChildrenForAccessibility(ArrayList<View> childrenForAccessibility) {
Svetoslav Ganov76f287e2012-04-23 11:02:36 -07001911 ChildListForAccessibility children = ChildListForAccessibility.obtain(this, true);
1912 try {
1913 final int childrenCount = children.getChildCount();
1914 for (int i = 0; i < childrenCount; i++) {
1915 View child = children.getChildAt(i);
Svetoslav Ganovc406be92012-05-11 16:12:32 -07001916 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
Svetoslav Ganov76f287e2012-04-23 11:02:36 -07001917 if (child.includeForAccessibility()) {
1918 childrenForAccessibility.add(child);
1919 } else {
1920 child.addChildrenForAccessibility(childrenForAccessibility);
1921 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07001922 }
1923 }
Svetoslav Ganov76f287e2012-04-23 11:02:36 -07001924 } finally {
1925 children.recycle();
Svetoslav Ganov42138042012-03-20 11:51:39 -07001926 }
1927 }
1928
1929 /**
Jeff Brown10b62902011-06-20 16:40:37 -07001930 * Implement this method to intercept hover events before they are handled
1931 * by child views.
1932 * <p>
1933 * This method is called before dispatching a hover event to a child of
1934 * the view group or to the view group's own {@link #onHoverEvent} to allow
1935 * the view group a chance to intercept the hover event.
1936 * This method can also be used to watch all pointer motions that occur within
1937 * the bounds of the view group even when the pointer is hovering over
1938 * a child of the view group rather than over the view group itself.
1939 * </p><p>
1940 * The view group can prevent its children from receiving hover events by
1941 * implementing this method and returning <code>true</code> to indicate
1942 * that it would like to intercept hover events. The view group must
1943 * continuously return <code>true</code> from {@link #onInterceptHoverEvent}
1944 * for as long as it wishes to continue intercepting hover events from
1945 * its children.
1946 * </p><p>
1947 * Interception preserves the invariant that at most one view can be
1948 * hovered at a time by transferring hover focus from the currently hovered
1949 * child to the view group or vice-versa as needed.
1950 * </p><p>
1951 * If this method returns <code>true</code> and a child is already hovered, then the
1952 * child view will first receive a hover exit event and then the view group
1953 * itself will receive a hover enter event in {@link #onHoverEvent}.
1954 * Likewise, if this method had previously returned <code>true</code> to intercept hover
1955 * events and instead returns <code>false</code> while the pointer is hovering
1956 * within the bounds of one of a child, then the view group will first receive a
1957 * hover exit event in {@link #onHoverEvent} and then the hovered child will
1958 * receive a hover enter event.
1959 * </p><p>
1960 * The default implementation always returns false.
1961 * </p>
1962 *
1963 * @param event The motion event that describes the hover.
1964 * @return True if the view group would like to intercept the hover event
1965 * and prevent its children from receiving it.
1966 */
1967 public boolean onInterceptHoverEvent(MotionEvent event) {
Svetoslav Ganov736c2752011-04-22 18:30:36 -07001968 return false;
1969 }
1970
Jeff Browna032cc02011-03-07 16:56:21 -08001971 private static MotionEvent obtainMotionEventNoHistoryOrSelf(MotionEvent event) {
1972 if (event.getHistorySize() == 0) {
1973 return event;
1974 }
1975 return MotionEvent.obtainNoHistory(event);
1976 }
1977
Jeff Brown10b62902011-06-20 16:40:37 -07001978 /**
1979 * {@inheritDoc}
1980 */
Jeff Browna032cc02011-03-07 16:56:21 -08001981 @Override
1982 protected boolean dispatchGenericPointerEvent(MotionEvent event) {
1983 // Send the event to the child under the pointer.
1984 final int childrenCount = mChildrenCount;
1985 if (childrenCount != 0) {
Jeff Browna032cc02011-03-07 16:56:21 -08001986 final float x = event.getX();
1987 final float y = event.getY();
1988
Chris Craikab008f02014-05-23 17:55:03 -07001989 final ArrayList<View> preorderedList = buildOrderedChildList();
1990 final boolean customOrder = preorderedList == null
1991 && isChildrenDrawingOrderEnabled();
1992 final View[] children = mChildren;
Jeff Browna032cc02011-03-07 16:56:21 -08001993 for (int i = childrenCount - 1; i >= 0; i--) {
Chris Craikab008f02014-05-23 17:55:03 -07001994 int childIndex = customOrder ? getChildDrawingOrder(childrenCount, i) : i;
1995 final View child = (preorderedList == null)
1996 ? children[childIndex] : preorderedList.get(childIndex);
Jeff Browna032cc02011-03-07 16:56:21 -08001997 if (!canViewReceivePointerEvents(child)
1998 || !isTransformedTouchPointInView(x, y, child, null)) {
1999 continue;
2000 }
2001
2002 if (dispatchTransformedGenericPointerEvent(event, child)) {
Chris Craikab008f02014-05-23 17:55:03 -07002003 if (preorderedList != null) preorderedList.clear();
Jeff Browna032cc02011-03-07 16:56:21 -08002004 return true;
2005 }
2006 }
Chris Craikab008f02014-05-23 17:55:03 -07002007 if (preorderedList != null) preorderedList.clear();
Jeff Browna032cc02011-03-07 16:56:21 -08002008 }
2009
2010 // No child handled the event. Send it to this view group.
2011 return super.dispatchGenericPointerEvent(event);
2012 }
2013
Jeff Brown10b62902011-06-20 16:40:37 -07002014 /**
2015 * {@inheritDoc}
2016 */
Jeff Browna032cc02011-03-07 16:56:21 -08002017 @Override
2018 protected boolean dispatchGenericFocusedEvent(MotionEvent event) {
Jeff Brown33bbfd22011-02-24 20:55:35 -08002019 // Send the event to the focused child or to this view group if it has focus.
Dianne Hackborn4702a852012-08-17 15:18:29 -07002020 if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
2021 == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
Jeff Browna032cc02011-03-07 16:56:21 -08002022 return super.dispatchGenericFocusedEvent(event);
Dianne Hackborn4702a852012-08-17 15:18:29 -07002023 } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
2024 == PFLAG_HAS_BOUNDS) {
Jeff Browncb1404e2011-01-15 18:14:15 -08002025 return mFocused.dispatchGenericMotionEvent(event);
2026 }
2027 return false;
2028 }
2029
2030 /**
Jeff Browna032cc02011-03-07 16:56:21 -08002031 * Dispatches a generic pointer event to a child, taking into account
2032 * transformations that apply to the child.
2033 *
2034 * @param event The event to send.
2035 * @param child The view to send the event to.
2036 * @return {@code true} if the child handled the event.
2037 */
2038 private boolean dispatchTransformedGenericPointerEvent(MotionEvent event, View child) {
2039 final float offsetX = mScrollX - child.mLeft;
2040 final float offsetY = mScrollY - child.mTop;
2041
2042 boolean handled;
2043 if (!child.hasIdentityMatrix()) {
2044 MotionEvent transformedEvent = MotionEvent.obtain(event);
2045 transformedEvent.offsetLocation(offsetX, offsetY);
2046 transformedEvent.transform(child.getInverseMatrix());
2047 handled = child.dispatchGenericMotionEvent(transformedEvent);
2048 transformedEvent.recycle();
2049 } else {
2050 event.offsetLocation(offsetX, offsetY);
2051 handled = child.dispatchGenericMotionEvent(event);
2052 event.offsetLocation(-offsetX, -offsetY);
2053 }
2054 return handled;
2055 }
2056
2057 /**
Jeff Browncb1404e2011-01-15 18:14:15 -08002058 * {@inheritDoc}
2059 */
2060 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002061 public boolean dispatchTouchEvent(MotionEvent ev) {
Jeff Brown21bc5c92011-02-28 18:27:14 -08002062 if (mInputEventConsistencyVerifier != null) {
2063 mInputEventConsistencyVerifier.onTouchEvent(ev, 1);
2064 }
2065
Svet Ganov0a2ccee2015-02-06 10:12:32 -08002066 // If the event targets the accessibility focused view and this is it, start
2067 // normal event dispatch. Maybe a descendant is what will handle the click.
Svet Ganovf33fe1f2015-02-06 19:23:31 -08002068 if (ev.isTargetAccessibilityFocus() && isAccessibilityFocusedViewOrHost()) {
Svet Ganov0a2ccee2015-02-06 10:12:32 -08002069 ev.setTargetAccessibilityFocus(false);
2070 }
2071
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002072 boolean handled = false;
2073 if (onFilterTouchEventForSecurity(ev)) {
2074 final int action = ev.getAction();
2075 final int actionMasked = action & MotionEvent.ACTION_MASK;
Jeff Brown85a31762010-09-01 17:01:00 -07002076
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002077 // Handle an initial down.
2078 if (actionMasked == MotionEvent.ACTION_DOWN) {
2079 // Throw away all previous state when starting a new touch gesture.
2080 // The framework may have dropped the up or cancel event for the previous gesture
2081 // due to an app switch, ANR, or some other state change.
2082 cancelAndClearTouchTargets(ev);
2083 resetTouchState();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002084 }
Adam Powellb08013c2010-09-16 16:28:11 -07002085
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002086 // Check for interception.
2087 final boolean intercepted;
Svet Ganovf33fe1f2015-02-06 19:23:31 -08002088 if (actionMasked == MotionEvent.ACTION_DOWN
2089 || mFirstTouchTarget != null) {
2090 final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
2091 if (!disallowIntercept) {
2092 intercepted = onInterceptTouchEvent(ev);
2093 ev.setAction(action); // restore action in case it was changed
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002094 } else {
Svet Ganovf33fe1f2015-02-06 19:23:31 -08002095 intercepted = false;
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002096 }
2097 } else {
Svet Ganovf33fe1f2015-02-06 19:23:31 -08002098 // There are no touch targets and this action is not an initial down
2099 // so this view group continues to intercept touches.
2100 intercepted = true;
2101 }
2102
2103 // If intercepted, start normal event dispatch. Also if there is already
2104 // a view that is handling the gesture, do normal event dispatch.
2105 if (intercepted || mFirstTouchTarget != null) {
2106 ev.setTargetAccessibilityFocus(false);
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002107 }
Jeff Brown20e987b2010-08-23 12:01:02 -07002108
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002109 // Check for cancelation.
2110 final boolean canceled = resetCancelNextUpFlag(this)
2111 || actionMasked == MotionEvent.ACTION_CANCEL;
Jeff Brown20e987b2010-08-23 12:01:02 -07002112
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002113 // Update list of touch targets for pointer down, if needed.
2114 final boolean split = (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) != 0;
2115 TouchTarget newTouchTarget = null;
2116 boolean alreadyDispatchedToNewTouchTarget = false;
2117 if (!canceled && !intercepted) {
Svetoslavc73cfa02015-02-09 17:14:28 -08002118
2119 // If the event is targeting accessiiblity focus we give it to the
2120 // view that has accessibility focus and if it does not handle it
2121 // we clear the flag and dispatch the event to all children as usual.
2122 // We are looking up the accessibility focused host to avoid keeping
2123 // state since these events are very rare.
2124 View childWithAccessibilityFocus = ev.isTargetAccessibilityFocus()
2125 ? findChildWithAccessibilityFocus() : null;
2126
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002127 if (actionMasked == MotionEvent.ACTION_DOWN
2128 || (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN)
Svet Ganovf33fe1f2015-02-06 19:23:31 -08002129 || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002130 final int actionIndex = ev.getActionIndex(); // always 0 for down
2131 final int idBitsToAssign = split ? 1 << ev.getPointerId(actionIndex)
2132 : TouchTarget.ALL_POINTER_IDS;
Jeff Brown20e987b2010-08-23 12:01:02 -07002133
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002134 // Clean up earlier touch targets for this pointer id in case they
2135 // have become out of sync.
2136 removePointersFromTouchTargets(idBitsToAssign);
2137
2138 final int childrenCount = mChildrenCount;
Chet Haase9c17fe62013-03-22 17:05:55 -07002139 if (newTouchTarget == null && childrenCount != 0) {
Chet Haaseedf6f4b2013-03-26 07:55:30 -07002140 final float x = ev.getX(actionIndex);
2141 final float y = ev.getY(actionIndex);
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002142 // Find a child that can receive the event.
2143 // Scan children from front to back.
Chris Craikab008f02014-05-23 17:55:03 -07002144 final ArrayList<View> preorderedList = buildOrderedChildList();
2145 final boolean customOrder = preorderedList == null
2146 && isChildrenDrawingOrderEnabled();
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002147 final View[] children = mChildren;
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002148 for (int i = childrenCount - 1; i >= 0; i--) {
Chris Craikab008f02014-05-23 17:55:03 -07002149 final int childIndex = customOrder
2150 ? getChildDrawingOrder(childrenCount, i) : i;
2151 final View child = (preorderedList == null)
2152 ? children[childIndex] : preorderedList.get(childIndex);
Svetoslavc73cfa02015-02-09 17:14:28 -08002153
2154 // If there is a view that has accessibility focus we want it
2155 // to get the event first and if not handled we will perform a
2156 // normal dispatch. We may do a double iteration but this is
2157 // safer given the timeframe.
2158 if (childWithAccessibilityFocus != null) {
2159 if (childWithAccessibilityFocus != child) {
2160 continue;
2161 }
2162 childWithAccessibilityFocus = null;
2163 i = childrenCount - 1;
2164 }
2165
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002166 if (!canViewReceivePointerEvents(child)
2167 || !isTransformedTouchPointInView(x, y, child, null)) {
Svetoslavc73cfa02015-02-09 17:14:28 -08002168 ev.setTargetAccessibilityFocus(false);
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002169 continue;
2170 }
2171
2172 newTouchTarget = getTouchTarget(child);
2173 if (newTouchTarget != null) {
2174 // Child is already receiving touch within its bounds.
2175 // Give it the new pointer in addition to the ones it is handling.
2176 newTouchTarget.pointerIdBits |= idBitsToAssign;
2177 break;
2178 }
2179
2180 resetCancelNextUpFlag(child);
2181 if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
2182 // Child wants to receive touch within its bounds.
2183 mLastTouchDownTime = ev.getDownTime();
Chris Craikab008f02014-05-23 17:55:03 -07002184 if (preorderedList != null) {
2185 // childIndex points into presorted list, find original index
2186 for (int j = 0; j < childrenCount; j++) {
2187 if (children[childIndex] == mChildren[j]) {
2188 mLastTouchDownIndex = j;
2189 break;
2190 }
2191 }
2192 } else {
2193 mLastTouchDownIndex = childIndex;
2194 }
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002195 mLastTouchDownX = ev.getX();
2196 mLastTouchDownY = ev.getY();
2197 newTouchTarget = addTouchTarget(child, idBitsToAssign);
2198 alreadyDispatchedToNewTouchTarget = true;
2199 break;
2200 }
Svetoslavc73cfa02015-02-09 17:14:28 -08002201
2202 // The accessibility focus didn't handle the event, so clear
2203 // the flag and do a normal dispatch to all children.
2204 ev.setTargetAccessibilityFocus(false);
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002205 }
Chris Craikab008f02014-05-23 17:55:03 -07002206 if (preorderedList != null) preorderedList.clear();
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002207 }
2208
2209 if (newTouchTarget == null && mFirstTouchTarget != null) {
2210 // Did not find a child to receive the event.
2211 // Assign the pointer to the least recently added target.
2212 newTouchTarget = mFirstTouchTarget;
2213 while (newTouchTarget.next != null) {
2214 newTouchTarget = newTouchTarget.next;
2215 }
2216 newTouchTarget.pointerIdBits |= idBitsToAssign;
2217 }
2218 }
2219 }
2220
2221 // Dispatch to touch targets.
2222 if (mFirstTouchTarget == null) {
2223 // No touch targets so treat this as an ordinary view.
2224 handled = dispatchTransformedTouchEvent(ev, canceled, null,
2225 TouchTarget.ALL_POINTER_IDS);
2226 } else {
2227 // Dispatch to touch targets, excluding the new touch target if we already
2228 // dispatched to it. Cancel touch targets if necessary.
2229 TouchTarget predecessor = null;
2230 TouchTarget target = mFirstTouchTarget;
2231 while (target != null) {
2232 final TouchTarget next = target.next;
2233 if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) {
2234 handled = true;
2235 } else {
2236 final boolean cancelChild = resetCancelNextUpFlag(target.child)
Chet Haase9c17fe62013-03-22 17:05:55 -07002237 || intercepted;
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002238 if (dispatchTransformedTouchEvent(ev, cancelChild,
2239 target.child, target.pointerIdBits)) {
2240 handled = true;
2241 }
2242 if (cancelChild) {
2243 if (predecessor == null) {
2244 mFirstTouchTarget = next;
2245 } else {
2246 predecessor.next = next;
2247 }
2248 target.recycle();
2249 target = next;
Jeff Brown20e987b2010-08-23 12:01:02 -07002250 continue;
2251 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002252 }
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002253 predecessor = target;
2254 target = next;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002255 }
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002256 }
Jeff Brown20e987b2010-08-23 12:01:02 -07002257
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002258 // Update list of touch targets for pointer up or cancel, if needed.
2259 if (canceled
2260 || actionMasked == MotionEvent.ACTION_UP
2261 || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
2262 resetTouchState();
2263 } else if (split && actionMasked == MotionEvent.ACTION_POINTER_UP) {
2264 final int actionIndex = ev.getActionIndex();
2265 final int idBitsToRemove = 1 << ev.getPointerId(actionIndex);
2266 removePointersFromTouchTargets(idBitsToRemove);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002267 }
2268 }
Romain Guy8506ab42009-06-11 17:35:47 -07002269
Jeff Brownbbdc50b2011-04-19 23:46:52 -07002270 if (!handled && mInputEventConsistencyVerifier != null) {
2271 mInputEventConsistencyVerifier.onUnhandledEvent(ev, 1);
Jeff Brown20e987b2010-08-23 12:01:02 -07002272 }
Jeff Brown20e987b2010-08-23 12:01:02 -07002273 return handled;
2274 }
2275
Romain Guy469b1db2010-10-05 11:49:57 -07002276 /**
Svetoslavc73cfa02015-02-09 17:14:28 -08002277 * Finds the child which has accessibility focus.
2278 *
2279 * @return The child that has focus.
2280 */
2281 private View findChildWithAccessibilityFocus() {
2282 ViewRootImpl viewRoot = getViewRootImpl();
2283 if (viewRoot == null) {
2284 return null;
2285 }
2286
2287 View current = viewRoot.getAccessibilityFocusedHost();
2288 if (current == null) {
2289 return null;
2290 }
2291
2292 ViewParent parent = current.getParent();
2293 while (parent instanceof View) {
2294 if (parent == this) {
2295 return current;
2296 }
2297 current = (View) parent;
2298 parent = current.getParent();
2299 }
2300
2301 return null;
2302 }
2303
2304 /**
Romain Guy469b1db2010-10-05 11:49:57 -07002305 * Resets all touch state in preparation for a new cycle.
2306 */
2307 private void resetTouchState() {
Jeff Brown20e987b2010-08-23 12:01:02 -07002308 clearTouchTargets();
2309 resetCancelNextUpFlag(this);
2310 mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
Adam Powell10ba2772014-04-15 09:46:51 -07002311 mNestedScrollAxes = SCROLL_AXIS_NONE;
Jeff Brown20e987b2010-08-23 12:01:02 -07002312 }
2313
Romain Guy469b1db2010-10-05 11:49:57 -07002314 /**
2315 * Resets the cancel next up flag.
2316 * Returns true if the flag was previously set.
2317 */
Romain Guya998dff2012-03-23 18:58:36 -07002318 private static boolean resetCancelNextUpFlag(View view) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07002319 if ((view.mPrivateFlags & PFLAG_CANCEL_NEXT_UP_EVENT) != 0) {
2320 view.mPrivateFlags &= ~PFLAG_CANCEL_NEXT_UP_EVENT;
Jeff Brown20e987b2010-08-23 12:01:02 -07002321 return true;
Adam Cohen9b073942010-08-19 16:49:52 -07002322 }
2323 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002324 }
2325
Romain Guy469b1db2010-10-05 11:49:57 -07002326 /**
2327 * Clears all touch targets.
2328 */
2329 private void clearTouchTargets() {
Jeff Brown20e987b2010-08-23 12:01:02 -07002330 TouchTarget target = mFirstTouchTarget;
2331 if (target != null) {
2332 do {
2333 TouchTarget next = target.next;
2334 target.recycle();
2335 target = next;
2336 } while (target != null);
2337 mFirstTouchTarget = null;
2338 }
2339 }
2340
Romain Guy469b1db2010-10-05 11:49:57 -07002341 /**
2342 * Cancels and clears all touch targets.
2343 */
2344 private void cancelAndClearTouchTargets(MotionEvent event) {
Jeff Brown20e987b2010-08-23 12:01:02 -07002345 if (mFirstTouchTarget != null) {
2346 boolean syntheticEvent = false;
2347 if (event == null) {
2348 final long now = SystemClock.uptimeMillis();
2349 event = MotionEvent.obtain(now, now,
2350 MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
Jeff Brown2fdbc5a2011-06-30 12:25:54 -07002351 event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
Jeff Brown20e987b2010-08-23 12:01:02 -07002352 syntheticEvent = true;
2353 }
2354
2355 for (TouchTarget target = mFirstTouchTarget; target != null; target = target.next) {
2356 resetCancelNextUpFlag(target.child);
2357 dispatchTransformedTouchEvent(event, true, target.child, target.pointerIdBits);
2358 }
2359 clearTouchTargets();
2360
2361 if (syntheticEvent) {
2362 event.recycle();
2363 }
2364 }
2365 }
2366
Romain Guy469b1db2010-10-05 11:49:57 -07002367 /**
2368 * Gets the touch target for specified child view.
2369 * Returns null if not found.
2370 */
2371 private TouchTarget getTouchTarget(View child) {
Jeff Brown20e987b2010-08-23 12:01:02 -07002372 for (TouchTarget target = mFirstTouchTarget; target != null; target = target.next) {
2373 if (target.child == child) {
2374 return target;
2375 }
2376 }
2377 return null;
2378 }
2379
Romain Guy469b1db2010-10-05 11:49:57 -07002380 /**
2381 * Adds a touch target for specified child to the beginning of the list.
2382 * Assumes the target child is not already present.
2383 */
2384 private TouchTarget addTouchTarget(View child, int pointerIdBits) {
Jeff Brown20e987b2010-08-23 12:01:02 -07002385 TouchTarget target = TouchTarget.obtain(child, pointerIdBits);
2386 target.next = mFirstTouchTarget;
2387 mFirstTouchTarget = target;
2388 return target;
2389 }
2390
Romain Guy469b1db2010-10-05 11:49:57 -07002391 /**
2392 * Removes the pointer ids from consideration.
2393 */
2394 private void removePointersFromTouchTargets(int pointerIdBits) {
Jeff Brown20e987b2010-08-23 12:01:02 -07002395 TouchTarget predecessor = null;
2396 TouchTarget target = mFirstTouchTarget;
2397 while (target != null) {
2398 final TouchTarget next = target.next;
2399 if ((target.pointerIdBits & pointerIdBits) != 0) {
2400 target.pointerIdBits &= ~pointerIdBits;
2401 if (target.pointerIdBits == 0) {
2402 if (predecessor == null) {
2403 mFirstTouchTarget = next;
2404 } else {
2405 predecessor.next = next;
2406 }
2407 target.recycle();
2408 target = next;
2409 continue;
2410 }
2411 }
2412 predecessor = target;
2413 target = next;
2414 }
2415 }
2416
Jeff Brown59a422e2012-04-19 15:19:19 -07002417 private void cancelTouchTarget(View view) {
2418 TouchTarget predecessor = null;
2419 TouchTarget target = mFirstTouchTarget;
2420 while (target != null) {
2421 final TouchTarget next = target.next;
2422 if (target.child == view) {
2423 if (predecessor == null) {
2424 mFirstTouchTarget = next;
2425 } else {
2426 predecessor.next = next;
2427 }
2428 target.recycle();
2429
2430 final long now = SystemClock.uptimeMillis();
2431 MotionEvent event = MotionEvent.obtain(now, now,
2432 MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
2433 event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
2434 view.dispatchTouchEvent(event);
2435 event.recycle();
2436 return;
2437 }
2438 predecessor = target;
2439 target = next;
2440 }
2441 }
2442
Romain Guy469b1db2010-10-05 11:49:57 -07002443 /**
Jeff Browna032cc02011-03-07 16:56:21 -08002444 * Returns true if a child view can receive pointer events.
2445 * @hide
2446 */
2447 private static boolean canViewReceivePointerEvents(View child) {
2448 return (child.mViewFlags & VISIBILITY_MASK) == VISIBLE
2449 || child.getAnimation() != null;
2450 }
2451
Alan Viveretteb942b6f2014-12-08 10:37:39 -08002452 private float[] getTempPoint() {
2453 if (mTempPoint == null) {
2454 mTempPoint = new float[2];
2455 }
2456 return mTempPoint;
2457 }
2458
Jeff Browna032cc02011-03-07 16:56:21 -08002459 /**
Romain Guy469b1db2010-10-05 11:49:57 -07002460 * Returns true if a child view contains the specified point when transformed
Jeff Brown20e987b2010-08-23 12:01:02 -07002461 * into its coordinate space.
Romain Guy469b1db2010-10-05 11:49:57 -07002462 * Child must not be null.
Adam Cohena32edd42010-10-26 10:35:01 -07002463 * @hide
Romain Guy469b1db2010-10-05 11:49:57 -07002464 */
Adam Cohena32edd42010-10-26 10:35:01 -07002465 protected boolean isTransformedTouchPointInView(float x, float y, View child,
Christopher Tate2c095f32010-10-04 14:13:40 -07002466 PointF outLocalPoint) {
Alan Viveretteb942b6f2014-12-08 10:37:39 -08002467 final float[] point = getTempPoint();
2468 point[0] = x;
2469 point[1] = y;
2470 transformPointToViewLocal(point, child);
2471 final boolean isInView = child.pointInView(point[0], point[1]);
Christopher Tate2c095f32010-10-04 14:13:40 -07002472 if (isInView && outLocalPoint != null) {
Alan Viveretteb942b6f2014-12-08 10:37:39 -08002473 outLocalPoint.set(point[0], point[1]);
Christopher Tate2c095f32010-10-04 14:13:40 -07002474 }
2475 return isInView;
Adam Powell2b342f02010-08-18 18:14:13 -07002476 }
2477
Romain Guy469b1db2010-10-05 11:49:57 -07002478 /**
Alan Viveretteb942b6f2014-12-08 10:37:39 -08002479 * @hide
2480 */
2481 public void transformPointToViewLocal(float[] point, View child) {
2482 point[0] += mScrollX - child.mLeft;
2483 point[1] += mScrollY - child.mTop;
2484
2485 if (!child.hasIdentityMatrix()) {
2486 child.getInverseMatrix().mapPoints(point);
2487 }
2488 }
2489
2490 /**
Romain Guy469b1db2010-10-05 11:49:57 -07002491 * Transforms a motion event into the coordinate space of a particular child view,
Jeff Brown20e987b2010-08-23 12:01:02 -07002492 * filters out irrelevant pointer ids, and overrides its action if necessary.
Romain Guy469b1db2010-10-05 11:49:57 -07002493 * If child is null, assumes the MotionEvent will be sent to this ViewGroup instead.
2494 */
2495 private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,
Jeff Brown20e987b2010-08-23 12:01:02 -07002496 View child, int desiredPointerIdBits) {
2497 final boolean handled;
Adam Powell2b342f02010-08-18 18:14:13 -07002498
Jeff Brown20e987b2010-08-23 12:01:02 -07002499 // Canceling motions is a special case. We don't need to perform any transformations
2500 // or filtering. The important part is the action, not the contents.
2501 final int oldAction = event.getAction();
2502 if (cancel || oldAction == MotionEvent.ACTION_CANCEL) {
2503 event.setAction(MotionEvent.ACTION_CANCEL);
2504 if (child == null) {
2505 handled = super.dispatchTouchEvent(event);
2506 } else {
2507 handled = child.dispatchTouchEvent(event);
2508 }
2509 event.setAction(oldAction);
2510 return handled;
2511 }
Adam Powell2b342f02010-08-18 18:14:13 -07002512
Jeff Brown20e987b2010-08-23 12:01:02 -07002513 // Calculate the number of pointers to deliver.
Jeff Brownfe9f8ab2011-05-06 18:20:01 -07002514 final int oldPointerIdBits = event.getPointerIdBits();
2515 final int newPointerIdBits = oldPointerIdBits & desiredPointerIdBits;
Adam Powell2b342f02010-08-18 18:14:13 -07002516
Jeff Brown20e987b2010-08-23 12:01:02 -07002517 // If for some reason we ended up in an inconsistent state where it looks like we
2518 // might produce a motion event with no pointers in it, then drop the event.
Jeff Brownfe9f8ab2011-05-06 18:20:01 -07002519 if (newPointerIdBits == 0) {
Jeff Brown20e987b2010-08-23 12:01:02 -07002520 return false;
2521 }
Adam Powell2b342f02010-08-18 18:14:13 -07002522
Jeff Brown20e987b2010-08-23 12:01:02 -07002523 // If the number of pointers is the same and we don't need to perform any fancy
2524 // irreversible transformations, then we can reuse the motion event for this
2525 // dispatch as long as we are careful to revert any changes we make.
Jeff Brownfe9f8ab2011-05-06 18:20:01 -07002526 // Otherwise we need to make a copy.
2527 final MotionEvent transformedEvent;
2528 if (newPointerIdBits == oldPointerIdBits) {
2529 if (child == null || child.hasIdentityMatrix()) {
2530 if (child == null) {
2531 handled = super.dispatchTouchEvent(event);
2532 } else {
2533 final float offsetX = mScrollX - child.mLeft;
2534 final float offsetY = mScrollY - child.mTop;
2535 event.offsetLocation(offsetX, offsetY);
Adam Powell2b342f02010-08-18 18:14:13 -07002536
Jeff Brownfe9f8ab2011-05-06 18:20:01 -07002537 handled = child.dispatchTouchEvent(event);
Jeff Brown20e987b2010-08-23 12:01:02 -07002538
Jeff Brownfe9f8ab2011-05-06 18:20:01 -07002539 event.offsetLocation(-offsetX, -offsetY);
2540 }
2541 return handled;
Jeff Brown20e987b2010-08-23 12:01:02 -07002542 }
Jeff Brown20e987b2010-08-23 12:01:02 -07002543 transformedEvent = MotionEvent.obtain(event);
2544 } else {
Jeff Brownfe9f8ab2011-05-06 18:20:01 -07002545 transformedEvent = event.split(newPointerIdBits);
Adam Powell2b342f02010-08-18 18:14:13 -07002546 }
2547
Jeff Brown20e987b2010-08-23 12:01:02 -07002548 // Perform any necessary transformations and dispatch.
2549 if (child == null) {
2550 handled = super.dispatchTouchEvent(transformedEvent);
2551 } else {
2552 final float offsetX = mScrollX - child.mLeft;
2553 final float offsetY = mScrollY - child.mTop;
2554 transformedEvent.offsetLocation(offsetX, offsetY);
2555 if (! child.hasIdentityMatrix()) {
2556 transformedEvent.transform(child.getInverseMatrix());
Adam Powell2b342f02010-08-18 18:14:13 -07002557 }
2558
Jeff Brown20e987b2010-08-23 12:01:02 -07002559 handled = child.dispatchTouchEvent(transformedEvent);
Adam Powell2b342f02010-08-18 18:14:13 -07002560 }
2561
Jeff Brown20e987b2010-08-23 12:01:02 -07002562 // Done.
2563 transformedEvent.recycle();
Adam Powell2b342f02010-08-18 18:14:13 -07002564 return handled;
2565 }
2566
Romain Guy469b1db2010-10-05 11:49:57 -07002567 /**
Adam Powell2b342f02010-08-18 18:14:13 -07002568 * Enable or disable the splitting of MotionEvents to multiple children during touch event
Jeff Brown995e7742010-12-22 16:59:36 -08002569 * dispatch. This behavior is enabled by default for applications that target an
2570 * SDK version of {@link Build.VERSION_CODES#HONEYCOMB} or newer.
Adam Powell2b342f02010-08-18 18:14:13 -07002571 *
2572 * <p>When this option is enabled MotionEvents may be split and dispatched to different child
2573 * views depending on where each pointer initially went down. This allows for user interactions
2574 * such as scrolling two panes of content independently, chording of buttons, and performing
2575 * independent gestures on different pieces of content.
2576 *
2577 * @param split <code>true</code> to allow MotionEvents to be split and dispatched to multiple
2578 * child views. <code>false</code> to only allow one child view to be the target of
2579 * any MotionEvent received by this ViewGroup.
Scott Main27a85082013-06-10 10:39:48 -07002580 * @attr ref android.R.styleable#ViewGroup_splitMotionEvents
Adam Powell2b342f02010-08-18 18:14:13 -07002581 */
2582 public void setMotionEventSplittingEnabled(boolean split) {
2583 // TODO Applications really shouldn't change this setting mid-touch event,
2584 // but perhaps this should handle that case and send ACTION_CANCELs to any child views
2585 // with gestures in progress when this is changed.
2586 if (split) {
Adam Powell2b342f02010-08-18 18:14:13 -07002587 mGroupFlags |= FLAG_SPLIT_MOTION_EVENTS;
2588 } else {
2589 mGroupFlags &= ~FLAG_SPLIT_MOTION_EVENTS;
Adam Powell2b342f02010-08-18 18:14:13 -07002590 }
2591 }
2592
2593 /**
Jeff Brown995e7742010-12-22 16:59:36 -08002594 * Returns true if MotionEvents dispatched to this ViewGroup can be split to multiple children.
Adam Powell2b342f02010-08-18 18:14:13 -07002595 * @return true if MotionEvents dispatched to this ViewGroup can be split to multiple children.
2596 */
2597 public boolean isMotionEventSplittingEnabled() {
2598 return (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) == FLAG_SPLIT_MOTION_EVENTS;
2599 }
2600
2601 /**
George Mount0a778ed2013-12-13 13:35:36 -08002602 * Returns true if this ViewGroup should be considered as a single entity for removal
2603 * when executing an Activity transition. If this is false, child elements will move
2604 * individually during the transition.
George Mount427c6412014-11-05 16:45:36 -08002605 *
George Mount0a778ed2013-12-13 13:35:36 -08002606 * @return True if the ViewGroup should be acted on together during an Activity transition.
George Mount427c6412014-11-05 16:45:36 -08002607 * The default value is true when there is a non-null background or if
2608 * {@link #getTransitionName()} is not null or if a
2609 * non-null {@link android.view.ViewOutlineProvider} other than
2610 * {@link android.view.ViewOutlineProvider#BACKGROUND} was given to
2611 * {@link #setOutlineProvider(ViewOutlineProvider)} and false otherwise.
George Mount0a778ed2013-12-13 13:35:36 -08002612 */
2613 public boolean isTransitionGroup() {
2614 if ((mGroupFlags & FLAG_IS_TRANSITION_GROUP_SET) != 0) {
2615 return ((mGroupFlags & FLAG_IS_TRANSITION_GROUP) != 0);
2616 } else {
George Mount427c6412014-11-05 16:45:36 -08002617 final ViewOutlineProvider outlineProvider = getOutlineProvider();
2618 return getBackground() != null || getTransitionName() != null ||
2619 (outlineProvider != null && outlineProvider != ViewOutlineProvider.BACKGROUND);
George Mount0a778ed2013-12-13 13:35:36 -08002620 }
2621 }
2622
2623 /**
2624 * Changes whether or not this ViewGroup should be treated as a single entity during
George Mount31a21722014-03-24 17:44:36 -07002625 * Activity Transitions.
George Mount0a778ed2013-12-13 13:35:36 -08002626 * @param isTransitionGroup Whether or not the ViewGroup should be treated as a unit
2627 * in Activity transitions. If false, the ViewGroup won't transition,
2628 * only its children. If true, the entire ViewGroup will transition
2629 * together.
George Mount62ab9b72014-05-02 13:51:17 -07002630 * @see android.app.ActivityOptions#makeSceneTransitionAnimation(android.app.Activity,
2631 * android.util.Pair[])
George Mount0a778ed2013-12-13 13:35:36 -08002632 */
2633 public void setTransitionGroup(boolean isTransitionGroup) {
2634 mGroupFlags |= FLAG_IS_TRANSITION_GROUP_SET;
2635 if (isTransitionGroup) {
2636 mGroupFlags |= FLAG_IS_TRANSITION_GROUP;
2637 } else {
2638 mGroupFlags &= ~FLAG_IS_TRANSITION_GROUP;
2639 }
2640 }
2641
2642 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002643 * {@inheritDoc}
2644 */
2645 public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
Romain Guy8506ab42009-06-11 17:35:47 -07002646
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002647 if (disallowIntercept == ((mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0)) {
2648 // We're already in this state, assume our ancestors are too
2649 return;
2650 }
Romain Guy8506ab42009-06-11 17:35:47 -07002651
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002652 if (disallowIntercept) {
2653 mGroupFlags |= FLAG_DISALLOW_INTERCEPT;
2654 } else {
2655 mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
2656 }
Romain Guy8506ab42009-06-11 17:35:47 -07002657
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002658 // Pass it up to our parent
2659 if (mParent != null) {
2660 mParent.requestDisallowInterceptTouchEvent(disallowIntercept);
2661 }
2662 }
2663
2664 /**
2665 * Implement this method to intercept all touch screen motion events. This
2666 * allows you to watch events as they are dispatched to your children, and
2667 * take ownership of the current gesture at any point.
2668 *
2669 * <p>Using this function takes some care, as it has a fairly complicated
2670 * interaction with {@link View#onTouchEvent(MotionEvent)
2671 * View.onTouchEvent(MotionEvent)}, and using it requires implementing
2672 * that method as well as this one in the correct way. Events will be
2673 * received in the following order:
2674 *
2675 * <ol>
2676 * <li> You will receive the down event here.
2677 * <li> The down event will be handled either by a child of this view
2678 * group, or given to your own onTouchEvent() method to handle; this means
2679 * you should implement onTouchEvent() to return true, so you will
2680 * continue to see the rest of the gesture (instead of looking for
2681 * a parent view to handle it). Also, by returning true from
2682 * onTouchEvent(), you will not receive any following
2683 * events in onInterceptTouchEvent() and all touch processing must
2684 * happen in onTouchEvent() like normal.
2685 * <li> For as long as you return false from this function, each following
2686 * event (up to and including the final up) will be delivered first here
2687 * and then to the target's onTouchEvent().
2688 * <li> If you return true from here, you will not receive any
2689 * following events: the target view will receive the same event but
2690 * with the action {@link MotionEvent#ACTION_CANCEL}, and all further
2691 * events will be delivered to your onTouchEvent() method and no longer
2692 * appear here.
2693 * </ol>
2694 *
2695 * @param ev The motion event being dispatched down the hierarchy.
2696 * @return Return true to steal motion events from the children and have
2697 * them dispatched to this ViewGroup through onTouchEvent().
2698 * The current target will receive an ACTION_CANCEL event, and no further
2699 * messages will be delivered here.
2700 */
2701 public boolean onInterceptTouchEvent(MotionEvent ev) {
2702 return false;
2703 }
2704
2705 /**
2706 * {@inheritDoc}
2707 *
2708 * Looks for a view to give focus to respecting the setting specified by
2709 * {@link #getDescendantFocusability()}.
2710 *
2711 * Uses {@link #onRequestFocusInDescendants(int, android.graphics.Rect)} to
2712 * find focus within the children of this group when appropriate.
2713 *
2714 * @see #FOCUS_BEFORE_DESCENDANTS
2715 * @see #FOCUS_AFTER_DESCENDANTS
2716 * @see #FOCUS_BLOCK_DESCENDANTS
Romain Guy02739a82011-05-16 11:43:18 -07002717 * @see #onRequestFocusInDescendants(int, android.graphics.Rect)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002718 */
2719 @Override
2720 public boolean requestFocus(int direction, Rect previouslyFocusedRect) {
2721 if (DBG) {
2722 System.out.println(this + " ViewGroup.requestFocus direction="
2723 + direction);
2724 }
2725 int descendantFocusability = getDescendantFocusability();
2726
2727 switch (descendantFocusability) {
2728 case FOCUS_BLOCK_DESCENDANTS:
2729 return super.requestFocus(direction, previouslyFocusedRect);
2730 case FOCUS_BEFORE_DESCENDANTS: {
2731 final boolean took = super.requestFocus(direction, previouslyFocusedRect);
2732 return took ? took : onRequestFocusInDescendants(direction, previouslyFocusedRect);
2733 }
2734 case FOCUS_AFTER_DESCENDANTS: {
2735 final boolean took = onRequestFocusInDescendants(direction, previouslyFocusedRect);
2736 return took ? took : super.requestFocus(direction, previouslyFocusedRect);
2737 }
2738 default:
2739 throw new IllegalStateException("descendant focusability must be "
2740 + "one of FOCUS_BEFORE_DESCENDANTS, FOCUS_AFTER_DESCENDANTS, FOCUS_BLOCK_DESCENDANTS "
2741 + "but is " + descendantFocusability);
2742 }
2743 }
2744
2745 /**
2746 * Look for a descendant to call {@link View#requestFocus} on.
2747 * Called by {@link ViewGroup#requestFocus(int, android.graphics.Rect)}
2748 * when it wants to request focus within its children. Override this to
2749 * customize how your {@link ViewGroup} requests focus within its children.
2750 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT
2751 * @param previouslyFocusedRect The rectangle (in this View's coordinate system)
2752 * to give a finer grained hint about where focus is coming from. May be null
2753 * if there is no hint.
2754 * @return Whether focus was taken.
2755 */
2756 @SuppressWarnings({"ConstantConditions"})
2757 protected boolean onRequestFocusInDescendants(int direction,
2758 Rect previouslyFocusedRect) {
2759 int index;
2760 int increment;
2761 int end;
2762 int count = mChildrenCount;
2763 if ((direction & FOCUS_FORWARD) != 0) {
2764 index = 0;
2765 increment = 1;
2766 end = count;
2767 } else {
2768 index = count - 1;
2769 increment = -1;
2770 end = -1;
2771 }
2772 final View[] children = mChildren;
2773 for (int i = index; i != end; i += increment) {
2774 View child = children[i];
2775 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
2776 if (child.requestFocus(direction, previouslyFocusedRect)) {
2777 return true;
2778 }
2779 }
2780 }
2781 return false;
2782 }
Chet Haase5c13d892010-10-08 08:37:55 -07002783
Romain Guya440b002010-02-24 15:57:54 -08002784 /**
2785 * {@inheritDoc}
Chet Haase5c13d892010-10-08 08:37:55 -07002786 *
Romain Guydcc490f2010-02-24 17:59:35 -08002787 * @hide
Romain Guya440b002010-02-24 15:57:54 -08002788 */
2789 @Override
2790 public void dispatchStartTemporaryDetach() {
2791 super.dispatchStartTemporaryDetach();
2792 final int count = mChildrenCount;
2793 final View[] children = mChildren;
2794 for (int i = 0; i < count; i++) {
2795 children[i].dispatchStartTemporaryDetach();
2796 }
2797 }
Chet Haase5c13d892010-10-08 08:37:55 -07002798
Romain Guya440b002010-02-24 15:57:54 -08002799 /**
2800 * {@inheritDoc}
Chet Haase5c13d892010-10-08 08:37:55 -07002801 *
Romain Guydcc490f2010-02-24 17:59:35 -08002802 * @hide
Romain Guya440b002010-02-24 15:57:54 -08002803 */
2804 @Override
2805 public void dispatchFinishTemporaryDetach() {
2806 super.dispatchFinishTemporaryDetach();
2807 final int count = mChildrenCount;
2808 final View[] children = mChildren;
2809 for (int i = 0; i < count; i++) {
2810 children[i].dispatchFinishTemporaryDetach();
2811 }
2812 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002813
2814 /**
2815 * {@inheritDoc}
2816 */
2817 @Override
2818 void dispatchAttachedToWindow(AttachInfo info, int visibility) {
Adam Powell4b867882011-09-16 12:59:46 -07002819 mGroupFlags |= FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002820 super.dispatchAttachedToWindow(info, visibility);
Adam Powell4b867882011-09-16 12:59:46 -07002821 mGroupFlags &= ~FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW;
2822
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002823 final int count = mChildrenCount;
2824 final View[] children = mChildren;
2825 for (int i = 0; i < count; i++) {
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07002826 final View child = children[i];
2827 child.dispatchAttachedToWindow(info,
Philip Milne7b757812012-09-19 18:13:44 -07002828 visibility | (child.mViewFlags & VISIBILITY_MASK));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002829 }
Chet Haasec633d2f2015-04-07 10:29:39 -07002830 final int transientCount = mTransientIndices == null ? 0 : mTransientIndices.size();
2831 for (int i = 0; i < transientCount; ++i) {
2832 View view = mTransientViews.get(i);
2833 view.dispatchAttachedToWindow(info, visibility | (view.mViewFlags & VISIBILITY_MASK));
2834 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002835 }
2836
svetoslavganov75986cf2009-05-14 22:28:01 -07002837 @Override
Romain Guybb9908b2012-03-08 11:14:07 -08002838 void dispatchScreenStateChanged(int screenState) {
2839 super.dispatchScreenStateChanged(screenState);
2840
2841 final int count = mChildrenCount;
2842 final View[] children = mChildren;
2843 for (int i = 0; i < count; i++) {
2844 children[i].dispatchScreenStateChanged(screenState);
2845 }
2846 }
2847
Alan Viverettea54956a2015-01-07 16:05:02 -08002848 /** @hide */
Romain Guybb9908b2012-03-08 11:14:07 -08002849 @Override
Alan Viverettea54956a2015-01-07 16:05:02 -08002850 public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07002851 boolean handled = false;
2852 if (includeForAccessibility()) {
2853 handled = super.dispatchPopulateAccessibilityEventInternal(event);
2854 if (handled) {
2855 return handled;
2856 }
Svetoslav Ganovb84b94e2011-09-22 19:26:56 -07002857 }
Svetoslav Ganov736c2752011-04-22 18:30:36 -07002858 // Let our children have a shot in populating the event.
Svetoslav Ganov42138042012-03-20 11:51:39 -07002859 ChildListForAccessibility children = ChildListForAccessibility.obtain(this, true);
Svetoslav Ganov76f287e2012-04-23 11:02:36 -07002860 try {
2861 final int childCount = children.getChildCount();
2862 for (int i = 0; i < childCount; i++) {
2863 View child = children.getChildAt(i);
2864 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
2865 handled = child.dispatchPopulateAccessibilityEvent(event);
2866 if (handled) {
Svetoslav Ganov76f287e2012-04-23 11:02:36 -07002867 return handled;
2868 }
Svetoslav Ganov6179ea32011-06-28 01:12:41 -07002869 }
Svetoslav Ganov736c2752011-04-22 18:30:36 -07002870 }
Svetoslav Ganov76f287e2012-04-23 11:02:36 -07002871 } finally {
2872 children.recycle();
svetoslavganov75986cf2009-05-14 22:28:01 -07002873 }
Svetoslav Ganov736c2752011-04-22 18:30:36 -07002874 return false;
svetoslavganov75986cf2009-05-14 22:28:01 -07002875 }
2876
Dianne Hackborn6251f0d2015-04-01 16:45:03 -07002877 /**
2878 * Dispatch creation of {@link ViewAssistStructure} down the hierarchy. This implementation
2879 * adds in all child views of the view group, in addition to calling the default View
2880 * implementation.
2881 */
2882 public void dispatchProvideAssistStructure(ViewAssistStructure structure) {
2883 super.dispatchProvideAssistStructure(structure);
2884 if (structure.getChildCount() == 0) {
2885 final int childrenCount = getChildCount();
2886 if (childrenCount > 0) {
2887 structure.setChildCount(childrenCount);
2888 final ArrayList<View> preorderedList = buildOrderedChildList();
2889 final boolean customOrder = preorderedList == null
2890 && isChildrenDrawingOrderEnabled();
2891 final View[] children = mChildren;
2892 for (int i=0; i<childrenCount; i++) {
2893 final int childIndex = customOrder
2894 ? getChildDrawingOrder(childrenCount, i) : i;
2895 final View child = (preorderedList == null)
2896 ? children[childIndex] : preorderedList.get(childIndex);
2897 ViewAssistStructure cstructure = structure.newChild(i);
2898 child.dispatchProvideAssistStructure(cstructure);
2899 }
2900 }
2901 }
2902 }
2903
Alan Viverettea54956a2015-01-07 16:05:02 -08002904 /** @hide */
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002905 @Override
Alan Viverettea54956a2015-01-07 16:05:02 -08002906 public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
Svetoslav Ganov031d9c12011-09-09 16:41:13 -07002907 super.onInitializeAccessibilityNodeInfoInternal(info);
Svet Ganov55bdb102015-02-06 12:41:17 -08002908 if (getAccessibilityNodeProvider() != null) {
2909 return;
2910 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07002911 if (mAttachInfo != null) {
Alan Viverettef0aed092013-11-06 15:33:03 -08002912 final ArrayList<View> childrenForAccessibility = mAttachInfo.mTempArrayList;
Svetoslav Ganov42138042012-03-20 11:51:39 -07002913 childrenForAccessibility.clear();
2914 addChildrenForAccessibility(childrenForAccessibility);
2915 final int childrenForAccessibilityCount = childrenForAccessibility.size();
2916 for (int i = 0; i < childrenForAccessibilityCount; i++) {
Alan Viverettef0aed092013-11-06 15:33:03 -08002917 final View child = childrenForAccessibility.get(i);
2918 info.addChildUnchecked(child);
Svetoslav Ganovea1da3d2011-06-15 17:16:02 -07002919 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07002920 childrenForAccessibility.clear();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002921 }
2922 }
2923
Alan Viverettea54956a2015-01-07 16:05:02 -08002924 /** @hide */
Svetoslav Ganov8a78fd42012-01-17 14:36:46 -08002925 @Override
Alan Viverettea54956a2015-01-07 16:05:02 -08002926 public void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
Svetoslav Ganov8a78fd42012-01-17 14:36:46 -08002927 super.onInitializeAccessibilityEventInternal(event);
2928 event.setClassName(ViewGroup.class.getName());
2929 }
2930
Svetoslav Ganov42138042012-03-20 11:51:39 -07002931 @Override
Alan Viverette77e9a282013-09-12 17:16:09 -07002932 public void notifySubtreeAccessibilityStateChanged(View child, View source, int changeType) {
2933 // If this is a live region, we should send a subtree change event
2934 // from this view. Otherwise, we can let it propagate up.
2935 if (getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE) {
2936 notifyViewAccessibilityStateChangedIfNeeded(changeType);
2937 } else if (mParent != null) {
Adam Powell504a10f2013-07-11 15:25:59 -07002938 try {
Alan Viverette77e9a282013-09-12 17:16:09 -07002939 mParent.notifySubtreeAccessibilityStateChanged(this, source, changeType);
Adam Powell504a10f2013-07-11 15:25:59 -07002940 } catch (AbstractMethodError e) {
2941 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() +
2942 " does not fully implement ViewParent", e);
2943 }
Svetoslav6254f482013-06-04 17:22:14 -07002944 }
2945 }
2946
2947 @Override
2948 void resetSubtreeAccessibilityStateChanged() {
2949 super.resetSubtreeAccessibilityStateChanged();
Svetoslav Ganov42138042012-03-20 11:51:39 -07002950 View[] children = mChildren;
2951 final int childCount = mChildrenCount;
2952 for (int i = 0; i < childCount; i++) {
Svetoslav6254f482013-06-04 17:22:14 -07002953 children[i].resetSubtreeAccessibilityStateChanged();
Svetoslav Ganov42138042012-03-20 11:51:39 -07002954 }
2955 }
2956
2957 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002958 * {@inheritDoc}
Adam Powellb6ab0982015-01-07 17:00:12 -08002959 *
2960 * <p>Subclasses should always call <code>super.onNestedPrePerformAccessibilityAction</code></p>
2961 *
2962 * @param target The target view dispatching this action
2963 * @param action Action being performed; see
2964 * {@link android.view.accessibility.AccessibilityNodeInfo}
2965 * @param args Optional action arguments
2966 * @return false by default. Subclasses should return true if they handle the event.
2967 */
2968 @Override
2969 public boolean onNestedPrePerformAccessibilityAction(View target, int action, Bundle args) {
2970 return false;
2971 }
2972
2973 /**
2974 * {@inheritDoc}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002975 */
2976 @Override
2977 void dispatchDetachedFromWindow() {
Jeff Brown20e987b2010-08-23 12:01:02 -07002978 // If we still have a touch target, we are still in the process of
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002979 // dispatching motion events to a child; we need to get rid of that
2980 // child to avoid dispatching events to it after the window is torn
2981 // down. To make sure we keep the child in a consistent state, we
2982 // first send it an ACTION_CANCEL motion event.
Jeff Brown20e987b2010-08-23 12:01:02 -07002983 cancelAndClearTouchTargets(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002984
Jeff Brown59a422e2012-04-19 15:19:19 -07002985 // Similarly, set ACTION_EXIT to all hover targets and clear them.
2986 exitHoverTargets();
2987
Chet Haase9c087442011-01-12 16:20:16 -08002988 // In case view is detached while transition is running
Chet Haaseb9895022013-04-02 15:10:58 -07002989 mLayoutCalledWhileSuppressed = false;
Chet Haase9c087442011-01-12 16:20:16 -08002990
Christopher Tate86cab1b2011-01-13 20:28:55 -08002991 // Tear down our drag tracking
2992 mDragNotifiedChildren = null;
2993 if (mCurrentDrag != null) {
2994 mCurrentDrag.recycle();
2995 mCurrentDrag = null;
2996 }
2997
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002998 final int count = mChildrenCount;
2999 final View[] children = mChildren;
3000 for (int i = 0; i < count; i++) {
3001 children[i].dispatchDetachedFromWindow();
3002 }
John Reckca7a9da2014-03-05 16:29:07 -08003003 clearDisappearingChildren();
Chet Haasec633d2f2015-04-07 10:29:39 -07003004 final int transientCount = mTransientViews == null ? 0 : mTransientIndices.size();
3005 for (int i = 0; i < transientCount; ++i) {
3006 View view = mTransientViews.get(i);
3007 view.dispatchDetachedFromWindow();
3008 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003009 super.dispatchDetachedFromWindow();
3010 }
3011
Fabrice Di Meglio23c89fd2012-08-13 12:17:42 -07003012 /**
3013 * @hide
3014 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003015 @Override
Fabrice Di Meglio23c89fd2012-08-13 12:17:42 -07003016 protected void internalSetPadding(int left, int top, int right, int bottom) {
Romain Guy2440e672012-08-07 14:43:43 -07003017 super.internalSetPadding(left, top, right, bottom);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003018
Romain Guy13f35f32011-03-24 12:03:17 -07003019 if ((mPaddingLeft | mPaddingTop | mPaddingRight | mPaddingBottom) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003020 mGroupFlags |= FLAG_PADDING_NOT_NULL;
3021 } else {
3022 mGroupFlags &= ~FLAG_PADDING_NOT_NULL;
3023 }
3024 }
3025
3026 /**
3027 * {@inheritDoc}
3028 */
3029 @Override
3030 protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {
3031 super.dispatchSaveInstanceState(container);
3032 final int count = mChildrenCount;
3033 final View[] children = mChildren;
3034 for (int i = 0; i < count; i++) {
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07003035 View c = children[i];
3036 if ((c.mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED) {
3037 c.dispatchSaveInstanceState(container);
3038 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003039 }
3040 }
3041
3042 /**
Romain Guy9fc27812011-04-27 14:21:41 -07003043 * Perform dispatching of a {@link #saveHierarchyState(android.util.SparseArray)} freeze()}
3044 * to only this view, not to its children. For use when overriding
3045 * {@link #dispatchSaveInstanceState(android.util.SparseArray)} dispatchFreeze()} to allow
3046 * subclasses to freeze their own state but not the state of their children.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003047 *
3048 * @param container the container
3049 */
3050 protected void dispatchFreezeSelfOnly(SparseArray<Parcelable> container) {
3051 super.dispatchSaveInstanceState(container);
3052 }
3053
3054 /**
3055 * {@inheritDoc}
3056 */
3057 @Override
3058 protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {
3059 super.dispatchRestoreInstanceState(container);
3060 final int count = mChildrenCount;
3061 final View[] children = mChildren;
3062 for (int i = 0; i < count; i++) {
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07003063 View c = children[i];
3064 if ((c.mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED) {
3065 c.dispatchRestoreInstanceState(container);
3066 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003067 }
3068 }
3069
3070 /**
Romain Guy02739a82011-05-16 11:43:18 -07003071 * Perform dispatching of a {@link #restoreHierarchyState(android.util.SparseArray)}
3072 * to only this view, not to its children. For use when overriding
3073 * {@link #dispatchRestoreInstanceState(android.util.SparseArray)} to allow
3074 * subclasses to thaw their own state but not the state of their children.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003075 *
3076 * @param container the container
3077 */
3078 protected void dispatchThawSelfOnly(SparseArray<Parcelable> container) {
3079 super.dispatchRestoreInstanceState(container);
3080 }
3081
3082 /**
3083 * Enables or disables the drawing cache for each child of this view group.
3084 *
3085 * @param enabled true to enable the cache, false to dispose of it
3086 */
3087 protected void setChildrenDrawingCacheEnabled(boolean enabled) {
3088 if (enabled || (mPersistentDrawingCache & PERSISTENT_ALL_CACHES) != PERSISTENT_ALL_CACHES) {
3089 final View[] children = mChildren;
3090 final int count = mChildrenCount;
3091 for (int i = 0; i < count; i++) {
3092 children[i].setDrawingCacheEnabled(enabled);
3093 }
3094 }
3095 }
3096
3097 @Override
Romain Guy223ff5c2010-03-02 17:07:47 -08003098 Bitmap createSnapshot(Bitmap.Config quality, int backgroundColor, boolean skipChildren) {
Romain Guy65554f22010-03-22 18:58:21 -07003099 int count = mChildrenCount;
3100 int[] visibilities = null;
3101
Romain Guy223ff5c2010-03-02 17:07:47 -08003102 if (skipChildren) {
Romain Guy65554f22010-03-22 18:58:21 -07003103 visibilities = new int[count];
3104 for (int i = 0; i < count; i++) {
3105 View child = getChildAt(i);
3106 visibilities[i] = child.getVisibility();
3107 if (visibilities[i] == View.VISIBLE) {
3108 child.setVisibility(INVISIBLE);
3109 }
3110 }
Romain Guy223ff5c2010-03-02 17:07:47 -08003111 }
3112
3113 Bitmap b = super.createSnapshot(quality, backgroundColor, skipChildren);
Romain Guy65554f22010-03-22 18:58:21 -07003114
3115 if (skipChildren) {
3116 for (int i = 0; i < count; i++) {
3117 getChildAt(i).setVisibility(visibilities[i]);
Chet Haase5c13d892010-10-08 08:37:55 -07003118 }
Romain Guy65554f22010-03-22 18:58:21 -07003119 }
Romain Guy223ff5c2010-03-02 17:07:47 -08003120
3121 return b;
3122 }
3123
Philip Milne7b757812012-09-19 18:13:44 -07003124 /** Return true if this ViewGroup is laying out using optical bounds. */
3125 boolean isLayoutModeOptical() {
3126 return mLayoutMode == LAYOUT_MODE_OPTICAL_BOUNDS;
3127 }
Romain Guycbc67742012-04-27 16:12:57 -07003128
Philip Milne7b757812012-09-19 18:13:44 -07003129 Insets computeOpticalInsets() {
3130 if (isLayoutModeOptical()) {
3131 int left = 0;
3132 int top = 0;
3133 int right = 0;
3134 int bottom = 0;
3135 for (int i = 0; i < mChildrenCount; i++) {
3136 View child = getChildAt(i);
3137 if (child.getVisibility() == VISIBLE) {
3138 Insets insets = child.getOpticalInsets();
3139 left = Math.max(left, insets.left);
3140 top = Math.max(top, insets.top);
3141 right = Math.max(right, insets.right);
3142 bottom = Math.max(bottom, insets.bottom);
3143 }
3144 }
3145 return Insets.of(left, top, right, bottom);
3146 } else {
3147 return Insets.NONE;
3148 }
3149 }
3150
3151 private static void fillRect(Canvas canvas, Paint paint, int x1, int y1, int x2, int y2) {
3152 if (x1 != x2 && y1 != y2) {
3153 if (x1 > x2) {
3154 int tmp = x1; x1 = x2; x2 = tmp;
3155 }
3156 if (y1 > y2) {
3157 int tmp = y1; y1 = y2; y2 = tmp;
3158 }
3159 canvas.drawRect(x1, y1, x2, y2, paint);
3160 }
3161 }
3162
3163 private static int sign(int x) {
3164 return (x >= 0) ? 1 : -1;
3165 }
3166
3167 private static void drawCorner(Canvas c, Paint paint, int x1, int y1, int dx, int dy, int lw) {
3168 fillRect(c, paint, x1, y1, x1 + dx, y1 + lw * sign(dy));
3169 fillRect(c, paint, x1, y1, x1 + lw * sign(dx), y1 + dy);
3170 }
3171
3172 private int dipsToPixels(int dips) {
3173 float scale = getContext().getResources().getDisplayMetrics().density;
3174 return (int) (dips * scale + 0.5f);
3175 }
3176
Romain Guy6410c0a2013-06-17 11:21:58 -07003177 private static void drawRectCorners(Canvas canvas, int x1, int y1, int x2, int y2, Paint paint,
3178 int lineLength, int lineWidth) {
Philip Milne7b757812012-09-19 18:13:44 -07003179 drawCorner(canvas, paint, x1, y1, lineLength, lineLength, lineWidth);
3180 drawCorner(canvas, paint, x1, y2, lineLength, -lineLength, lineWidth);
3181 drawCorner(canvas, paint, x2, y1, -lineLength, lineLength, lineWidth);
3182 drawCorner(canvas, paint, x2, y2, -lineLength, -lineLength, lineWidth);
3183 }
3184
3185 private static void fillDifference(Canvas canvas,
3186 int x2, int y2, int x3, int y3,
3187 int dx1, int dy1, int dx2, int dy2, Paint paint) {
3188 int x1 = x2 - dx1;
3189 int y1 = y2 - dy1;
3190
3191 int x4 = x3 + dx2;
3192 int y4 = y3 + dy2;
3193
3194 fillRect(canvas, paint, x1, y1, x4, y2);
3195 fillRect(canvas, paint, x1, y2, x2, y3);
3196 fillRect(canvas, paint, x3, y2, x4, y3);
3197 fillRect(canvas, paint, x1, y3, x4, y4);
Philip Milne10ca24a2012-04-23 15:38:27 -07003198 }
3199
3200 /**
3201 * @hide
3202 */
Philip Milne7b757812012-09-19 18:13:44 -07003203 protected void onDebugDrawMargins(Canvas canvas, Paint paint) {
Philip Milne10ca24a2012-04-23 15:38:27 -07003204 for (int i = 0; i < getChildCount(); i++) {
3205 View c = getChildAt(i);
Philip Milne7b757812012-09-19 18:13:44 -07003206 c.getLayoutParams().onDebugDraw(c, canvas, paint);
Philip Milne10ca24a2012-04-23 15:38:27 -07003207 }
3208 }
3209
3210 /**
3211 * @hide
3212 */
3213 protected void onDebugDraw(Canvas canvas) {
Philip Milne7b757812012-09-19 18:13:44 -07003214 Paint paint = getDebugPaint();
3215
Philip Milne10ca24a2012-04-23 15:38:27 -07003216 // Draw optical bounds
Philip Milne7b757812012-09-19 18:13:44 -07003217 {
3218 paint.setColor(Color.RED);
3219 paint.setStyle(Paint.Style.STROKE);
Philip Milne7b757812012-09-19 18:13:44 -07003220
Philip Milne10ca24a2012-04-23 15:38:27 -07003221 for (int i = 0; i < getChildCount(); i++) {
3222 View c = getChildAt(i);
Philip Milne7a23b492012-04-24 22:12:36 -07003223 Insets insets = c.getOpticalInsets();
Philip Milne7b757812012-09-19 18:13:44 -07003224
3225 drawRect(canvas, paint,
3226 c.getLeft() + insets.left,
3227 c.getTop() + insets.top,
3228 c.getRight() - insets.right - 1,
3229 c.getBottom() - insets.bottom - 1);
Philip Milne10ca24a2012-04-23 15:38:27 -07003230 }
3231 }
3232
Philip Milne10ca24a2012-04-23 15:38:27 -07003233 // Draw margins
Philip Milne7b757812012-09-19 18:13:44 -07003234 {
3235 paint.setColor(Color.argb(63, 255, 0, 255));
3236 paint.setStyle(Paint.Style.FILL);
Philip Milne604f4402012-04-24 19:27:11 -07003237
Philip Milne7b757812012-09-19 18:13:44 -07003238 onDebugDrawMargins(canvas, paint);
3239 }
3240
3241 // Draw clip bounds
3242 {
3243 paint.setColor(Color.rgb(63, 127, 255));
3244 paint.setStyle(Paint.Style.FILL);
3245
3246 int lineLength = dipsToPixels(8);
3247 int lineWidth = dipsToPixels(1);
3248 for (int i = 0; i < getChildCount(); i++) {
3249 View c = getChildAt(i);
3250 drawRectCorners(canvas, c.getLeft(), c.getTop(), c.getRight(), c.getBottom(),
3251 paint, lineLength, lineWidth);
3252 }
Philip Milne604f4402012-04-24 19:27:11 -07003253 }
Philip Milne10ca24a2012-04-23 15:38:27 -07003254 }
3255
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003256 /**
3257 * {@inheritDoc}
3258 */
3259 @Override
3260 protected void dispatchDraw(Canvas canvas) {
Chris Craika753f4c2014-07-24 12:39:17 -07003261 boolean usingRenderNodeProperties = canvas.isRecordingFor(mRenderNode);
Chris Craikab008f02014-05-23 17:55:03 -07003262 final int childrenCount = mChildrenCount;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003263 final View[] children = mChildren;
3264 int flags = mGroupFlags;
3265
3266 if ((flags & FLAG_RUN_ANIMATION) != 0 && canAnimate()) {
Romain Guy0d9275e2010-10-26 14:22:30 -07003267 final boolean buildCache = !isHardwareAccelerated();
Chris Craikab008f02014-05-23 17:55:03 -07003268 for (int i = 0; i < childrenCount; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003269 final View child = children[i];
3270 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
3271 final LayoutParams params = child.getLayoutParams();
Chris Craikab008f02014-05-23 17:55:03 -07003272 attachLayoutAnimationParameters(child, params, i, childrenCount);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003273 bindLayoutAnimation(child);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003274 }
3275 }
3276
3277 final LayoutAnimationController controller = mLayoutAnimationController;
3278 if (controller.willOverlap()) {
3279 mGroupFlags |= FLAG_OPTIMIZE_INVALIDATE;
3280 }
3281
3282 controller.start();
3283
3284 mGroupFlags &= ~FLAG_RUN_ANIMATION;
3285 mGroupFlags &= ~FLAG_ANIMATION_DONE;
3286
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003287 if (mAnimationListener != null) {
3288 mAnimationListener.onAnimationStart(controller.getAnimation());
3289 }
3290 }
3291
Selim Cinek19cadc22014-04-16 17:27:19 +02003292 int clipSaveCount = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003293 final boolean clipToPadding = (flags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK;
3294 if (clipToPadding) {
Chris Craike4cf1522014-08-04 17:55:22 -07003295 clipSaveCount = canvas.save();
Romain Guy8f2d94f2009-03-25 18:04:42 -07003296 canvas.clipRect(mScrollX + mPaddingLeft, mScrollY + mPaddingTop,
3297 mScrollX + mRight - mLeft - mPaddingRight,
3298 mScrollY + mBottom - mTop - mPaddingBottom);
Selim Cinek19cadc22014-04-16 17:27:19 +02003299 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003300
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003301 // We will draw our child's animation, let's reset the flag
Dianne Hackborn4702a852012-08-17 15:18:29 -07003302 mPrivateFlags &= ~PFLAG_DRAW_ANIMATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003303 mGroupFlags &= ~FLAG_INVALIDATE_REQUIRED;
3304
3305 boolean more = false;
3306 final long drawingTime = getDrawingTime();
3307
Chris Craik8afd0f22014-08-21 17:41:57 -07003308 if (usingRenderNodeProperties) canvas.insertReorderBarrier();
Chet Haasec633d2f2015-04-07 10:29:39 -07003309 final int transientCount = mTransientIndices == null ? 0 : mTransientIndices.size();
3310 int transientIndex = transientCount != 0 ? 0 : -1;
Chris Craikab008f02014-05-23 17:55:03 -07003311 // Only use the preordered list if not HW accelerated, since the HW pipeline will do the
3312 // draw reordering internally
Chris Craika753f4c2014-07-24 12:39:17 -07003313 final ArrayList<View> preorderedList = usingRenderNodeProperties
Chris Craikab008f02014-05-23 17:55:03 -07003314 ? null : buildOrderedChildList();
3315 final boolean customOrder = preorderedList == null
3316 && isChildrenDrawingOrderEnabled();
3317 for (int i = 0; i < childrenCount; i++) {
Chet Haasec633d2f2015-04-07 10:29:39 -07003318 while (transientIndex >= 0 && mTransientIndices.get(transientIndex) == i) {
3319 final View transientChild = mTransientViews.get(transientIndex);
3320 if ((transientChild.mViewFlags & VISIBILITY_MASK) == VISIBLE ||
3321 transientChild.getAnimation() != null) {
3322 more |= drawChild(canvas, transientChild, drawingTime);
3323 }
3324 transientIndex++;
3325 if (transientIndex >= transientCount) {
3326 transientIndex = -1;
3327 }
3328 }
Chris Craikab008f02014-05-23 17:55:03 -07003329 int childIndex = customOrder ? getChildDrawingOrder(childrenCount, i) : i;
3330 final View child = (preorderedList == null)
3331 ? children[childIndex] : preorderedList.get(childIndex);
3332 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
3333 more |= drawChild(canvas, child, drawingTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003334 }
3335 }
Chet Haasec633d2f2015-04-07 10:29:39 -07003336 while (transientIndex >= 0) {
3337 // there may be additional transient views after the normal views
3338 final View transientChild = mTransientViews.get(transientIndex);
3339 if ((transientChild.mViewFlags & VISIBILITY_MASK) == VISIBLE ||
3340 transientChild.getAnimation() != null) {
3341 more |= drawChild(canvas, transientChild, drawingTime);
3342 }
3343 transientIndex++;
3344 if (transientIndex >= transientCount) {
3345 break;
3346 }
3347 }
Chris Craikab008f02014-05-23 17:55:03 -07003348 if (preorderedList != null) preorderedList.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003349
3350 // Draw any disappearing views that have animations
3351 if (mDisappearingChildren != null) {
3352 final ArrayList<View> disappearingChildren = mDisappearingChildren;
3353 final int disappearingCount = disappearingChildren.size() - 1;
3354 // Go backwards -- we may delete as animations finish
3355 for (int i = disappearingCount; i >= 0; i--) {
3356 final View child = disappearingChildren.get(i);
3357 more |= drawChild(canvas, child, drawingTime);
3358 }
3359 }
Chris Craik8afd0f22014-08-21 17:41:57 -07003360 if (usingRenderNodeProperties) canvas.insertInorderBarrier();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003361
Philip Milne10ca24a2012-04-23 15:38:27 -07003362 if (debugDraw()) {
3363 onDebugDraw(canvas);
3364 }
3365
Chris Craike4cf1522014-08-04 17:55:22 -07003366 if (clipToPadding) {
Selim Cinek19cadc22014-04-16 17:27:19 +02003367 canvas.restoreToCount(clipSaveCount);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003368 }
3369
3370 // mGroupFlags might have been updated by drawChild()
3371 flags = mGroupFlags;
3372
3373 if ((flags & FLAG_INVALIDATE_REQUIRED) == FLAG_INVALIDATE_REQUIRED) {
Romain Guy849d0a32011-02-01 17:20:48 -08003374 invalidate(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003375 }
3376
3377 if ((flags & FLAG_ANIMATION_DONE) == 0 && (flags & FLAG_NOTIFY_ANIMATION_LISTENER) == 0 &&
3378 mLayoutAnimationController.isDone() && !more) {
3379 // We want to erase the drawing cache and notify the listener after the
3380 // next frame is drawn because one extra invalidate() is caused by
3381 // drawChild() after the animation is over
3382 mGroupFlags |= FLAG_NOTIFY_ANIMATION_LISTENER;
3383 final Runnable end = new Runnable() {
3384 public void run() {
3385 notifyAnimationListener();
3386 }
3387 };
3388 post(end);
3389 }
3390 }
Romain Guy8506ab42009-06-11 17:35:47 -07003391
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003392 /**
Chet Haaseedf6f4b2013-03-26 07:55:30 -07003393 * Returns the ViewGroupOverlay for this view group, creating it if it does
3394 * not yet exist. In addition to {@link ViewOverlay}'s support for drawables,
3395 * {@link ViewGroupOverlay} allows views to be added to the overlay. These
3396 * views, like overlay drawables, are visual-only; they do not receive input
3397 * events and should not be used as anything other than a temporary
3398 * representation of a view in a parent container, such as might be used
3399 * by an animation effect.
3400 *
Chet Haase95399492013-04-08 14:30:31 -07003401 * <p>Note: Overlays do not currently work correctly with {@link
3402 * SurfaceView} or {@link TextureView}; contents in overlays for these
3403 * types of views may not display correctly.</p>
3404 *
Chet Haaseedf6f4b2013-03-26 07:55:30 -07003405 * @return The ViewGroupOverlay object for this view.
3406 * @see ViewGroupOverlay
3407 */
3408 @Override
3409 public ViewGroupOverlay getOverlay() {
3410 if (mOverlay == null) {
3411 mOverlay = new ViewGroupOverlay(mContext, this);
3412 }
3413 return (ViewGroupOverlay) mOverlay;
3414 }
3415
3416 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003417 * Returns the index of the child to draw for this iteration. Override this
3418 * if you want to change the drawing order of children. By default, it
3419 * returns i.
3420 * <p>
Romain Guy293451e2009-11-04 13:59:48 -08003421 * NOTE: In order for this method to be called, you must enable child ordering
3422 * first by calling {@link #setChildrenDrawingOrderEnabled(boolean)}.
Romain Guy8506ab42009-06-11 17:35:47 -07003423 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003424 * @param i The current iteration.
3425 * @return The index of the child to draw this iteration.
Chet Haase5c13d892010-10-08 08:37:55 -07003426 *
Romain Guy293451e2009-11-04 13:59:48 -08003427 * @see #setChildrenDrawingOrderEnabled(boolean)
3428 * @see #isChildrenDrawingOrderEnabled()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003429 */
3430 protected int getChildDrawingOrder(int childCount, int i) {
3431 return i;
3432 }
Romain Guy8506ab42009-06-11 17:35:47 -07003433
Chris Craikab008f02014-05-23 17:55:03 -07003434 private boolean hasChildWithZ() {
3435 for (int i = 0; i < mChildrenCount; i++) {
3436 if (mChildren[i].getZ() != 0) return true;
3437 }
3438 return false;
3439 }
3440
3441 /**
3442 * Populates (and returns) mPreSortedChildren with a pre-ordered list of the View's children,
Chris Craik57c79c82014-09-30 12:54:31 -07003443 * sorted first by Z, then by child drawing order (if applicable). This list must be cleared
3444 * after use to avoid leaking child Views.
Chris Craikab008f02014-05-23 17:55:03 -07003445 *
3446 * Uses a stable, insertion sort which is commonly O(n) for ViewGroups with very few elevated
3447 * children.
3448 */
George Mount81206522014-09-26 21:53:39 -07003449 ArrayList<View> buildOrderedChildList() {
Chris Craikab008f02014-05-23 17:55:03 -07003450 final int count = mChildrenCount;
3451 if (count <= 1 || !hasChildWithZ()) return null;
3452
3453 if (mPreSortedChildren == null) {
3454 mPreSortedChildren = new ArrayList<View>(count);
3455 } else {
3456 mPreSortedChildren.ensureCapacity(count);
3457 }
3458
3459 final boolean useCustomOrder = isChildrenDrawingOrderEnabled();
3460 for (int i = 0; i < mChildrenCount; i++) {
3461 // add next child (in child order) to end of list
3462 int childIndex = useCustomOrder ? getChildDrawingOrder(mChildrenCount, i) : i;
3463 View nextChild = mChildren[childIndex];
3464 float currentZ = nextChild.getZ();
3465
3466 // insert ahead of any Views with greater Z
3467 int insertIndex = i;
3468 while (insertIndex > 0 && mPreSortedChildren.get(insertIndex - 1).getZ() > currentZ) {
3469 insertIndex--;
3470 }
3471 mPreSortedChildren.add(insertIndex, nextChild);
3472 }
3473 return mPreSortedChildren;
3474 }
3475
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003476 private void notifyAnimationListener() {
3477 mGroupFlags &= ~FLAG_NOTIFY_ANIMATION_LISTENER;
3478 mGroupFlags |= FLAG_ANIMATION_DONE;
3479
3480 if (mAnimationListener != null) {
3481 final Runnable end = new Runnable() {
3482 public void run() {
3483 mAnimationListener.onAnimationEnd(mLayoutAnimationController.getAnimation());
3484 }
3485 };
3486 post(end);
3487 }
3488
Romain Guy849d0a32011-02-01 17:20:48 -08003489 invalidate(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003490 }
3491
3492 /**
Chet Haasedaf98e92011-01-10 14:10:36 -08003493 * This method is used to cause children of this ViewGroup to restore or recreate their
3494 * display lists. It is called by getDisplayList() when the parent ViewGroup does not need
3495 * to recreate its own display list, which would happen if it went through the normal
3496 * draw/dispatchDraw mechanisms.
3497 *
3498 * @hide
3499 */
3500 @Override
3501 protected void dispatchGetDisplayList() {
3502 final int count = mChildrenCount;
3503 final View[] children = mChildren;
3504 for (int i = 0; i < count; i++) {
3505 final View child = children[i];
Romain Guy59c7f802011-09-29 17:21:45 -07003506 if (((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) &&
3507 child.hasStaticLayer()) {
Chet Haase6c0665f2014-08-01 13:32:27 -07003508 recreateChildDisplayList(child);
Romain Guy2f57ba52011-02-03 18:03:29 -08003509 }
Chet Haasedaf98e92011-01-10 14:10:36 -08003510 }
Chet Haase91cedf12013-03-11 07:56:30 -07003511 if (mOverlay != null) {
Chet Haaseedf6f4b2013-03-26 07:55:30 -07003512 View overlayView = mOverlay.getOverlayView();
Chet Haase6c0665f2014-08-01 13:32:27 -07003513 recreateChildDisplayList(overlayView);
Chet Haase91cedf12013-03-11 07:56:30 -07003514 }
Chet Haase6c0665f2014-08-01 13:32:27 -07003515 if (mDisappearingChildren != null) {
3516 final ArrayList<View> disappearingChildren = mDisappearingChildren;
3517 final int disappearingCount = disappearingChildren.size();
3518 for (int i = 0; i < disappearingCount; ++i) {
3519 final View child = disappearingChildren.get(i);
3520 recreateChildDisplayList(child);
3521 }
3522 }
3523 }
3524
3525 private void recreateChildDisplayList(View child) {
3526 child.mRecreateDisplayList = (child.mPrivateFlags & PFLAG_INVALIDATED)
3527 == PFLAG_INVALIDATED;
3528 child.mPrivateFlags &= ~PFLAG_INVALIDATED;
3529 child.getDisplayList();
3530 child.mRecreateDisplayList = false;
Chet Haasedaf98e92011-01-10 14:10:36 -08003531 }
3532
3533 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003534 * Draw one child of this View Group. This method is responsible for getting
3535 * the canvas in the right state. This includes clipping, translating so
3536 * that the child's scrolled origin is at 0, 0, and applying any animation
3537 * transformations.
3538 *
3539 * @param canvas The canvas on which to draw the child
3540 * @param child Who to draw
Chet Haasebcca79a2012-02-14 08:45:14 -08003541 * @param drawingTime The time at which draw is occurring
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003542 * @return True if an invalidate() was issued
3543 */
3544 protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
Chet Haase64a48c12012-02-13 16:33:29 -08003545 return child.draw(canvas, this, drawingTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003546 }
3547
3548 /**
Chris Craikd863a102013-12-19 13:31:15 -08003549 * Returns whether this group's children are clipped to their bounds before drawing.
Chet Haase430742f2013-04-12 11:18:36 -07003550 * The default value is true.
3551 * @see #setClipChildren(boolean)
3552 *
3553 * @return True if the group's children will be clipped to their bounds,
3554 * false otherwise.
3555 */
Chris Craik5c75c522014-09-05 14:08:08 -07003556 @ViewDebug.ExportedProperty(category = "drawing")
Chet Haase430742f2013-04-12 11:18:36 -07003557 public boolean getClipChildren() {
3558 return ((mGroupFlags & FLAG_CLIP_CHILDREN) != 0);
3559 }
3560
3561 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003562 * By default, children are clipped to their bounds before drawing. This
3563 * allows view groups to override this behavior for animations, etc.
3564 *
3565 * @param clipChildren true to clip children to their bounds,
3566 * false otherwise
3567 * @attr ref android.R.styleable#ViewGroup_clipChildren
3568 */
3569 public void setClipChildren(boolean clipChildren) {
Chet Haasea1cff502012-02-21 13:43:44 -08003570 boolean previousValue = (mGroupFlags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN;
3571 if (clipChildren != previousValue) {
3572 setBooleanFlag(FLAG_CLIP_CHILDREN, clipChildren);
Chet Haase1271e2c2012-04-20 09:54:27 -07003573 for (int i = 0; i < mChildrenCount; ++i) {
3574 View child = getChildAt(i);
Chris Craik64a12e12014-03-28 18:12:12 -07003575 if (child.mRenderNode != null) {
3576 child.mRenderNode.setClipToBounds(clipChildren);
Chet Haasea1cff502012-02-21 13:43:44 -08003577 }
3578 }
John Reckaae9f3b2014-07-28 09:30:36 -07003579 invalidate(true);
Chet Haasea1cff502012-02-21 13:43:44 -08003580 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003581 }
3582
3583 /**
Chris Craikb1652962014-11-14 17:05:06 -08003584 * Sets whether this ViewGroup will clip its children to its padding, if
3585 * padding is present.
3586 * <p>
3587 * By default, children are clipped to the padding of their parent
3588 * Viewgroup. This clipping behavior is only enabled if padding is non-zero.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003589 *
3590 * @param clipToPadding true to clip children to the padding of the
3591 * group, false otherwise
3592 * @attr ref android.R.styleable#ViewGroup_clipToPadding
3593 */
3594 public void setClipToPadding(boolean clipToPadding) {
John Reck9fa3a242014-06-27 15:57:19 -07003595 if (hasBooleanFlag(FLAG_CLIP_TO_PADDING) != clipToPadding) {
3596 setBooleanFlag(FLAG_CLIP_TO_PADDING, clipToPadding);
John Reckaae9f3b2014-07-28 09:30:36 -07003597 invalidate(true);
John Reck9fa3a242014-06-27 15:57:19 -07003598 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003599 }
3600
3601 /**
Chris Craikb1652962014-11-14 17:05:06 -08003602 * Returns whether this ViewGroup will clip its children to its padding, if
3603 * padding is present.
3604 * <p>
3605 * By default, children are clipped to the padding of their parent
3606 * Viewgroup. This clipping behavior is only enabled if padding is non-zero.
Adam Powell1c35b082014-07-11 15:37:15 -07003607 *
3608 * @return true if this ViewGroup clips children to its padding, false otherwise
3609 *
3610 * @attr ref android.R.styleable#ViewGroup_clipToPadding
3611 */
Chris Craik5c75c522014-09-05 14:08:08 -07003612 @ViewDebug.ExportedProperty(category = "drawing")
Adam Powell1c35b082014-07-11 15:37:15 -07003613 public boolean getClipToPadding() {
3614 return hasBooleanFlag(FLAG_CLIP_TO_PADDING);
3615 }
3616
3617 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003618 * {@inheritDoc}
3619 */
3620 @Override
3621 public void dispatchSetSelected(boolean selected) {
3622 final View[] children = mChildren;
3623 final int count = mChildrenCount;
3624 for (int i = 0; i < count; i++) {
3625 children[i].setSelected(selected);
3626 }
3627 }
Romain Guy8506ab42009-06-11 17:35:47 -07003628
Dianne Hackbornd0fa3712010-09-14 18:57:14 -07003629 /**
3630 * {@inheritDoc}
3631 */
3632 @Override
3633 public void dispatchSetActivated(boolean activated) {
3634 final View[] children = mChildren;
3635 final int count = mChildrenCount;
3636 for (int i = 0; i < count; i++) {
Dianne Hackbornd0fa3712010-09-14 18:57:14 -07003637 children[i].setActivated(activated);
3638 }
3639 }
3640
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003641 @Override
3642 protected void dispatchSetPressed(boolean pressed) {
3643 final View[] children = mChildren;
3644 final int count = mChildrenCount;
3645 for (int i = 0; i < count; i++) {
Adam Powell035a1fc2012-02-27 15:23:50 -08003646 final View child = children[i];
3647 // Children that are clickable on their own should not
3648 // show a pressed state when their parent view does.
3649 // Clearing a pressed state always propagates.
3650 if (!pressed || (!child.isClickable() && !child.isLongClickable())) {
3651 child.setPressed(pressed);
3652 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003653 }
3654 }
3655
Alan Viveretteb942b6f2014-12-08 10:37:39 -08003656 /**
3657 * Dispatches drawable hotspot changes to child views that meet at least
3658 * one of the following criteria:
3659 * <ul>
3660 * <li>Returns {@code false} from both {@link View#isClickable()} and
3661 * {@link View#isLongClickable()}</li>
3662 * <li>Requests duplication of parent state via
3663 * {@link View#setDuplicateParentStateEnabled(boolean)}</li>
3664 * </ul>
3665 *
3666 * @param x hotspot x coordinate
3667 * @param y hotspot y coordinate
3668 * @see #drawableHotspotChanged(float, float)
3669 */
3670 @Override
3671 public void dispatchDrawableHotspotChanged(float x, float y) {
3672 final int count = mChildrenCount;
3673 if (count == 0) {
3674 return;
3675 }
3676
3677 final View[] children = mChildren;
3678 for (int i = 0; i < count; i++) {
3679 final View child = children[i];
3680 // Children that are clickable on their own should not
3681 // receive hotspots when their parent view does.
3682 final boolean nonActionable = !child.isClickable() && !child.isLongClickable();
3683 final boolean duplicatesState = (child.mViewFlags & DUPLICATE_PARENT_STATE) != 0;
3684 if (nonActionable || duplicatesState) {
3685 final float[] point = getTempPoint();
3686 point[0] = x;
3687 point[1] = y;
3688 transformPointToViewLocal(point, child);
3689 child.drawableHotspotChanged(point[0], point[1]);
3690 }
3691 }
3692 }
3693
Adam Powell14874662013-07-18 19:42:41 -07003694 @Override
3695 void dispatchCancelPendingInputEvents() {
3696 super.dispatchCancelPendingInputEvents();
3697
3698 final View[] children = mChildren;
3699 final int count = mChildrenCount;
3700 for (int i = 0; i < count; i++) {
3701 children[i].dispatchCancelPendingInputEvents();
3702 }
3703 }
3704
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003705 /**
3706 * When this property is set to true, this ViewGroup supports static transformations on
3707 * children; this causes
3708 * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} to be
3709 * invoked when a child is drawn.
3710 *
3711 * Any subclass overriding
3712 * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} should
3713 * set this property to true.
3714 *
3715 * @param enabled True to enable static transformations on children, false otherwise.
3716 *
Chet Haase599913d2012-07-23 16:22:05 -07003717 * @see #getChildStaticTransformation(View, android.view.animation.Transformation)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003718 */
3719 protected void setStaticTransformationsEnabled(boolean enabled) {
3720 setBooleanFlag(FLAG_SUPPORT_STATIC_TRANSFORMATIONS, enabled);
3721 }
3722
3723 /**
Chet Haase2d46fcc2011-12-19 18:01:05 -08003724 * Sets <code>t</code> to be the static transformation of the child, if set, returning a
3725 * boolean to indicate whether a static transform was set. The default implementation
3726 * simply returns <code>false</code>; subclasses may override this method for different
Chet Haase599913d2012-07-23 16:22:05 -07003727 * behavior. {@link #setStaticTransformationsEnabled(boolean)} must be set to true
3728 * for this method to be called.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003729 *
Chet Haase2d46fcc2011-12-19 18:01:05 -08003730 * @param child The child view whose static transform is being requested
3731 * @param t The Transformation which will hold the result
3732 * @return true if the transformation was set, false otherwise
Romain Guy8506ab42009-06-11 17:35:47 -07003733 * @see #setStaticTransformationsEnabled(boolean)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003734 */
3735 protected boolean getChildStaticTransformation(View child, Transformation t) {
3736 return false;
3737 }
3738
Romain Guyf6991302013-06-05 17:19:01 -07003739 Transformation getChildTransformation() {
3740 if (mChildTransformation == null) {
3741 mChildTransformation = new Transformation();
3742 }
3743 return mChildTransformation;
3744 }
3745
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003746 /**
3747 * {@hide}
3748 */
3749 @Override
Tor Norbye7b9c9122013-05-30 16:48:33 -07003750 protected View findViewTraversal(@IdRes int id) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003751 if (id == mID) {
3752 return this;
3753 }
3754
3755 final View[] where = mChildren;
3756 final int len = mChildrenCount;
3757
3758 for (int i = 0; i < len; i++) {
3759 View v = where[i];
3760
Dianne Hackborn4702a852012-08-17 15:18:29 -07003761 if ((v.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003762 v = v.findViewById(id);
3763
3764 if (v != null) {
3765 return v;
3766 }
3767 }
3768 }
3769
3770 return null;
3771 }
3772
3773 /**
3774 * {@hide}
3775 */
3776 @Override
3777 protected View findViewWithTagTraversal(Object tag) {
3778 if (tag != null && tag.equals(mTag)) {
3779 return this;
3780 }
3781
3782 final View[] where = mChildren;
3783 final int len = mChildrenCount;
3784
3785 for (int i = 0; i < len; i++) {
3786 View v = where[i];
3787
Dianne Hackborn4702a852012-08-17 15:18:29 -07003788 if ((v.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003789 v = v.findViewWithTag(tag);
3790
3791 if (v != null) {
3792 return v;
3793 }
3794 }
3795 }
3796
3797 return null;
3798 }
3799
3800 /**
Jeff Brown4e6319b2010-12-13 10:36:51 -08003801 * {@hide}
3802 */
3803 @Override
Jeff Brown4dfbec22011-08-15 14:55:37 -07003804 protected View findViewByPredicateTraversal(Predicate<View> predicate, View childToSkip) {
Jeff Brown4e6319b2010-12-13 10:36:51 -08003805 if (predicate.apply(this)) {
3806 return this;
3807 }
3808
3809 final View[] where = mChildren;
3810 final int len = mChildrenCount;
3811
3812 for (int i = 0; i < len; i++) {
3813 View v = where[i];
3814
Dianne Hackborn4702a852012-08-17 15:18:29 -07003815 if (v != childToSkip && (v.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) {
Jeff Brown4e6319b2010-12-13 10:36:51 -08003816 v = v.findViewByPredicate(predicate);
3817
3818 if (v != null) {
3819 return v;
3820 }
3821 }
3822 }
3823
3824 return null;
3825 }
3826
3827 /**
Chet Haasec633d2f2015-04-07 10:29:39 -07003828 * This method adds a view to this container at the specified index purely for the
3829 * purposes of allowing that view to draw even though it is not a normal child of
3830 * the container. That is, the view does not participate in layout, focus, accessibility,
3831 * input, or other normal view operations; it is purely an item to be drawn during the normal
3832 * rendering operation of this container. The index that it is added at is the order
3833 * in which it will be drawn, with respect to the other views in the container.
3834 * For example, a transient view added at index 0 will be drawn before all other views
3835 * in the container because it will be drawn first (including before any real view
3836 * at index 0). There can be more than one transient view at any particular index;
3837 * these views will be drawn in the order in which they were added to the list of
3838 * transient views. The index of transient views can also be greater than the number
3839 * of normal views in the container; that just means that they will be drawn after all
3840 * other views are drawn.
3841 *
3842 * <p>Note that since transient views do not participate in layout, they must be sized
3843 * manually or, more typically, they should just use the size that they had before they
3844 * were removed from their container.</p>
3845 *
3846 * <p>Transient views are useful for handling animations of views that have been removed
3847 * from the container, but which should be animated out after the removal. Adding these
3848 * views as transient views allows them to participate in drawing without side-effecting
3849 * the layout of the container.</p>
3850 *
3851 * <p>Transient views must always be explicitly {@link #removeTransientView(View) removed}
3852 * from the container when they are no longer needed. For example, a transient view
3853 * which is added in order to fade it out in its old location should be removed
3854 * once the animation is complete.</p>
3855 *
3856 * @param view The view to be added
3857 * @param index The index at which this view should be drawn, must be >= 0.
3858 * This value is relative to the {@link #getChildAt(int) index} values in the normal
3859 * child list of this container, where any transient view at a particular index will
3860 * be drawn before any normal child at that same index.
Chris Craik66b41392015-04-17 10:08:10 -07003861 *
3862 * @hide
Chet Haasec633d2f2015-04-07 10:29:39 -07003863 */
3864 public void addTransientView(View view, int index) {
3865 if (index < 0) {
3866 return;
3867 }
3868 if (mTransientIndices == null) {
3869 mTransientIndices = new ArrayList<Integer>();
3870 mTransientViews = new ArrayList<View>();
3871 }
3872 final int oldSize = mTransientIndices.size();
3873 if (oldSize > 0) {
3874 int insertionIndex;
3875 for (insertionIndex = 0; insertionIndex < oldSize; ++insertionIndex) {
3876 if (index < mTransientIndices.get(insertionIndex)) {
3877 break;
3878 }
3879 }
3880 mTransientIndices.add(insertionIndex, index);
3881 mTransientViews.add(insertionIndex, view);
3882 } else {
3883 mTransientIndices.add(index);
3884 mTransientViews.add(view);
3885 }
3886 view.mParent = this;
3887 view.dispatchAttachedToWindow(mAttachInfo, (mViewFlags&VISIBILITY_MASK));
3888 invalidate(true);
3889 }
3890
3891 /**
3892 * Removes a view from the list of transient views in this container. If there is no
3893 * such transient view, this method does nothing.
3894 *
3895 * @param view The transient view to be removed
Chris Craik66b41392015-04-17 10:08:10 -07003896 *
3897 * @hide
Chet Haasec633d2f2015-04-07 10:29:39 -07003898 */
3899 public void removeTransientView(View view) {
3900 if (mTransientViews == null) {
3901 return;
3902 }
3903 final int size = mTransientViews.size();
3904 for (int i = 0; i < size; ++i) {
3905 if (view == mTransientViews.get(i)) {
3906 mTransientViews.remove(i);
3907 mTransientIndices.remove(i);
3908 view.mParent = null;
3909 view.dispatchDetachedFromWindow();
3910 invalidate(true);
3911 return;
3912 }
3913 }
3914 }
3915
3916 /**
3917 * Returns the number of transient views in this container. Specific transient
3918 * views and the index at which they were added can be retrieved via
3919 * {@link #getTransientView(int)} and {@link #getTransientViewIndex(int)}.
3920 *
3921 * @see #addTransientView(View, int)
3922 * @return The number of transient views in this container
Chris Craik66b41392015-04-17 10:08:10 -07003923 *
3924 * @hide
Chet Haasec633d2f2015-04-07 10:29:39 -07003925 */
3926 public int getTransientViewCount() {
3927 return mTransientIndices == null ? 0 : mTransientIndices.size();
3928 }
3929
3930 /**
3931 * Given a valid position within the list of transient views, returns the index of
3932 * the transient view at that position.
3933 *
3934 * @param position The position of the index being queried. Must be at least 0
3935 * and less than the value returned by {@link #getTransientViewCount()}.
3936 * @return The index of the transient view stored in the given position if the
3937 * position is valid, otherwise -1
Chris Craik66b41392015-04-17 10:08:10 -07003938 *
3939 * @hide
Chet Haasec633d2f2015-04-07 10:29:39 -07003940 */
3941 public int getTransientViewIndex(int position) {
3942 if (position < 0 || mTransientIndices == null || position >= mTransientIndices.size()) {
3943 return -1;
3944 }
3945 return mTransientIndices.get(position);
3946 }
3947
3948 /**
3949 * Given a valid position within the list of transient views, returns the
3950 * transient view at that position.
3951 *
3952 * @param position The position of the view being queried. Must be at least 0
3953 * and less than the value returned by {@link #getTransientViewCount()}.
3954 * @return The transient view stored in the given position if the
3955 * position is valid, otherwise null
Chris Craik66b41392015-04-17 10:08:10 -07003956 *
3957 * @hide
Chet Haasec633d2f2015-04-07 10:29:39 -07003958 */
3959 public View getTransientView(int position) {
3960 if (mTransientViews == null || position >= mTransientViews.size()) {
3961 return null;
3962 }
3963 return mTransientViews.get(position);
3964 }
3965
3966 /**
Romain Guy393a52c2012-05-22 20:21:08 -07003967 * <p>Adds a child view. If no layout parameters are already set on the child, the
3968 * default parameters for this ViewGroup are set on the child.</p>
3969 *
3970 * <p><strong>Note:</strong> do not invoke this method from
3971 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3972 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003973 *
3974 * @param child the child view to add
3975 *
3976 * @see #generateDefaultLayoutParams()
3977 */
3978 public void addView(View child) {
3979 addView(child, -1);
3980 }
3981
3982 /**
3983 * Adds a child view. If no layout parameters are already set on the child, the
3984 * default parameters for this ViewGroup are set on the child.
Romain Guy393a52c2012-05-22 20:21:08 -07003985 *
3986 * <p><strong>Note:</strong> do not invoke this method from
3987 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3988 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003989 *
3990 * @param child the child view to add
3991 * @param index the position at which to add the child
3992 *
3993 * @see #generateDefaultLayoutParams()
3994 */
3995 public void addView(View child, int index) {
Adam Powell45a9da52014-10-09 09:44:18 -07003996 if (child == null) {
3997 throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup");
3998 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003999 LayoutParams params = child.getLayoutParams();
4000 if (params == null) {
4001 params = generateDefaultLayoutParams();
4002 if (params == null) {
4003 throw new IllegalArgumentException("generateDefaultLayoutParams() cannot return null");
4004 }
4005 }
4006 addView(child, index, params);
4007 }
4008
4009 /**
4010 * Adds a child view with this ViewGroup's default layout parameters and the
4011 * specified width and height.
4012 *
Romain Guy393a52c2012-05-22 20:21:08 -07004013 * <p><strong>Note:</strong> do not invoke this method from
4014 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
4015 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
4016 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004017 * @param child the child view to add
4018 */
4019 public void addView(View child, int width, int height) {
4020 final LayoutParams params = generateDefaultLayoutParams();
4021 params.width = width;
4022 params.height = height;
4023 addView(child, -1, params);
4024 }
4025
4026 /**
4027 * Adds a child view with the specified layout parameters.
4028 *
Romain Guy393a52c2012-05-22 20:21:08 -07004029 * <p><strong>Note:</strong> do not invoke this method from
4030 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
4031 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
4032 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004033 * @param child the child view to add
4034 * @param params the layout parameters to set on the child
4035 */
4036 public void addView(View child, LayoutParams params) {
4037 addView(child, -1, params);
4038 }
4039
4040 /**
4041 * Adds a child view with the specified layout parameters.
4042 *
Romain Guy393a52c2012-05-22 20:21:08 -07004043 * <p><strong>Note:</strong> do not invoke this method from
4044 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
4045 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
4046 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004047 * @param child the child view to add
Alan Viverette77bb6f12015-02-11 17:24:33 -08004048 * @param index the position at which to add the child or -1 to add last
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004049 * @param params the layout parameters to set on the child
4050 */
4051 public void addView(View child, int index, LayoutParams params) {
4052 if (DBG) {
4053 System.out.println(this + " addView");
4054 }
4055
Adam Powell45a9da52014-10-09 09:44:18 -07004056 if (child == null) {
4057 throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup");
4058 }
4059
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004060 // addViewInner() will call child.requestLayout() when setting the new LayoutParams
4061 // therefore, we call requestLayout() on ourselves before, so that the child's request
4062 // will be blocked at our level
4063 requestLayout();
Romain Guy849d0a32011-02-01 17:20:48 -08004064 invalidate(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004065 addViewInner(child, index, params, false);
4066 }
4067
4068 /**
4069 * {@inheritDoc}
4070 */
4071 public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
4072 if (!checkLayoutParams(params)) {
4073 throw new IllegalArgumentException("Invalid LayoutParams supplied to " + this);
4074 }
4075 if (view.mParent != this) {
4076 throw new IllegalArgumentException("Given view not a child of " + this);
4077 }
4078 view.setLayoutParams(params);
4079 }
4080
4081 /**
4082 * {@inheritDoc}
4083 */
4084 protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
4085 return p != null;
4086 }
4087
4088 /**
4089 * Interface definition for a callback to be invoked when the hierarchy
4090 * within this view changed. The hierarchy changes whenever a child is added
4091 * to or removed from this view.
4092 */
4093 public interface OnHierarchyChangeListener {
4094 /**
4095 * Called when a new child is added to a parent view.
4096 *
4097 * @param parent the view in which a child was added
4098 * @param child the new child view added in the hierarchy
4099 */
4100 void onChildViewAdded(View parent, View child);
4101
4102 /**
4103 * Called when a child is removed from a parent view.
4104 *
4105 * @param parent the view from which the child was removed
4106 * @param child the child removed from the hierarchy
4107 */
4108 void onChildViewRemoved(View parent, View child);
4109 }
4110
4111 /**
4112 * Register a callback to be invoked when a child is added to or removed
4113 * from this view.
4114 *
4115 * @param listener the callback to invoke on hierarchy change
4116 */
4117 public void setOnHierarchyChangeListener(OnHierarchyChangeListener listener) {
4118 mOnHierarchyChangeListener = listener;
4119 }
4120
4121 /**
Philip Milnef51d91c2011-07-18 16:12:19 -07004122 * @hide
4123 */
4124 protected void onViewAdded(View child) {
4125 if (mOnHierarchyChangeListener != null) {
4126 mOnHierarchyChangeListener.onChildViewAdded(this, child);
4127 }
4128 }
4129
4130 /**
4131 * @hide
4132 */
4133 protected void onViewRemoved(View child) {
4134 if (mOnHierarchyChangeListener != null) {
4135 mOnHierarchyChangeListener.onChildViewRemoved(this, child);
4136 }
4137 }
4138
Philip Milnecfb631b2012-10-26 10:51:46 -07004139 private void clearCachedLayoutMode() {
Svetoslav6254f482013-06-04 17:22:14 -07004140 if (!hasBooleanFlag(FLAG_LAYOUT_MODE_WAS_EXPLICITLY_SET)) {
Philip Milnecfb631b2012-10-26 10:51:46 -07004141 mLayoutMode = LAYOUT_MODE_UNDEFINED;
4142 }
4143 }
4144
4145 @Override
4146 protected void onAttachedToWindow() {
4147 super.onAttachedToWindow();
4148 clearCachedLayoutMode();
4149 }
4150
4151 @Override
4152 protected void onDetachedFromWindow() {
4153 super.onDetachedFromWindow();
4154 clearCachedLayoutMode();
4155 }
4156
Philip Milnef51d91c2011-07-18 16:12:19 -07004157 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004158 * Adds a view during layout. This is useful if in your onLayout() method,
4159 * you need to add more views (as does the list view for example).
4160 *
4161 * If index is negative, it means put it at the end of the list.
4162 *
4163 * @param child the view to add to the group
Alan Viverette77bb6f12015-02-11 17:24:33 -08004164 * @param index the index at which the child must be added or -1 to add last
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004165 * @param params the layout parameters to associate with the child
4166 * @return true if the child was added, false otherwise
4167 */
4168 protected boolean addViewInLayout(View child, int index, LayoutParams params) {
4169 return addViewInLayout(child, index, params, false);
4170 }
4171
4172 /**
4173 * Adds a view during layout. This is useful if in your onLayout() method,
4174 * you need to add more views (as does the list view for example).
4175 *
4176 * If index is negative, it means put it at the end of the list.
4177 *
4178 * @param child the view to add to the group
Alan Viverette77bb6f12015-02-11 17:24:33 -08004179 * @param index the index at which the child must be added or -1 to add last
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004180 * @param params the layout parameters to associate with the child
4181 * @param preventRequestLayout if true, calling this method will not trigger a
4182 * layout request on child
4183 * @return true if the child was added, false otherwise
4184 */
4185 protected boolean addViewInLayout(View child, int index, LayoutParams params,
4186 boolean preventRequestLayout) {
Adam Powell45a9da52014-10-09 09:44:18 -07004187 if (child == null) {
4188 throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup");
4189 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004190 child.mParent = null;
4191 addViewInner(child, index, params, preventRequestLayout);
Dianne Hackborn4702a852012-08-17 15:18:29 -07004192 child.mPrivateFlags = (child.mPrivateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004193 return true;
4194 }
4195
4196 /**
4197 * Prevents the specified child to be laid out during the next layout pass.
4198 *
4199 * @param child the child on which to perform the cleanup
4200 */
4201 protected void cleanupLayoutState(View child) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07004202 child.mPrivateFlags &= ~View.PFLAG_FORCE_LAYOUT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004203 }
4204
4205 private void addViewInner(View child, int index, LayoutParams params,
4206 boolean preventRequestLayout) {
4207
Chet Haasee8e45d32011-03-02 17:07:35 -08004208 if (mTransition != null) {
4209 // Don't prevent other add transitions from completing, but cancel remove
4210 // transitions to let them complete the process before we add to the container
4211 mTransition.cancel(LayoutTransition.DISAPPEARING);
Chet Haaseadd65772011-02-09 16:47:29 -08004212 }
4213
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004214 if (child.getParent() != null) {
4215 throw new IllegalStateException("The specified child already has a parent. " +
4216 "You must call removeView() on the child's parent first.");
4217 }
4218
Chet Haase21cd1382010-09-01 17:42:29 -07004219 if (mTransition != null) {
Chet Haase5e25c2c2010-09-16 11:15:56 -07004220 mTransition.addChild(this, child);
Chet Haase21cd1382010-09-01 17:42:29 -07004221 }
4222
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004223 if (!checkLayoutParams(params)) {
4224 params = generateLayoutParams(params);
4225 }
4226
4227 if (preventRequestLayout) {
4228 child.mLayoutParams = params;
4229 } else {
4230 child.setLayoutParams(params);
4231 }
4232
4233 if (index < 0) {
4234 index = mChildrenCount;
4235 }
4236
4237 addInArray(child, index);
4238
4239 // tell our children
4240 if (preventRequestLayout) {
4241 child.assignParent(this);
4242 } else {
4243 child.mParent = this;
4244 }
4245
4246 if (child.hasFocus()) {
4247 requestChildFocus(child, child.findFocus());
4248 }
Romain Guy8506ab42009-06-11 17:35:47 -07004249
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004250 AttachInfo ai = mAttachInfo;
Adam Powell4b867882011-09-16 12:59:46 -07004251 if (ai != null && (mGroupFlags & FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW) == 0) {
Romain Guy8506ab42009-06-11 17:35:47 -07004252 boolean lastKeepOn = ai.mKeepScreenOn;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004253 ai.mKeepScreenOn = false;
4254 child.dispatchAttachedToWindow(mAttachInfo, (mViewFlags&VISIBILITY_MASK));
4255 if (ai.mKeepScreenOn) {
4256 needGlobalAttributesUpdate(true);
4257 }
4258 ai.mKeepScreenOn = lastKeepOn;
4259 }
4260
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07004261 if (child.isLayoutDirectionInherited()) {
Fabrice Di Meglioa7e0bcd2012-10-16 19:55:01 -07004262 child.resetRtlProperties();
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07004263 }
4264
Philip Milnef51d91c2011-07-18 16:12:19 -07004265 onViewAdded(child);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004266
4267 if ((child.mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE) {
4268 mGroupFlags |= FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE;
4269 }
Adam Powell539ee872012-02-03 19:00:49 -08004270
4271 if (child.hasTransientState()) {
4272 childHasTransientStateChanged(child, true);
4273 }
Svetoslav6254f482013-06-04 17:22:14 -07004274
Svetoslav8e3feb12014-02-24 13:46:47 -08004275 if (child.getVisibility() != View.GONE) {
Svetoslav00dbe812013-06-10 12:51:09 -07004276 notifySubtreeAccessibilityStateChangedIfNeeded();
Svetoslav6254f482013-06-04 17:22:14 -07004277 }
Chet Haasec633d2f2015-04-07 10:29:39 -07004278
4279 if (mTransientIndices != null) {
4280 final int transientCount = mTransientIndices.size();
4281 for (int i = 0; i < transientCount; ++i) {
4282 final int oldIndex = mTransientIndices.get(i);
4283 if (index <= oldIndex) {
4284 mTransientIndices.set(i, oldIndex + 1);
4285 }
4286 }
4287 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004288 }
4289
4290 private void addInArray(View child, int index) {
4291 View[] children = mChildren;
4292 final int count = mChildrenCount;
4293 final int size = children.length;
4294 if (index == count) {
4295 if (size == count) {
4296 mChildren = new View[size + ARRAY_CAPACITY_INCREMENT];
4297 System.arraycopy(children, 0, mChildren, 0, size);
4298 children = mChildren;
4299 }
4300 children[mChildrenCount++] = child;
4301 } else if (index < count) {
4302 if (size == count) {
4303 mChildren = new View[size + ARRAY_CAPACITY_INCREMENT];
4304 System.arraycopy(children, 0, mChildren, 0, index);
4305 System.arraycopy(children, index, mChildren, index + 1, count - index);
4306 children = mChildren;
4307 } else {
4308 System.arraycopy(children, index, children, index + 1, count - index);
4309 }
4310 children[index] = child;
4311 mChildrenCount++;
Joe Onorato03ab0c72011-01-06 15:46:27 -08004312 if (mLastTouchDownIndex >= index) {
4313 mLastTouchDownIndex++;
4314 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004315 } else {
4316 throw new IndexOutOfBoundsException("index=" + index + " count=" + count);
4317 }
4318 }
4319
4320 // This method also sets the child's mParent to null
4321 private void removeFromArray(int index) {
4322 final View[] children = mChildren;
Chet Haase21cd1382010-09-01 17:42:29 -07004323 if (!(mTransitioningViews != null && mTransitioningViews.contains(children[index]))) {
4324 children[index].mParent = null;
4325 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004326 final int count = mChildrenCount;
4327 if (index == count - 1) {
4328 children[--mChildrenCount] = null;
4329 } else if (index >= 0 && index < count) {
4330 System.arraycopy(children, index + 1, children, index, count - index - 1);
4331 children[--mChildrenCount] = null;
4332 } else {
4333 throw new IndexOutOfBoundsException();
4334 }
Joe Onorato03ab0c72011-01-06 15:46:27 -08004335 if (mLastTouchDownIndex == index) {
4336 mLastTouchDownTime = 0;
4337 mLastTouchDownIndex = -1;
4338 } else if (mLastTouchDownIndex > index) {
4339 mLastTouchDownIndex--;
4340 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004341 }
4342
4343 // This method also sets the children's mParent to null
4344 private void removeFromArray(int start, int count) {
4345 final View[] children = mChildren;
4346 final int childrenCount = mChildrenCount;
4347
4348 start = Math.max(0, start);
4349 final int end = Math.min(childrenCount, start + count);
4350
4351 if (start == end) {
4352 return;
4353 }
4354
4355 if (end == childrenCount) {
4356 for (int i = start; i < end; i++) {
4357 children[i].mParent = null;
4358 children[i] = null;
4359 }
4360 } else {
4361 for (int i = start; i < end; i++) {
4362 children[i].mParent = null;
4363 }
4364
4365 // Since we're looping above, we might as well do the copy, but is arraycopy()
4366 // faster than the extra 2 bounds checks we would do in the loop?
4367 System.arraycopy(children, end, children, start, childrenCount - end);
4368
4369 for (int i = childrenCount - (end - start); i < childrenCount; i++) {
4370 children[i] = null;
4371 }
4372 }
4373
4374 mChildrenCount -= (end - start);
4375 }
4376
4377 private void bindLayoutAnimation(View child) {
4378 Animation a = mLayoutAnimationController.getAnimationForView(child);
4379 child.setAnimation(a);
4380 }
4381
4382 /**
4383 * Subclasses should override this method to set layout animation
4384 * parameters on the supplied child.
4385 *
4386 * @param child the child to associate with animation parameters
4387 * @param params the child's layout parameters which hold the animation
4388 * parameters
4389 * @param index the index of the child in the view group
4390 * @param count the number of children in the view group
4391 */
4392 protected void attachLayoutAnimationParameters(View child,
4393 LayoutParams params, int index, int count) {
4394 LayoutAnimationController.AnimationParameters animationParams =
4395 params.layoutAnimationParameters;
4396 if (animationParams == null) {
4397 animationParams = new LayoutAnimationController.AnimationParameters();
4398 params.layoutAnimationParameters = animationParams;
4399 }
4400
4401 animationParams.count = count;
4402 animationParams.index = index;
4403 }
4404
4405 /**
4406 * {@inheritDoc}
Romain Guy393a52c2012-05-22 20:21:08 -07004407 *
4408 * <p><strong>Note:</strong> do not invoke this method from
4409 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
4410 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004411 */
4412 public void removeView(View view) {
Alan Viverette177ec4602014-10-17 13:34:50 -07004413 if (removeViewInternal(view)) {
4414 requestLayout();
4415 invalidate(true);
4416 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004417 }
4418
4419 /**
4420 * Removes a view during layout. This is useful if in your onLayout() method,
4421 * you need to remove more views.
4422 *
Romain Guy393a52c2012-05-22 20:21:08 -07004423 * <p><strong>Note:</strong> do not invoke this method from
4424 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
4425 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
4426 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004427 * @param view the view to remove from the group
4428 */
4429 public void removeViewInLayout(View view) {
4430 removeViewInternal(view);
4431 }
4432
4433 /**
4434 * Removes a range of views during layout. This is useful if in your onLayout() method,
4435 * you need to remove more views.
4436 *
Romain Guy393a52c2012-05-22 20:21:08 -07004437 * <p><strong>Note:</strong> do not invoke this method from
4438 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
4439 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
4440 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004441 * @param start the index of the first view to remove from the group
4442 * @param count the number of views to remove from the group
4443 */
4444 public void removeViewsInLayout(int start, int count) {
4445 removeViewsInternal(start, count);
4446 }
4447
4448 /**
4449 * Removes the view at the specified position in the group.
4450 *
Romain Guy393a52c2012-05-22 20:21:08 -07004451 * <p><strong>Note:</strong> do not invoke this method from
4452 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
4453 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
4454 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004455 * @param index the position in the group of the view to remove
4456 */
4457 public void removeViewAt(int index) {
4458 removeViewInternal(index, getChildAt(index));
4459 requestLayout();
Romain Guy849d0a32011-02-01 17:20:48 -08004460 invalidate(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004461 }
4462
4463 /**
4464 * Removes the specified range of views from the group.
4465 *
Romain Guy393a52c2012-05-22 20:21:08 -07004466 * <p><strong>Note:</strong> do not invoke this method from
4467 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
4468 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
4469 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004470 * @param start the first position in the group of the range of views to remove
4471 * @param count the number of views to remove
4472 */
4473 public void removeViews(int start, int count) {
4474 removeViewsInternal(start, count);
4475 requestLayout();
Romain Guy849d0a32011-02-01 17:20:48 -08004476 invalidate(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004477 }
4478
Alan Viverette177ec4602014-10-17 13:34:50 -07004479 private boolean removeViewInternal(View view) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004480 final int index = indexOfChild(view);
4481 if (index >= 0) {
4482 removeViewInternal(index, view);
Alan Viverette177ec4602014-10-17 13:34:50 -07004483 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004484 }
Alan Viverette177ec4602014-10-17 13:34:50 -07004485 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004486 }
4487
4488 private void removeViewInternal(int index, View view) {
Chet Haase21cd1382010-09-01 17:42:29 -07004489
4490 if (mTransition != null) {
Chet Haase5e25c2c2010-09-16 11:15:56 -07004491 mTransition.removeChild(this, view);
Chet Haase21cd1382010-09-01 17:42:29 -07004492 }
4493
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004494 boolean clearChildFocus = false;
4495 if (view == mFocused) {
Alan Viverette223622a2013-12-17 13:29:02 -08004496 view.unFocus(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004497 clearChildFocus = true;
4498 }
4499
Alan Viverette632af842014-10-28 13:45:11 -07004500 view.clearAccessibilityFocus();
Svetoslav Ganov961bf0e2012-05-08 09:40:03 -07004501
Jeff Brown59a422e2012-04-19 15:19:19 -07004502 cancelTouchTarget(view);
4503 cancelHoverTarget(view);
4504
Chet Haase21cd1382010-09-01 17:42:29 -07004505 if (view.getAnimation() != null ||
4506 (mTransitioningViews != null && mTransitioningViews.contains(view))) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004507 addDisappearingView(view);
4508 } else if (view.mAttachInfo != null) {
4509 view.dispatchDetachedFromWindow();
4510 }
4511
Adam Powell539ee872012-02-03 19:00:49 -08004512 if (view.hasTransientState()) {
4513 childHasTransientStateChanged(view, false);
4514 }
4515
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004516 needGlobalAttributesUpdate(false);
Romain Guy8506ab42009-06-11 17:35:47 -07004517
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004518 removeFromArray(index);
4519
4520 if (clearChildFocus) {
4521 clearChildFocus(view);
Svetoslav Ganov149567f2013-01-08 15:23:34 -08004522 if (!rootViewRequestFocus()) {
4523 notifyGlobalFocusCleared(this);
4524 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07004525 }
Romain Guy6fb05632012-11-29 10:50:33 -08004526
4527 onViewRemoved(view);
Svetoslav6254f482013-06-04 17:22:14 -07004528
Svetoslav8e3feb12014-02-24 13:46:47 -08004529 if (view.getVisibility() != View.GONE) {
Svetoslav00dbe812013-06-10 12:51:09 -07004530 notifySubtreeAccessibilityStateChangedIfNeeded();
Svetoslav6254f482013-06-04 17:22:14 -07004531 }
Chet Haasec633d2f2015-04-07 10:29:39 -07004532
4533 int transientCount = mTransientIndices == null ? 0 : mTransientIndices.size();
4534 for (int i = 0; i < transientCount; ++i) {
4535 final int oldIndex = mTransientIndices.get(i);
4536 if (index < oldIndex) {
4537 mTransientIndices.set(i, oldIndex - 1);
4538 }
4539 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004540 }
4541
Chet Haase21cd1382010-09-01 17:42:29 -07004542 /**
4543 * Sets the LayoutTransition object for this ViewGroup. If the LayoutTransition object is
4544 * not null, changes in layout which occur because of children being added to or removed from
4545 * the ViewGroup will be animated according to the animations defined in that LayoutTransition
4546 * object. By default, the transition object is null (so layout changes are not animated).
4547 *
Chet Haaseef3cbfd2013-08-21 14:01:02 -07004548 * <p>Replacing a non-null transition will cause that previous transition to be
4549 * canceled, if it is currently running, to restore this container to
4550 * its correct post-transition state.</p>
4551 *
Chet Haase21cd1382010-09-01 17:42:29 -07004552 * @param transition The LayoutTransition object that will animated changes in layout. A value
4553 * of <code>null</code> means no transition will run on layout changes.
Chet Haase13cc1202010-09-03 15:39:20 -07004554 * @attr ref android.R.styleable#ViewGroup_animateLayoutChanges
Chet Haase21cd1382010-09-01 17:42:29 -07004555 */
4556 public void setLayoutTransition(LayoutTransition transition) {
Chet Haaseb20db3e2010-09-10 13:07:30 -07004557 if (mTransition != null) {
Chet Haasefee6f2b2013-08-27 12:22:29 -07004558 LayoutTransition previousTransition = mTransition;
4559 previousTransition.cancel();
4560 previousTransition.removeTransitionListener(mLayoutTransitionListener);
Chet Haaseb20db3e2010-09-10 13:07:30 -07004561 }
Chet Haase21cd1382010-09-01 17:42:29 -07004562 mTransition = transition;
Chet Haase13cc1202010-09-03 15:39:20 -07004563 if (mTransition != null) {
4564 mTransition.addTransitionListener(mLayoutTransitionListener);
4565 }
4566 }
4567
4568 /**
4569 * Gets the LayoutTransition object for this ViewGroup. If the LayoutTransition object is
4570 * not null, changes in layout which occur because of children being added to or removed from
4571 * the ViewGroup will be animated according to the animations defined in that LayoutTransition
4572 * object. By default, the transition object is null (so layout changes are not animated).
4573 *
4574 * @return LayoutTranstion The LayoutTransition object that will animated changes in layout.
4575 * A value of <code>null</code> means no transition will run on layout changes.
4576 */
4577 public LayoutTransition getLayoutTransition() {
4578 return mTransition;
Chet Haase21cd1382010-09-01 17:42:29 -07004579 }
4580
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004581 private void removeViewsInternal(int start, int count) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004582 final View focused = mFocused;
4583 final boolean detach = mAttachInfo != null;
Svetoslav Ganov149567f2013-01-08 15:23:34 -08004584 boolean clearChildFocus = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004585
4586 final View[] children = mChildren;
4587 final int end = start + count;
4588
4589 for (int i = start; i < end; i++) {
4590 final View view = children[i];
4591
Chet Haase21cd1382010-09-01 17:42:29 -07004592 if (mTransition != null) {
Chet Haase5e25c2c2010-09-16 11:15:56 -07004593 mTransition.removeChild(this, view);
Chet Haase21cd1382010-09-01 17:42:29 -07004594 }
4595
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004596 if (view == focused) {
Alan Viverette223622a2013-12-17 13:29:02 -08004597 view.unFocus(null);
Svetoslav Ganov149567f2013-01-08 15:23:34 -08004598 clearChildFocus = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004599 }
4600
Alan Viverette632af842014-10-28 13:45:11 -07004601 view.clearAccessibilityFocus();
Svetoslav Ganov961bf0e2012-05-08 09:40:03 -07004602
Jeff Brown59a422e2012-04-19 15:19:19 -07004603 cancelTouchTarget(view);
4604 cancelHoverTarget(view);
4605
Chet Haase21cd1382010-09-01 17:42:29 -07004606 if (view.getAnimation() != null ||
4607 (mTransitioningViews != null && mTransitioningViews.contains(view))) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004608 addDisappearingView(view);
4609 } else if (detach) {
4610 view.dispatchDetachedFromWindow();
4611 }
4612
Adam Powell539ee872012-02-03 19:00:49 -08004613 if (view.hasTransientState()) {
4614 childHasTransientStateChanged(view, false);
4615 }
4616
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004617 needGlobalAttributesUpdate(false);
Romain Guy8506ab42009-06-11 17:35:47 -07004618
Philip Milnef51d91c2011-07-18 16:12:19 -07004619 onViewRemoved(view);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004620 }
4621
4622 removeFromArray(start, count);
4623
Svetoslav Ganov149567f2013-01-08 15:23:34 -08004624 if (clearChildFocus) {
4625 clearChildFocus(focused);
4626 if (!rootViewRequestFocus()) {
4627 notifyGlobalFocusCleared(focused);
4628 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004629 }
4630 }
4631
4632 /**
4633 * Call this method to remove all child views from the
4634 * ViewGroup.
Romain Guy393a52c2012-05-22 20:21:08 -07004635 *
4636 * <p><strong>Note:</strong> do not invoke this method from
4637 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
4638 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004639 */
4640 public void removeAllViews() {
4641 removeAllViewsInLayout();
4642 requestLayout();
Romain Guy849d0a32011-02-01 17:20:48 -08004643 invalidate(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004644 }
4645
4646 /**
4647 * Called by a ViewGroup subclass to remove child views from itself,
4648 * when it must first know its size on screen before it can calculate how many
4649 * child views it will render. An example is a Gallery or a ListView, which
4650 * may "have" 50 children, but actually only render the number of children
4651 * that can currently fit inside the object on screen. Do not call
4652 * this method unless you are extending ViewGroup and understand the
4653 * view measuring and layout pipeline.
Romain Guy393a52c2012-05-22 20:21:08 -07004654 *
4655 * <p><strong>Note:</strong> do not invoke this method from
4656 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
4657 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004658 */
4659 public void removeAllViewsInLayout() {
4660 final int count = mChildrenCount;
4661 if (count <= 0) {
4662 return;
4663 }
4664
4665 final View[] children = mChildren;
4666 mChildrenCount = 0;
4667
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004668 final View focused = mFocused;
4669 final boolean detach = mAttachInfo != null;
Svetoslav Ganov149567f2013-01-08 15:23:34 -08004670 boolean clearChildFocus = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004671
4672 needGlobalAttributesUpdate(false);
Romain Guy8506ab42009-06-11 17:35:47 -07004673
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004674 for (int i = count - 1; i >= 0; i--) {
4675 final View view = children[i];
4676
Chet Haase21cd1382010-09-01 17:42:29 -07004677 if (mTransition != null) {
Chet Haase5e25c2c2010-09-16 11:15:56 -07004678 mTransition.removeChild(this, view);
Chet Haase21cd1382010-09-01 17:42:29 -07004679 }
4680
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004681 if (view == focused) {
Alan Viverette223622a2013-12-17 13:29:02 -08004682 view.unFocus(null);
Svetoslav Ganov149567f2013-01-08 15:23:34 -08004683 clearChildFocus = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004684 }
4685
Alan Viverette632af842014-10-28 13:45:11 -07004686 view.clearAccessibilityFocus();
Svetoslav Ganov961bf0e2012-05-08 09:40:03 -07004687
Jeff Brown59a422e2012-04-19 15:19:19 -07004688 cancelTouchTarget(view);
4689 cancelHoverTarget(view);
4690
Chet Haase21cd1382010-09-01 17:42:29 -07004691 if (view.getAnimation() != null ||
4692 (mTransitioningViews != null && mTransitioningViews.contains(view))) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004693 addDisappearingView(view);
4694 } else if (detach) {
4695 view.dispatchDetachedFromWindow();
4696 }
4697
Adam Powell539ee872012-02-03 19:00:49 -08004698 if (view.hasTransientState()) {
4699 childHasTransientStateChanged(view, false);
4700 }
4701
Philip Milnef51d91c2011-07-18 16:12:19 -07004702 onViewRemoved(view);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004703
4704 view.mParent = null;
4705 children[i] = null;
4706 }
4707
Svetoslav Ganov149567f2013-01-08 15:23:34 -08004708 if (clearChildFocus) {
4709 clearChildFocus(focused);
4710 if (!rootViewRequestFocus()) {
4711 notifyGlobalFocusCleared(focused);
4712 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004713 }
4714 }
4715
4716 /**
4717 * Finishes the removal of a detached view. This method will dispatch the detached from
4718 * window event and notify the hierarchy change listener.
Chet Haaseca479d42012-08-30 17:20:08 -07004719 * <p>
4720 * This method is intended to be lightweight and makes no assumptions about whether the
4721 * parent or child should be redrawn. Proper use of this method will include also making
4722 * any appropriate {@link #requestLayout()} or {@link #invalidate()} calls.
4723 * For example, callers can {@link #post(Runnable) post} a {@link Runnable}
4724 * which performs a {@link #requestLayout()} on the next frame, after all detach/remove
4725 * calls are finished, causing layout to be run prior to redrawing the view hierarchy.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004726 *
4727 * @param child the child to be definitely removed from the view hierarchy
4728 * @param animate if true and the view has an animation, the view is placed in the
4729 * disappearing views list, otherwise, it is detached from the window
4730 *
4731 * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
4732 * @see #detachAllViewsFromParent()
4733 * @see #detachViewFromParent(View)
4734 * @see #detachViewFromParent(int)
4735 */
4736 protected void removeDetachedView(View child, boolean animate) {
Chet Haase21cd1382010-09-01 17:42:29 -07004737 if (mTransition != null) {
Chet Haase5e25c2c2010-09-16 11:15:56 -07004738 mTransition.removeChild(this, child);
Chet Haase21cd1382010-09-01 17:42:29 -07004739 }
4740
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004741 if (child == mFocused) {
4742 child.clearFocus();
4743 }
Romain Guy8506ab42009-06-11 17:35:47 -07004744
Svetoslav Ganov961bf0e2012-05-08 09:40:03 -07004745 child.clearAccessibilityFocus();
4746
Jeff Brown59a422e2012-04-19 15:19:19 -07004747 cancelTouchTarget(child);
4748 cancelHoverTarget(child);
4749
Chet Haase21cd1382010-09-01 17:42:29 -07004750 if ((animate && child.getAnimation() != null) ||
4751 (mTransitioningViews != null && mTransitioningViews.contains(child))) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004752 addDisappearingView(child);
4753 } else if (child.mAttachInfo != null) {
4754 child.dispatchDetachedFromWindow();
4755 }
4756
Adam Powell539ee872012-02-03 19:00:49 -08004757 if (child.hasTransientState()) {
4758 childHasTransientStateChanged(child, false);
4759 }
4760
Philip Milnef51d91c2011-07-18 16:12:19 -07004761 onViewRemoved(child);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004762 }
4763
4764 /**
4765 * Attaches a view to this view group. Attaching a view assigns this group as the parent,
Chet Haaseca479d42012-08-30 17:20:08 -07004766 * sets the layout parameters and puts the view in the list of children so that
4767 * it can be retrieved by calling {@link #getChildAt(int)}.
4768 * <p>
4769 * This method is intended to be lightweight and makes no assumptions about whether the
4770 * parent or child should be redrawn. Proper use of this method will include also making
4771 * any appropriate {@link #requestLayout()} or {@link #invalidate()} calls.
4772 * For example, callers can {@link #post(Runnable) post} a {@link Runnable}
4773 * which performs a {@link #requestLayout()} on the next frame, after all detach/attach
4774 * calls are finished, causing layout to be run prior to redrawing the view hierarchy.
4775 * <p>
4776 * This method should be called only for views which were detached from their parent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004777 *
4778 * @param child the child to attach
4779 * @param index the index at which the child should be attached
4780 * @param params the layout parameters of the child
4781 *
4782 * @see #removeDetachedView(View, boolean)
4783 * @see #detachAllViewsFromParent()
4784 * @see #detachViewFromParent(View)
4785 * @see #detachViewFromParent(int)
4786 */
4787 protected void attachViewToParent(View child, int index, LayoutParams params) {
4788 child.mLayoutParams = params;
4789
4790 if (index < 0) {
4791 index = mChildrenCount;
4792 }
4793
4794 addInArray(child, index);
4795
4796 child.mParent = this;
Dianne Hackborn4702a852012-08-17 15:18:29 -07004797 child.mPrivateFlags = (child.mPrivateFlags & ~PFLAG_DIRTY_MASK
4798 & ~PFLAG_DRAWING_CACHE_VALID)
4799 | PFLAG_DRAWN | PFLAG_INVALIDATED;
4800 this.mPrivateFlags |= PFLAG_INVALIDATED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004801
4802 if (child.hasFocus()) {
4803 requestChildFocus(child, child.findFocus());
4804 }
4805 }
4806
4807 /**
Chet Haaseca479d42012-08-30 17:20:08 -07004808 * Detaches a view from its parent. Detaching a view should be followed
4809 * either by a call to
4810 * {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
4811 * or a call to {@link #removeDetachedView(View, boolean)}. Detachment should only be
4812 * temporary; reattachment or removal should happen within the same drawing cycle as
4813 * detachment. When a view is detached, its parent is null and cannot be retrieved by a
4814 * call to {@link #getChildAt(int)}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004815 *
4816 * @param child the child to detach
4817 *
4818 * @see #detachViewFromParent(int)
4819 * @see #detachViewsFromParent(int, int)
4820 * @see #detachAllViewsFromParent()
4821 * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
4822 * @see #removeDetachedView(View, boolean)
4823 */
4824 protected void detachViewFromParent(View child) {
4825 removeFromArray(indexOfChild(child));
4826 }
4827
4828 /**
Chet Haaseca479d42012-08-30 17:20:08 -07004829 * Detaches a view from its parent. Detaching a view should be followed
4830 * either by a call to
4831 * {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
4832 * or a call to {@link #removeDetachedView(View, boolean)}. Detachment should only be
4833 * temporary; reattachment or removal should happen within the same drawing cycle as
4834 * detachment. When a view is detached, its parent is null and cannot be retrieved by a
4835 * call to {@link #getChildAt(int)}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004836 *
4837 * @param index the index of the child to detach
4838 *
4839 * @see #detachViewFromParent(View)
4840 * @see #detachAllViewsFromParent()
4841 * @see #detachViewsFromParent(int, int)
4842 * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
4843 * @see #removeDetachedView(View, boolean)
4844 */
4845 protected void detachViewFromParent(int index) {
4846 removeFromArray(index);
4847 }
4848
4849 /**
Chet Haaseca479d42012-08-30 17:20:08 -07004850 * Detaches a range of views from their parents. Detaching a view should be followed
4851 * either by a call to
4852 * {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
4853 * or a call to {@link #removeDetachedView(View, boolean)}. Detachment should only be
4854 * temporary; reattachment or removal should happen within the same drawing cycle as
4855 * detachment. When a view is detached, its parent is null and cannot be retrieved by a
4856 * call to {@link #getChildAt(int)}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004857 *
4858 * @param start the first index of the childrend range to detach
4859 * @param count the number of children to detach
4860 *
4861 * @see #detachViewFromParent(View)
4862 * @see #detachViewFromParent(int)
4863 * @see #detachAllViewsFromParent()
4864 * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
4865 * @see #removeDetachedView(View, boolean)
4866 */
4867 protected void detachViewsFromParent(int start, int count) {
4868 removeFromArray(start, count);
4869 }
4870
4871 /**
Chet Haaseca479d42012-08-30 17:20:08 -07004872 * Detaches all views from the parent. Detaching a view should be followed
4873 * either by a call to
4874 * {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
4875 * or a call to {@link #removeDetachedView(View, boolean)}. Detachment should only be
4876 * temporary; reattachment or removal should happen within the same drawing cycle as
4877 * detachment. When a view is detached, its parent is null and cannot be retrieved by a
4878 * call to {@link #getChildAt(int)}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004879 *
4880 * @see #detachViewFromParent(View)
4881 * @see #detachViewFromParent(int)
4882 * @see #detachViewsFromParent(int, int)
4883 * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
4884 * @see #removeDetachedView(View, boolean)
4885 */
4886 protected void detachAllViewsFromParent() {
4887 final int count = mChildrenCount;
4888 if (count <= 0) {
4889 return;
4890 }
4891
4892 final View[] children = mChildren;
4893 mChildrenCount = 0;
4894
4895 for (int i = count - 1; i >= 0; i--) {
4896 children[i].mParent = null;
4897 children[i] = null;
4898 }
4899 }
4900
4901 /**
4902 * Don't call or override this method. It is used for the implementation of
4903 * the view hierarchy.
4904 */
4905 public final void invalidateChild(View child, final Rect dirty) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004906 ViewParent parent = this;
4907
4908 final AttachInfo attachInfo = mAttachInfo;
4909 if (attachInfo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004910 // If the child is drawing an animation, we want to copy this flag onto
4911 // ourselves and the parent to make sure the invalidate request goes
4912 // through
Dianne Hackborn4702a852012-08-17 15:18:29 -07004913 final boolean drawAnimation = (child.mPrivateFlags & PFLAG_DRAW_ANIMATION)
4914 == PFLAG_DRAW_ANIMATION;
Romain Guy24443ea2009-05-11 11:56:30 -07004915
Romain Guyfe455af2012-02-15 16:40:20 -08004916 // Check whether the child that requests the invalidate is fully opaque
4917 // Views being animated or transformed are not considered opaque because we may
4918 // be invalidating their old position and need the parent to paint behind them.
4919 Matrix childMatrix = child.getMatrix();
4920 final boolean isOpaque = child.isOpaque() && !drawAnimation &&
4921 child.getAnimation() == null && childMatrix.isIdentity();
4922 // Mark the child as dirty, using the appropriate flag
4923 // Make sure we do not set both flags at the same time
Dianne Hackborn4702a852012-08-17 15:18:29 -07004924 int opaqueFlag = isOpaque ? PFLAG_DIRTY_OPAQUE : PFLAG_DIRTY;
Romain Guyfe455af2012-02-15 16:40:20 -08004925
John Reck96bb8ad2014-06-19 10:53:03 -07004926 if (child.mLayerType != LAYER_TYPE_NONE) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07004927 mPrivateFlags |= PFLAG_INVALIDATED;
4928 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
Romain Guyfe455af2012-02-15 16:40:20 -08004929 }
4930
4931 final int[] location = attachInfo.mInvalidateChildLocation;
4932 location[CHILD_LEFT_INDEX] = child.mLeft;
4933 location[CHILD_TOP_INDEX] = child.mTop;
Chet Haase599913d2012-07-23 16:22:05 -07004934 if (!childMatrix.isIdentity() ||
4935 (mGroupFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) {
Romain Guyfe455af2012-02-15 16:40:20 -08004936 RectF boundingRect = attachInfo.mTmpTransformRect;
4937 boundingRect.set(dirty);
Chet Haase599913d2012-07-23 16:22:05 -07004938 Matrix transformMatrix;
4939 if ((mGroupFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) {
4940 Transformation t = attachInfo.mTmpTransformation;
4941 boolean transformed = getChildStaticTransformation(child, t);
4942 if (transformed) {
4943 transformMatrix = attachInfo.mTmpMatrix;
4944 transformMatrix.set(t.getMatrix());
4945 if (!childMatrix.isIdentity()) {
4946 transformMatrix.preConcat(childMatrix);
4947 }
4948 } else {
4949 transformMatrix = childMatrix;
4950 }
4951 } else {
4952 transformMatrix = childMatrix;
4953 }
4954 transformMatrix.mapRect(boundingRect);
Romain Guyfe455af2012-02-15 16:40:20 -08004955 dirty.set((int) (boundingRect.left - 0.5f),
4956 (int) (boundingRect.top - 0.5f),
4957 (int) (boundingRect.right + 0.5f),
4958 (int) (boundingRect.bottom + 0.5f));
4959 }
4960
4961 do {
4962 View view = null;
4963 if (parent instanceof View) {
4964 view = (View) parent;
Romain Guyfe455af2012-02-15 16:40:20 -08004965 }
4966
4967 if (drawAnimation) {
4968 if (view != null) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07004969 view.mPrivateFlags |= PFLAG_DRAW_ANIMATION;
Romain Guyfe455af2012-02-15 16:40:20 -08004970 } else if (parent instanceof ViewRootImpl) {
4971 ((ViewRootImpl) parent).mIsAnimating = true;
4972 }
4973 }
4974
4975 // If the parent is dirty opaque or not dirty, mark it dirty with the opaque
4976 // flag coming from the child that initiated the invalidate
4977 if (view != null) {
4978 if ((view.mViewFlags & FADING_EDGE_MASK) != 0 &&
4979 view.getSolidColor() == 0) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07004980 opaqueFlag = PFLAG_DIRTY;
Romain Guyfe455af2012-02-15 16:40:20 -08004981 }
Dianne Hackborn4702a852012-08-17 15:18:29 -07004982 if ((view.mPrivateFlags & PFLAG_DIRTY_MASK) != PFLAG_DIRTY) {
4983 view.mPrivateFlags = (view.mPrivateFlags & ~PFLAG_DIRTY_MASK) | opaqueFlag;
Romain Guyfe455af2012-02-15 16:40:20 -08004984 }
4985 }
4986
4987 parent = parent.invalidateChildInParent(location, dirty);
4988 if (view != null) {
4989 // Account for transform on current parent
4990 Matrix m = view.getMatrix();
4991 if (!m.isIdentity()) {
4992 RectF boundingRect = attachInfo.mTmpTransformRect;
4993 boundingRect.set(dirty);
4994 m.mapRect(boundingRect);
Romain Guye8585b12012-02-17 18:28:47 -08004995 dirty.set((int) (boundingRect.left - 0.5f),
4996 (int) (boundingRect.top - 0.5f),
Romain Guyfe455af2012-02-15 16:40:20 -08004997 (int) (boundingRect.right + 0.5f),
4998 (int) (boundingRect.bottom + 0.5f));
4999 }
5000 }
5001 } while (parent != null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005002 }
5003 }
5004
5005 /**
5006 * Don't call or override this method. It is used for the implementation of
5007 * the view hierarchy.
5008 *
5009 * This implementation returns null if this ViewGroup does not have a parent,
5010 * if this ViewGroup is already fully invalidated or if the dirty rectangle
5011 * does not intersect with this ViewGroup's bounds.
5012 */
5013 public ViewParent invalidateChildInParent(final int[] location, final Rect dirty) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07005014 if ((mPrivateFlags & PFLAG_DRAWN) == PFLAG_DRAWN ||
5015 (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005016 if ((mGroupFlags & (FLAG_OPTIMIZE_INVALIDATE | FLAG_ANIMATION_DONE)) !=
5017 FLAG_OPTIMIZE_INVALIDATE) {
5018 dirty.offset(location[CHILD_LEFT_INDEX] - mScrollX,
5019 location[CHILD_TOP_INDEX] - mScrollY);
Chet Haasea4f14eb2013-04-22 11:11:39 -07005020 if ((mGroupFlags & FLAG_CLIP_CHILDREN) == 0) {
5021 dirty.union(0, 0, mRight - mLeft, mBottom - mTop);
5022 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005023
5024 final int left = mLeft;
5025 final int top = mTop;
5026
Chet Haase05e91ed2012-07-03 14:17:57 -07005027 if ((mGroupFlags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN) {
5028 if (!dirty.intersect(0, 0, mRight - left, mBottom - top)) {
5029 dirty.setEmpty();
Romain Guy3a3133d2011-02-01 22:59:58 -08005030 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005031 }
Dianne Hackborn4702a852012-08-17 15:18:29 -07005032 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
Chet Haase05e91ed2012-07-03 14:17:57 -07005033
5034 location[CHILD_LEFT_INDEX] = left;
5035 location[CHILD_TOP_INDEX] = top;
5036
John Reck96bb8ad2014-06-19 10:53:03 -07005037 if (mLayerType != LAYER_TYPE_NONE) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07005038 mPrivateFlags |= PFLAG_INVALIDATED;
Chet Haase05e91ed2012-07-03 14:17:57 -07005039 }
5040
5041 return mParent;
5042
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005043 } else {
Dianne Hackborn4702a852012-08-17 15:18:29 -07005044 mPrivateFlags &= ~PFLAG_DRAWN & ~PFLAG_DRAWING_CACHE_VALID;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005045
5046 location[CHILD_LEFT_INDEX] = mLeft;
5047 location[CHILD_TOP_INDEX] = mTop;
Chet Haasea3db8662011-07-19 10:36:05 -07005048 if ((mGroupFlags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN) {
5049 dirty.set(0, 0, mRight - mLeft, mBottom - mTop);
5050 } else {
5051 // in case the dirty rect extends outside the bounds of this container
5052 dirty.union(0, 0, mRight - mLeft, mBottom - mTop);
5053 }
Romain Guy3a3133d2011-02-01 22:59:58 -08005054
John Reck96bb8ad2014-06-19 10:53:03 -07005055 if (mLayerType != LAYER_TYPE_NONE) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07005056 mPrivateFlags |= PFLAG_INVALIDATED;
Romain Guy3a3133d2011-02-01 22:59:58 -08005057 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005058
5059 return mParent;
5060 }
5061 }
5062
5063 return null;
5064 }
5065
5066 /**
John Recke4267ea2014-06-03 15:53:15 -07005067 * Native-calculated damage path
5068 * Returns false if this path was unable to complete successfully. This means
5069 * it hit a ViewParent it doesn't recognize and needs to fall back to calculating
5070 * damage area
5071 * @hide
5072 */
5073 public boolean damageChildDeferred(View child) {
5074 ViewParent parent = getParent();
5075 while (parent != null) {
5076 if (parent instanceof ViewGroup) {
5077 parent = parent.getParent();
5078 } else if (parent instanceof ViewRootImpl) {
5079 ((ViewRootImpl) parent).invalidate();
5080 return true;
5081 } else {
5082 parent = null;
5083 }
5084 }
5085 return false;
5086 }
5087
5088 /**
Chet Haase9d1992d2012-03-13 11:03:25 -07005089 * Quick invalidation method called by View.invalidateViewProperty. This doesn't set the
5090 * DRAWN flags and doesn't handle the Animation logic that the default invalidation methods
5091 * do; all we want to do here is schedule a traversal with the appropriate dirty rect.
5092 *
5093 * @hide
5094 */
Chris Craik49e6c732014-03-31 12:34:11 -07005095 public void damageChild(View child, final Rect dirty) {
John Recke4267ea2014-06-03 15:53:15 -07005096 if (damageChildDeferred(child)) {
5097 return;
5098 }
5099
Chet Haase9d1992d2012-03-13 11:03:25 -07005100 ViewParent parent = this;
5101
5102 final AttachInfo attachInfo = mAttachInfo;
5103 if (attachInfo != null) {
Chet Haase9d1992d2012-03-13 11:03:25 -07005104 int left = child.mLeft;
5105 int top = child.mTop;
5106 if (!child.getMatrix().isIdentity()) {
5107 child.transformRect(dirty);
5108 }
5109
5110 do {
5111 if (parent instanceof ViewGroup) {
5112 ViewGroup parentVG = (ViewGroup) parent;
Chet Haaseb85967b2012-03-26 14:37:51 -07005113 if (parentVG.mLayerType != LAYER_TYPE_NONE) {
5114 // Layered parents should be recreated, not just re-issued
5115 parentVG.invalidate();
5116 parent = null;
5117 } else {
Chris Craik49e6c732014-03-31 12:34:11 -07005118 parent = parentVG.damageChildInParent(left, top, dirty);
Chet Haaseb85967b2012-03-26 14:37:51 -07005119 left = parentVG.mLeft;
5120 top = parentVG.mTop;
5121 }
Chet Haase9d1992d2012-03-13 11:03:25 -07005122 } else {
5123 // Reached the top; this calls into the usual invalidate method in
5124 // ViewRootImpl, which schedules a traversal
5125 final int[] location = attachInfo.mInvalidateChildLocation;
5126 location[0] = left;
5127 location[1] = top;
5128 parent = parent.invalidateChildInParent(location, dirty);
5129 }
5130 } while (parent != null);
5131 }
5132 }
5133
5134 /**
5135 * Quick invalidation method that simply transforms the dirty rect into the parent's
5136 * coordinate system, pruning the invalidation if the parent has already been invalidated.
Chet Haasee4a2d7c2013-06-21 17:49:36 -07005137 *
5138 * @hide
Chet Haase9d1992d2012-03-13 11:03:25 -07005139 */
Chris Craik49e6c732014-03-31 12:34:11 -07005140 protected ViewParent damageChildInParent(int left, int top, final Rect dirty) {
5141 if ((mPrivateFlags & PFLAG_DRAWN) != 0
5142 || (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) != 0) {
Chet Haase9d1992d2012-03-13 11:03:25 -07005143 dirty.offset(left - mScrollX, top - mScrollY);
Chet Haasea4f14eb2013-04-22 11:11:39 -07005144 if ((mGroupFlags & FLAG_CLIP_CHILDREN) == 0) {
5145 dirty.union(0, 0, mRight - mLeft, mBottom - mTop);
5146 }
Chet Haase9d1992d2012-03-13 11:03:25 -07005147
5148 if ((mGroupFlags & FLAG_CLIP_CHILDREN) == 0 ||
5149 dirty.intersect(0, 0, mRight - mLeft, mBottom - mTop)) {
5150
Chet Haase9d1992d2012-03-13 11:03:25 -07005151 if (!getMatrix().isIdentity()) {
5152 transformRect(dirty);
5153 }
5154
5155 return mParent;
5156 }
5157 }
5158
5159 return null;
5160 }
5161
5162 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005163 * Offset a rectangle that is in a descendant's coordinate
5164 * space into our coordinate space.
5165 * @param descendant A descendant of this view
5166 * @param rect A rectangle defined in descendant's coordinate space.
5167 */
5168 public final void offsetDescendantRectToMyCoords(View descendant, Rect rect) {
5169 offsetRectBetweenParentAndChild(descendant, rect, true, false);
5170 }
5171
5172 /**
5173 * Offset a rectangle that is in our coordinate space into an ancestor's
5174 * coordinate space.
5175 * @param descendant A descendant of this view
5176 * @param rect A rectangle defined in descendant's coordinate space.
5177 */
5178 public final void offsetRectIntoDescendantCoords(View descendant, Rect rect) {
5179 offsetRectBetweenParentAndChild(descendant, rect, false, false);
5180 }
5181
5182 /**
5183 * Helper method that offsets a rect either from parent to descendant or
5184 * descendant to parent.
5185 */
5186 void offsetRectBetweenParentAndChild(View descendant, Rect rect,
5187 boolean offsetFromChildToParent, boolean clipToBounds) {
5188
5189 // already in the same coord system :)
5190 if (descendant == this) {
5191 return;
5192 }
5193
5194 ViewParent theParent = descendant.mParent;
5195
5196 // search and offset up to the parent
5197 while ((theParent != null)
5198 && (theParent instanceof View)
5199 && (theParent != this)) {
5200
5201 if (offsetFromChildToParent) {
5202 rect.offset(descendant.mLeft - descendant.mScrollX,
5203 descendant.mTop - descendant.mScrollY);
5204 if (clipToBounds) {
5205 View p = (View) theParent;
5206 rect.intersect(0, 0, p.mRight - p.mLeft, p.mBottom - p.mTop);
5207 }
5208 } else {
5209 if (clipToBounds) {
5210 View p = (View) theParent;
5211 rect.intersect(0, 0, p.mRight - p.mLeft, p.mBottom - p.mTop);
5212 }
5213 rect.offset(descendant.mScrollX - descendant.mLeft,
5214 descendant.mScrollY - descendant.mTop);
5215 }
5216
5217 descendant = (View) theParent;
5218 theParent = descendant.mParent;
5219 }
5220
5221 // now that we are up to this view, need to offset one more time
5222 // to get into our coordinate space
5223 if (theParent == this) {
5224 if (offsetFromChildToParent) {
5225 rect.offset(descendant.mLeft - descendant.mScrollX,
5226 descendant.mTop - descendant.mScrollY);
5227 } else {
5228 rect.offset(descendant.mScrollX - descendant.mLeft,
5229 descendant.mScrollY - descendant.mTop);
5230 }
5231 } else {
5232 throw new IllegalArgumentException("parameter must be a descendant of this view");
5233 }
5234 }
5235
5236 /**
5237 * Offset the vertical location of all children of this view by the specified number of pixels.
5238 *
5239 * @param offset the number of pixels to offset
5240 *
5241 * @hide
5242 */
5243 public void offsetChildrenTopAndBottom(int offset) {
5244 final int count = mChildrenCount;
5245 final View[] children = mChildren;
Romain Guy5549cb52013-05-06 18:42:08 -07005246 boolean invalidate = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005247
5248 for (int i = 0; i < count; i++) {
5249 final View v = children[i];
5250 v.mTop += offset;
5251 v.mBottom += offset;
Chris Craik64a12e12014-03-28 18:12:12 -07005252 if (v.mRenderNode != null) {
Romain Guy5549cb52013-05-06 18:42:08 -07005253 invalidate = true;
Chris Craik64a12e12014-03-28 18:12:12 -07005254 v.mRenderNode.offsetTopAndBottom(offset);
Chet Haasea1cff502012-02-21 13:43:44 -08005255 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005256 }
Romain Guy5549cb52013-05-06 18:42:08 -07005257
5258 if (invalidate) {
5259 invalidateViewProperty(false, false);
5260 }
Guang Zhu84e25092014-05-01 21:12:55 -07005261 notifySubtreeAccessibilityStateChangedIfNeeded();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005262 }
5263
5264 /**
5265 * {@inheritDoc}
5266 */
5267 public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) {
Adam Powellf93bb6d2011-12-12 15:21:57 -08005268 // It doesn't make a whole lot of sense to call this on a view that isn't attached,
5269 // but for some simple tests it can be useful. If we don't have attach info this
5270 // will allocate memory.
5271 final RectF rect = mAttachInfo != null ? mAttachInfo.mTmpTransformRect : new RectF();
Gilles Debunnecea45132011-11-24 02:19:27 +01005272 rect.set(r);
5273
5274 if (!child.hasIdentityMatrix()) {
George Mount002d43d2014-11-11 12:54:43 -08005275 child.getMatrix().mapRect(rect);
Gilles Debunnecea45132011-11-24 02:19:27 +01005276 }
5277
Alan Viveretteab2cf6d2014-11-26 14:34:36 -08005278 final int dx = child.mLeft - mScrollX;
5279 final int dy = child.mTop - mScrollY;
Gilles Debunnecea45132011-11-24 02:19:27 +01005280
5281 rect.offset(dx, dy);
5282
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005283 if (offset != null) {
Gilles Debunnecea45132011-11-24 02:19:27 +01005284 if (!child.hasIdentityMatrix()) {
Adam Powellf93bb6d2011-12-12 15:21:57 -08005285 float[] position = mAttachInfo != null ? mAttachInfo.mTmpTransformLocation
5286 : new float[2];
Gilles Debunnecea45132011-11-24 02:19:27 +01005287 position[0] = offset.x;
5288 position[1] = offset.y;
5289 child.getMatrix().mapPoints(position);
5290 offset.x = (int) (position[0] + 0.5f);
5291 offset.y = (int) (position[1] + 0.5f);
5292 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005293 offset.x += dx;
5294 offset.y += dy;
5295 }
Gilles Debunnecea45132011-11-24 02:19:27 +01005296
Alan Viveretteab2cf6d2014-11-26 14:34:36 -08005297 final int width = mRight - mLeft;
5298 final int height = mBottom - mTop;
5299
George Mount002d43d2014-11-11 12:54:43 -08005300 boolean rectIsVisible = true;
Adam Powell35da41e2014-12-10 18:59:34 -08005301 if (mParent == null ||
5302 (mParent instanceof ViewGroup && ((ViewGroup) mParent).getClipChildren())) {
Alan Viveretteab2cf6d2014-11-26 14:34:36 -08005303 // Clip to bounds.
5304 rectIsVisible = rect.intersect(0, 0, width, height);
Gilles Debunnecea45132011-11-24 02:19:27 +01005305 }
5306
George Mount002d43d2014-11-11 12:54:43 -08005307 if (rectIsVisible && (mGroupFlags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK) {
Alan Viveretteab2cf6d2014-11-26 14:34:36 -08005308 // Clip to padding.
George Mount002d43d2014-11-11 12:54:43 -08005309 rectIsVisible = rect.intersect(mPaddingLeft, mPaddingTop,
Alan Viveretteab2cf6d2014-11-26 14:34:36 -08005310 width - mPaddingRight, height - mPaddingBottom);
George Mount002d43d2014-11-11 12:54:43 -08005311 }
5312
5313 if (rectIsVisible && mClipBounds != null) {
Alan Viveretteab2cf6d2014-11-26 14:34:36 -08005314 // Clip to clipBounds.
George Mount002d43d2014-11-11 12:54:43 -08005315 rectIsVisible = rect.intersect(mClipBounds.left, mClipBounds.top, mClipBounds.right,
5316 mClipBounds.bottom);
5317 }
5318 r.set((int) (rect.left + 0.5f), (int) (rect.top + 0.5f), (int) (rect.right + 0.5f),
5319 (int) (rect.bottom + 0.5f));
5320 if (rectIsVisible && mParent != null) {
5321 rectIsVisible = mParent.getChildVisibleRect(this, r, offset);
5322 }
5323 return rectIsVisible;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005324 }
5325
5326 /**
5327 * {@inheritDoc}
5328 */
5329 @Override
Chet Haase9c087442011-01-12 16:20:16 -08005330 public final void layout(int l, int t, int r, int b) {
Chet Haase430742f2013-04-12 11:18:36 -07005331 if (!mSuppressLayout && (mTransition == null || !mTransition.isChangingLayout())) {
Chet Haase7dd4a532012-04-16 13:35:09 -07005332 if (mTransition != null) {
5333 mTransition.layoutChange(this);
5334 }
Chet Haase9c087442011-01-12 16:20:16 -08005335 super.layout(l, t, r, b);
5336 } else {
5337 // record the fact that we noop'd it; request layout when transition finishes
Chet Haaseb9895022013-04-02 15:10:58 -07005338 mLayoutCalledWhileSuppressed = true;
Chet Haase9c087442011-01-12 16:20:16 -08005339 }
5340 }
5341
5342 /**
5343 * {@inheritDoc}
5344 */
5345 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005346 protected abstract void onLayout(boolean changed,
5347 int l, int t, int r, int b);
5348
5349 /**
5350 * Indicates whether the view group has the ability to animate its children
5351 * after the first layout.
5352 *
5353 * @return true if the children can be animated, false otherwise
5354 */
5355 protected boolean canAnimate() {
5356 return mLayoutAnimationController != null;
5357 }
5358
5359 /**
5360 * Runs the layout animation. Calling this method triggers a relayout of
5361 * this view group.
5362 */
5363 public void startLayoutAnimation() {
5364 if (mLayoutAnimationController != null) {
5365 mGroupFlags |= FLAG_RUN_ANIMATION;
5366 requestLayout();
5367 }
5368 }
5369
5370 /**
5371 * Schedules the layout animation to be played after the next layout pass
5372 * of this view group. This can be used to restart the layout animation
5373 * when the content of the view group changes or when the activity is
5374 * paused and resumed.
5375 */
5376 public void scheduleLayoutAnimation() {
5377 mGroupFlags |= FLAG_RUN_ANIMATION;
5378 }
5379
5380 /**
5381 * Sets the layout animation controller used to animate the group's
5382 * children after the first layout.
5383 *
5384 * @param controller the animation controller
5385 */
5386 public void setLayoutAnimation(LayoutAnimationController controller) {
5387 mLayoutAnimationController = controller;
5388 if (mLayoutAnimationController != null) {
5389 mGroupFlags |= FLAG_RUN_ANIMATION;
5390 }
5391 }
5392
5393 /**
5394 * Returns the layout animation controller used to animate the group's
5395 * children.
5396 *
5397 * @return the current animation controller
5398 */
5399 public LayoutAnimationController getLayoutAnimation() {
5400 return mLayoutAnimationController;
5401 }
5402
5403 /**
5404 * Indicates whether the children's drawing cache is used during a layout
5405 * animation. By default, the drawing cache is enabled but this will prevent
5406 * nested layout animations from working. To nest animations, you must disable
5407 * the cache.
5408 *
5409 * @return true if the animation cache is enabled, false otherwise
5410 *
5411 * @see #setAnimationCacheEnabled(boolean)
5412 * @see View#setDrawingCacheEnabled(boolean)
Chris Craik5a6bbae2015-04-10 17:41:34 -07005413 *
5414 * @deprecated As of {@link android.os.Build.VERSION_CODES#MNC}, this property is ignored.
5415 * Caching behavior of children may be controlled through {@link View#setLayerType(int, Paint)}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005416 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005417 public boolean isAnimationCacheEnabled() {
5418 return (mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE;
5419 }
5420
5421 /**
5422 * Enables or disables the children's drawing cache during a layout animation.
5423 * By default, the drawing cache is enabled but this will prevent nested
5424 * layout animations from working. To nest animations, you must disable the
5425 * cache.
5426 *
5427 * @param enabled true to enable the animation cache, false otherwise
5428 *
5429 * @see #isAnimationCacheEnabled()
5430 * @see View#setDrawingCacheEnabled(boolean)
Chris Craik5a6bbae2015-04-10 17:41:34 -07005431 *
5432 * @deprecated As of {@link android.os.Build.VERSION_CODES#MNC}, this property is ignored.
5433 * Caching behavior of children may be controlled through {@link View#setLayerType(int, Paint)}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005434 */
5435 public void setAnimationCacheEnabled(boolean enabled) {
5436 setBooleanFlag(FLAG_ANIMATION_CACHE, enabled);
5437 }
5438
5439 /**
5440 * Indicates whether this ViewGroup will always try to draw its children using their
5441 * drawing cache. By default this property is enabled.
5442 *
5443 * @return true if the animation cache is enabled, false otherwise
5444 *
5445 * @see #setAlwaysDrawnWithCacheEnabled(boolean)
5446 * @see #setChildrenDrawnWithCacheEnabled(boolean)
5447 * @see View#setDrawingCacheEnabled(boolean)
Chris Craik5a6bbae2015-04-10 17:41:34 -07005448 *
5449 * @deprecated As of {@link android.os.Build.VERSION_CODES#MNC}, this property is ignored.
5450 * Child views may no longer have their caching behavior disabled by parents.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005451 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005452 public boolean isAlwaysDrawnWithCacheEnabled() {
5453 return (mGroupFlags & FLAG_ALWAYS_DRAWN_WITH_CACHE) == FLAG_ALWAYS_DRAWN_WITH_CACHE;
5454 }
5455
5456 /**
5457 * Indicates whether this ViewGroup will always try to draw its children using their
5458 * drawing cache. This property can be set to true when the cache rendering is
5459 * slightly different from the children's normal rendering. Renderings can be different,
5460 * for instance, when the cache's quality is set to low.
5461 *
5462 * When this property is disabled, the ViewGroup will use the drawing cache of its
5463 * children only when asked to. It's usually the task of subclasses to tell ViewGroup
5464 * when to start using the drawing cache and when to stop using it.
5465 *
5466 * @param always true to always draw with the drawing cache, false otherwise
5467 *
5468 * @see #isAlwaysDrawnWithCacheEnabled()
5469 * @see #setChildrenDrawnWithCacheEnabled(boolean)
5470 * @see View#setDrawingCacheEnabled(boolean)
5471 * @see View#setDrawingCacheQuality(int)
Chris Craik5a6bbae2015-04-10 17:41:34 -07005472 *
5473 * @deprecated As of {@link android.os.Build.VERSION_CODES#MNC}, this property is ignored.
5474 * Child views may no longer have their caching behavior disabled by parents.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005475 */
5476 public void setAlwaysDrawnWithCacheEnabled(boolean always) {
5477 setBooleanFlag(FLAG_ALWAYS_DRAWN_WITH_CACHE, always);
5478 }
5479
5480 /**
5481 * Indicates whether the ViewGroup is currently drawing its children using
5482 * their drawing cache.
5483 *
5484 * @return true if children should be drawn with their cache, false otherwise
5485 *
5486 * @see #setAlwaysDrawnWithCacheEnabled(boolean)
5487 * @see #setChildrenDrawnWithCacheEnabled(boolean)
Chris Craik5a6bbae2015-04-10 17:41:34 -07005488 *
5489 * @deprecated As of {@link android.os.Build.VERSION_CODES#MNC}, this property is ignored.
5490 * Child views may no longer be forced to cache their rendering state by their parents.
5491 * Use {@link View#setLayerType(int, Paint)} on individual Views instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005492 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005493 protected boolean isChildrenDrawnWithCacheEnabled() {
5494 return (mGroupFlags & FLAG_CHILDREN_DRAWN_WITH_CACHE) == FLAG_CHILDREN_DRAWN_WITH_CACHE;
5495 }
5496
5497 /**
5498 * Tells the ViewGroup to draw its children using their drawing cache. This property
5499 * is ignored when {@link #isAlwaysDrawnWithCacheEnabled()} is true. A child's drawing cache
5500 * will be used only if it has been enabled.
5501 *
5502 * Subclasses should call this method to start and stop using the drawing cache when
5503 * they perform performance sensitive operations, like scrolling or animating.
5504 *
5505 * @param enabled true if children should be drawn with their cache, false otherwise
5506 *
5507 * @see #setAlwaysDrawnWithCacheEnabled(boolean)
5508 * @see #isChildrenDrawnWithCacheEnabled()
Chris Craik5a6bbae2015-04-10 17:41:34 -07005509 *
5510 * @deprecated As of {@link android.os.Build.VERSION_CODES#MNC}, this property is ignored.
5511 * Child views may no longer be forced to cache their rendering state by their parents.
5512 * Use {@link View#setLayerType(int, Paint)} on individual Views instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005513 */
5514 protected void setChildrenDrawnWithCacheEnabled(boolean enabled) {
5515 setBooleanFlag(FLAG_CHILDREN_DRAWN_WITH_CACHE, enabled);
5516 }
5517
Romain Guy293451e2009-11-04 13:59:48 -08005518 /**
5519 * Indicates whether the ViewGroup is drawing its children in the order defined by
5520 * {@link #getChildDrawingOrder(int, int)}.
5521 *
5522 * @return true if children drawing order is defined by {@link #getChildDrawingOrder(int, int)},
5523 * false otherwise
5524 *
5525 * @see #setChildrenDrawingOrderEnabled(boolean)
5526 * @see #getChildDrawingOrder(int, int)
5527 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07005528 @ViewDebug.ExportedProperty(category = "drawing")
Romain Guy293451e2009-11-04 13:59:48 -08005529 protected boolean isChildrenDrawingOrderEnabled() {
5530 return (mGroupFlags & FLAG_USE_CHILD_DRAWING_ORDER) == FLAG_USE_CHILD_DRAWING_ORDER;
5531 }
5532
5533 /**
5534 * Tells the ViewGroup whether to draw its children in the order defined by the method
5535 * {@link #getChildDrawingOrder(int, int)}.
Chris Craike83cbd42014-09-03 17:52:24 -07005536 * <p>
5537 * Note that {@link View#getZ() Z} reordering, done by {@link #dispatchDraw(Canvas)},
5538 * will override custom child ordering done via this method.
Romain Guy293451e2009-11-04 13:59:48 -08005539 *
5540 * @param enabled true if the order of the children when drawing is determined by
5541 * {@link #getChildDrawingOrder(int, int)}, false otherwise
5542 *
5543 * @see #isChildrenDrawingOrderEnabled()
5544 * @see #getChildDrawingOrder(int, int)
5545 */
5546 protected void setChildrenDrawingOrderEnabled(boolean enabled) {
5547 setBooleanFlag(FLAG_USE_CHILD_DRAWING_ORDER, enabled);
5548 }
5549
Svetoslav6254f482013-06-04 17:22:14 -07005550 private boolean hasBooleanFlag(int flag) {
Philip Milnef091b662013-02-27 11:15:21 -08005551 return (mGroupFlags & flag) == flag;
5552 }
5553
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005554 private void setBooleanFlag(int flag, boolean value) {
5555 if (value) {
5556 mGroupFlags |= flag;
5557 } else {
5558 mGroupFlags &= ~flag;
5559 }
5560 }
5561
5562 /**
5563 * Returns an integer indicating what types of drawing caches are kept in memory.
5564 *
5565 * @see #setPersistentDrawingCache(int)
5566 * @see #setAnimationCacheEnabled(boolean)
5567 *
5568 * @return one or a combination of {@link #PERSISTENT_NO_CACHE},
5569 * {@link #PERSISTENT_ANIMATION_CACHE}, {@link #PERSISTENT_SCROLLING_CACHE}
5570 * and {@link #PERSISTENT_ALL_CACHES}
5571 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07005572 @ViewDebug.ExportedProperty(category = "drawing", mapping = {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005573 @ViewDebug.IntToString(from = PERSISTENT_NO_CACHE, to = "NONE"),
Romain Guy203688c2010-05-12 15:41:32 -07005574 @ViewDebug.IntToString(from = PERSISTENT_ANIMATION_CACHE, to = "ANIMATION"),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005575 @ViewDebug.IntToString(from = PERSISTENT_SCROLLING_CACHE, to = "SCROLLING"),
5576 @ViewDebug.IntToString(from = PERSISTENT_ALL_CACHES, to = "ALL")
5577 })
5578 public int getPersistentDrawingCache() {
5579 return mPersistentDrawingCache;
5580 }
5581
5582 /**
5583 * Indicates what types of drawing caches should be kept in memory after
5584 * they have been created.
5585 *
5586 * @see #getPersistentDrawingCache()
5587 * @see #setAnimationCacheEnabled(boolean)
5588 *
5589 * @param drawingCacheToKeep one or a combination of {@link #PERSISTENT_NO_CACHE},
5590 * {@link #PERSISTENT_ANIMATION_CACHE}, {@link #PERSISTENT_SCROLLING_CACHE}
5591 * and {@link #PERSISTENT_ALL_CACHES}
5592 */
5593 public void setPersistentDrawingCache(int drawingCacheToKeep) {
5594 mPersistentDrawingCache = drawingCacheToKeep & PERSISTENT_ALL_CACHES;
5595 }
5596
Philip Milnef091b662013-02-27 11:15:21 -08005597 private void setLayoutMode(int layoutMode, boolean explicitly) {
5598 mLayoutMode = layoutMode;
5599 setBooleanFlag(FLAG_LAYOUT_MODE_WAS_EXPLICITLY_SET, explicitly);
5600 }
5601
5602 /**
5603 * Recursively traverse the view hierarchy, resetting the layoutMode of any
5604 * descendants that had inherited a different layoutMode from a previous parent.
5605 * Recursion terminates when a descendant's mode is:
5606 * <ul>
5607 * <li>Undefined</li>
5608 * <li>The same as the root node's</li>
5609 * <li>A mode that had been explicitly set</li>
5610 * <ul/>
5611 * The first two clauses are optimizations.
5612 * @param layoutModeOfRoot
5613 */
5614 @Override
5615 void invalidateInheritedLayoutMode(int layoutModeOfRoot) {
5616 if (mLayoutMode == LAYOUT_MODE_UNDEFINED ||
5617 mLayoutMode == layoutModeOfRoot ||
Svetoslav6254f482013-06-04 17:22:14 -07005618 hasBooleanFlag(FLAG_LAYOUT_MODE_WAS_EXPLICITLY_SET)) {
Philip Milnef091b662013-02-27 11:15:21 -08005619 return;
5620 }
5621 setLayoutMode(LAYOUT_MODE_UNDEFINED, false);
5622
5623 // apply recursively
5624 for (int i = 0, N = getChildCount(); i < N; i++) {
5625 getChildAt(i).invalidateInheritedLayoutMode(layoutModeOfRoot);
5626 }
5627 }
5628
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005629 /**
Philip Milnecfb631b2012-10-26 10:51:46 -07005630 * Returns the basis of alignment during layout operations on this ViewGroup:
Philip Milne7b757812012-09-19 18:13:44 -07005631 * either {@link #LAYOUT_MODE_CLIP_BOUNDS} or {@link #LAYOUT_MODE_OPTICAL_BOUNDS}.
Philip Milnecfb631b2012-10-26 10:51:46 -07005632 * <p>
5633 * If no layoutMode was explicitly set, either programmatically or in an XML resource,
5634 * the method returns the layoutMode of the view's parent ViewGroup if such a parent exists,
5635 * otherwise the method returns a default value of {@link #LAYOUT_MODE_CLIP_BOUNDS}.
Philip Milne1557fd72012-04-04 23:41:34 -07005636 *
Philip Milnefcc6a0f2012-04-16 16:12:19 -07005637 * @return the layout mode to use during layout operations
Philip Milne1557fd72012-04-04 23:41:34 -07005638 *
5639 * @see #setLayoutMode(int)
5640 */
5641 public int getLayoutMode() {
Philip Milnecfb631b2012-10-26 10:51:46 -07005642 if (mLayoutMode == LAYOUT_MODE_UNDEFINED) {
Philip Milnef091b662013-02-27 11:15:21 -08005643 int inheritedLayoutMode = (mParent instanceof ViewGroup) ?
5644 ((ViewGroup) mParent).getLayoutMode() : LAYOUT_MODE_DEFAULT;
5645 setLayoutMode(inheritedLayoutMode, false);
Philip Milnecfb631b2012-10-26 10:51:46 -07005646 }
Philip Milne1557fd72012-04-04 23:41:34 -07005647 return mLayoutMode;
5648 }
5649
5650 /**
Philip Milnecfb631b2012-10-26 10:51:46 -07005651 * Sets the basis of alignment during the layout of this ViewGroup.
Philip Milne7b757812012-09-19 18:13:44 -07005652 * Valid values are either {@link #LAYOUT_MODE_CLIP_BOUNDS} or
5653 * {@link #LAYOUT_MODE_OPTICAL_BOUNDS}.
Philip Milne1557fd72012-04-04 23:41:34 -07005654 *
Philip Milnefcc6a0f2012-04-16 16:12:19 -07005655 * @param layoutMode the layout mode to use during layout operations
Philip Milne1557fd72012-04-04 23:41:34 -07005656 *
5657 * @see #getLayoutMode()
Scott Main27a85082013-06-10 10:39:48 -07005658 * @attr ref android.R.styleable#ViewGroup_layoutMode
Philip Milne1557fd72012-04-04 23:41:34 -07005659 */
5660 public void setLayoutMode(int layoutMode) {
5661 if (mLayoutMode != layoutMode) {
Philip Milnef091b662013-02-27 11:15:21 -08005662 invalidateInheritedLayoutMode(layoutMode);
5663 setLayoutMode(layoutMode, layoutMode != LAYOUT_MODE_UNDEFINED);
Philip Milne1557fd72012-04-04 23:41:34 -07005664 requestLayout();
5665 }
5666 }
5667
5668 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005669 * Returns a new set of layout parameters based on the supplied attributes set.
5670 *
5671 * @param attrs the attributes to build the layout parameters from
5672 *
5673 * @return an instance of {@link android.view.ViewGroup.LayoutParams} or one
5674 * of its descendants
5675 */
5676 public LayoutParams generateLayoutParams(AttributeSet attrs) {
5677 return new LayoutParams(getContext(), attrs);
5678 }
5679
5680 /**
5681 * Returns a safe set of layout parameters based on the supplied layout params.
5682 * When a ViewGroup is passed a View whose layout params do not pass the test of
5683 * {@link #checkLayoutParams(android.view.ViewGroup.LayoutParams)}, this method
5684 * is invoked. This method should return a new set of layout params suitable for
5685 * this ViewGroup, possibly by copying the appropriate attributes from the
5686 * specified set of layout params.
5687 *
5688 * @param p The layout parameters to convert into a suitable set of layout parameters
5689 * for this ViewGroup.
5690 *
5691 * @return an instance of {@link android.view.ViewGroup.LayoutParams} or one
5692 * of its descendants
5693 */
5694 protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
5695 return p;
5696 }
5697
5698 /**
5699 * Returns a set of default layout parameters. These parameters are requested
5700 * when the View passed to {@link #addView(View)} has no layout parameters
5701 * already set. If null is returned, an exception is thrown from addView.
5702 *
5703 * @return a set of default layout parameters or null
5704 */
5705 protected LayoutParams generateDefaultLayoutParams() {
5706 return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
5707 }
5708
5709 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005710 * {@inheritDoc}
5711 */
5712 @Override
5713 protected void debug(int depth) {
5714 super.debug(depth);
5715 String output;
5716
5717 if (mFocused != null) {
5718 output = debugIndent(depth);
5719 output += "mFocused";
5720 Log.d(VIEW_LOG_TAG, output);
5721 }
5722 if (mChildrenCount != 0) {
5723 output = debugIndent(depth);
5724 output += "{";
5725 Log.d(VIEW_LOG_TAG, output);
5726 }
5727 int count = mChildrenCount;
5728 for (int i = 0; i < count; i++) {
5729 View child = mChildren[i];
5730 child.debug(depth + 1);
5731 }
5732
5733 if (mChildrenCount != 0) {
5734 output = debugIndent(depth);
5735 output += "}";
5736 Log.d(VIEW_LOG_TAG, output);
5737 }
5738 }
5739
5740 /**
5741 * Returns the position in the group of the specified child view.
5742 *
5743 * @param child the view for which to get the position
5744 * @return a positive integer representing the position of the view in the
5745 * group, or -1 if the view does not exist in the group
5746 */
5747 public int indexOfChild(View child) {
5748 final int count = mChildrenCount;
5749 final View[] children = mChildren;
5750 for (int i = 0; i < count; i++) {
5751 if (children[i] == child) {
5752 return i;
5753 }
5754 }
5755 return -1;
5756 }
5757
5758 /**
5759 * Returns the number of children in the group.
5760 *
5761 * @return a positive integer representing the number of children in
5762 * the group
5763 */
5764 public int getChildCount() {
5765 return mChildrenCount;
5766 }
5767
5768 /**
5769 * Returns the view at the specified position in the group.
5770 *
5771 * @param index the position at which to get the view from
5772 * @return the view at the specified position or null if the position
5773 * does not exist within the group
5774 */
5775 public View getChildAt(int index) {
Adam Powell3ba8f5d62011-03-07 15:36:33 -08005776 if (index < 0 || index >= mChildrenCount) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005777 return null;
5778 }
Adam Powell3ba8f5d62011-03-07 15:36:33 -08005779 return mChildren[index];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005780 }
5781
5782 /**
5783 * Ask all of the children of this view to measure themselves, taking into
5784 * account both the MeasureSpec requirements for this view and its padding.
5785 * We skip children that are in the GONE state The heavy lifting is done in
5786 * getChildMeasureSpec.
5787 *
5788 * @param widthMeasureSpec The width requirements for this view
5789 * @param heightMeasureSpec The height requirements for this view
5790 */
5791 protected void measureChildren(int widthMeasureSpec, int heightMeasureSpec) {
5792 final int size = mChildrenCount;
5793 final View[] children = mChildren;
5794 for (int i = 0; i < size; ++i) {
5795 final View child = children[i];
5796 if ((child.mViewFlags & VISIBILITY_MASK) != GONE) {
5797 measureChild(child, widthMeasureSpec, heightMeasureSpec);
5798 }
5799 }
5800 }
5801
5802 /**
5803 * Ask one of the children of this view to measure itself, taking into
5804 * account both the MeasureSpec requirements for this view and its padding.
5805 * The heavy lifting is done in getChildMeasureSpec.
5806 *
5807 * @param child The child to measure
5808 * @param parentWidthMeasureSpec The width requirements for this view
5809 * @param parentHeightMeasureSpec The height requirements for this view
5810 */
5811 protected void measureChild(View child, int parentWidthMeasureSpec,
5812 int parentHeightMeasureSpec) {
5813 final LayoutParams lp = child.getLayoutParams();
5814
5815 final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
5816 mPaddingLeft + mPaddingRight, lp.width);
5817 final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
5818 mPaddingTop + mPaddingBottom, lp.height);
5819
5820 child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
5821 }
5822
5823 /**
5824 * Ask one of the children of this view to measure itself, taking into
5825 * account both the MeasureSpec requirements for this view and its padding
5826 * and margins. The child must have MarginLayoutParams The heavy lifting is
5827 * done in getChildMeasureSpec.
5828 *
5829 * @param child The child to measure
5830 * @param parentWidthMeasureSpec The width requirements for this view
5831 * @param widthUsed Extra space that has been used up by the parent
5832 * horizontally (possibly by other children of the parent)
5833 * @param parentHeightMeasureSpec The height requirements for this view
5834 * @param heightUsed Extra space that has been used up by the parent
5835 * vertically (possibly by other children of the parent)
5836 */
5837 protected void measureChildWithMargins(View child,
5838 int parentWidthMeasureSpec, int widthUsed,
5839 int parentHeightMeasureSpec, int heightUsed) {
5840 final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
5841
5842 final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
5843 mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin
5844 + widthUsed, lp.width);
5845 final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
5846 mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin
5847 + heightUsed, lp.height);
5848
5849 child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
5850 }
5851
5852 /**
5853 * Does the hard part of measureChildren: figuring out the MeasureSpec to
5854 * pass to a particular child. This method figures out the right MeasureSpec
5855 * for one dimension (height or width) of one child view.
5856 *
5857 * The goal is to combine information from our MeasureSpec with the
5858 * LayoutParams of the child to get the best possible results. For example,
5859 * if the this view knows its size (because its MeasureSpec has a mode of
5860 * EXACTLY), and the child has indicated in its LayoutParams that it wants
5861 * to be the same size as the parent, the parent should ask the child to
5862 * layout given an exact size.
5863 *
5864 * @param spec The requirements for this view
5865 * @param padding The padding of this view for the current dimension and
5866 * margins, if applicable
5867 * @param childDimension How big the child wants to be in the current
5868 * dimension
5869 * @return a MeasureSpec integer for the child
5870 */
5871 public static int getChildMeasureSpec(int spec, int padding, int childDimension) {
5872 int specMode = MeasureSpec.getMode(spec);
5873 int specSize = MeasureSpec.getSize(spec);
5874
5875 int size = Math.max(0, specSize - padding);
5876
5877 int resultSize = 0;
5878 int resultMode = 0;
5879
5880 switch (specMode) {
5881 // Parent has imposed an exact size on us
5882 case MeasureSpec.EXACTLY:
5883 if (childDimension >= 0) {
5884 resultSize = childDimension;
5885 resultMode = MeasureSpec.EXACTLY;
Romain Guy980a9382010-01-08 15:06:28 -08005886 } else if (childDimension == LayoutParams.MATCH_PARENT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005887 // Child wants to be our size. So be it.
5888 resultSize = size;
5889 resultMode = MeasureSpec.EXACTLY;
5890 } else if (childDimension == LayoutParams.WRAP_CONTENT) {
5891 // Child wants to determine its own size. It can't be
5892 // bigger than us.
5893 resultSize = size;
5894 resultMode = MeasureSpec.AT_MOST;
5895 }
5896 break;
5897
5898 // Parent has imposed a maximum size on us
5899 case MeasureSpec.AT_MOST:
5900 if (childDimension >= 0) {
5901 // Child wants a specific size... so be it
5902 resultSize = childDimension;
5903 resultMode = MeasureSpec.EXACTLY;
Romain Guy980a9382010-01-08 15:06:28 -08005904 } else if (childDimension == LayoutParams.MATCH_PARENT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005905 // Child wants to be our size, but our size is not fixed.
5906 // Constrain child to not be bigger than us.
5907 resultSize = size;
5908 resultMode = MeasureSpec.AT_MOST;
5909 } else if (childDimension == LayoutParams.WRAP_CONTENT) {
5910 // Child wants to determine its own size. It can't be
5911 // bigger than us.
5912 resultSize = size;
5913 resultMode = MeasureSpec.AT_MOST;
5914 }
5915 break;
5916
5917 // Parent asked to see how big we want to be
5918 case MeasureSpec.UNSPECIFIED:
5919 if (childDimension >= 0) {
5920 // Child wants a specific size... let him have it
5921 resultSize = childDimension;
5922 resultMode = MeasureSpec.EXACTLY;
Romain Guy980a9382010-01-08 15:06:28 -08005923 } else if (childDimension == LayoutParams.MATCH_PARENT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005924 // Child wants to be our size... find out how big it should
5925 // be
Filip Gruszczynski415ab1a2015-03-11 16:42:00 -07005926 resultSize = size;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005927 resultMode = MeasureSpec.UNSPECIFIED;
5928 } else if (childDimension == LayoutParams.WRAP_CONTENT) {
5929 // Child wants to determine its own size.... find out how
5930 // big it should be
Filip Gruszczynski415ab1a2015-03-11 16:42:00 -07005931 resultSize = size;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005932 resultMode = MeasureSpec.UNSPECIFIED;
5933 }
5934 break;
5935 }
5936 return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
5937 }
5938
5939
5940 /**
5941 * Removes any pending animations for views that have been removed. Call
5942 * this if you don't want animations for exiting views to stack up.
5943 */
5944 public void clearDisappearingChildren() {
John Reckca7a9da2014-03-05 16:29:07 -08005945 final ArrayList<View> disappearingChildren = mDisappearingChildren;
5946 if (disappearingChildren != null) {
5947 final int count = disappearingChildren.size();
5948 for (int i = 0; i < count; i++) {
5949 final View view = disappearingChildren.get(i);
5950 if (view.mAttachInfo != null) {
5951 view.dispatchDetachedFromWindow();
5952 }
5953 view.clearAnimation();
5954 }
5955 disappearingChildren.clear();
Chet Haaseb85967b2012-03-26 14:37:51 -07005956 invalidate();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005957 }
5958 }
5959
5960 /**
5961 * Add a view which is removed from mChildren but still needs animation
5962 *
5963 * @param v View to add
5964 */
5965 private void addDisappearingView(View v) {
5966 ArrayList<View> disappearingChildren = mDisappearingChildren;
5967
5968 if (disappearingChildren == null) {
5969 disappearingChildren = mDisappearingChildren = new ArrayList<View>();
5970 }
5971
5972 disappearingChildren.add(v);
5973 }
5974
5975 /**
5976 * Cleanup a view when its animation is done. This may mean removing it from
5977 * the list of disappearing views.
5978 *
5979 * @param view The view whose animation has finished
5980 * @param animation The animation, cannot be null
5981 */
Chet Haase64a48c12012-02-13 16:33:29 -08005982 void finishAnimatingView(final View view, Animation animation) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005983 final ArrayList<View> disappearingChildren = mDisappearingChildren;
5984 if (disappearingChildren != null) {
5985 if (disappearingChildren.contains(view)) {
5986 disappearingChildren.remove(view);
5987
5988 if (view.mAttachInfo != null) {
5989 view.dispatchDetachedFromWindow();
5990 }
5991
5992 view.clearAnimation();
5993 mGroupFlags |= FLAG_INVALIDATE_REQUIRED;
5994 }
5995 }
5996
5997 if (animation != null && !animation.getFillAfter()) {
5998 view.clearAnimation();
5999 }
6000
Dianne Hackborn4702a852012-08-17 15:18:29 -07006001 if ((view.mPrivateFlags & PFLAG_ANIMATION_STARTED) == PFLAG_ANIMATION_STARTED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006002 view.onAnimationEnd();
6003 // Should be performed by onAnimationEnd() but this avoid an infinite loop,
6004 // so we'd rather be safe than sorry
Dianne Hackborn4702a852012-08-17 15:18:29 -07006005 view.mPrivateFlags &= ~PFLAG_ANIMATION_STARTED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006006 // Draw one more frame after the animation is done
6007 mGroupFlags |= FLAG_INVALIDATE_REQUIRED;
6008 }
6009 }
6010
Chet Haaseb20db3e2010-09-10 13:07:30 -07006011 /**
Chet Haaseaceafe62011-08-26 15:44:33 -07006012 * Utility function called by View during invalidation to determine whether a view that
6013 * is invisible or gone should still be invalidated because it is being transitioned (and
6014 * therefore still needs to be drawn).
6015 */
6016 boolean isViewTransitioning(View view) {
6017 return (mTransitioningViews != null && mTransitioningViews.contains(view));
6018 }
6019
6020 /**
Chet Haaseb20db3e2010-09-10 13:07:30 -07006021 * This method tells the ViewGroup that the given View object, which should have this
6022 * ViewGroup as its parent,
6023 * should be kept around (re-displayed when the ViewGroup draws its children) even if it
6024 * is removed from its parent. This allows animations, such as those used by
6025 * {@link android.app.Fragment} and {@link android.animation.LayoutTransition} to animate
6026 * the removal of views. A call to this method should always be accompanied by a later call
6027 * to {@link #endViewTransition(View)}, such as after an animation on the View has finished,
6028 * so that the View finally gets removed.
6029 *
6030 * @param view The View object to be kept visible even if it gets removed from its parent.
6031 */
6032 public void startViewTransition(View view) {
6033 if (view.mParent == this) {
6034 if (mTransitioningViews == null) {
6035 mTransitioningViews = new ArrayList<View>();
6036 }
6037 mTransitioningViews.add(view);
6038 }
6039 }
6040
6041 /**
6042 * This method should always be called following an earlier call to
6043 * {@link #startViewTransition(View)}. The given View is finally removed from its parent
6044 * and will no longer be displayed. Note that this method does not perform the functionality
6045 * of removing a view from its parent; it just discontinues the display of a View that
6046 * has previously been removed.
6047 *
6048 * @return view The View object that has been removed but is being kept around in the visible
6049 * hierarchy by an earlier call to {@link #startViewTransition(View)}.
6050 */
6051 public void endViewTransition(View view) {
6052 if (mTransitioningViews != null) {
6053 mTransitioningViews.remove(view);
6054 final ArrayList<View> disappearingChildren = mDisappearingChildren;
6055 if (disappearingChildren != null && disappearingChildren.contains(view)) {
6056 disappearingChildren.remove(view);
Chet Haase5e25c2c2010-09-16 11:15:56 -07006057 if (mVisibilityChangingChildren != null &&
6058 mVisibilityChangingChildren.contains(view)) {
6059 mVisibilityChangingChildren.remove(view);
6060 } else {
6061 if (view.mAttachInfo != null) {
6062 view.dispatchDetachedFromWindow();
6063 }
6064 if (view.mParent != null) {
6065 view.mParent = null;
6066 }
Chet Haaseb20db3e2010-09-10 13:07:30 -07006067 }
Chet Haaseb85967b2012-03-26 14:37:51 -07006068 invalidate();
Chet Haaseb20db3e2010-09-10 13:07:30 -07006069 }
6070 }
6071 }
6072
Chet Haase21cd1382010-09-01 17:42:29 -07006073 private LayoutTransition.TransitionListener mLayoutTransitionListener =
6074 new LayoutTransition.TransitionListener() {
6075 @Override
6076 public void startTransition(LayoutTransition transition, ViewGroup container,
6077 View view, int transitionType) {
6078 // We only care about disappearing items, since we need special logic to keep
6079 // those items visible after they've been 'removed'
6080 if (transitionType == LayoutTransition.DISAPPEARING) {
Chet Haaseb20db3e2010-09-10 13:07:30 -07006081 startViewTransition(view);
Chet Haase21cd1382010-09-01 17:42:29 -07006082 }
6083 }
6084
6085 @Override
6086 public void endTransition(LayoutTransition transition, ViewGroup container,
6087 View view, int transitionType) {
Chet Haaseb9895022013-04-02 15:10:58 -07006088 if (mLayoutCalledWhileSuppressed && !transition.isChangingLayout()) {
Chet Haase9c087442011-01-12 16:20:16 -08006089 requestLayout();
Chet Haaseb9895022013-04-02 15:10:58 -07006090 mLayoutCalledWhileSuppressed = false;
Chet Haase9c087442011-01-12 16:20:16 -08006091 }
Chet Haase21cd1382010-09-01 17:42:29 -07006092 if (transitionType == LayoutTransition.DISAPPEARING && mTransitioningViews != null) {
Chet Haaseb20db3e2010-09-10 13:07:30 -07006093 endViewTransition(view);
Chet Haase21cd1382010-09-01 17:42:29 -07006094 }
6095 }
6096 };
6097
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006098 /**
Chet Haaseb9895022013-04-02 15:10:58 -07006099 * Tells this ViewGroup to suppress all layout() calls until layout
6100 * suppression is disabled with a later call to suppressLayout(false).
6101 * When layout suppression is disabled, a requestLayout() call is sent
6102 * if layout() was attempted while layout was being suppressed.
6103 *
6104 * @hide
6105 */
6106 public void suppressLayout(boolean suppress) {
6107 mSuppressLayout = suppress;
6108 if (!suppress) {
6109 if (mLayoutCalledWhileSuppressed) {
6110 requestLayout();
6111 mLayoutCalledWhileSuppressed = false;
6112 }
6113 }
6114 }
6115
6116 /**
Chet Haase199acdf2013-07-24 18:40:55 -07006117 * Returns whether layout calls on this container are currently being
6118 * suppressed, due to an earlier call to {@link #suppressLayout(boolean)}.
6119 *
6120 * @return true if layout calls are currently suppressed, false otherwise.
6121 *
6122 * @hide
6123 */
6124 public boolean isLayoutSuppressed() {
6125 return mSuppressLayout;
6126 }
6127
6128 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006129 * {@inheritDoc}
6130 */
6131 @Override
6132 public boolean gatherTransparentRegion(Region region) {
6133 // If no transparent regions requested, we are always opaque.
Dianne Hackborn4702a852012-08-17 15:18:29 -07006134 final boolean meOpaque = (mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) == 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006135 if (meOpaque && region == null) {
6136 // The caller doesn't care about the region, so stop now.
6137 return true;
6138 }
6139 super.gatherTransparentRegion(region);
6140 final View[] children = mChildren;
6141 final int count = mChildrenCount;
6142 boolean noneOfTheChildrenAreTransparent = true;
6143 for (int i = 0; i < count; i++) {
6144 final View child = children[i];
Mathias Agopiane3381152010-12-02 15:19:36 -08006145 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006146 if (!child.gatherTransparentRegion(region)) {
6147 noneOfTheChildrenAreTransparent = false;
6148 }
6149 }
6150 }
6151 return meOpaque || noneOfTheChildrenAreTransparent;
6152 }
6153
6154 /**
6155 * {@inheritDoc}
6156 */
6157 public void requestTransparentRegion(View child) {
6158 if (child != null) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07006159 child.mPrivateFlags |= View.PFLAG_REQUEST_TRANSPARENT_REGIONS;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006160 if (mParent != null) {
6161 mParent.requestTransparentRegion(this);
6162 }
6163 }
6164 }
Romain Guy8506ab42009-06-11 17:35:47 -07006165
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006166 @Override
Adam Powell46e38fd2014-02-03 10:16:49 -08006167 public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) {
6168 insets = super.dispatchApplyWindowInsets(insets);
Adam Powell0d9fdba2014-06-11 15:33:08 -07006169 if (!insets.isConsumed()) {
Adam Powell46e38fd2014-02-03 10:16:49 -08006170 final int count = getChildCount();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006171 for (int i = 0; i < count; i++) {
Adam Powell46e38fd2014-02-03 10:16:49 -08006172 insets = getChildAt(i).dispatchApplyWindowInsets(insets);
Adam Powell0d9fdba2014-06-11 15:33:08 -07006173 if (insets.isConsumed()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006174 break;
6175 }
6176 }
6177 }
Adam Powell46e38fd2014-02-03 10:16:49 -08006178 return insets;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006179 }
6180
6181 /**
6182 * Returns the animation listener to which layout animation events are
6183 * sent.
6184 *
6185 * @return an {@link android.view.animation.Animation.AnimationListener}
6186 */
6187 public Animation.AnimationListener getLayoutAnimationListener() {
6188 return mAnimationListener;
6189 }
6190
6191 @Override
6192 protected void drawableStateChanged() {
6193 super.drawableStateChanged();
6194
6195 if ((mGroupFlags & FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE) != 0) {
6196 if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0) {
6197 throw new IllegalStateException("addStateFromChildren cannot be enabled if a"
6198 + " child has duplicateParentState set to true");
6199 }
6200
6201 final View[] children = mChildren;
6202 final int count = mChildrenCount;
6203
6204 for (int i = 0; i < count; i++) {
6205 final View child = children[i];
6206 if ((child.mViewFlags & DUPLICATE_PARENT_STATE) != 0) {
6207 child.refreshDrawableState();
6208 }
6209 }
6210 }
6211 }
6212
6213 @Override
Dianne Hackborne2136772010-11-04 15:08:59 -07006214 public void jumpDrawablesToCurrentState() {
6215 super.jumpDrawablesToCurrentState();
6216 final View[] children = mChildren;
6217 final int count = mChildrenCount;
6218 for (int i = 0; i < count; i++) {
6219 children[i].jumpDrawablesToCurrentState();
6220 }
6221 }
6222
6223 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006224 protected int[] onCreateDrawableState(int extraSpace) {
6225 if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) == 0) {
6226 return super.onCreateDrawableState(extraSpace);
6227 }
6228
6229 int need = 0;
6230 int n = getChildCount();
6231 for (int i = 0; i < n; i++) {
6232 int[] childState = getChildAt(i).getDrawableState();
6233
6234 if (childState != null) {
6235 need += childState.length;
6236 }
6237 }
6238
6239 int[] state = super.onCreateDrawableState(extraSpace + need);
6240
6241 for (int i = 0; i < n; i++) {
6242 int[] childState = getChildAt(i).getDrawableState();
6243
6244 if (childState != null) {
6245 state = mergeDrawableStates(state, childState);
6246 }
6247 }
6248
6249 return state;
6250 }
6251
6252 /**
6253 * Sets whether this ViewGroup's drawable states also include
6254 * its children's drawable states. This is used, for example, to
6255 * make a group appear to be focused when its child EditText or button
6256 * is focused.
6257 */
6258 public void setAddStatesFromChildren(boolean addsStates) {
6259 if (addsStates) {
6260 mGroupFlags |= FLAG_ADD_STATES_FROM_CHILDREN;
6261 } else {
6262 mGroupFlags &= ~FLAG_ADD_STATES_FROM_CHILDREN;
6263 }
6264
6265 refreshDrawableState();
6266 }
6267
6268 /**
6269 * Returns whether this ViewGroup's drawable states also include
6270 * its children's drawable states. This is used, for example, to
6271 * make a group appear to be focused when its child EditText or button
6272 * is focused.
6273 */
6274 public boolean addStatesFromChildren() {
6275 return (mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0;
6276 }
6277
6278 /**
Jeff Smitha45746e2012-07-19 14:19:24 -05006279 * If {@link #addStatesFromChildren} is true, refreshes this group's
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006280 * drawable state (to include the states from its children).
6281 */
6282 public void childDrawableStateChanged(View child) {
6283 if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0) {
6284 refreshDrawableState();
6285 }
6286 }
6287
6288 /**
6289 * Specifies the animation listener to which layout animation events must
6290 * be sent. Only
6291 * {@link android.view.animation.Animation.AnimationListener#onAnimationStart(Animation)}
6292 * and
6293 * {@link android.view.animation.Animation.AnimationListener#onAnimationEnd(Animation)}
6294 * are invoked.
6295 *
6296 * @param animationListener the layout animation listener
6297 */
6298 public void setLayoutAnimationListener(Animation.AnimationListener animationListener) {
6299 mAnimationListener = animationListener;
6300 }
6301
6302 /**
Chet Haasecca2c982011-05-20 14:34:18 -07006303 * This method is called by LayoutTransition when there are 'changing' animations that need
6304 * to start after the layout/setup phase. The request is forwarded to the ViewAncestor, who
6305 * starts all pending transitions prior to the drawing phase in the current traversal.
6306 *
6307 * @param transition The LayoutTransition to be started on the next traversal.
6308 *
6309 * @hide
6310 */
6311 public void requestTransitionStart(LayoutTransition transition) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07006312 ViewRootImpl viewAncestor = getViewRootImpl();
Chet Haase1abf7fa2011-08-17 18:31:56 -07006313 if (viewAncestor != null) {
6314 viewAncestor.requestTransitionStart(transition);
6315 }
Chet Haasecca2c982011-05-20 14:34:18 -07006316 }
6317
Fabrice Di Meglio4457e852012-09-18 19:23:12 -07006318 /**
6319 * @hide
6320 */
Fabrice Di Meglio80dc53d2011-06-21 18:36:33 -07006321 @Override
Fabrice Di Meglio09ecb252013-05-03 16:51:55 -07006322 public boolean resolveRtlPropertiesIfNeeded() {
6323 final boolean result = super.resolveRtlPropertiesIfNeeded();
6324 // We dont need to resolve the children RTL properties if nothing has changed for the parent
6325 if (result) {
6326 int count = getChildCount();
6327 for (int i = 0; i < count; i++) {
6328 final View child = getChildAt(i);
6329 if (child.isLayoutDirectionInherited()) {
6330 child.resolveRtlPropertiesIfNeeded();
6331 }
Fabrice Di Meglio84ebb352012-10-11 16:27:37 -07006332 }
6333 }
Fabrice Di Meglio09ecb252013-05-03 16:51:55 -07006334 return result;
Fabrice Di Meglio84ebb352012-10-11 16:27:37 -07006335 }
6336
6337 /**
6338 * @hide
6339 */
6340 @Override
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07006341 public boolean resolveLayoutDirection() {
6342 final boolean result = super.resolveLayoutDirection();
6343 if (result) {
6344 int count = getChildCount();
6345 for (int i = 0; i < count; i++) {
6346 final View child = getChildAt(i);
6347 if (child.isLayoutDirectionInherited()) {
6348 child.resolveLayoutDirection();
6349 }
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07006350 }
6351 }
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07006352 return result;
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07006353 }
6354
6355 /**
6356 * @hide
6357 */
6358 @Override
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07006359 public boolean resolveTextDirection() {
6360 final boolean result = super.resolveTextDirection();
6361 if (result) {
6362 int count = getChildCount();
6363 for (int i = 0; i < count; i++) {
6364 final View child = getChildAt(i);
6365 if (child.isTextDirectionInherited()) {
6366 child.resolveTextDirection();
6367 }
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07006368 }
6369 }
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07006370 return result;
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07006371 }
6372
6373 /**
6374 * @hide
6375 */
6376 @Override
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07006377 public boolean resolveTextAlignment() {
6378 final boolean result = super.resolveTextAlignment();
6379 if (result) {
6380 int count = getChildCount();
6381 for (int i = 0; i < count; i++) {
6382 final View child = getChildAt(i);
6383 if (child.isTextAlignmentInherited()) {
6384 child.resolveTextAlignment();
6385 }
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07006386 }
6387 }
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07006388 return result;
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07006389 }
6390
6391 /**
6392 * @hide
6393 */
6394 @Override
Fabrice Di Meglio84ebb352012-10-11 16:27:37 -07006395 public void resolvePadding() {
6396 super.resolvePadding();
6397 int count = getChildCount();
6398 for (int i = 0; i < count; i++) {
6399 final View child = getChildAt(i);
Adam Powell05f35122014-11-10 17:47:37 -08006400 if (child.isLayoutDirectionInherited() && !child.isPaddingResolved()) {
Fabrice Di Meglio84ebb352012-10-11 16:27:37 -07006401 child.resolvePadding();
6402 }
6403 }
6404 }
6405
6406 /**
6407 * @hide
6408 */
6409 @Override
6410 protected void resolveDrawables() {
6411 super.resolveDrawables();
6412 int count = getChildCount();
6413 for (int i = 0; i < count; i++) {
6414 final View child = getChildAt(i);
Adam Powell05f35122014-11-10 17:47:37 -08006415 if (child.isLayoutDirectionInherited() && !child.areDrawablesResolved()) {
Fabrice Di Meglio84ebb352012-10-11 16:27:37 -07006416 child.resolveDrawables();
6417 }
6418 }
6419 }
6420
Fabrice Di Meglio1e0ed6b2012-10-18 16:06:52 -07006421 /**
6422 * @hide
6423 */
Fabrice Di Megliofcc33482012-10-18 11:11:51 -07006424 @Override
6425 public void resolveLayoutParams() {
6426 super.resolveLayoutParams();
6427 int count = getChildCount();
6428 for (int i = 0; i < count; i++) {
6429 final View child = getChildAt(i);
6430 child.resolveLayoutParams();
6431 }
6432 }
6433
Fabrice Di Meglio84ebb352012-10-11 16:27:37 -07006434 /**
6435 * @hide
6436 */
6437 @Override
Fabrice Di Meglio4457e852012-09-18 19:23:12 -07006438 public void resetResolvedLayoutDirection() {
6439 super.resetResolvedLayoutDirection();
6440
Fabrice Di Meglio4457e852012-09-18 19:23:12 -07006441 int count = getChildCount();
Fabrice Di Meglio80dc53d2011-06-21 18:36:33 -07006442 for (int i = 0; i < count; i++) {
6443 final View child = getChildAt(i);
Fabrice Di Meglioe56ffdc2012-09-23 14:51:16 -07006444 if (child.isLayoutDirectionInherited()) {
Fabrice Di Meglio7f86c802011-07-01 15:09:24 -07006445 child.resetResolvedLayoutDirection();
Fabrice Di Meglio80dc53d2011-06-21 18:36:33 -07006446 }
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07006447 }
6448 }
6449
6450 /**
6451 * @hide
6452 */
6453 @Override
6454 public void resetResolvedTextDirection() {
6455 super.resetResolvedTextDirection();
6456
6457 int count = getChildCount();
6458 for (int i = 0; i < count; i++) {
6459 final View child = getChildAt(i);
Fabrice Di Meglio97e146c2012-09-23 15:45:16 -07006460 if (child.isTextDirectionInherited()) {
Fabrice Di Meglio22268862011-06-27 18:13:18 -07006461 child.resetResolvedTextDirection();
6462 }
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07006463 }
6464 }
6465
6466 /**
6467 * @hide
6468 */
6469 @Override
6470 public void resetResolvedTextAlignment() {
6471 super.resetResolvedTextAlignment();
6472
6473 int count = getChildCount();
6474 for (int i = 0; i < count; i++) {
6475 final View child = getChildAt(i);
Fabrice Di Meglio1a7d4872012-09-23 16:19:58 -07006476 if (child.isTextAlignmentInherited()) {
Fabrice Di Meglio9da0f8a2012-03-13 19:37:57 -07006477 child.resetResolvedTextAlignment();
6478 }
6479 }
6480 }
6481
Fabrice Di Meglio22268862011-06-27 18:13:18 -07006482 /**
Fabrice Di Meglio84ebb352012-10-11 16:27:37 -07006483 * @hide
6484 */
6485 @Override
6486 public void resetResolvedPadding() {
6487 super.resetResolvedPadding();
6488
6489 int count = getChildCount();
6490 for (int i = 0; i < count; i++) {
6491 final View child = getChildAt(i);
6492 if (child.isLayoutDirectionInherited()) {
6493 child.resetResolvedPadding();
6494 }
6495 }
6496 }
6497
6498 /**
6499 * @hide
6500 */
6501 @Override
6502 protected void resetResolvedDrawables() {
6503 super.resetResolvedDrawables();
6504
6505 int count = getChildCount();
6506 for (int i = 0; i < count; i++) {
6507 final View child = getChildAt(i);
6508 if (child.isLayoutDirectionInherited()) {
6509 child.resetResolvedDrawables();
6510 }
6511 }
6512 }
6513
6514 /**
Patrick Dubroye0a799a2011-05-04 16:19:22 -07006515 * Return true if the pressed state should be delayed for children or descendants of this
6516 * ViewGroup. Generally, this should be done for containers that can scroll, such as a List.
6517 * This prevents the pressed state from appearing when the user is actually trying to scroll
6518 * the content.
6519 *
6520 * The default implementation returns true for compatibility reasons. Subclasses that do
6521 * not scroll should generally override this method and return false.
6522 */
6523 public boolean shouldDelayChildPressedState() {
6524 return true;
6525 }
6526
Adam Powell10ba2772014-04-15 09:46:51 -07006527 /**
6528 * @inheritDoc
6529 */
6530 @Override
6531 public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {
6532 return false;
6533 }
6534
6535 /**
6536 * @inheritDoc
6537 */
6538 @Override
6539 public void onNestedScrollAccepted(View child, View target, int axes) {
6540 mNestedScrollAxes = axes;
6541 }
6542
6543 /**
6544 * @inheritDoc
6545 *
6546 * <p>The default implementation of onStopNestedScroll calls
6547 * {@link #stopNestedScroll()} to halt any recursive nested scrolling in progress.</p>
6548 */
6549 @Override
6550 public void onStopNestedScroll(View child) {
6551 // Stop any recursive nested scrolling.
6552 stopNestedScroll();
Adam Powelld4a22d42015-04-16 15:44:10 -07006553 mNestedScrollAxes = 0;
Adam Powell10ba2772014-04-15 09:46:51 -07006554 }
6555
6556 /**
6557 * @inheritDoc
6558 */
6559 @Override
6560 public void onNestedScroll(View target, int dxConsumed, int dyConsumed,
6561 int dxUnconsumed, int dyUnconsumed) {
6562 // Do nothing
6563 }
6564
6565 /**
6566 * @inheritDoc
6567 */
6568 @Override
6569 public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {
6570 // Do nothing
6571 }
6572
6573 /**
6574 * @inheritDoc
6575 */
6576 @Override
Adam Powellb36e4f92014-05-01 10:23:33 -07006577 public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
Adam Powell10ba2772014-04-15 09:46:51 -07006578 return false;
6579 }
6580
6581 /**
Adam Powellb72be592014-07-16 21:41:31 -07006582 * @inheritDoc
6583 */
6584 @Override
6585 public boolean onNestedPreFling(View target, float velocityX, float velocityY) {
6586 return false;
6587 }
6588
6589 /**
Adam Powell10ba2772014-04-15 09:46:51 -07006590 * Return the current axes of nested scrolling for this ViewGroup.
6591 *
6592 * <p>A ViewGroup returning something other than {@link #SCROLL_AXIS_NONE} is currently
6593 * acting as a nested scrolling parent for one or more descendant views in the hierarchy.</p>
6594 *
6595 * @return Flags indicating the current axes of nested scrolling
6596 * @see #SCROLL_AXIS_HORIZONTAL
6597 * @see #SCROLL_AXIS_VERTICAL
6598 * @see #SCROLL_AXIS_NONE
6599 */
6600 public int getNestedScrollAxes() {
6601 return mNestedScrollAxes;
6602 }
6603
Philip Milned7dd8902012-01-26 16:55:30 -08006604 /** @hide */
6605 protected void onSetLayoutParams(View child, LayoutParams layoutParams) {
6606 }
6607
George Mounte1803372014-02-26 19:00:52 +00006608 /** @hide */
6609 @Override
6610 public void captureTransitioningViews(List<View> transitioningViews) {
6611 if (getVisibility() != View.VISIBLE) {
6612 return;
6613 }
6614 if (isTransitionGroup()) {
6615 transitioningViews.add(this);
6616 } else {
6617 int count = getChildCount();
6618 for (int i = 0; i < count; i++) {
6619 View child = getChildAt(i);
6620 child.captureTransitioningViews(transitioningViews);
6621 }
6622 }
6623 }
6624
6625 /** @hide */
6626 @Override
George Mountabb352a2014-05-09 10:27:20 -07006627 public void findNamedViews(Map<String, View> namedElements) {
George Mountfe361d22014-07-08 17:25:25 -07006628 if (getVisibility() != VISIBLE && mGhostView == null) {
George Mounte1803372014-02-26 19:00:52 +00006629 return;
6630 }
George Mountabb352a2014-05-09 10:27:20 -07006631 super.findNamedViews(namedElements);
George Mounte1803372014-02-26 19:00:52 +00006632 int count = getChildCount();
6633 for (int i = 0; i < count; i++) {
6634 View child = getChildAt(i);
George Mountabb352a2014-05-09 10:27:20 -07006635 child.findNamedViews(namedElements);
George Mounte1803372014-02-26 19:00:52 +00006636 }
6637 }
6638
Patrick Dubroye0a799a2011-05-04 16:19:22 -07006639 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006640 * LayoutParams are used by views to tell their parents how they want to be
6641 * laid out. See
6642 * {@link android.R.styleable#ViewGroup_Layout ViewGroup Layout Attributes}
6643 * for a list of all child view attributes that this class supports.
Romain Guy8506ab42009-06-11 17:35:47 -07006644 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006645 * <p>
6646 * The base LayoutParams class just describes how big the view wants to be
6647 * for both width and height. For each dimension, it can specify one of:
6648 * <ul>
Dirk Dougherty75c66da2010-03-25 16:33:33 -07006649 * <li>FILL_PARENT (renamed MATCH_PARENT in API Level 8 and higher), which
6650 * means that the view wants to be as big as its parent (minus padding)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006651 * <li> WRAP_CONTENT, which means that the view wants to be just big enough
6652 * to enclose its content (plus padding)
Dirk Dougherty75c66da2010-03-25 16:33:33 -07006653 * <li> an exact number
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006654 * </ul>
6655 * There are subclasses of LayoutParams for different subclasses of
6656 * ViewGroup. For example, AbsoluteLayout has its own subclass of
Joe Fernandez558459f2011-10-13 16:47:36 -07006657 * LayoutParams which adds an X and Y value.</p>
6658 *
6659 * <div class="special reference">
6660 * <h3>Developer Guides</h3>
6661 * <p>For more information about creating user interface layouts, read the
6662 * <a href="{@docRoot}guide/topics/ui/declaring-layout.html">XML Layouts</a> developer
6663 * guide.</p></div>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006664 *
6665 * @attr ref android.R.styleable#ViewGroup_Layout_layout_height
6666 * @attr ref android.R.styleable#ViewGroup_Layout_layout_width
6667 */
6668 public static class LayoutParams {
6669 /**
Dirk Dougherty75c66da2010-03-25 16:33:33 -07006670 * Special value for the height or width requested by a View.
6671 * FILL_PARENT means that the view wants to be as big as its parent,
6672 * minus the parent's padding, if any. This value is deprecated
6673 * starting in API Level 8 and replaced by {@link #MATCH_PARENT}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006674 */
Romain Guy980a9382010-01-08 15:06:28 -08006675 @SuppressWarnings({"UnusedDeclaration"})
6676 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006677 public static final int FILL_PARENT = -1;
6678
6679 /**
6680 * Special value for the height or width requested by a View.
Gilles Debunnef5c6eff2010-02-09 19:08:36 -08006681 * MATCH_PARENT means that the view wants to be as big as its parent,
Dirk Dougherty75c66da2010-03-25 16:33:33 -07006682 * minus the parent's padding, if any. Introduced in API Level 8.
Romain Guy980a9382010-01-08 15:06:28 -08006683 */
6684 public static final int MATCH_PARENT = -1;
6685
6686 /**
6687 * Special value for the height or width requested by a View.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006688 * WRAP_CONTENT means that the view wants to be just large enough to fit
6689 * its own internal content, taking its own padding into account.
6690 */
6691 public static final int WRAP_CONTENT = -2;
6692
6693 /**
Dirk Dougherty75c66da2010-03-25 16:33:33 -07006694 * Information about how wide the view wants to be. Can be one of the
Mark Dolinerd0646dc2014-08-27 16:04:02 -07006695 * constants FILL_PARENT (replaced by MATCH_PARENT
6696 * in API Level 8) or WRAP_CONTENT, or an exact size.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006697 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07006698 @ViewDebug.ExportedProperty(category = "layout", mapping = {
Romain Guy980a9382010-01-08 15:06:28 -08006699 @ViewDebug.IntToString(from = MATCH_PARENT, to = "MATCH_PARENT"),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006700 @ViewDebug.IntToString(from = WRAP_CONTENT, to = "WRAP_CONTENT")
6701 })
6702 public int width;
6703
6704 /**
Dirk Dougherty75c66da2010-03-25 16:33:33 -07006705 * Information about how tall the view wants to be. Can be one of the
Mark Dolinerd0646dc2014-08-27 16:04:02 -07006706 * constants FILL_PARENT (replaced by MATCH_PARENT
6707 * in API Level 8) or WRAP_CONTENT, or an exact size.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006708 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07006709 @ViewDebug.ExportedProperty(category = "layout", mapping = {
Romain Guy980a9382010-01-08 15:06:28 -08006710 @ViewDebug.IntToString(from = MATCH_PARENT, to = "MATCH_PARENT"),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006711 @ViewDebug.IntToString(from = WRAP_CONTENT, to = "WRAP_CONTENT")
6712 })
6713 public int height;
6714
6715 /**
6716 * Used to animate layouts.
6717 */
6718 public LayoutAnimationController.AnimationParameters layoutAnimationParameters;
6719
6720 /**
6721 * Creates a new set of layout parameters. The values are extracted from
6722 * the supplied attributes set and context. The XML attributes mapped
6723 * to this set of layout parameters are:
6724 *
6725 * <ul>
6726 * <li><code>layout_width</code>: the width, either an exact value,
Dirk Dougherty75c66da2010-03-25 16:33:33 -07006727 * {@link #WRAP_CONTENT}, or {@link #FILL_PARENT} (replaced by
6728 * {@link #MATCH_PARENT} in API Level 8)</li>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006729 * <li><code>layout_height</code>: the height, either an exact value,
Dirk Dougherty75c66da2010-03-25 16:33:33 -07006730 * {@link #WRAP_CONTENT}, or {@link #FILL_PARENT} (replaced by
6731 * {@link #MATCH_PARENT} in API Level 8)</li>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006732 * </ul>
6733 *
6734 * @param c the application environment
6735 * @param attrs the set of attributes from which to extract the layout
6736 * parameters' values
6737 */
6738 public LayoutParams(Context c, AttributeSet attrs) {
6739 TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.ViewGroup_Layout);
6740 setBaseAttributes(a,
6741 R.styleable.ViewGroup_Layout_layout_width,
6742 R.styleable.ViewGroup_Layout_layout_height);
6743 a.recycle();
6744 }
6745
6746 /**
6747 * Creates a new set of layout parameters with the specified width
6748 * and height.
6749 *
Dirk Dougherty75c66da2010-03-25 16:33:33 -07006750 * @param width the width, either {@link #WRAP_CONTENT},
6751 * {@link #FILL_PARENT} (replaced by {@link #MATCH_PARENT} in
6752 * API Level 8), or a fixed size in pixels
6753 * @param height the height, either {@link #WRAP_CONTENT},
6754 * {@link #FILL_PARENT} (replaced by {@link #MATCH_PARENT} in
6755 * API Level 8), or a fixed size in pixels
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006756 */
6757 public LayoutParams(int width, int height) {
6758 this.width = width;
6759 this.height = height;
6760 }
6761
6762 /**
6763 * Copy constructor. Clones the width and height values of the source.
6764 *
6765 * @param source The layout params to copy from.
6766 */
6767 public LayoutParams(LayoutParams source) {
6768 this.width = source.width;
6769 this.height = source.height;
6770 }
6771
6772 /**
6773 * Used internally by MarginLayoutParams.
6774 * @hide
6775 */
6776 LayoutParams() {
6777 }
6778
6779 /**
Dave Burke579e1402012-10-18 20:41:55 -07006780 * Extracts the layout parameters from the supplied attributes.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006781 *
6782 * @param a the style attributes to extract the parameters from
6783 * @param widthAttr the identifier of the width attribute
6784 * @param heightAttr the identifier of the height attribute
6785 */
6786 protected void setBaseAttributes(TypedArray a, int widthAttr, int heightAttr) {
Dave Burke579e1402012-10-18 20:41:55 -07006787 width = a.getLayoutDimension(widthAttr, "layout_width");
6788 height = a.getLayoutDimension(heightAttr, "layout_height");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006789 }
6790
6791 /**
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006792 * Resolve layout parameters depending on the layout direction. Subclasses that care about
6793 * layoutDirection changes should override this method. The default implementation does
6794 * nothing.
6795 *
6796 * @param layoutDirection the direction of the layout
6797 *
6798 * {@link View#LAYOUT_DIRECTION_LTR}
6799 * {@link View#LAYOUT_DIRECTION_RTL}
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006800 */
Fabrice Di Meglio2918ab62012-10-10 16:39:25 -07006801 public void resolveLayoutDirection(int layoutDirection) {
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006802 }
6803
6804 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006805 * Returns a String representation of this set of layout parameters.
6806 *
6807 * @param output the String to prepend to the internal representation
6808 * @return a String with the following format: output +
6809 * "ViewGroup.LayoutParams={ width=WIDTH, height=HEIGHT }"
Romain Guy8506ab42009-06-11 17:35:47 -07006810 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006811 * @hide
6812 */
6813 public String debug(String output) {
6814 return output + "ViewGroup.LayoutParams={ width="
6815 + sizeToString(width) + ", height=" + sizeToString(height) + " }";
6816 }
6817
6818 /**
Philip Milne10ca24a2012-04-23 15:38:27 -07006819 * Use {@code canvas} to draw suitable debugging annotations for these LayoutParameters.
6820 *
6821 * @param view the view that contains these layout parameters
6822 * @param canvas the canvas on which to draw
6823 *
6824 * @hide
6825 */
Philip Milne7b757812012-09-19 18:13:44 -07006826 public void onDebugDraw(View view, Canvas canvas, Paint paint) {
Philip Milne10ca24a2012-04-23 15:38:27 -07006827 }
6828
6829 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006830 * Converts the specified size to a readable String.
6831 *
6832 * @param size the size to convert
6833 * @return a String instance representing the supplied size
Romain Guy8506ab42009-06-11 17:35:47 -07006834 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006835 * @hide
6836 */
6837 protected static String sizeToString(int size) {
6838 if (size == WRAP_CONTENT) {
6839 return "wrap-content";
6840 }
Romain Guy980a9382010-01-08 15:06:28 -08006841 if (size == MATCH_PARENT) {
6842 return "match-parent";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006843 }
6844 return String.valueOf(size);
6845 }
6846 }
6847
6848 /**
6849 * Per-child layout information for layouts that support margins.
6850 * See
6851 * {@link android.R.styleable#ViewGroup_MarginLayout ViewGroup Margin Layout Attributes}
6852 * for a list of all child view attributes that this class supports.
6853 */
6854 public static class MarginLayoutParams extends ViewGroup.LayoutParams {
6855 /**
Adam Powella7a735f2014-10-09 12:54:52 -07006856 * The left margin in pixels of the child. Margin values should be positive.
Philip Milned7dd8902012-01-26 16:55:30 -08006857 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
6858 * to this field.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006859 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07006860 @ViewDebug.ExportedProperty(category = "layout")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006861 public int leftMargin;
6862
6863 /**
Adam Powella7a735f2014-10-09 12:54:52 -07006864 * The top margin in pixels of the child. Margin values should be positive.
Philip Milned7dd8902012-01-26 16:55:30 -08006865 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
6866 * to this field.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006867 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07006868 @ViewDebug.ExportedProperty(category = "layout")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006869 public int topMargin;
6870
6871 /**
Adam Powella7a735f2014-10-09 12:54:52 -07006872 * The right margin in pixels of the child. Margin values should be positive.
Philip Milned7dd8902012-01-26 16:55:30 -08006873 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
6874 * to this field.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006875 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07006876 @ViewDebug.ExportedProperty(category = "layout")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006877 public int rightMargin;
6878
6879 /**
Adam Powella7a735f2014-10-09 12:54:52 -07006880 * The bottom margin in pixels of the child. Margin values should be positive.
Philip Milned7dd8902012-01-26 16:55:30 -08006881 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
6882 * to this field.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006883 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07006884 @ViewDebug.ExportedProperty(category = "layout")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006885 public int bottomMargin;
6886
6887 /**
Adam Powella7a735f2014-10-09 12:54:52 -07006888 * The start margin in pixels of the child. Margin values should be positive.
Fabrice Di Meglio54546f22012-02-14 16:26:16 -08006889 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
6890 * to this field.
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006891 */
6892 @ViewDebug.ExportedProperty(category = "layout")
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006893 private int startMargin = DEFAULT_MARGIN_RELATIVE;
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006894
6895 /**
Adam Powella7a735f2014-10-09 12:54:52 -07006896 * The end margin in pixels of the child. Margin values should be positive.
Fabrice Di Meglio54546f22012-02-14 16:26:16 -08006897 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
6898 * to this field.
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006899 */
6900 @ViewDebug.ExportedProperty(category = "layout")
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006901 private int endMargin = DEFAULT_MARGIN_RELATIVE;
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006902
6903 /**
6904 * The default start and end margin.
Fabrice Di Megliof443f982012-07-13 20:24:03 -07006905 * @hide
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006906 */
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006907 public static final int DEFAULT_MARGIN_RELATIVE = Integer.MIN_VALUE;
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006908
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006909 /**
6910 * Bit 0: layout direction
6911 * Bit 1: layout direction
6912 * Bit 2: left margin undefined
6913 * Bit 3: right margin undefined
6914 * Bit 4: is RTL compatibility mode
6915 * Bit 5: need resolution
6916 *
6917 * Bit 6 to 7 not used
6918 *
6919 * @hide
6920 */
6921 @ViewDebug.ExportedProperty(category = "layout", flagMapping = {
6922 @ViewDebug.FlagToString(mask = LAYOUT_DIRECTION_MASK,
6923 equals = LAYOUT_DIRECTION_MASK, name = "LAYOUT_DIRECTION"),
6924 @ViewDebug.FlagToString(mask = LEFT_MARGIN_UNDEFINED_MASK,
6925 equals = LEFT_MARGIN_UNDEFINED_MASK, name = "LEFT_MARGIN_UNDEFINED_MASK"),
6926 @ViewDebug.FlagToString(mask = RIGHT_MARGIN_UNDEFINED_MASK,
6927 equals = RIGHT_MARGIN_UNDEFINED_MASK, name = "RIGHT_MARGIN_UNDEFINED_MASK"),
6928 @ViewDebug.FlagToString(mask = RTL_COMPATIBILITY_MODE_MASK,
6929 equals = RTL_COMPATIBILITY_MODE_MASK, name = "RTL_COMPATIBILITY_MODE_MASK"),
6930 @ViewDebug.FlagToString(mask = NEED_RESOLUTION_MASK,
6931 equals = NEED_RESOLUTION_MASK, name = "NEED_RESOLUTION_MASK")
Jon Miranda4597e982014-07-29 07:25:49 -07006932 }, formatToHexString = true)
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006933 byte mMarginFlags;
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07006934
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006935 private static final int LAYOUT_DIRECTION_MASK = 0x00000003;
6936 private static final int LEFT_MARGIN_UNDEFINED_MASK = 0x00000004;
6937 private static final int RIGHT_MARGIN_UNDEFINED_MASK = 0x00000008;
6938 private static final int RTL_COMPATIBILITY_MODE_MASK = 0x00000010;
6939 private static final int NEED_RESOLUTION_MASK = 0x00000020;
Fabrice Di Megliof443f982012-07-13 20:24:03 -07006940
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006941 private static final int DEFAULT_MARGIN_RESOLVED = 0;
6942 private static final int UNDEFINED_MARGIN = DEFAULT_MARGIN_RELATIVE;
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07006943
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006944 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006945 * Creates a new set of layout parameters. The values are extracted from
6946 * the supplied attributes set and context.
6947 *
6948 * @param c the application environment
6949 * @param attrs the set of attributes from which to extract the layout
6950 * parameters' values
6951 */
6952 public MarginLayoutParams(Context c, AttributeSet attrs) {
6953 super();
6954
6955 TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.ViewGroup_MarginLayout);
6956 setBaseAttributes(a,
6957 R.styleable.ViewGroup_MarginLayout_layout_width,
6958 R.styleable.ViewGroup_MarginLayout_layout_height);
6959
6960 int margin = a.getDimensionPixelSize(
6961 com.android.internal.R.styleable.ViewGroup_MarginLayout_layout_margin, -1);
6962 if (margin >= 0) {
6963 leftMargin = margin;
6964 topMargin = margin;
6965 rightMargin= margin;
6966 bottomMargin = margin;
6967 } else {
6968 leftMargin = a.getDimensionPixelSize(
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006969 R.styleable.ViewGroup_MarginLayout_layout_marginLeft,
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07006970 UNDEFINED_MARGIN);
6971 if (leftMargin == UNDEFINED_MARGIN) {
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006972 mMarginFlags |= LEFT_MARGIN_UNDEFINED_MASK;
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07006973 leftMargin = DEFAULT_MARGIN_RESOLVED;
6974 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006975 rightMargin = a.getDimensionPixelSize(
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006976 R.styleable.ViewGroup_MarginLayout_layout_marginRight,
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07006977 UNDEFINED_MARGIN);
6978 if (rightMargin == UNDEFINED_MARGIN) {
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006979 mMarginFlags |= RIGHT_MARGIN_UNDEFINED_MASK;
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07006980 rightMargin = DEFAULT_MARGIN_RESOLVED;
6981 }
6982
6983 topMargin = a.getDimensionPixelSize(
6984 R.styleable.ViewGroup_MarginLayout_layout_marginTop,
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006985 DEFAULT_MARGIN_RESOLVED);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006986 bottomMargin = a.getDimensionPixelSize(
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006987 R.styleable.ViewGroup_MarginLayout_layout_marginBottom,
6988 DEFAULT_MARGIN_RESOLVED);
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07006989
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006990 startMargin = a.getDimensionPixelSize(
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006991 R.styleable.ViewGroup_MarginLayout_layout_marginStart,
6992 DEFAULT_MARGIN_RELATIVE);
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006993 endMargin = a.getDimensionPixelSize(
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006994 R.styleable.ViewGroup_MarginLayout_layout_marginEnd,
6995 DEFAULT_MARGIN_RELATIVE);
6996
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006997 if (isMarginRelative()) {
6998 mMarginFlags |= NEED_RESOLUTION_MASK;
6999 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007000 }
7001
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07007002 final boolean hasRtlSupport = c.getApplicationInfo().hasRtlSupport();
7003 final int targetSdkVersion = c.getApplicationInfo().targetSdkVersion;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007004 if (targetSdkVersion < JELLY_BEAN_MR1 || !hasRtlSupport) {
7005 mMarginFlags |= RTL_COMPATIBILITY_MODE_MASK;
7006 }
7007
7008 // Layout direction is LTR by default
7009 mMarginFlags |= LAYOUT_DIRECTION_LTR;
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07007010
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007011 a.recycle();
7012 }
7013
7014 /**
7015 * {@inheritDoc}
7016 */
7017 public MarginLayoutParams(int width, int height) {
7018 super(width, height);
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07007019
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007020 mMarginFlags |= LEFT_MARGIN_UNDEFINED_MASK;
7021 mMarginFlags |= RIGHT_MARGIN_UNDEFINED_MASK;
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07007022
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007023 mMarginFlags &= ~NEED_RESOLUTION_MASK;
7024 mMarginFlags &= ~RTL_COMPATIBILITY_MODE_MASK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007025 }
7026
7027 /**
7028 * Copy constructor. Clones the width, height and margin values of the source.
7029 *
7030 * @param source The layout params to copy from.
7031 */
7032 public MarginLayoutParams(MarginLayoutParams source) {
7033 this.width = source.width;
7034 this.height = source.height;
7035
7036 this.leftMargin = source.leftMargin;
7037 this.topMargin = source.topMargin;
7038 this.rightMargin = source.rightMargin;
7039 this.bottomMargin = source.bottomMargin;
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007040 this.startMargin = source.startMargin;
7041 this.endMargin = source.endMargin;
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07007042
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007043 this.mMarginFlags = source.mMarginFlags;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007044 }
7045
7046 /**
7047 * {@inheritDoc}
7048 */
7049 public MarginLayoutParams(LayoutParams source) {
7050 super(source);
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07007051
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007052 mMarginFlags |= LEFT_MARGIN_UNDEFINED_MASK;
7053 mMarginFlags |= RIGHT_MARGIN_UNDEFINED_MASK;
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07007054
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007055 mMarginFlags &= ~NEED_RESOLUTION_MASK;
7056 mMarginFlags &= ~RTL_COMPATIBILITY_MODE_MASK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007057 }
7058
7059 /**
Adam Powelld7600832014-07-01 15:22:50 -07007060 * @hide Used internally.
7061 */
7062 public final void copyMarginsFrom(MarginLayoutParams source) {
7063 this.leftMargin = source.leftMargin;
7064 this.topMargin = source.topMargin;
7065 this.rightMargin = source.rightMargin;
7066 this.bottomMargin = source.bottomMargin;
7067 this.startMargin = source.startMargin;
7068 this.endMargin = source.endMargin;
7069
7070 this.mMarginFlags = source.mMarginFlags;
7071 }
7072
7073 /**
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007074 * Sets the margins, in pixels. A call to {@link android.view.View#requestLayout()} needs
7075 * to be done so that the new margins are taken into account. Left and right margins may be
7076 * overriden by {@link android.view.View#requestLayout()} depending on layout direction.
Adam Powella7a735f2014-10-09 12:54:52 -07007077 * Margin values should be positive.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007078 *
7079 * @param left the left margin size
7080 * @param top the top margin size
7081 * @param right the right margin size
7082 * @param bottom the bottom margin size
7083 *
7084 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginLeft
7085 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginTop
7086 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginRight
7087 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginBottom
7088 */
7089 public void setMargins(int left, int top, int right, int bottom) {
7090 leftMargin = left;
7091 topMargin = top;
7092 rightMargin = right;
7093 bottomMargin = bottom;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007094 mMarginFlags &= ~LEFT_MARGIN_UNDEFINED_MASK;
7095 mMarginFlags &= ~RIGHT_MARGIN_UNDEFINED_MASK;
7096 if (isMarginRelative()) {
7097 mMarginFlags |= NEED_RESOLUTION_MASK;
7098 } else {
7099 mMarginFlags &= ~NEED_RESOLUTION_MASK;
7100 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007101 }
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007102
7103 /**
7104 * Sets the relative margins, in pixels. A call to {@link android.view.View#requestLayout()}
7105 * needs to be done so that the new relative margins are taken into account. Left and right
7106 * margins may be overriden by {@link android.view.View#requestLayout()} depending on layout
Adam Powella7a735f2014-10-09 12:54:52 -07007107 * direction. Margin values should be positive.
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007108 *
7109 * @param start the start margin size
7110 * @param top the top margin size
7111 * @param end the right margin size
7112 * @param bottom the bottom margin size
7113 *
7114 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart
7115 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginTop
7116 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd
7117 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginBottom
7118 *
7119 * @hide
7120 */
7121 public void setMarginsRelative(int start, int top, int end, int bottom) {
7122 startMargin = start;
7123 topMargin = top;
7124 endMargin = end;
7125 bottomMargin = bottom;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007126 mMarginFlags |= NEED_RESOLUTION_MASK;
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007127 }
7128
7129 /**
Adam Powella7a735f2014-10-09 12:54:52 -07007130 * Sets the relative start margin. Margin values should be positive.
Fabrice Di Meglioa40627d2012-09-11 16:47:21 -07007131 *
Fabrice Di Meglio61a21772012-09-12 16:33:13 -07007132 * @param start the start margin size
Fabrice Di Meglioa40627d2012-09-11 16:47:21 -07007133 *
7134 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart
7135 */
7136 public void setMarginStart(int start) {
7137 startMargin = start;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007138 mMarginFlags |= NEED_RESOLUTION_MASK;
Fabrice Di Meglioa40627d2012-09-11 16:47:21 -07007139 }
7140
7141 /**
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007142 * Returns the start margin in pixels.
7143 *
7144 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart
7145 *
7146 * @return the start margin in pixels.
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007147 */
7148 public int getMarginStart() {
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07007149 if (startMargin != DEFAULT_MARGIN_RELATIVE) return startMargin;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007150 if ((mMarginFlags & NEED_RESOLUTION_MASK) == NEED_RESOLUTION_MASK) {
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07007151 doResolveMargins();
7152 }
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007153 switch(mMarginFlags & LAYOUT_DIRECTION_MASK) {
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07007154 case View.LAYOUT_DIRECTION_RTL:
7155 return rightMargin;
7156 case View.LAYOUT_DIRECTION_LTR:
7157 default:
7158 return leftMargin;
7159 }
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007160 }
7161
7162 /**
Adam Powella7a735f2014-10-09 12:54:52 -07007163 * Sets the relative end margin. Margin values should be positive.
Fabrice Di Meglioa40627d2012-09-11 16:47:21 -07007164 *
Fabrice Di Meglio61a21772012-09-12 16:33:13 -07007165 * @param end the end margin size
Fabrice Di Meglioa40627d2012-09-11 16:47:21 -07007166 *
7167 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd
7168 */
7169 public void setMarginEnd(int end) {
7170 endMargin = end;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007171 mMarginFlags |= NEED_RESOLUTION_MASK;
Fabrice Di Meglioa40627d2012-09-11 16:47:21 -07007172 }
7173
7174 /**
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007175 * Returns the end margin in pixels.
7176 *
7177 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd
7178 *
7179 * @return the end margin in pixels.
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007180 */
7181 public int getMarginEnd() {
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07007182 if (endMargin != DEFAULT_MARGIN_RELATIVE) return endMargin;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007183 if ((mMarginFlags & NEED_RESOLUTION_MASK) == NEED_RESOLUTION_MASK) {
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07007184 doResolveMargins();
7185 }
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007186 switch(mMarginFlags & LAYOUT_DIRECTION_MASK) {
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07007187 case View.LAYOUT_DIRECTION_RTL:
7188 return leftMargin;
7189 case View.LAYOUT_DIRECTION_LTR:
7190 default:
7191 return rightMargin;
7192 }
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007193 }
7194
7195 /**
7196 * Check if margins are relative.
7197 *
7198 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart
7199 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd
7200 *
Fabrice Di Megliof443f982012-07-13 20:24:03 -07007201 * @return true if either marginStart or marginEnd has been set.
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007202 */
7203 public boolean isMarginRelative() {
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07007204 return (startMargin != DEFAULT_MARGIN_RELATIVE || endMargin != DEFAULT_MARGIN_RELATIVE);
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007205 }
7206
7207 /**
Fabrice Di Megliof443f982012-07-13 20:24:03 -07007208 * Set the layout direction
7209 * @param layoutDirection the layout direction.
7210 * Should be either {@link View#LAYOUT_DIRECTION_LTR}
7211 * or {@link View#LAYOUT_DIRECTION_RTL}.
7212 */
7213 public void setLayoutDirection(int layoutDirection) {
7214 if (layoutDirection != View.LAYOUT_DIRECTION_LTR &&
7215 layoutDirection != View.LAYOUT_DIRECTION_RTL) return;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007216 if (layoutDirection != (mMarginFlags & LAYOUT_DIRECTION_MASK)) {
7217 mMarginFlags &= ~LAYOUT_DIRECTION_MASK;
7218 mMarginFlags |= (layoutDirection & LAYOUT_DIRECTION_MASK);
7219 if (isMarginRelative()) {
7220 mMarginFlags |= NEED_RESOLUTION_MASK;
7221 } else {
7222 mMarginFlags &= ~NEED_RESOLUTION_MASK;
7223 }
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07007224 }
Fabrice Di Megliof443f982012-07-13 20:24:03 -07007225 }
7226
7227 /**
7228 * Retuns the layout direction. Can be either {@link View#LAYOUT_DIRECTION_LTR} or
7229 * {@link View#LAYOUT_DIRECTION_RTL}.
7230 *
7231 * @return the layout direction.
7232 */
7233 public int getLayoutDirection() {
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007234 return (mMarginFlags & LAYOUT_DIRECTION_MASK);
Fabrice Di Megliof443f982012-07-13 20:24:03 -07007235 }
7236
7237 /**
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007238 * This will be called by {@link android.view.View#requestLayout()}. Left and Right margins
Fabrice Di Meglio98aec1c2012-02-13 16:54:05 -08007239 * may be overridden depending on layout direction.
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007240 */
7241 @Override
Fabrice Di Meglio2918ab62012-10-10 16:39:25 -07007242 public void resolveLayoutDirection(int layoutDirection) {
Fabrice Di Megliof443f982012-07-13 20:24:03 -07007243 setLayoutDirection(layoutDirection);
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07007244
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07007245 // No relative margin or pre JB-MR1 case or no need to resolve, just dont do anything
7246 // Will use the left and right margins if no relative margin is defined.
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007247 if (!isMarginRelative() ||
7248 (mMarginFlags & NEED_RESOLUTION_MASK) != NEED_RESOLUTION_MASK) return;
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07007249
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07007250 // Proceed with resolution
7251 doResolveMargins();
7252 }
7253
7254 private void doResolveMargins() {
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007255 if ((mMarginFlags & RTL_COMPATIBILITY_MODE_MASK) == RTL_COMPATIBILITY_MODE_MASK) {
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07007256 // if left or right margins are not defined and if we have some start or end margin
7257 // defined then use those start and end margins.
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007258 if ((mMarginFlags & LEFT_MARGIN_UNDEFINED_MASK) == LEFT_MARGIN_UNDEFINED_MASK
7259 && startMargin > DEFAULT_MARGIN_RELATIVE) {
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07007260 leftMargin = startMargin;
7261 }
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007262 if ((mMarginFlags & RIGHT_MARGIN_UNDEFINED_MASK) == RIGHT_MARGIN_UNDEFINED_MASK
7263 && endMargin > DEFAULT_MARGIN_RELATIVE) {
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07007264 rightMargin = endMargin;
7265 }
7266 } else {
7267 // We have some relative margins (either the start one or the end one or both). So use
7268 // them and override what has been defined for left and right margins. If either start
7269 // or end margin is not defined, just set it to default "0".
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007270 switch(mMarginFlags & LAYOUT_DIRECTION_MASK) {
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07007271 case View.LAYOUT_DIRECTION_RTL:
7272 leftMargin = (endMargin > DEFAULT_MARGIN_RELATIVE) ?
7273 endMargin : DEFAULT_MARGIN_RESOLVED;
7274 rightMargin = (startMargin > DEFAULT_MARGIN_RELATIVE) ?
7275 startMargin : DEFAULT_MARGIN_RESOLVED;
7276 break;
7277 case View.LAYOUT_DIRECTION_LTR:
7278 default:
7279 leftMargin = (startMargin > DEFAULT_MARGIN_RELATIVE) ?
7280 startMargin : DEFAULT_MARGIN_RESOLVED;
7281 rightMargin = (endMargin > DEFAULT_MARGIN_RELATIVE) ?
7282 endMargin : DEFAULT_MARGIN_RESOLVED;
7283 break;
7284 }
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007285 }
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007286 mMarginFlags &= ~NEED_RESOLUTION_MASK;
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07007287 }
Philip Milne10ca24a2012-04-23 15:38:27 -07007288
Fabrice Di Meglio03b8d3a2012-09-27 17:05:27 -07007289 /**
7290 * @hide
7291 */
7292 public boolean isLayoutRtl() {
Fabrice Di Megliob365f912013-03-27 16:36:21 -07007293 return ((mMarginFlags & LAYOUT_DIRECTION_MASK) == View.LAYOUT_DIRECTION_RTL);
Fabrice Di Megliof443f982012-07-13 20:24:03 -07007294 }
7295
Philip Milne10ca24a2012-04-23 15:38:27 -07007296 /**
7297 * @hide
7298 */
7299 @Override
Philip Milne7b757812012-09-19 18:13:44 -07007300 public void onDebugDraw(View view, Canvas canvas, Paint paint) {
7301 Insets oi = isLayoutModeOptical(view.mParent) ? view.getOpticalInsets() : Insets.NONE;
7302
7303 fillDifference(canvas,
7304 view.getLeft() + oi.left,
7305 view.getTop() + oi.top,
7306 view.getRight() - oi.right,
7307 view.getBottom() - oi.bottom,
7308 leftMargin,
7309 topMargin,
7310 rightMargin,
7311 bottomMargin,
7312 paint);
Philip Milne10ca24a2012-04-23 15:38:27 -07007313 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007314 }
Adam Powell2b342f02010-08-18 18:14:13 -07007315
Jeff Brown20e987b2010-08-23 12:01:02 -07007316 /* Describes a touched view and the ids of the pointers that it has captured.
7317 *
7318 * This code assumes that pointer ids are always in the range 0..31 such that
7319 * it can use a bitfield to track which pointer ids are present.
7320 * As it happens, the lower layers of the input dispatch pipeline also use the
7321 * same trick so the assumption should be safe here...
7322 */
7323 private static final class TouchTarget {
7324 private static final int MAX_RECYCLED = 32;
Romain Guy6410c0a2013-06-17 11:21:58 -07007325 private static final Object sRecycleLock = new Object[0];
Jeff Brown20e987b2010-08-23 12:01:02 -07007326 private static TouchTarget sRecycleBin;
7327 private static int sRecycledCount;
Adam Powell2b342f02010-08-18 18:14:13 -07007328
Jeff Brown20e987b2010-08-23 12:01:02 -07007329 public static final int ALL_POINTER_IDS = -1; // all ones
Adam Powell2b342f02010-08-18 18:14:13 -07007330
Jeff Brown20e987b2010-08-23 12:01:02 -07007331 // The touched child view.
7332 public View child;
7333
7334 // The combined bit mask of pointer ids for all pointers captured by the target.
7335 public int pointerIdBits;
7336
7337 // The next target in the target list.
7338 public TouchTarget next;
7339
7340 private TouchTarget() {
Adam Powell2b342f02010-08-18 18:14:13 -07007341 }
7342
Jeff Brown20e987b2010-08-23 12:01:02 -07007343 public static TouchTarget obtain(View child, int pointerIdBits) {
7344 final TouchTarget target;
7345 synchronized (sRecycleLock) {
Adam Powell816c3be2010-08-23 18:00:05 -07007346 if (sRecycleBin == null) {
Jeff Brown20e987b2010-08-23 12:01:02 -07007347 target = new TouchTarget();
Adam Powell816c3be2010-08-23 18:00:05 -07007348 } else {
Jeff Brown20e987b2010-08-23 12:01:02 -07007349 target = sRecycleBin;
7350 sRecycleBin = target.next;
7351 sRecycledCount--;
7352 target.next = null;
Adam Powell816c3be2010-08-23 18:00:05 -07007353 }
Adam Powell816c3be2010-08-23 18:00:05 -07007354 }
Jeff Brown20e987b2010-08-23 12:01:02 -07007355 target.child = child;
7356 target.pointerIdBits = pointerIdBits;
7357 return target;
7358 }
Adam Powell816c3be2010-08-23 18:00:05 -07007359
Jeff Brown20e987b2010-08-23 12:01:02 -07007360 public void recycle() {
7361 synchronized (sRecycleLock) {
7362 if (sRecycledCount < MAX_RECYCLED) {
7363 next = sRecycleBin;
7364 sRecycleBin = this;
7365 sRecycledCount += 1;
Patrick Dubroyfb0547d22010-10-19 17:36:18 -07007366 } else {
7367 next = null;
Adam Powell816c3be2010-08-23 18:00:05 -07007368 }
Patrick Dubroyfb0547d22010-10-19 17:36:18 -07007369 child = null;
Adam Powell816c3be2010-08-23 18:00:05 -07007370 }
7371 }
Adam Powell2b342f02010-08-18 18:14:13 -07007372 }
Jeff Brown87b7f802011-06-21 18:35:45 -07007373
7374 /* Describes a hovered view. */
7375 private static final class HoverTarget {
7376 private static final int MAX_RECYCLED = 32;
Romain Guy6410c0a2013-06-17 11:21:58 -07007377 private static final Object sRecycleLock = new Object[0];
Jeff Brown87b7f802011-06-21 18:35:45 -07007378 private static HoverTarget sRecycleBin;
7379 private static int sRecycledCount;
7380
7381 // The hovered child view.
7382 public View child;
7383
7384 // The next target in the target list.
7385 public HoverTarget next;
7386
7387 private HoverTarget() {
7388 }
7389
7390 public static HoverTarget obtain(View child) {
7391 final HoverTarget target;
7392 synchronized (sRecycleLock) {
7393 if (sRecycleBin == null) {
7394 target = new HoverTarget();
7395 } else {
7396 target = sRecycleBin;
7397 sRecycleBin = target.next;
7398 sRecycledCount--;
7399 target.next = null;
7400 }
7401 }
7402 target.child = child;
7403 return target;
7404 }
7405
7406 public void recycle() {
7407 synchronized (sRecycleLock) {
7408 if (sRecycledCount < MAX_RECYCLED) {
7409 next = sRecycleBin;
7410 sRecycleBin = this;
7411 sRecycledCount += 1;
7412 } else {
7413 next = null;
7414 }
7415 child = null;
7416 }
7417 }
7418 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07007419
7420 /**
7421 * Pooled class that orderes the children of a ViewGroup from start
7422 * to end based on how they are laid out and the layout direction.
7423 */
7424 static class ChildListForAccessibility {
7425
7426 private static final int MAX_POOL_SIZE = 32;
7427
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08007428 private static final SynchronizedPool<ChildListForAccessibility> sPool =
7429 new SynchronizedPool<ChildListForAccessibility>(MAX_POOL_SIZE);
Svetoslav Ganov42138042012-03-20 11:51:39 -07007430
7431 private final ArrayList<View> mChildren = new ArrayList<View>();
7432
7433 private final ArrayList<ViewLocationHolder> mHolders = new ArrayList<ViewLocationHolder>();
7434
7435 public static ChildListForAccessibility obtain(ViewGroup parent, boolean sort) {
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08007436 ChildListForAccessibility list = sPool.acquire();
7437 if (list == null) {
7438 list = new ChildListForAccessibility();
Svetoslav Ganov42138042012-03-20 11:51:39 -07007439 }
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08007440 list.init(parent, sort);
7441 return list;
Svetoslav Ganov42138042012-03-20 11:51:39 -07007442 }
7443
7444 public void recycle() {
Svetoslav Ganov42138042012-03-20 11:51:39 -07007445 clear();
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08007446 sPool.release(this);
Svetoslav Ganov42138042012-03-20 11:51:39 -07007447 }
7448
7449 public int getChildCount() {
7450 return mChildren.size();
7451 }
7452
7453 public View getChildAt(int index) {
7454 return mChildren.get(index);
7455 }
7456
7457 public int getChildIndex(View child) {
7458 return mChildren.indexOf(child);
7459 }
7460
7461 private void init(ViewGroup parent, boolean sort) {
7462 ArrayList<View> children = mChildren;
7463 final int childCount = parent.getChildCount();
7464 for (int i = 0; i < childCount; i++) {
7465 View child = parent.getChildAt(i);
7466 children.add(child);
7467 }
7468 if (sort) {
7469 ArrayList<ViewLocationHolder> holders = mHolders;
7470 for (int i = 0; i < childCount; i++) {
7471 View child = children.get(i);
7472 ViewLocationHolder holder = ViewLocationHolder.obtain(parent, child);
7473 holders.add(holder);
7474 }
Svetoslav88e447b2014-10-09 15:49:02 -07007475 sort(holders);
Svetoslav Ganov42138042012-03-20 11:51:39 -07007476 for (int i = 0; i < childCount; i++) {
7477 ViewLocationHolder holder = holders.get(i);
7478 children.set(i, holder.mView);
7479 holder.recycle();
7480 }
7481 holders.clear();
7482 }
7483 }
7484
Svetoslav88e447b2014-10-09 15:49:02 -07007485 private void sort(ArrayList<ViewLocationHolder> holders) {
7486 // This is gross but the least risky solution. The current comparison
7487 // strategy breaks transitivity but produces very good results. Coming
7488 // up with a new strategy requires time which we do not have, so ...
7489 try {
7490 ViewLocationHolder.setComparisonStrategy(
7491 ViewLocationHolder.COMPARISON_STRATEGY_STRIPE);
7492 Collections.sort(holders);
7493 } catch (IllegalArgumentException iae) {
7494 // Note that in practice this occurs extremely rarely in a couple
7495 // of pathological cases.
7496 ViewLocationHolder.setComparisonStrategy(
7497 ViewLocationHolder.COMPARISON_STRATEGY_LOCATION);
7498 Collections.sort(holders);
7499 }
7500 }
7501
Svetoslav Ganov42138042012-03-20 11:51:39 -07007502 private void clear() {
7503 mChildren.clear();
7504 }
7505 }
7506
7507 /**
7508 * Pooled class that holds a View and its location with respect to
7509 * a specified root. This enables sorting of views based on their
7510 * coordinates without recomputing the position relative to the root
7511 * on every comparison.
7512 */
7513 static class ViewLocationHolder implements Comparable<ViewLocationHolder> {
7514
7515 private static final int MAX_POOL_SIZE = 32;
7516
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08007517 private static final SynchronizedPool<ViewLocationHolder> sPool =
7518 new SynchronizedPool<ViewLocationHolder>(MAX_POOL_SIZE);
Svetoslav Ganov42138042012-03-20 11:51:39 -07007519
Svetoslav88e447b2014-10-09 15:49:02 -07007520 public static final int COMPARISON_STRATEGY_STRIPE = 1;
7521
7522 public static final int COMPARISON_STRATEGY_LOCATION = 2;
7523
7524 private static int sComparisonStrategy = COMPARISON_STRATEGY_STRIPE;
7525
Svetoslav Ganov42138042012-03-20 11:51:39 -07007526 private final Rect mLocation = new Rect();
7527
7528 public View mView;
7529
7530 private int mLayoutDirection;
7531
7532 public static ViewLocationHolder obtain(ViewGroup root, View view) {
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08007533 ViewLocationHolder holder = sPool.acquire();
7534 if (holder == null) {
7535 holder = new ViewLocationHolder();
Svetoslav Ganov42138042012-03-20 11:51:39 -07007536 }
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08007537 holder.init(root, view);
7538 return holder;
Svetoslav Ganov42138042012-03-20 11:51:39 -07007539 }
7540
Svetoslav88e447b2014-10-09 15:49:02 -07007541 public static void setComparisonStrategy(int strategy) {
7542 sComparisonStrategy = strategy;
7543 }
7544
Svetoslav Ganov42138042012-03-20 11:51:39 -07007545 public void recycle() {
Svetoslav Ganov42138042012-03-20 11:51:39 -07007546 clear();
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08007547 sPool.release(this);
Svetoslav Ganov42138042012-03-20 11:51:39 -07007548 }
7549
7550 @Override
7551 public int compareTo(ViewLocationHolder another) {
7552 // This instance is greater than an invalid argument.
7553 if (another == null) {
7554 return 1;
7555 }
Svetoslav88e447b2014-10-09 15:49:02 -07007556
7557 if (sComparisonStrategy == COMPARISON_STRATEGY_STRIPE) {
7558 // First is above second.
7559 if (mLocation.bottom - another.mLocation.top <= 0) {
7560 return -1;
7561 }
7562 // First is below second.
7563 if (mLocation.top - another.mLocation.bottom >= 0) {
7564 return 1;
7565 }
7566 }
7567
Svetoslav04cab1b2014-08-25 18:35:57 -07007568 // We are ordering left-to-right, top-to-bottom.
Svetoslav Ganov42138042012-03-20 11:51:39 -07007569 if (mLayoutDirection == LAYOUT_DIRECTION_LTR) {
7570 final int leftDifference = mLocation.left - another.mLocation.left;
Svetoslav Ganov42138042012-03-20 11:51:39 -07007571 if (leftDifference != 0) {
7572 return leftDifference;
7573 }
7574 } else { // RTL
7575 final int rightDifference = mLocation.right - another.mLocation.right;
Svetoslav Ganov42138042012-03-20 11:51:39 -07007576 if (rightDifference != 0) {
7577 return -rightDifference;
7578 }
7579 }
Svetoslav04cab1b2014-08-25 18:35:57 -07007580 // We are ordering left-to-right, top-to-bottom.
7581 final int topDifference = mLocation.top - another.mLocation.top;
7582 if (topDifference != 0) {
7583 return topDifference;
7584 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07007585 // Break tie by height.
7586 final int heightDiference = mLocation.height() - another.mLocation.height();
7587 if (heightDiference != 0) {
7588 return -heightDiference;
7589 }
7590 // Break tie by width.
7591 final int widthDiference = mLocation.width() - another.mLocation.width();
7592 if (widthDiference != 0) {
7593 return -widthDiference;
7594 }
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07007595 // Just break the tie somehow. The accessibliity ids are unique
7596 // and stable, hence this is deterministic tie breaking.
7597 return mView.getAccessibilityViewId() - another.mView.getAccessibilityViewId();
Svetoslav Ganov42138042012-03-20 11:51:39 -07007598 }
7599
7600 private void init(ViewGroup root, View view) {
7601 Rect viewLocation = mLocation;
7602 view.getDrawingRect(viewLocation);
7603 root.offsetDescendantRectToMyCoords(view, viewLocation);
7604 mView = view;
Fabrice Di Meglioe56ffdc2012-09-23 14:51:16 -07007605 mLayoutDirection = root.getLayoutDirection();
Svetoslav Ganov42138042012-03-20 11:51:39 -07007606 }
7607
7608 private void clear() {
7609 mView = null;
7610 mLocation.set(0, 0, 0, 0);
7611 }
7612 }
Romain Guycbc67742012-04-27 16:12:57 -07007613
7614 private static Paint getDebugPaint() {
7615 if (sDebugPaint == null) {
7616 sDebugPaint = new Paint();
7617 sDebugPaint.setAntiAlias(false);
7618 }
7619 return sDebugPaint;
7620 }
7621
Romain Guy6410c0a2013-06-17 11:21:58 -07007622 private static void drawRect(Canvas canvas, Paint paint, int x1, int y1, int x2, int y2) {
Romain Guycbc67742012-04-27 16:12:57 -07007623 if (sDebugLines== null) {
Romain Guy6410c0a2013-06-17 11:21:58 -07007624 // TODO: This won't work with multiple UI threads in a single process
Romain Guycbc67742012-04-27 16:12:57 -07007625 sDebugLines = new float[16];
7626 }
7627
Romain Guycbc67742012-04-27 16:12:57 -07007628 sDebugLines[0] = x1;
7629 sDebugLines[1] = y1;
7630 sDebugLines[2] = x2;
7631 sDebugLines[3] = y1;
7632
7633 sDebugLines[4] = x2;
7634 sDebugLines[5] = y1;
7635 sDebugLines[6] = x2;
Philip Milne7b757812012-09-19 18:13:44 -07007636 sDebugLines[7] = y2;
Romain Guycbc67742012-04-27 16:12:57 -07007637
Philip Milne7b757812012-09-19 18:13:44 -07007638 sDebugLines[8] = x2;
Romain Guycbc67742012-04-27 16:12:57 -07007639 sDebugLines[9] = y2;
7640 sDebugLines[10] = x1;
7641 sDebugLines[11] = y2;
7642
Philip Milne7b757812012-09-19 18:13:44 -07007643 sDebugLines[12] = x1;
7644 sDebugLines[13] = y2;
Romain Guycbc67742012-04-27 16:12:57 -07007645 sDebugLines[14] = x1;
7646 sDebugLines[15] = y1;
7647
Philip Milne7b757812012-09-19 18:13:44 -07007648 canvas.drawLines(sDebugLines, paint);
Romain Guycbc67742012-04-27 16:12:57 -07007649 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007650}