blob: 5763e72eb06261d0b2507989db8e8e1852f3970a [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.view;
18
Chet Haase21cd1382010-09-01 17:42:29 -070019import android.animation.LayoutTransition;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080020import android.content.Context;
Dianne Hackborne36d6e22010-02-17 19:46:25 -080021import android.content.res.Configuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080022import android.content.res.TypedArray;
23import android.graphics.Bitmap;
24import android.graphics.Canvas;
Philip Milne10ca24a2012-04-23 15:38:27 -070025import android.graphics.Color;
26import android.graphics.Insets;
Adam Powell6e346362010-07-23 10:18:23 -070027import android.graphics.Matrix;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028import android.graphics.Paint;
Christopher Tatea53146c2010-09-07 11:57:52 -070029import android.graphics.PointF;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080030import android.graphics.Rect;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031import android.graphics.RectF;
svetoslavganov75986cf2009-05-14 22:28:01 -070032import android.graphics.Region;
Jeff Brown995e7742010-12-22 16:59:36 -080033import android.os.Build;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034import android.os.Parcelable;
35import android.os.SystemClock;
36import android.util.AttributeSet;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037import android.util.Log;
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -080038import android.util.Pools.SynchronizedPool;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039import android.util.SparseArray;
svetoslavganov75986cf2009-05-14 22:28:01 -070040import android.view.accessibility.AccessibilityEvent;
Alan Viverette77e9a282013-09-12 17:16:09 -070041import android.view.accessibility.AccessibilityManager;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070042import android.view.accessibility.AccessibilityNodeInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043import android.view.animation.Animation;
44import android.view.animation.AnimationUtils;
45import android.view.animation.LayoutAnimationController;
46import android.view.animation.Transformation;
Doug Feltcb379122011-07-07 11:57:48 -070047
Romain Guy0211a0a2011-02-14 16:34:59 -080048import com.android.internal.R;
49import com.android.internal.util.Predicate;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050
51import java.util.ArrayList;
Svetoslav Ganov42138042012-03-20 11:51:39 -070052import java.util.Collections;
Christopher Tate86cab1b2011-01-13 20:28:55 -080053import java.util.HashSet;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080054
Fabrice Di Meglio0072f642013-03-26 15:50:24 -070055import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
56
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080057/**
58 * <p>
59 * A <code>ViewGroup</code> is a special view that can contain other views
60 * (called children.) The view group is the base class for layouts and views
61 * containers. This class also defines the
62 * {@link android.view.ViewGroup.LayoutParams} class which serves as the base
63 * class for layouts parameters.
64 * </p>
65 *
66 * <p>
67 * Also see {@link LayoutParams} for layout attributes.
68 * </p>
Romain Guyd6a463a2009-05-21 23:10:10 -070069 *
Joe Fernandez558459f2011-10-13 16:47:36 -070070 * <div class="special reference">
71 * <h3>Developer Guides</h3>
72 * <p>For more information about creating user interface layouts, read the
73 * <a href="{@docRoot}guide/topics/ui/declaring-layout.html">XML Layouts</a> developer
74 * guide.</p></div>
75 *
Dianne Hackborn7caab0f2013-03-06 13:47:04 -080076 * <p>Here is a complete implementation of a custom ViewGroup that implements
77 * a simple {@link android.widget.FrameLayout} along with the ability to stack
78 * children in left and right gutters.</p>
79 *
80 * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/CustomLayout.java
81 * Complete}
82 *
83 * <p>If you are implementing XML layout attributes as shown in the example, this is the
84 * corresponding definition for them that would go in <code>res/values/attrs.xml</code>:</p>
85 *
86 * {@sample development/samples/ApiDemos/res/values/attrs.xml CustomLayout}
87 *
88 * <p>Finally the layout manager can be used in an XML layout like so:</p>
89 *
90 * {@sample development/samples/ApiDemos/res/layout/custom_layout.xml Complete}
91 *
Romain Guyd6a463a2009-05-21 23:10:10 -070092 * @attr ref android.R.styleable#ViewGroup_clipChildren
93 * @attr ref android.R.styleable#ViewGroup_clipToPadding
94 * @attr ref android.R.styleable#ViewGroup_layoutAnimation
95 * @attr ref android.R.styleable#ViewGroup_animationCache
96 * @attr ref android.R.styleable#ViewGroup_persistentDrawingCache
97 * @attr ref android.R.styleable#ViewGroup_alwaysDrawnWithCache
98 * @attr ref android.R.styleable#ViewGroup_addStatesFromChildren
99 * @attr ref android.R.styleable#ViewGroup_descendantFocusability
Chet Haase13cc1202010-09-03 15:39:20 -0700100 * @attr ref android.R.styleable#ViewGroup_animateLayoutChanges
Scott Main27a85082013-06-10 10:39:48 -0700101 * @attr ref android.R.styleable#ViewGroup_splitMotionEvents
102 * @attr ref android.R.styleable#ViewGroup_layoutMode
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800103 */
104public abstract class ViewGroup extends View implements ViewParent, ViewManager {
Adam Powell539ee872012-02-03 19:00:49 -0800105 private static final String TAG = "ViewGroup";
Chet Haase21cd1382010-09-01 17:42:29 -0700106
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800107 private static final boolean DBG = false;
Philip Milne7b757812012-09-19 18:13:44 -0700108 /** @hide */
109 public static boolean DEBUG_DRAW = false;
Gilles Debunnecea45132011-11-24 02:19:27 +0100110
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800111 /**
112 * Views which have been hidden or removed which need to be animated on
113 * their way out.
114 * This field should be made private, so it is hidden from the SDK.
115 * {@hide}
116 */
117 protected ArrayList<View> mDisappearingChildren;
118
119 /**
120 * Listener used to propagate events indicating when children are added
121 * and/or removed from a view group.
122 * This field should be made private, so it is hidden from the SDK.
123 * {@hide}
124 */
125 protected OnHierarchyChangeListener mOnHierarchyChangeListener;
126
127 // The view contained within this ViewGroup that has or contains focus.
128 private View mFocused;
129
Chet Haase48460322010-06-11 14:22:25 -0700130 /**
131 * A Transformation used when drawing children, to
132 * apply on the child being drawn.
133 */
Romain Guyf6991302013-06-05 17:19:01 -0700134 private Transformation mChildTransformation;
Chet Haase48460322010-06-11 14:22:25 -0700135
136 /**
137 * Used to track the current invalidation region.
138 */
Chet Haase64a48c12012-02-13 16:33:29 -0800139 RectF mInvalidateRegion;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800140
Chet Haase48460322010-06-11 14:22:25 -0700141 /**
142 * A Transformation used to calculate a correct
143 * invalidation area when the application is autoscaled.
144 */
Chet Haase64a48c12012-02-13 16:33:29 -0800145 Transformation mInvalidationTransformation;
Chet Haase48460322010-06-11 14:22:25 -0700146
Christopher Tatea53146c2010-09-07 11:57:52 -0700147 // View currently under an ongoing drag
148 private View mCurrentDragView;
149
Christopher Tate86cab1b2011-01-13 20:28:55 -0800150 // Metadata about the ongoing drag
151 private DragEvent mCurrentDrag;
152 private HashSet<View> mDragNotifiedChildren;
153
Christopher Tatea53146c2010-09-07 11:57:52 -0700154 // Does this group have a child that can accept the current drag payload?
155 private boolean mChildAcceptsDrag;
156
157 // Used during drag dispatch
Romain Guy6410c0a2013-06-17 11:21:58 -0700158 private PointF mLocalPoint;
Christopher Tatea53146c2010-09-07 11:57:52 -0700159
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800160 // Layout animation
161 private LayoutAnimationController mLayoutAnimationController;
162 private Animation.AnimationListener mAnimationListener;
163
Jeff Brown20e987b2010-08-23 12:01:02 -0700164 // First touch target in the linked list of touch targets.
165 private TouchTarget mFirstTouchTarget;
166
Joe Onorato03ab0c72011-01-06 15:46:27 -0800167 // For debugging only. You can see these in hierarchyviewer.
Romain Guye95003e2011-01-09 13:53:06 -0800168 @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"})
Joe Onorato03ab0c72011-01-06 15:46:27 -0800169 @ViewDebug.ExportedProperty(category = "events")
170 private long mLastTouchDownTime;
171 @ViewDebug.ExportedProperty(category = "events")
172 private int mLastTouchDownIndex = -1;
Romain Guye95003e2011-01-09 13:53:06 -0800173 @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"})
Joe Onorato03ab0c72011-01-06 15:46:27 -0800174 @ViewDebug.ExportedProperty(category = "events")
175 private float mLastTouchDownX;
Romain Guye95003e2011-01-09 13:53:06 -0800176 @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"})
Joe Onorato03ab0c72011-01-06 15:46:27 -0800177 @ViewDebug.ExportedProperty(category = "events")
178 private float mLastTouchDownY;
179
Jeff Brown87b7f802011-06-21 18:35:45 -0700180 // First hover target in the linked list of hover targets.
181 // The hover targets are children which have received ACTION_HOVER_ENTER.
182 // They might not have actually handled the hover event, but we will
183 // continue sending hover events to them as long as the pointer remains over
184 // their bounds and the view group does not intercept hover.
185 private HoverTarget mFirstHoverTarget;
Jeff Browna032cc02011-03-07 16:56:21 -0800186
Jeff Brown10b62902011-06-20 16:40:37 -0700187 // True if the view group itself received a hover event.
188 // It might not have actually handled the hover event.
189 private boolean mHoveredSelf;
190
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800191 /**
192 * Internal flags.
Romain Guy8506ab42009-06-11 17:35:47 -0700193 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800194 * This field should be made private, so it is hidden from the SDK.
195 * {@hide}
196 */
Romain Guy2440e672012-08-07 14:43:43 -0700197 @ViewDebug.ExportedProperty(flagMapping = {
198 @ViewDebug.FlagToString(mask = FLAG_CLIP_CHILDREN, equals = FLAG_CLIP_CHILDREN,
199 name = "CLIP_CHILDREN"),
200 @ViewDebug.FlagToString(mask = FLAG_CLIP_TO_PADDING, equals = FLAG_CLIP_TO_PADDING,
201 name = "CLIP_TO_PADDING"),
202 @ViewDebug.FlagToString(mask = FLAG_PADDING_NOT_NULL, equals = FLAG_PADDING_NOT_NULL,
203 name = "PADDING_NOT_NULL")
204 })
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800205 protected int mGroupFlags;
206
Philip Milne7b757812012-09-19 18:13:44 -0700207 /**
208 * Either {@link #LAYOUT_MODE_CLIP_BOUNDS} or {@link #LAYOUT_MODE_OPTICAL_BOUNDS}.
Philip Milne1557fd72012-04-04 23:41:34 -0700209 */
Philip Milnecfb631b2012-10-26 10:51:46 -0700210 private int mLayoutMode = LAYOUT_MODE_UNDEFINED;
Philip Milne1557fd72012-04-04 23:41:34 -0700211
Romain Guy33f6beb2012-02-16 19:24:51 -0800212 /**
213 * NOTE: If you change the flags below make sure to reflect the changes
214 * the DisplayList class
215 */
216
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800217 // When set, ViewGroup invalidates only the child's rectangle
218 // Set by default
Chet Haase64a48c12012-02-13 16:33:29 -0800219 static final int FLAG_CLIP_CHILDREN = 0x1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800220
221 // When set, ViewGroup excludes the padding area from the invalidate rectangle
222 // Set by default
223 private static final int FLAG_CLIP_TO_PADDING = 0x2;
224
225 // When set, dispatchDraw() will invoke invalidate(); this is set by drawChild() when
226 // a child needs to be invalidated and FLAG_OPTIMIZE_INVALIDATE is set
Chet Haase64a48c12012-02-13 16:33:29 -0800227 static final int FLAG_INVALIDATE_REQUIRED = 0x4;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800228
229 // When set, dispatchDraw() will run the layout animation and unset the flag
230 private static final int FLAG_RUN_ANIMATION = 0x8;
231
232 // When set, there is either no layout animation on the ViewGroup or the layout
233 // animation is over
234 // Set by default
Chet Haase64a48c12012-02-13 16:33:29 -0800235 static final int FLAG_ANIMATION_DONE = 0x10;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800236
237 // If set, this ViewGroup has padding; if unset there is no padding and we don't need
238 // to clip it, even if FLAG_CLIP_TO_PADDING is set
239 private static final int FLAG_PADDING_NOT_NULL = 0x20;
240
241 // When set, this ViewGroup caches its children in a Bitmap before starting a layout animation
242 // Set by default
243 private static final int FLAG_ANIMATION_CACHE = 0x40;
244
245 // When set, this ViewGroup converts calls to invalidate(Rect) to invalidate() during a
246 // layout animation; this avoid clobbering the hierarchy
247 // Automatically set when the layout animation starts, depending on the animation's
248 // characteristics
Chet Haase64a48c12012-02-13 16:33:29 -0800249 static final int FLAG_OPTIMIZE_INVALIDATE = 0x80;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800250
251 // When set, the next call to drawChild() will clear mChildTransformation's matrix
Chet Haase64a48c12012-02-13 16:33:29 -0800252 static final int FLAG_CLEAR_TRANSFORMATION = 0x100;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800253
254 // When set, this ViewGroup invokes mAnimationListener.onAnimationEnd() and removes
255 // the children's Bitmap caches if necessary
256 // This flag is set when the layout animation is over (after FLAG_ANIMATION_DONE is set)
257 private static final int FLAG_NOTIFY_ANIMATION_LISTENER = 0x200;
258
259 /**
260 * When set, the drawing method will call {@link #getChildDrawingOrder(int, int)}
261 * to get the index of the child to draw for that iteration.
Romain Guy293451e2009-11-04 13:59:48 -0800262 *
263 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800264 */
265 protected static final int FLAG_USE_CHILD_DRAWING_ORDER = 0x400;
Romain Guy8506ab42009-06-11 17:35:47 -0700266
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800267 /**
268 * When set, this ViewGroup supports static transformations on children; this causes
269 * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} to be
270 * invoked when a child is drawn.
271 *
272 * Any subclass overriding
273 * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} should
274 * set this flags in {@link #mGroupFlags}.
Romain Guy8506ab42009-06-11 17:35:47 -0700275 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800276 * {@hide}
277 */
278 protected static final int FLAG_SUPPORT_STATIC_TRANSFORMATIONS = 0x800;
279
280 // When the previous drawChild() invocation used an alpha value that was lower than
281 // 1.0 and set it in mCachePaint
Chet Haase64a48c12012-02-13 16:33:29 -0800282 static final int FLAG_ALPHA_LOWER_THAN_ONE = 0x1000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800283
284 /**
285 * When set, this ViewGroup's drawable states also include those
286 * of its children.
287 */
288 private static final int FLAG_ADD_STATES_FROM_CHILDREN = 0x2000;
289
290 /**
291 * When set, this ViewGroup tries to always draw its children using their drawing cache.
292 */
Chet Haase64a48c12012-02-13 16:33:29 -0800293 static final int FLAG_ALWAYS_DRAWN_WITH_CACHE = 0x4000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800294
295 /**
296 * When set, and if FLAG_ALWAYS_DRAWN_WITH_CACHE is not set, this ViewGroup will try to
297 * draw its children with their drawing cache.
298 */
Chet Haase64a48c12012-02-13 16:33:29 -0800299 static final int FLAG_CHILDREN_DRAWN_WITH_CACHE = 0x8000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800300
301 /**
302 * When set, this group will go through its list of children to notify them of
303 * any drawable state change.
304 */
305 private static final int FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE = 0x10000;
306
307 private static final int FLAG_MASK_FOCUSABILITY = 0x60000;
308
309 /**
310 * This view will get focus before any of its descendants.
311 */
312 public static final int FOCUS_BEFORE_DESCENDANTS = 0x20000;
313
314 /**
315 * This view will get focus only if none of its descendants want it.
316 */
317 public static final int FOCUS_AFTER_DESCENDANTS = 0x40000;
318
319 /**
320 * This view will block any of its descendants from getting focus, even
321 * if they are focusable.
322 */
323 public static final int FOCUS_BLOCK_DESCENDANTS = 0x60000;
324
325 /**
326 * Used to map between enum in attrubutes and flag values.
327 */
328 private static final int[] DESCENDANT_FOCUSABILITY_FLAGS =
329 {FOCUS_BEFORE_DESCENDANTS, FOCUS_AFTER_DESCENDANTS,
330 FOCUS_BLOCK_DESCENDANTS};
331
332 /**
333 * When set, this ViewGroup should not intercept touch events.
Adam Powell110486f2010-06-22 17:14:44 -0700334 * {@hide}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800335 */
Adam Powell110486f2010-06-22 17:14:44 -0700336 protected static final int FLAG_DISALLOW_INTERCEPT = 0x80000;
Romain Guy8506ab42009-06-11 17:35:47 -0700337
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800338 /**
Adam Powell2b342f02010-08-18 18:14:13 -0700339 * When set, this ViewGroup will split MotionEvents to multiple child Views when appropriate.
340 */
Adam Powellf37df072010-09-17 16:22:49 -0700341 private static final int FLAG_SPLIT_MOTION_EVENTS = 0x200000;
Adam Powell2b342f02010-08-18 18:14:13 -0700342
343 /**
Adam Powell4b867882011-09-16 12:59:46 -0700344 * When set, this ViewGroup will not dispatch onAttachedToWindow calls
345 * to children when adding new views. This is used to prevent multiple
346 * onAttached calls when a ViewGroup adds children in its own onAttached method.
347 */
348 private static final int FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW = 0x400000;
349
350 /**
Philip Milnecfb631b2012-10-26 10:51:46 -0700351 * When true, indicates that a layoutMode has been explicitly set, either with
352 * an explicit call to {@link #setLayoutMode(int)} in code or from an XML resource.
353 * This distinguishes the situation in which a layout mode was inherited from
354 * one of the ViewGroup's ancestors and cached locally.
355 */
356 private static final int FLAG_LAYOUT_MODE_WAS_EXPLICITLY_SET = 0x800000;
357
358 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800359 * Indicates which types of drawing caches are to be kept in memory.
360 * This field should be made private, so it is hidden from the SDK.
361 * {@hide}
362 */
363 protected int mPersistentDrawingCache;
364
365 /**
366 * Used to indicate that no drawing cache should be kept in memory.
367 */
368 public static final int PERSISTENT_NO_CACHE = 0x0;
369
370 /**
371 * Used to indicate that the animation drawing cache should be kept in memory.
372 */
373 public static final int PERSISTENT_ANIMATION_CACHE = 0x1;
374
375 /**
376 * Used to indicate that the scrolling drawing cache should be kept in memory.
377 */
378 public static final int PERSISTENT_SCROLLING_CACHE = 0x2;
379
380 /**
381 * Used to indicate that all drawing caches should be kept in memory.
382 */
383 public static final int PERSISTENT_ALL_CACHES = 0x3;
384
Philip Milne1557fd72012-04-04 23:41:34 -0700385 // Layout Modes
386
Philip Milnecfb631b2012-10-26 10:51:46 -0700387 private static final int LAYOUT_MODE_UNDEFINED = -1;
388
Philip Milne1557fd72012-04-04 23:41:34 -0700389 /**
390 * This constant is a {@link #setLayoutMode(int) layoutMode}.
Philip Milne7a23b492012-04-24 22:12:36 -0700391 * Clip bounds are the raw values of {@link #getLeft() left}, {@link #getTop() top},
Philip Milne1557fd72012-04-04 23:41:34 -0700392 * {@link #getRight() right} and {@link #getBottom() bottom}.
393 */
Philip Milne7b757812012-09-19 18:13:44 -0700394 public static final int LAYOUT_MODE_CLIP_BOUNDS = 0;
Philip Milne1557fd72012-04-04 23:41:34 -0700395
396 /**
397 * This constant is a {@link #setLayoutMode(int) layoutMode}.
Philip Milne7a23b492012-04-24 22:12:36 -0700398 * Optical bounds describe where a widget appears to be. They sit inside the clip
399 * bounds which need to cover a larger area to allow other effects,
400 * such as shadows and glows, to be drawn.
Philip Milne1557fd72012-04-04 23:41:34 -0700401 */
Philip Milne7b757812012-09-19 18:13:44 -0700402 public static final int LAYOUT_MODE_OPTICAL_BOUNDS = 1;
403
404 /** @hide */
Philip Milnecfb631b2012-10-26 10:51:46 -0700405 public static int LAYOUT_MODE_DEFAULT = LAYOUT_MODE_CLIP_BOUNDS;
Philip Milne1557fd72012-04-04 23:41:34 -0700406
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800407 /**
408 * We clip to padding when FLAG_CLIP_TO_PADDING and FLAG_PADDING_NOT_NULL
409 * are set at the same time.
410 */
411 protected static final int CLIP_TO_PADDING_MASK = FLAG_CLIP_TO_PADDING | FLAG_PADDING_NOT_NULL;
412
413 // Index of the child's left position in the mLocation array
414 private static final int CHILD_LEFT_INDEX = 0;
415 // Index of the child's top position in the mLocation array
416 private static final int CHILD_TOP_INDEX = 1;
417
418 // Child views of this ViewGroup
419 private View[] mChildren;
420 // Number of valid children in the mChildren array, the rest should be null or not
421 // considered as children
422 private int mChildrenCount;
423
Chet Haaseb9895022013-04-02 15:10:58 -0700424 // Whether layout calls are currently being suppressed, controlled by calls to
425 // suppressLayout()
426 boolean mSuppressLayout = false;
427
428 // Whether any layout calls have actually been suppressed while mSuppressLayout
429 // has been true. This tracks whether we need to issue a requestLayout() when
430 // layout is later re-enabled.
431 private boolean mLayoutCalledWhileSuppressed = false;
432
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800433 private static final int ARRAY_INITIAL_CAPACITY = 12;
434 private static final int ARRAY_CAPACITY_INCREMENT = 12;
435
Romain Guycbc67742012-04-27 16:12:57 -0700436 private static Paint sDebugPaint;
437 private static float[] sDebugLines;
Philip Milne604f4402012-04-24 19:27:11 -0700438
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800439 // Used to draw cached views
Chet Haase64a48c12012-02-13 16:33:29 -0800440 Paint mCachePaint;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800441
Chet Haase21cd1382010-09-01 17:42:29 -0700442 // Used to animate add/remove changes in layout
443 private LayoutTransition mTransition;
444
445 // The set of views that are currently being transitioned. This list is used to track views
446 // being removed that should not actually be removed from the parent yet because they are
447 // being animated.
448 private ArrayList<View> mTransitioningViews;
449
Chet Haase5e25c2c2010-09-16 11:15:56 -0700450 // List of children changing visibility. This is used to potentially keep rendering
451 // views during a transition when they otherwise would have become gone/invisible
452 private ArrayList<View> mVisibilityChangingChildren;
453
Adam Powell539ee872012-02-03 19:00:49 -0800454 // Indicates how many of this container's child subtrees contain transient state
455 @ViewDebug.ExportedProperty(category = "layout")
456 private int mChildCountWithTransientState = 0;
457
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800458 public ViewGroup(Context context) {
459 super(context);
460 initViewGroup();
461 }
462
463 public ViewGroup(Context context, AttributeSet attrs) {
464 super(context, attrs);
465 initViewGroup();
Filip Gruszczyńskic16ba8c2014-03-05 14:43:49 -0800466 initFromAttributes(context, attrs, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800467 }
468
469 public ViewGroup(Context context, AttributeSet attrs, int defStyle) {
470 super(context, attrs, defStyle);
471 initViewGroup();
Filip Gruszczyńskic16ba8c2014-03-05 14:43:49 -0800472 initFromAttributes(context, attrs, defStyle);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800473 }
474
Philip Milne10ca24a2012-04-23 15:38:27 -0700475 private boolean debugDraw() {
Philip Milne7b757812012-09-19 18:13:44 -0700476 return DEBUG_DRAW || mAttachInfo != null && mAttachInfo.mDebugLayout;
Philip Milne10ca24a2012-04-23 15:38:27 -0700477 }
478
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800479 private void initViewGroup() {
480 // ViewGroup doesn't draw by default
Philip Milne10ca24a2012-04-23 15:38:27 -0700481 if (!debugDraw()) {
482 setFlags(WILL_NOT_DRAW, DRAW_MASK);
483 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800484 mGroupFlags |= FLAG_CLIP_CHILDREN;
485 mGroupFlags |= FLAG_CLIP_TO_PADDING;
486 mGroupFlags |= FLAG_ANIMATION_DONE;
487 mGroupFlags |= FLAG_ANIMATION_CACHE;
488 mGroupFlags |= FLAG_ALWAYS_DRAWN_WITH_CACHE;
489
Jeff Brown995e7742010-12-22 16:59:36 -0800490 if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB) {
491 mGroupFlags |= FLAG_SPLIT_MOTION_EVENTS;
492 }
493
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800494 setDescendantFocusability(FOCUS_BEFORE_DESCENDANTS);
495
496 mChildren = new View[ARRAY_INITIAL_CAPACITY];
497 mChildrenCount = 0;
498
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800499 mPersistentDrawingCache = PERSISTENT_SCROLLING_CACHE;
500 }
501
Filip Gruszczyńskic16ba8c2014-03-05 14:43:49 -0800502 private void initFromAttributes(Context context, AttributeSet attrs, int defStyle) {
503 TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ViewGroup, defStyle, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800504
505 final int N = a.getIndexCount();
506 for (int i = 0; i < N; i++) {
507 int attr = a.getIndex(i);
508 switch (attr) {
509 case R.styleable.ViewGroup_clipChildren:
510 setClipChildren(a.getBoolean(attr, true));
511 break;
512 case R.styleable.ViewGroup_clipToPadding:
513 setClipToPadding(a.getBoolean(attr, true));
514 break;
515 case R.styleable.ViewGroup_animationCache:
516 setAnimationCacheEnabled(a.getBoolean(attr, true));
517 break;
518 case R.styleable.ViewGroup_persistentDrawingCache:
519 setPersistentDrawingCache(a.getInt(attr, PERSISTENT_SCROLLING_CACHE));
520 break;
521 case R.styleable.ViewGroup_addStatesFromChildren:
522 setAddStatesFromChildren(a.getBoolean(attr, false));
523 break;
524 case R.styleable.ViewGroup_alwaysDrawnWithCache:
525 setAlwaysDrawnWithCacheEnabled(a.getBoolean(attr, true));
526 break;
527 case R.styleable.ViewGroup_layoutAnimation:
528 int id = a.getResourceId(attr, -1);
529 if (id > 0) {
530 setLayoutAnimation(AnimationUtils.loadLayoutAnimation(mContext, id));
531 }
532 break;
533 case R.styleable.ViewGroup_descendantFocusability:
534 setDescendantFocusability(DESCENDANT_FOCUSABILITY_FLAGS[a.getInt(attr, 0)]);
535 break;
Adam Powell2b342f02010-08-18 18:14:13 -0700536 case R.styleable.ViewGroup_splitMotionEvents:
537 setMotionEventSplittingEnabled(a.getBoolean(attr, false));
538 break;
Chet Haase13cc1202010-09-03 15:39:20 -0700539 case R.styleable.ViewGroup_animateLayoutChanges:
540 boolean animateLayoutChanges = a.getBoolean(attr, false);
541 if (animateLayoutChanges) {
542 setLayoutTransition(new LayoutTransition());
543 }
544 break;
Philip Milne7b757812012-09-19 18:13:44 -0700545 case R.styleable.ViewGroup_layoutMode:
Philip Milnecfb631b2012-10-26 10:51:46 -0700546 setLayoutMode(a.getInt(attr, LAYOUT_MODE_UNDEFINED));
Philip Milne7b757812012-09-19 18:13:44 -0700547 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800548 }
549 }
550
551 a.recycle();
552 }
553
554 /**
555 * Gets the descendant focusability of this view group. The descendant
556 * focusability defines the relationship between this view group and its
557 * descendants when looking for a view to take focus in
558 * {@link #requestFocus(int, android.graphics.Rect)}.
559 *
560 * @return one of {@link #FOCUS_BEFORE_DESCENDANTS}, {@link #FOCUS_AFTER_DESCENDANTS},
561 * {@link #FOCUS_BLOCK_DESCENDANTS}.
562 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -0700563 @ViewDebug.ExportedProperty(category = "focus", mapping = {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800564 @ViewDebug.IntToString(from = FOCUS_BEFORE_DESCENDANTS, to = "FOCUS_BEFORE_DESCENDANTS"),
565 @ViewDebug.IntToString(from = FOCUS_AFTER_DESCENDANTS, to = "FOCUS_AFTER_DESCENDANTS"),
566 @ViewDebug.IntToString(from = FOCUS_BLOCK_DESCENDANTS, to = "FOCUS_BLOCK_DESCENDANTS")
567 })
568 public int getDescendantFocusability() {
569 return mGroupFlags & FLAG_MASK_FOCUSABILITY;
570 }
571
572 /**
573 * Set the descendant focusability of this view group. This defines the relationship
574 * between this view group and its descendants when looking for a view to
575 * take focus in {@link #requestFocus(int, android.graphics.Rect)}.
576 *
577 * @param focusability one of {@link #FOCUS_BEFORE_DESCENDANTS}, {@link #FOCUS_AFTER_DESCENDANTS},
578 * {@link #FOCUS_BLOCK_DESCENDANTS}.
579 */
580 public void setDescendantFocusability(int focusability) {
581 switch (focusability) {
582 case FOCUS_BEFORE_DESCENDANTS:
583 case FOCUS_AFTER_DESCENDANTS:
584 case FOCUS_BLOCK_DESCENDANTS:
585 break;
586 default:
587 throw new IllegalArgumentException("must be one of FOCUS_BEFORE_DESCENDANTS, "
588 + "FOCUS_AFTER_DESCENDANTS, FOCUS_BLOCK_DESCENDANTS");
589 }
590 mGroupFlags &= ~FLAG_MASK_FOCUSABILITY;
591 mGroupFlags |= (focusability & FLAG_MASK_FOCUSABILITY);
592 }
593
594 /**
595 * {@inheritDoc}
596 */
597 @Override
598 void handleFocusGainInternal(int direction, Rect previouslyFocusedRect) {
599 if (mFocused != null) {
600 mFocused.unFocus();
601 mFocused = null;
602 }
603 super.handleFocusGainInternal(direction, previouslyFocusedRect);
604 }
605
606 /**
607 * {@inheritDoc}
608 */
609 public void requestChildFocus(View child, View focused) {
610 if (DBG) {
611 System.out.println(this + " requestChildFocus()");
612 }
613 if (getDescendantFocusability() == FOCUS_BLOCK_DESCENDANTS) {
614 return;
615 }
616
617 // Unfocus us, if necessary
618 super.unFocus();
619
620 // We had a previous notion of who had focus. Clear it.
621 if (mFocused != child) {
622 if (mFocused != null) {
623 mFocused.unFocus();
624 }
625
626 mFocused = child;
627 }
628 if (mParent != null) {
629 mParent.requestChildFocus(this, focused);
630 }
631 }
632
633 /**
634 * {@inheritDoc}
635 */
636 public void focusableViewAvailable(View v) {
637 if (mParent != null
638 // shortcut: don't report a new focusable view if we block our descendants from
639 // getting focus
640 && (getDescendantFocusability() != FOCUS_BLOCK_DESCENDANTS)
641 // shortcut: don't report a new focusable view if we already are focused
642 // (and we don't prefer our descendants)
643 //
644 // note: knowing that mFocused is non-null is not a good enough reason
645 // to break the traversal since in that case we'd actually have to find
646 // the focused view and make sure it wasn't FOCUS_AFTER_DESCENDANTS and
Joe Onoratoc6cc0f82011-04-12 11:53:13 -0700647 // an ancestor of v; this will get checked for at ViewAncestor
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800648 && !(isFocused() && getDescendantFocusability() != FOCUS_AFTER_DESCENDANTS)) {
649 mParent.focusableViewAvailable(v);
650 }
651 }
652
653 /**
654 * {@inheritDoc}
655 */
656 public boolean showContextMenuForChild(View originalView) {
657 return mParent != null && mParent.showContextMenuForChild(originalView);
658 }
659
660 /**
Adam Powell6e346362010-07-23 10:18:23 -0700661 * {@inheritDoc}
662 */
663 public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback) {
664 return mParent != null ? mParent.startActionModeForChild(originalView, callback) : null;
665 }
666
667 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800668 * Find the nearest view in the specified direction that wants to take
669 * focus.
670 *
671 * @param focused The view that currently has focus
672 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and
673 * FOCUS_RIGHT, or 0 for not applicable.
674 */
675 public View focusSearch(View focused, int direction) {
Svetoslav Ganov27e2da72012-07-02 18:12:00 -0700676 if (isRootNamespace()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800677 // root namespace means we should consider ourselves the top of the
678 // tree for focus searching; otherwise we could be focus searching
679 // into other tabs. see LocalActivityManager and TabHost for more info
680 return FocusFinder.getInstance().findNextFocus(this, focused, direction);
681 } else if (mParent != null) {
682 return mParent.focusSearch(focused, direction);
683 }
684 return null;
685 }
686
687 /**
688 * {@inheritDoc}
689 */
690 public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
691 return false;
692 }
693
694 /**
695 * {@inheritDoc}
696 */
Svetoslav Ganov42138042012-03-20 11:51:39 -0700697 @Override
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700698 public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event) {
Svetoslav Ganov42138042012-03-20 11:51:39 -0700699 ViewParent parent = mParent;
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700700 if (parent == null) {
701 return false;
702 }
703 final boolean propagate = onRequestSendAccessibilityEvent(child, event);
704 if (!propagate) {
705 return false;
706 }
707 return parent.requestSendAccessibilityEvent(this, event);
708 }
709
710 /**
711 * Called when a child has requested sending an {@link AccessibilityEvent} and
712 * gives an opportunity to its parent to augment the event.
Svetoslav Ganov031d9c12011-09-09 16:41:13 -0700713 * <p>
Adam Powell2fcbbd02011-09-28 18:56:43 -0700714 * If an {@link android.view.View.AccessibilityDelegate} has been specified via calling
715 * {@link android.view.View#setAccessibilityDelegate(android.view.View.AccessibilityDelegate)} its
716 * {@link android.view.View.AccessibilityDelegate#onRequestSendAccessibilityEvent(ViewGroup, View, AccessibilityEvent)}
Svetoslav Ganov031d9c12011-09-09 16:41:13 -0700717 * is responsible for handling this call.
718 * </p>
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700719 *
720 * @param child The child which requests sending the event.
721 * @param event The event to be sent.
722 * @return True if the event should be sent.
723 *
724 * @see #requestSendAccessibilityEvent(View, AccessibilityEvent)
725 */
726 public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
Svetoslav Ganov031d9c12011-09-09 16:41:13 -0700727 if (mAccessibilityDelegate != null) {
728 return mAccessibilityDelegate.onRequestSendAccessibilityEvent(this, child, event);
729 } else {
730 return onRequestSendAccessibilityEventInternal(child, event);
731 }
732 }
733
734 /**
735 * @see #onRequestSendAccessibilityEvent(View, AccessibilityEvent)
736 *
737 * Note: Called from the default {@link View.AccessibilityDelegate}.
738 */
739 boolean onRequestSendAccessibilityEventInternal(View child, AccessibilityEvent event) {
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700740 return true;
741 }
742
743 /**
Adam Powell539ee872012-02-03 19:00:49 -0800744 * Called when a child view has changed whether or not it is tracking transient state.
Adam Powell539ee872012-02-03 19:00:49 -0800745 */
746 public void childHasTransientStateChanged(View child, boolean childHasTransientState) {
747 final boolean oldHasTransientState = hasTransientState();
748 if (childHasTransientState) {
749 mChildCountWithTransientState++;
750 } else {
751 mChildCountWithTransientState--;
752 }
753
754 final boolean newHasTransientState = hasTransientState();
755 if (mParent != null && oldHasTransientState != newHasTransientState) {
756 try {
757 mParent.childHasTransientStateChanged(this, newHasTransientState);
758 } catch (AbstractMethodError e) {
759 Log.e(TAG, mParent.getClass().getSimpleName() +
760 " does not fully implement ViewParent", e);
761 }
762 }
763 }
764
Adam Powell539ee872012-02-03 19:00:49 -0800765 @Override
766 public boolean hasTransientState() {
767 return mChildCountWithTransientState > 0 || super.hasTransientState();
768 }
769
770 /**
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700771 * {@inheritDoc}
772 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800773 @Override
774 public boolean dispatchUnhandledMove(View focused, int direction) {
775 return mFocused != null &&
776 mFocused.dispatchUnhandledMove(focused, direction);
777 }
778
779 /**
780 * {@inheritDoc}
781 */
782 public void clearChildFocus(View child) {
783 if (DBG) {
784 System.out.println(this + " clearChildFocus()");
785 }
786
787 mFocused = null;
788 if (mParent != null) {
789 mParent.clearChildFocus(this);
790 }
791 }
792
793 /**
794 * {@inheritDoc}
795 */
796 @Override
797 public void clearFocus() {
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -0800798 if (DBG) {
799 System.out.println(this + " clearFocus()");
800 }
801 if (mFocused == null) {
802 super.clearFocus();
803 } else {
Svetoslav Ganovb552d892012-06-02 14:35:02 -0700804 View focused = mFocused;
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -0800805 mFocused = null;
Svetoslav Ganovb552d892012-06-02 14:35:02 -0700806 focused.clearFocus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800807 }
808 }
809
810 /**
811 * {@inheritDoc}
812 */
813 @Override
814 void unFocus() {
815 if (DBG) {
816 System.out.println(this + " unFocus()");
817 }
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -0800818 if (mFocused == null) {
819 super.unFocus();
820 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800821 mFocused.unFocus();
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -0800822 mFocused = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800823 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800824 }
825
826 /**
827 * Returns the focused child of this view, if any. The child may have focus
828 * or contain focus.
829 *
830 * @return the focused child or null.
831 */
832 public View getFocusedChild() {
833 return mFocused;
834 }
835
836 /**
837 * Returns true if this view has or contains focus
838 *
839 * @return true if this view has or contains focus
840 */
841 @Override
842 public boolean hasFocus() {
Dianne Hackborn4702a852012-08-17 15:18:29 -0700843 return (mPrivateFlags & PFLAG_FOCUSED) != 0 || mFocused != null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800844 }
845
846 /*
847 * (non-Javadoc)
848 *
849 * @see android.view.View#findFocus()
850 */
851 @Override
852 public View findFocus() {
853 if (DBG) {
854 System.out.println("Find focus in " + this + ": flags="
855 + isFocused() + ", child=" + mFocused);
856 }
857
858 if (isFocused()) {
859 return this;
860 }
861
862 if (mFocused != null) {
863 return mFocused.findFocus();
864 }
865 return null;
866 }
867
868 /**
869 * {@inheritDoc}
870 */
871 @Override
872 public boolean hasFocusable() {
873 if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) {
874 return false;
875 }
876
877 if (isFocusable()) {
878 return true;
879 }
880
881 final int descendantFocusability = getDescendantFocusability();
882 if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS) {
883 final int count = mChildrenCount;
884 final View[] children = mChildren;
885
886 for (int i = 0; i < count; i++) {
887 final View child = children[i];
888 if (child.hasFocusable()) {
889 return true;
890 }
891 }
892 }
893
894 return false;
895 }
896
897 /**
898 * {@inheritDoc}
899 */
900 @Override
svetoslavganov75986cf2009-05-14 22:28:01 -0700901 public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800902 final int focusableCount = views.size();
903
904 final int descendantFocusability = getDescendantFocusability();
905
Svetoslav Ganov27e2da72012-07-02 18:12:00 -0700906 if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800907 final int count = mChildrenCount;
908 final View[] children = mChildren;
909
910 for (int i = 0; i < count; i++) {
911 final View child = children[i];
912 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
svetoslavganov75986cf2009-05-14 22:28:01 -0700913 child.addFocusables(views, direction, focusableMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800914 }
915 }
916 }
917
918 // we add ourselves (if focusable) in all cases except for when we are
919 // FOCUS_AFTER_DESCENDANTS and there are some descendants focusable. this is
920 // to avoid the focus search finding layouts when a more precise search
921 // among the focusable children would be more interesting.
Svetoslav Ganove5dfa472012-05-08 15:58:32 -0700922 if (descendantFocusability != FOCUS_AFTER_DESCENDANTS
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800923 // No focusable descendants
Svetoslav Ganov27e2da72012-07-02 18:12:00 -0700924 || (focusableCount == views.size())) {
svetoslavganov75986cf2009-05-14 22:28:01 -0700925 super.addFocusables(views, direction, focusableMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800926 }
927 }
928
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700929 @Override
Svetoslav Ganovea515ae2011-09-14 18:15:32 -0700930 public void findViewsWithText(ArrayList<View> outViews, CharSequence text, int flags) {
931 super.findViewsWithText(outViews, text, flags);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700932 final int childrenCount = mChildrenCount;
933 final View[] children = mChildren;
934 for (int i = 0; i < childrenCount; i++) {
935 View child = children[i];
Svetoslav Ganovea515ae2011-09-14 18:15:32 -0700936 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE
Dianne Hackborn4702a852012-08-17 15:18:29 -0700937 && (child.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) {
Svetoslav Ganovea515ae2011-09-14 18:15:32 -0700938 child.findViewsWithText(outViews, text, flags);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700939 }
940 }
941 }
942
Svetoslav5b578da2013-05-08 14:23:32 -0700943 /** @hide */
Svetoslav Ganov2cdedff2011-10-03 14:18:42 -0700944 @Override
Svetoslav5b578da2013-05-08 14:23:32 -0700945 public View findViewByAccessibilityIdTraversal(int accessibilityId) {
Svetoslav Ganov2cdedff2011-10-03 14:18:42 -0700946 View foundView = super.findViewByAccessibilityIdTraversal(accessibilityId);
947 if (foundView != null) {
948 return foundView;
949 }
950 final int childrenCount = mChildrenCount;
951 final View[] children = mChildren;
952 for (int i = 0; i < childrenCount; i++) {
953 View child = children[i];
954 foundView = child.findViewByAccessibilityIdTraversal(accessibilityId);
955 if (foundView != null) {
956 return foundView;
957 }
958 }
959 return null;
960 }
961
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800962 /**
963 * {@inheritDoc}
964 */
965 @Override
966 public void dispatchWindowFocusChanged(boolean hasFocus) {
967 super.dispatchWindowFocusChanged(hasFocus);
968 final int count = mChildrenCount;
969 final View[] children = mChildren;
970 for (int i = 0; i < count; i++) {
971 children[i].dispatchWindowFocusChanged(hasFocus);
972 }
973 }
974
975 /**
976 * {@inheritDoc}
977 */
978 @Override
979 public void addTouchables(ArrayList<View> views) {
980 super.addTouchables(views);
981
982 final int count = mChildrenCount;
983 final View[] children = mChildren;
984
985 for (int i = 0; i < count; i++) {
986 final View child = children[i];
987 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
988 child.addTouchables(views);
989 }
990 }
991 }
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -0700992
993 /**
994 * @hide
995 */
996 @Override
997 public void makeOptionalFitsSystemWindows() {
998 super.makeOptionalFitsSystemWindows();
999 final int count = mChildrenCount;
1000 final View[] children = mChildren;
1001 for (int i = 0; i < count; i++) {
1002 children[i].makeOptionalFitsSystemWindows();
1003 }
1004 }
1005
Romain Guy43c9cdf2010-01-27 13:53:55 -08001006 /**
1007 * {@inheritDoc}
1008 */
1009 @Override
1010 public void dispatchDisplayHint(int hint) {
1011 super.dispatchDisplayHint(hint);
1012 final int count = mChildrenCount;
1013 final View[] children = mChildren;
1014 for (int i = 0; i < count; i++) {
1015 children[i].dispatchDisplayHint(hint);
1016 }
1017 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001018
1019 /**
Chet Haase0d299362012-01-26 10:51:48 -08001020 * Called when a view's visibility has changed. Notify the parent to take any appropriate
1021 * action.
1022 *
1023 * @param child The view whose visibility has changed
1024 * @param oldVisibility The previous visibility value (GONE, INVISIBLE, or VISIBLE).
1025 * @param newVisibility The new visibility value (GONE, INVISIBLE, or VISIBLE).
Chet Haase5e25c2c2010-09-16 11:15:56 -07001026 * @hide
Chet Haase5e25c2c2010-09-16 11:15:56 -07001027 */
Chet Haase0d299362012-01-26 10:51:48 -08001028 protected void onChildVisibilityChanged(View child, int oldVisibility, int newVisibility) {
Chet Haase5e25c2c2010-09-16 11:15:56 -07001029 if (mTransition != null) {
Chet Haase0d299362012-01-26 10:51:48 -08001030 if (newVisibility == VISIBLE) {
1031 mTransition.showChild(this, child, oldVisibility);
Chet Haase5e25c2c2010-09-16 11:15:56 -07001032 } else {
Chet Haase0d299362012-01-26 10:51:48 -08001033 mTransition.hideChild(this, child, newVisibility);
Chet Haase5e25c2c2010-09-16 11:15:56 -07001034 if (mTransitioningViews != null && mTransitioningViews.contains(child)) {
Chet Haaseddbb3462012-06-19 13:54:29 -07001035 // Only track this on disappearing views - appearing views are already visible
1036 // and don't need special handling during drawChild()
1037 if (mVisibilityChangingChildren == null) {
1038 mVisibilityChangingChildren = new ArrayList<View>();
1039 }
1040 mVisibilityChangingChildren.add(child);
Chet Haase5e25c2c2010-09-16 11:15:56 -07001041 addDisappearingView(child);
1042 }
1043 }
1044 }
Christopher Tate86cab1b2011-01-13 20:28:55 -08001045
1046 // in all cases, for drags
1047 if (mCurrentDrag != null) {
Chet Haase0d299362012-01-26 10:51:48 -08001048 if (newVisibility == VISIBLE) {
Christopher Tate86cab1b2011-01-13 20:28:55 -08001049 notifyChildOfDrag(child);
1050 }
1051 }
Chet Haase5e25c2c2010-09-16 11:15:56 -07001052 }
1053
1054 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001055 * {@inheritDoc}
1056 */
1057 @Override
Adam Powell326d8082009-12-09 15:10:07 -08001058 protected void dispatchVisibilityChanged(View changedView, int visibility) {
1059 super.dispatchVisibilityChanged(changedView, visibility);
1060 final int count = mChildrenCount;
1061 final View[] children = mChildren;
1062 for (int i = 0; i < count; i++) {
1063 children[i].dispatchVisibilityChanged(changedView, visibility);
1064 }
1065 }
1066
1067 /**
1068 * {@inheritDoc}
1069 */
1070 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001071 public void dispatchWindowVisibilityChanged(int visibility) {
1072 super.dispatchWindowVisibilityChanged(visibility);
1073 final int count = mChildrenCount;
1074 final View[] children = mChildren;
1075 for (int i = 0; i < count; i++) {
1076 children[i].dispatchWindowVisibilityChanged(visibility);
1077 }
1078 }
1079
1080 /**
1081 * {@inheritDoc}
1082 */
Dianne Hackborne36d6e22010-02-17 19:46:25 -08001083 @Override
1084 public void dispatchConfigurationChanged(Configuration newConfig) {
1085 super.dispatchConfigurationChanged(newConfig);
1086 final int count = mChildrenCount;
1087 final View[] children = mChildren;
1088 for (int i = 0; i < count; i++) {
1089 children[i].dispatchConfigurationChanged(newConfig);
1090 }
1091 }
1092
1093 /**
1094 * {@inheritDoc}
1095 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001096 public void recomputeViewAttributes(View child) {
Joe Onorato664644d2011-01-23 17:53:23 -08001097 if (mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) {
1098 ViewParent parent = mParent;
1099 if (parent != null) parent.recomputeViewAttributes(this);
1100 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001101 }
Romain Guy8506ab42009-06-11 17:35:47 -07001102
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001103 @Override
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001104 void dispatchCollectViewAttributes(AttachInfo attachInfo, int visibility) {
1105 if ((visibility & VISIBILITY_MASK) == VISIBLE) {
1106 super.dispatchCollectViewAttributes(attachInfo, visibility);
1107 final int count = mChildrenCount;
1108 final View[] children = mChildren;
1109 for (int i = 0; i < count; i++) {
1110 final View child = children[i];
1111 child.dispatchCollectViewAttributes(attachInfo,
1112 visibility | (child.mViewFlags&VISIBILITY_MASK));
1113 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001114 }
1115 }
1116
1117 /**
1118 * {@inheritDoc}
1119 */
1120 public void bringChildToFront(View child) {
1121 int index = indexOfChild(child);
1122 if (index >= 0) {
1123 removeFromArray(index);
1124 addInArray(child, mChildrenCount);
1125 child.mParent = this;
Chet Haasecb96db82013-09-04 10:21:46 -07001126 requestLayout();
1127 invalidate();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001128 }
1129 }
1130
Romain Guy6410c0a2013-06-17 11:21:58 -07001131 private PointF getLocalPoint() {
1132 if (mLocalPoint == null) mLocalPoint = new PointF();
1133 return mLocalPoint;
1134 }
1135
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001136 /**
1137 * {@inheritDoc}
Christopher Tatea53146c2010-09-07 11:57:52 -07001138 */
Steve Block8a7259b2012-03-01 11:24:41 +00001139 // TODO: Write real docs
Christopher Tatea53146c2010-09-07 11:57:52 -07001140 @Override
1141 public boolean dispatchDragEvent(DragEvent event) {
1142 boolean retval = false;
1143 final float tx = event.mX;
1144 final float ty = event.mY;
1145
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07001146 ViewRootImpl root = getViewRootImpl();
Christopher Tatea53146c2010-09-07 11:57:52 -07001147
1148 // Dispatch down the view hierarchy
Romain Guy6410c0a2013-06-17 11:21:58 -07001149 final PointF localPoint = getLocalPoint();
1150
Christopher Tatea53146c2010-09-07 11:57:52 -07001151 switch (event.mAction) {
1152 case DragEvent.ACTION_DRAG_STARTED: {
1153 // clear state to recalculate which views we drag over
Chris Tate9d1ab882010-11-02 15:55:39 -07001154 mCurrentDragView = null;
Christopher Tatea53146c2010-09-07 11:57:52 -07001155
Christopher Tate86cab1b2011-01-13 20:28:55 -08001156 // Set up our tracking of drag-started notifications
1157 mCurrentDrag = DragEvent.obtain(event);
1158 if (mDragNotifiedChildren == null) {
1159 mDragNotifiedChildren = new HashSet<View>();
1160 } else {
1161 mDragNotifiedChildren.clear();
1162 }
1163
Christopher Tatea53146c2010-09-07 11:57:52 -07001164 // Now dispatch down to our children, caching the responses
1165 mChildAcceptsDrag = false;
1166 final int count = mChildrenCount;
1167 final View[] children = mChildren;
1168 for (int i = 0; i < count; i++) {
Christopher Tate2c095f32010-10-04 14:13:40 -07001169 final View child = children[i];
Christopher Tate3d4bf172011-03-28 16:16:46 -07001170 child.mPrivateFlags2 &= ~View.DRAG_MASK;
Christopher Tate2c095f32010-10-04 14:13:40 -07001171 if (child.getVisibility() == VISIBLE) {
Christopher Tate86cab1b2011-01-13 20:28:55 -08001172 final boolean handled = notifyChildOfDrag(children[i]);
Christopher Tate2c095f32010-10-04 14:13:40 -07001173 if (handled) {
1174 mChildAcceptsDrag = true;
1175 }
Christopher Tatea53146c2010-09-07 11:57:52 -07001176 }
1177 }
1178
1179 // Return HANDLED if one of our children can accept the drag
1180 if (mChildAcceptsDrag) {
1181 retval = true;
1182 }
1183 } break;
1184
1185 case DragEvent.ACTION_DRAG_ENDED: {
Christopher Tate86cab1b2011-01-13 20:28:55 -08001186 // Release the bookkeeping now that the drag lifecycle has ended
Christopher Tate1fc014f2011-01-19 12:56:26 -08001187 if (mDragNotifiedChildren != null) {
1188 for (View child : mDragNotifiedChildren) {
1189 // If a child was notified about an ongoing drag, it's told that it's over
1190 child.dispatchDragEvent(event);
Christopher Tate3d4bf172011-03-28 16:16:46 -07001191 child.mPrivateFlags2 &= ~View.DRAG_MASK;
1192 child.refreshDrawableState();
Christopher Tate1fc014f2011-01-19 12:56:26 -08001193 }
1194
1195 mDragNotifiedChildren.clear();
Christopher Tatee9accff2013-03-04 12:57:23 -08001196 if (mCurrentDrag != null) {
1197 mCurrentDrag.recycle();
1198 mCurrentDrag = null;
1199 }
Christopher Tate1fc014f2011-01-19 12:56:26 -08001200 }
Christopher Tate86cab1b2011-01-13 20:28:55 -08001201
Christopher Tatea53146c2010-09-07 11:57:52 -07001202 // We consider drag-ended to have been handled if one of our children
1203 // had offered to handle the drag.
1204 if (mChildAcceptsDrag) {
1205 retval = true;
1206 }
1207 } break;
1208
1209 case DragEvent.ACTION_DRAG_LOCATION: {
1210 // Find the [possibly new] drag target
Romain Guy6410c0a2013-06-17 11:21:58 -07001211 final View target = findFrontmostDroppableChildAt(event.mX, event.mY, localPoint);
Christopher Tatea53146c2010-09-07 11:57:52 -07001212
1213 // If we've changed apparent drag target, tell the view root which view
Chris Tate9d1ab882010-11-02 15:55:39 -07001214 // we're over now [for purposes of the eventual drag-recipient-changed
1215 // notifications to the framework] and tell the new target that the drag
1216 // has entered its bounds. The root will see setDragFocus() calls all
1217 // the way down to the final leaf view that is handling the LOCATION event
1218 // before reporting the new potential recipient to the framework.
Christopher Tatea53146c2010-09-07 11:57:52 -07001219 if (mCurrentDragView != target) {
Chris Tate9d1ab882010-11-02 15:55:39 -07001220 root.setDragFocus(target);
1221
1222 final int action = event.mAction;
1223 // If we've dragged off of a child view, send it the EXITED message
1224 if (mCurrentDragView != null) {
Christopher Tate3d4bf172011-03-28 16:16:46 -07001225 final View view = mCurrentDragView;
Chris Tate9d1ab882010-11-02 15:55:39 -07001226 event.mAction = DragEvent.ACTION_DRAG_EXITED;
Christopher Tate3d4bf172011-03-28 16:16:46 -07001227 view.dispatchDragEvent(event);
Dianne Hackborn4702a852012-08-17 15:18:29 -07001228 view.mPrivateFlags2 &= ~View.PFLAG2_DRAG_HOVERED;
Christopher Tate3d4bf172011-03-28 16:16:46 -07001229 view.refreshDrawableState();
Chris Tate9d1ab882010-11-02 15:55:39 -07001230 }
Christopher Tatea53146c2010-09-07 11:57:52 -07001231 mCurrentDragView = target;
Chris Tate9d1ab882010-11-02 15:55:39 -07001232
1233 // If we've dragged over a new child view, send it the ENTERED message
1234 if (target != null) {
1235 event.mAction = DragEvent.ACTION_DRAG_ENTERED;
1236 target.dispatchDragEvent(event);
Dianne Hackborn4702a852012-08-17 15:18:29 -07001237 target.mPrivateFlags2 |= View.PFLAG2_DRAG_HOVERED;
Christopher Tate3d4bf172011-03-28 16:16:46 -07001238 target.refreshDrawableState();
Chris Tate9d1ab882010-11-02 15:55:39 -07001239 }
1240 event.mAction = action; // restore the event's original state
Christopher Tatea53146c2010-09-07 11:57:52 -07001241 }
Christopher Tate2c095f32010-10-04 14:13:40 -07001242
Christopher Tatea53146c2010-09-07 11:57:52 -07001243 // Dispatch the actual drag location notice, localized into its coordinates
1244 if (target != null) {
Romain Guy6410c0a2013-06-17 11:21:58 -07001245 event.mX = localPoint.x;
1246 event.mY = localPoint.y;
Christopher Tatea53146c2010-09-07 11:57:52 -07001247
1248 retval = target.dispatchDragEvent(event);
1249
1250 event.mX = tx;
1251 event.mY = ty;
1252 }
1253 } break;
1254
Chris Tate9d1ab882010-11-02 15:55:39 -07001255 /* Entered / exited dispatch
1256 *
1257 * DRAG_ENTERED is not dispatched downwards from ViewGroup. The reason for this is
1258 * that we're about to get the corresponding LOCATION event, which we will use to
1259 * determine which of our children is the new target; at that point we will
1260 * push a DRAG_ENTERED down to the new target child [which may itself be a ViewGroup].
1261 *
1262 * DRAG_EXITED *is* dispatched all the way down immediately: once we know the
1263 * drag has left this ViewGroup, we know by definition that every contained subview
1264 * is also no longer under the drag point.
1265 */
1266
1267 case DragEvent.ACTION_DRAG_EXITED: {
1268 if (mCurrentDragView != null) {
Christopher Tate3d4bf172011-03-28 16:16:46 -07001269 final View view = mCurrentDragView;
1270 view.dispatchDragEvent(event);
Dianne Hackborn4702a852012-08-17 15:18:29 -07001271 view.mPrivateFlags2 &= ~View.PFLAG2_DRAG_HOVERED;
Christopher Tate3d4bf172011-03-28 16:16:46 -07001272 view.refreshDrawableState();
1273
Chris Tate9d1ab882010-11-02 15:55:39 -07001274 mCurrentDragView = null;
1275 }
1276 } break;
1277
Christopher Tatea53146c2010-09-07 11:57:52 -07001278 case DragEvent.ACTION_DROP: {
Christopher Tate2c095f32010-10-04 14:13:40 -07001279 if (ViewDebug.DEBUG_DRAG) Log.d(View.VIEW_LOG_TAG, "Drop event: " + event);
Romain Guy6410c0a2013-06-17 11:21:58 -07001280 View target = findFrontmostDroppableChildAt(event.mX, event.mY, localPoint);
Christopher Tatea53146c2010-09-07 11:57:52 -07001281 if (target != null) {
Christopher Tate5ada6cb2010-10-05 14:15:29 -07001282 if (ViewDebug.DEBUG_DRAG) Log.d(View.VIEW_LOG_TAG, " dispatch drop to " + target);
Romain Guy6410c0a2013-06-17 11:21:58 -07001283 event.mX = localPoint.x;
1284 event.mY = localPoint.y;
Christopher Tatea53146c2010-09-07 11:57:52 -07001285 retval = target.dispatchDragEvent(event);
1286 event.mX = tx;
1287 event.mY = ty;
Christopher Tate5ada6cb2010-10-05 14:15:29 -07001288 } else {
1289 if (ViewDebug.DEBUG_DRAG) {
1290 Log.d(View.VIEW_LOG_TAG, " not dropped on an accepting view");
1291 }
Christopher Tatea53146c2010-09-07 11:57:52 -07001292 }
1293 } break;
1294 }
1295
1296 // If none of our children could handle the event, try here
1297 if (!retval) {
Chris Tate32affef2010-10-18 15:29:21 -07001298 // Call up to the View implementation that dispatches to installed listeners
1299 retval = super.dispatchDragEvent(event);
Christopher Tatea53146c2010-09-07 11:57:52 -07001300 }
1301 return retval;
1302 }
1303
1304 // Find the frontmost child view that lies under the given point, and calculate
1305 // the position within its own local coordinate system.
1306 View findFrontmostDroppableChildAt(float x, float y, PointF outLocalPoint) {
Christopher Tatea53146c2010-09-07 11:57:52 -07001307 final int count = mChildrenCount;
1308 final View[] children = mChildren;
1309 for (int i = count - 1; i >= 0; i--) {
1310 final View child = children[i];
Christopher Tate3d4bf172011-03-28 16:16:46 -07001311 if (!child.canAcceptDrag()) {
Christopher Tatea53146c2010-09-07 11:57:52 -07001312 continue;
1313 }
1314
Christopher Tate2c095f32010-10-04 14:13:40 -07001315 if (isTransformedTouchPointInView(x, y, child, outLocalPoint)) {
Christopher Tatea53146c2010-09-07 11:57:52 -07001316 return child;
1317 }
1318 }
1319 return null;
1320 }
1321
Christopher Tate86cab1b2011-01-13 20:28:55 -08001322 boolean notifyChildOfDrag(View child) {
1323 if (ViewDebug.DEBUG_DRAG) {
1324 Log.d(View.VIEW_LOG_TAG, "Sending drag-started to view: " + child);
1325 }
1326
Christopher Tate3d4bf172011-03-28 16:16:46 -07001327 boolean canAccept = false;
Christopher Tate86cab1b2011-01-13 20:28:55 -08001328 if (! mDragNotifiedChildren.contains(child)) {
1329 mDragNotifiedChildren.add(child);
Christopher Tate3d4bf172011-03-28 16:16:46 -07001330 canAccept = child.dispatchDragEvent(mCurrentDrag);
1331 if (canAccept && !child.canAcceptDrag()) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07001332 child.mPrivateFlags2 |= View.PFLAG2_DRAG_CAN_ACCEPT;
Christopher Tate3d4bf172011-03-28 16:16:46 -07001333 child.refreshDrawableState();
1334 }
Christopher Tate86cab1b2011-01-13 20:28:55 -08001335 }
Christopher Tate3d4bf172011-03-28 16:16:46 -07001336 return canAccept;
Christopher Tate86cab1b2011-01-13 20:28:55 -08001337 }
1338
Joe Onorato664644d2011-01-23 17:53:23 -08001339 @Override
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001340 public void dispatchWindowSystemUiVisiblityChanged(int visible) {
1341 super.dispatchWindowSystemUiVisiblityChanged(visible);
1342
1343 final int count = mChildrenCount;
1344 final View[] children = mChildren;
1345 for (int i=0; i <count; i++) {
1346 final View child = children[i];
1347 child.dispatchWindowSystemUiVisiblityChanged(visible);
1348 }
1349 }
1350
1351 @Override
Joe Onorato664644d2011-01-23 17:53:23 -08001352 public void dispatchSystemUiVisibilityChanged(int visible) {
1353 super.dispatchSystemUiVisibilityChanged(visible);
1354
1355 final int count = mChildrenCount;
1356 final View[] children = mChildren;
1357 for (int i=0; i <count; i++) {
1358 final View child = children[i];
1359 child.dispatchSystemUiVisibilityChanged(visible);
1360 }
1361 }
1362
Dianne Hackborn9a230e02011-10-06 11:51:27 -07001363 @Override
Dianne Hackborncf675782012-05-10 15:07:24 -07001364 boolean updateLocalSystemUiVisibility(int localValue, int localChanges) {
1365 boolean changed = super.updateLocalSystemUiVisibility(localValue, localChanges);
Dianne Hackborn9a230e02011-10-06 11:51:27 -07001366
1367 final int count = mChildrenCount;
1368 final View[] children = mChildren;
1369 for (int i=0; i <count; i++) {
1370 final View child = children[i];
Dianne Hackborncf675782012-05-10 15:07:24 -07001371 changed |= child.updateLocalSystemUiVisibility(localValue, localChanges);
Dianne Hackborn9a230e02011-10-06 11:51:27 -07001372 }
Dianne Hackborncf675782012-05-10 15:07:24 -07001373 return changed;
Dianne Hackborn9a230e02011-10-06 11:51:27 -07001374 }
1375
Christopher Tatea53146c2010-09-07 11:57:52 -07001376 /**
1377 * {@inheritDoc}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001378 */
1379 @Override
1380 public boolean dispatchKeyEventPreIme(KeyEvent event) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07001381 if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
1382 == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001383 return super.dispatchKeyEventPreIme(event);
Dianne Hackborn4702a852012-08-17 15:18:29 -07001384 } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
1385 == PFLAG_HAS_BOUNDS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001386 return mFocused.dispatchKeyEventPreIme(event);
1387 }
1388 return false;
1389 }
1390
1391 /**
1392 * {@inheritDoc}
1393 */
1394 @Override
1395 public boolean dispatchKeyEvent(KeyEvent event) {
Jeff Brown21bc5c92011-02-28 18:27:14 -08001396 if (mInputEventConsistencyVerifier != null) {
1397 mInputEventConsistencyVerifier.onKeyEvent(event, 1);
1398 }
1399
Dianne Hackborn4702a852012-08-17 15:18:29 -07001400 if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
1401 == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001402 if (super.dispatchKeyEvent(event)) {
1403 return true;
1404 }
Dianne Hackborn4702a852012-08-17 15:18:29 -07001405 } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
1406 == PFLAG_HAS_BOUNDS) {
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001407 if (mFocused.dispatchKeyEvent(event)) {
1408 return true;
1409 }
1410 }
1411
1412 if (mInputEventConsistencyVerifier != null) {
1413 mInputEventConsistencyVerifier.onUnhandledEvent(event, 1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001414 }
1415 return false;
1416 }
1417
1418 /**
1419 * {@inheritDoc}
1420 */
1421 @Override
1422 public boolean dispatchKeyShortcutEvent(KeyEvent event) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07001423 if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
1424 == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001425 return super.dispatchKeyShortcutEvent(event);
Dianne Hackborn4702a852012-08-17 15:18:29 -07001426 } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
1427 == PFLAG_HAS_BOUNDS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001428 return mFocused.dispatchKeyShortcutEvent(event);
1429 }
1430 return false;
1431 }
1432
1433 /**
1434 * {@inheritDoc}
1435 */
1436 @Override
1437 public boolean dispatchTrackballEvent(MotionEvent event) {
Jeff Brown21bc5c92011-02-28 18:27:14 -08001438 if (mInputEventConsistencyVerifier != null) {
1439 mInputEventConsistencyVerifier.onTrackballEvent(event, 1);
1440 }
1441
Dianne Hackborn4702a852012-08-17 15:18:29 -07001442 if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
1443 == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001444 if (super.dispatchTrackballEvent(event)) {
1445 return true;
1446 }
Dianne Hackborn4702a852012-08-17 15:18:29 -07001447 } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
1448 == PFLAG_HAS_BOUNDS) {
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001449 if (mFocused.dispatchTrackballEvent(event)) {
1450 return true;
1451 }
1452 }
1453
1454 if (mInputEventConsistencyVerifier != null) {
1455 mInputEventConsistencyVerifier.onUnhandledEvent(event, 1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001456 }
1457 return false;
1458 }
1459
Jeff Brown10b62902011-06-20 16:40:37 -07001460 /**
1461 * {@inheritDoc}
1462 */
Romain Guya9489272011-06-22 20:58:11 -07001463 @SuppressWarnings({"ConstantConditions"})
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001464 @Override
Jeff Browna032cc02011-03-07 16:56:21 -08001465 protected boolean dispatchHoverEvent(MotionEvent event) {
Jeff Browna032cc02011-03-07 16:56:21 -08001466 final int action = event.getAction();
Jeff Browna032cc02011-03-07 16:56:21 -08001467
Jeff Brown10b62902011-06-20 16:40:37 -07001468 // First check whether the view group wants to intercept the hover event.
1469 final boolean interceptHover = onInterceptHoverEvent(event);
1470 event.setAction(action); // restore action in case it was changed
1471
Jeff Brown87b7f802011-06-21 18:35:45 -07001472 MotionEvent eventNoHistory = event;
1473 boolean handled = false;
1474
1475 // Send events to the hovered children and build a new list of hover targets until
1476 // one is found that handles the event.
1477 HoverTarget firstOldHoverTarget = mFirstHoverTarget;
1478 mFirstHoverTarget = null;
Jeff Brown10b62902011-06-20 16:40:37 -07001479 if (!interceptHover && action != MotionEvent.ACTION_HOVER_EXIT) {
Jeff Browna032cc02011-03-07 16:56:21 -08001480 final float x = event.getX();
1481 final float y = event.getY();
Jeff Brown33bbfd22011-02-24 20:55:35 -08001482 final int childrenCount = mChildrenCount;
1483 if (childrenCount != 0) {
Svetoslav0e5e9aa2013-04-12 14:13:20 -07001484 final boolean customChildOrder = isChildrenDrawingOrderEnabled();
Jeff Brown33bbfd22011-02-24 20:55:35 -08001485 final View[] children = mChildren;
Jeff Brown87b7f802011-06-21 18:35:45 -07001486 HoverTarget lastHoverTarget = null;
Jeff Brown33bbfd22011-02-24 20:55:35 -08001487 for (int i = childrenCount - 1; i >= 0; i--) {
Svetoslav0e5e9aa2013-04-12 14:13:20 -07001488 final int childIndex = customChildOrder
1489 ? getChildDrawingOrder(childrenCount, i) : i;
1490 final View child = children[childIndex];
Jeff Brown87b7f802011-06-21 18:35:45 -07001491 if (!canViewReceivePointerEvents(child)
1492 || !isTransformedTouchPointInView(x, y, child, null)) {
1493 continue;
1494 }
1495
1496 // Obtain a hover target for this child. Dequeue it from the
1497 // old hover target list if the child was previously hovered.
1498 HoverTarget hoverTarget = firstOldHoverTarget;
1499 final boolean wasHovered;
1500 for (HoverTarget predecessor = null; ;) {
1501 if (hoverTarget == null) {
1502 hoverTarget = HoverTarget.obtain(child);
1503 wasHovered = false;
1504 break;
1505 }
1506
1507 if (hoverTarget.child == child) {
1508 if (predecessor != null) {
1509 predecessor.next = hoverTarget.next;
1510 } else {
1511 firstOldHoverTarget = hoverTarget.next;
1512 }
1513 hoverTarget.next = null;
1514 wasHovered = true;
1515 break;
1516 }
1517
1518 predecessor = hoverTarget;
1519 hoverTarget = hoverTarget.next;
1520 }
1521
1522 // Enqueue the hover target onto the new hover target list.
1523 if (lastHoverTarget != null) {
1524 lastHoverTarget.next = hoverTarget;
1525 } else {
Jeff Brown87b7f802011-06-21 18:35:45 -07001526 mFirstHoverTarget = hoverTarget;
1527 }
Sangkyu Lee8725f362013-03-13 09:38:45 +09001528 lastHoverTarget = hoverTarget;
Jeff Brown87b7f802011-06-21 18:35:45 -07001529
1530 // Dispatch the event to the child.
1531 if (action == MotionEvent.ACTION_HOVER_ENTER) {
1532 if (!wasHovered) {
1533 // Send the enter as is.
1534 handled |= dispatchTransformedGenericPointerEvent(
1535 event, child); // enter
1536 }
1537 } else if (action == MotionEvent.ACTION_HOVER_MOVE) {
1538 if (!wasHovered) {
1539 // Synthesize an enter from a move.
1540 eventNoHistory = obtainMotionEventNoHistoryOrSelf(eventNoHistory);
1541 eventNoHistory.setAction(MotionEvent.ACTION_HOVER_ENTER);
1542 handled |= dispatchTransformedGenericPointerEvent(
1543 eventNoHistory, child); // enter
1544 eventNoHistory.setAction(action);
1545
1546 handled |= dispatchTransformedGenericPointerEvent(
1547 eventNoHistory, child); // move
1548 } else {
1549 // Send the move as is.
1550 handled |= dispatchTransformedGenericPointerEvent(event, child);
1551 }
1552 }
1553 if (handled) {
Jeff Brown10b62902011-06-20 16:40:37 -07001554 break;
Jeff Brown33bbfd22011-02-24 20:55:35 -08001555 }
Jeff Brown10b62902011-06-20 16:40:37 -07001556 }
1557 }
1558 }
Jeff Brown33bbfd22011-02-24 20:55:35 -08001559
Jeff Brown87b7f802011-06-21 18:35:45 -07001560 // Send exit events to all previously hovered children that are no longer hovered.
1561 while (firstOldHoverTarget != null) {
1562 final View child = firstOldHoverTarget.child;
Jeff Brown10b62902011-06-20 16:40:37 -07001563
Jeff Brown87b7f802011-06-21 18:35:45 -07001564 // Exit the old hovered child.
1565 if (action == MotionEvent.ACTION_HOVER_EXIT) {
1566 // Send the exit as is.
1567 handled |= dispatchTransformedGenericPointerEvent(
1568 event, child); // exit
1569 } else {
1570 // Synthesize an exit from a move or enter.
1571 // Ignore the result because hover focus has moved to a different view.
1572 if (action == MotionEvent.ACTION_HOVER_MOVE) {
Jeff Brown10b62902011-06-20 16:40:37 -07001573 dispatchTransformedGenericPointerEvent(
Jeff Brown87b7f802011-06-21 18:35:45 -07001574 event, child); // move
Jeff Brown10b62902011-06-20 16:40:37 -07001575 }
Jeff Brown87b7f802011-06-21 18:35:45 -07001576 eventNoHistory = obtainMotionEventNoHistoryOrSelf(eventNoHistory);
1577 eventNoHistory.setAction(MotionEvent.ACTION_HOVER_EXIT);
1578 dispatchTransformedGenericPointerEvent(
1579 eventNoHistory, child); // exit
1580 eventNoHistory.setAction(action);
Jeff Brown10b62902011-06-20 16:40:37 -07001581 }
1582
Jeff Brown87b7f802011-06-21 18:35:45 -07001583 final HoverTarget nextOldHoverTarget = firstOldHoverTarget.next;
1584 firstOldHoverTarget.recycle();
1585 firstOldHoverTarget = nextOldHoverTarget;
Jeff Brown10b62902011-06-20 16:40:37 -07001586 }
1587
Jeff Brown87b7f802011-06-21 18:35:45 -07001588 // Send events to the view group itself if no children have handled it.
Jeff Brown10b62902011-06-20 16:40:37 -07001589 boolean newHoveredSelf = !handled;
1590 if (newHoveredSelf == mHoveredSelf) {
1591 if (newHoveredSelf) {
1592 // Send event to the view group as before.
1593 handled |= super.dispatchHoverEvent(event);
1594 }
1595 } else {
1596 if (mHoveredSelf) {
1597 // Exit the view group.
1598 if (action == MotionEvent.ACTION_HOVER_EXIT) {
1599 // Send the exit as is.
1600 handled |= super.dispatchHoverEvent(event); // exit
1601 } else {
1602 // Synthesize an exit from a move or enter.
1603 // Ignore the result because hover focus is moving to a different view.
1604 if (action == MotionEvent.ACTION_HOVER_MOVE) {
1605 super.dispatchHoverEvent(event); // move
1606 }
1607 eventNoHistory = obtainMotionEventNoHistoryOrSelf(eventNoHistory);
1608 eventNoHistory.setAction(MotionEvent.ACTION_HOVER_EXIT);
1609 super.dispatchHoverEvent(eventNoHistory); // exit
1610 eventNoHistory.setAction(action);
1611 }
1612 mHoveredSelf = false;
1613 }
1614
1615 if (newHoveredSelf) {
1616 // Enter the view group.
1617 if (action == MotionEvent.ACTION_HOVER_ENTER) {
1618 // Send the enter as is.
1619 handled |= super.dispatchHoverEvent(event); // enter
1620 mHoveredSelf = true;
1621 } else if (action == MotionEvent.ACTION_HOVER_MOVE) {
1622 // Synthesize an enter from a move.
1623 eventNoHistory = obtainMotionEventNoHistoryOrSelf(eventNoHistory);
1624 eventNoHistory.setAction(MotionEvent.ACTION_HOVER_ENTER);
1625 handled |= super.dispatchHoverEvent(eventNoHistory); // enter
1626 eventNoHistory.setAction(action);
1627
1628 handled |= super.dispatchHoverEvent(eventNoHistory); // move
1629 mHoveredSelf = true;
Jeff Brown33bbfd22011-02-24 20:55:35 -08001630 }
1631 }
Jeff Brown33bbfd22011-02-24 20:55:35 -08001632 }
1633
Jeff Browna032cc02011-03-07 16:56:21 -08001634 // Recycle the copy of the event that we made.
1635 if (eventNoHistory != event) {
1636 eventNoHistory.recycle();
1637 }
1638
Jeff Browna032cc02011-03-07 16:56:21 -08001639 // Done.
1640 return handled;
1641 }
1642
Jeff Brown59a422e2012-04-19 15:19:19 -07001643 private void exitHoverTargets() {
1644 if (mHoveredSelf || mFirstHoverTarget != null) {
1645 final long now = SystemClock.uptimeMillis();
1646 MotionEvent event = MotionEvent.obtain(now, now,
1647 MotionEvent.ACTION_HOVER_EXIT, 0.0f, 0.0f, 0);
1648 event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
1649 dispatchHoverEvent(event);
1650 event.recycle();
1651 }
1652 }
1653
1654 private void cancelHoverTarget(View view) {
1655 HoverTarget predecessor = null;
1656 HoverTarget target = mFirstHoverTarget;
1657 while (target != null) {
1658 final HoverTarget next = target.next;
1659 if (target.child == view) {
1660 if (predecessor == null) {
1661 mFirstHoverTarget = next;
1662 } else {
1663 predecessor.next = next;
1664 }
1665 target.recycle();
1666
1667 final long now = SystemClock.uptimeMillis();
1668 MotionEvent event = MotionEvent.obtain(now, now,
1669 MotionEvent.ACTION_HOVER_EXIT, 0.0f, 0.0f, 0);
1670 event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
1671 view.dispatchHoverEvent(event);
1672 event.recycle();
1673 return;
1674 }
1675 predecessor = target;
1676 target = next;
1677 }
1678 }
1679
Jeff Brown87b7f802011-06-21 18:35:45 -07001680 /** @hide */
1681 @Override
1682 protected boolean hasHoveredChild() {
1683 return mFirstHoverTarget != null;
1684 }
1685
Svetoslav Ganov42138042012-03-20 11:51:39 -07001686 @Override
1687 public void addChildrenForAccessibility(ArrayList<View> childrenForAccessibility) {
Svetoslav Ganov76f287e2012-04-23 11:02:36 -07001688 ChildListForAccessibility children = ChildListForAccessibility.obtain(this, true);
1689 try {
1690 final int childrenCount = children.getChildCount();
1691 for (int i = 0; i < childrenCount; i++) {
1692 View child = children.getChildAt(i);
Svetoslav Ganovc406be92012-05-11 16:12:32 -07001693 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
Svetoslav Ganov76f287e2012-04-23 11:02:36 -07001694 if (child.includeForAccessibility()) {
1695 childrenForAccessibility.add(child);
1696 } else {
1697 child.addChildrenForAccessibility(childrenForAccessibility);
1698 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07001699 }
1700 }
Svetoslav Ganov76f287e2012-04-23 11:02:36 -07001701 } finally {
1702 children.recycle();
Svetoslav Ganov42138042012-03-20 11:51:39 -07001703 }
1704 }
1705
1706 /**
Jeff Brown10b62902011-06-20 16:40:37 -07001707 * Implement this method to intercept hover events before they are handled
1708 * by child views.
1709 * <p>
1710 * This method is called before dispatching a hover event to a child of
1711 * the view group or to the view group's own {@link #onHoverEvent} to allow
1712 * the view group a chance to intercept the hover event.
1713 * This method can also be used to watch all pointer motions that occur within
1714 * the bounds of the view group even when the pointer is hovering over
1715 * a child of the view group rather than over the view group itself.
1716 * </p><p>
1717 * The view group can prevent its children from receiving hover events by
1718 * implementing this method and returning <code>true</code> to indicate
1719 * that it would like to intercept hover events. The view group must
1720 * continuously return <code>true</code> from {@link #onInterceptHoverEvent}
1721 * for as long as it wishes to continue intercepting hover events from
1722 * its children.
1723 * </p><p>
1724 * Interception preserves the invariant that at most one view can be
1725 * hovered at a time by transferring hover focus from the currently hovered
1726 * child to the view group or vice-versa as needed.
1727 * </p><p>
1728 * If this method returns <code>true</code> and a child is already hovered, then the
1729 * child view will first receive a hover exit event and then the view group
1730 * itself will receive a hover enter event in {@link #onHoverEvent}.
1731 * Likewise, if this method had previously returned <code>true</code> to intercept hover
1732 * events and instead returns <code>false</code> while the pointer is hovering
1733 * within the bounds of one of a child, then the view group will first receive a
1734 * hover exit event in {@link #onHoverEvent} and then the hovered child will
1735 * receive a hover enter event.
1736 * </p><p>
1737 * The default implementation always returns false.
1738 * </p>
1739 *
1740 * @param event The motion event that describes the hover.
1741 * @return True if the view group would like to intercept the hover event
1742 * and prevent its children from receiving it.
1743 */
1744 public boolean onInterceptHoverEvent(MotionEvent event) {
Svetoslav Ganov736c2752011-04-22 18:30:36 -07001745 return false;
1746 }
1747
Jeff Browna032cc02011-03-07 16:56:21 -08001748 private static MotionEvent obtainMotionEventNoHistoryOrSelf(MotionEvent event) {
1749 if (event.getHistorySize() == 0) {
1750 return event;
1751 }
1752 return MotionEvent.obtainNoHistory(event);
1753 }
1754
Jeff Brown10b62902011-06-20 16:40:37 -07001755 /**
1756 * {@inheritDoc}
1757 */
Jeff Browna032cc02011-03-07 16:56:21 -08001758 @Override
1759 protected boolean dispatchGenericPointerEvent(MotionEvent event) {
1760 // Send the event to the child under the pointer.
1761 final int childrenCount = mChildrenCount;
1762 if (childrenCount != 0) {
1763 final View[] children = mChildren;
1764 final float x = event.getX();
1765 final float y = event.getY();
1766
Adam Powella6478a32012-08-17 16:40:00 -07001767 final boolean customOrder = isChildrenDrawingOrderEnabled();
Jeff Browna032cc02011-03-07 16:56:21 -08001768 for (int i = childrenCount - 1; i >= 0; i--) {
Adam Powella6478a32012-08-17 16:40:00 -07001769 final int childIndex = customOrder ? getChildDrawingOrder(childrenCount, i) : i;
1770 final View child = children[childIndex];
Jeff Browna032cc02011-03-07 16:56:21 -08001771 if (!canViewReceivePointerEvents(child)
1772 || !isTransformedTouchPointInView(x, y, child, null)) {
1773 continue;
1774 }
1775
1776 if (dispatchTransformedGenericPointerEvent(event, child)) {
1777 return true;
1778 }
1779 }
1780 }
1781
1782 // No child handled the event. Send it to this view group.
1783 return super.dispatchGenericPointerEvent(event);
1784 }
1785
Jeff Brown10b62902011-06-20 16:40:37 -07001786 /**
1787 * {@inheritDoc}
1788 */
Jeff Browna032cc02011-03-07 16:56:21 -08001789 @Override
1790 protected boolean dispatchGenericFocusedEvent(MotionEvent event) {
Jeff Brown33bbfd22011-02-24 20:55:35 -08001791 // Send the event to the focused child or to this view group if it has focus.
Dianne Hackborn4702a852012-08-17 15:18:29 -07001792 if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
1793 == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
Jeff Browna032cc02011-03-07 16:56:21 -08001794 return super.dispatchGenericFocusedEvent(event);
Dianne Hackborn4702a852012-08-17 15:18:29 -07001795 } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
1796 == PFLAG_HAS_BOUNDS) {
Jeff Browncb1404e2011-01-15 18:14:15 -08001797 return mFocused.dispatchGenericMotionEvent(event);
1798 }
1799 return false;
1800 }
1801
1802 /**
Jeff Browna032cc02011-03-07 16:56:21 -08001803 * Dispatches a generic pointer event to a child, taking into account
1804 * transformations that apply to the child.
1805 *
1806 * @param event The event to send.
1807 * @param child The view to send the event to.
1808 * @return {@code true} if the child handled the event.
1809 */
1810 private boolean dispatchTransformedGenericPointerEvent(MotionEvent event, View child) {
1811 final float offsetX = mScrollX - child.mLeft;
1812 final float offsetY = mScrollY - child.mTop;
1813
1814 boolean handled;
1815 if (!child.hasIdentityMatrix()) {
1816 MotionEvent transformedEvent = MotionEvent.obtain(event);
1817 transformedEvent.offsetLocation(offsetX, offsetY);
1818 transformedEvent.transform(child.getInverseMatrix());
1819 handled = child.dispatchGenericMotionEvent(transformedEvent);
1820 transformedEvent.recycle();
1821 } else {
1822 event.offsetLocation(offsetX, offsetY);
1823 handled = child.dispatchGenericMotionEvent(event);
1824 event.offsetLocation(-offsetX, -offsetY);
1825 }
1826 return handled;
1827 }
1828
1829 /**
Jeff Browncb1404e2011-01-15 18:14:15 -08001830 * {@inheritDoc}
1831 */
1832 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001833 public boolean dispatchTouchEvent(MotionEvent ev) {
Jeff Brown21bc5c92011-02-28 18:27:14 -08001834 if (mInputEventConsistencyVerifier != null) {
1835 mInputEventConsistencyVerifier.onTouchEvent(ev, 1);
1836 }
1837
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001838 boolean handled = false;
1839 if (onFilterTouchEventForSecurity(ev)) {
1840 final int action = ev.getAction();
1841 final int actionMasked = action & MotionEvent.ACTION_MASK;
Jeff Brown85a31762010-09-01 17:01:00 -07001842
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001843 // Handle an initial down.
1844 if (actionMasked == MotionEvent.ACTION_DOWN) {
1845 // Throw away all previous state when starting a new touch gesture.
1846 // The framework may have dropped the up or cancel event for the previous gesture
1847 // due to an app switch, ANR, or some other state change.
1848 cancelAndClearTouchTargets(ev);
1849 resetTouchState();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001850 }
Adam Powellb08013c2010-09-16 16:28:11 -07001851
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001852 // Check for interception.
1853 final boolean intercepted;
Jeff Brown20e987b2010-08-23 12:01:02 -07001854 if (actionMasked == MotionEvent.ACTION_DOWN
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001855 || mFirstTouchTarget != null) {
1856 final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
1857 if (!disallowIntercept) {
1858 intercepted = onInterceptTouchEvent(ev);
1859 ev.setAction(action); // restore action in case it was changed
1860 } else {
1861 intercepted = false;
1862 }
1863 } else {
1864 // There are no touch targets and this action is not an initial down
1865 // so this view group continues to intercept touches.
1866 intercepted = true;
1867 }
Jeff Brown20e987b2010-08-23 12:01:02 -07001868
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001869 // Check for cancelation.
1870 final boolean canceled = resetCancelNextUpFlag(this)
1871 || actionMasked == MotionEvent.ACTION_CANCEL;
Jeff Brown20e987b2010-08-23 12:01:02 -07001872
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001873 // Update list of touch targets for pointer down, if needed.
1874 final boolean split = (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) != 0;
1875 TouchTarget newTouchTarget = null;
1876 boolean alreadyDispatchedToNewTouchTarget = false;
1877 if (!canceled && !intercepted) {
1878 if (actionMasked == MotionEvent.ACTION_DOWN
1879 || (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN)
1880 || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
1881 final int actionIndex = ev.getActionIndex(); // always 0 for down
1882 final int idBitsToAssign = split ? 1 << ev.getPointerId(actionIndex)
1883 : TouchTarget.ALL_POINTER_IDS;
Jeff Brown20e987b2010-08-23 12:01:02 -07001884
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001885 // Clean up earlier touch targets for this pointer id in case they
1886 // have become out of sync.
1887 removePointersFromTouchTargets(idBitsToAssign);
1888
1889 final int childrenCount = mChildrenCount;
Chet Haase9c17fe62013-03-22 17:05:55 -07001890 if (newTouchTarget == null && childrenCount != 0) {
Chet Haaseedf6f4b2013-03-26 07:55:30 -07001891 final float x = ev.getX(actionIndex);
1892 final float y = ev.getY(actionIndex);
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001893 // Find a child that can receive the event.
1894 // Scan children from front to back.
1895 final View[] children = mChildren;
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001896
Adam Powella6478a32012-08-17 16:40:00 -07001897 final boolean customOrder = isChildrenDrawingOrderEnabled();
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001898 for (int i = childrenCount - 1; i >= 0; i--) {
Adam Powella6478a32012-08-17 16:40:00 -07001899 final int childIndex = customOrder ?
1900 getChildDrawingOrder(childrenCount, i) : i;
1901 final View child = children[childIndex];
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001902 if (!canViewReceivePointerEvents(child)
1903 || !isTransformedTouchPointInView(x, y, child, null)) {
1904 continue;
1905 }
1906
1907 newTouchTarget = getTouchTarget(child);
1908 if (newTouchTarget != null) {
1909 // Child is already receiving touch within its bounds.
1910 // Give it the new pointer in addition to the ones it is handling.
1911 newTouchTarget.pointerIdBits |= idBitsToAssign;
1912 break;
1913 }
1914
1915 resetCancelNextUpFlag(child);
1916 if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
1917 // Child wants to receive touch within its bounds.
1918 mLastTouchDownTime = ev.getDownTime();
Adam Powella6478a32012-08-17 16:40:00 -07001919 mLastTouchDownIndex = childIndex;
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001920 mLastTouchDownX = ev.getX();
1921 mLastTouchDownY = ev.getY();
1922 newTouchTarget = addTouchTarget(child, idBitsToAssign);
1923 alreadyDispatchedToNewTouchTarget = true;
1924 break;
1925 }
1926 }
1927 }
1928
1929 if (newTouchTarget == null && mFirstTouchTarget != null) {
1930 // Did not find a child to receive the event.
1931 // Assign the pointer to the least recently added target.
1932 newTouchTarget = mFirstTouchTarget;
1933 while (newTouchTarget.next != null) {
1934 newTouchTarget = newTouchTarget.next;
1935 }
1936 newTouchTarget.pointerIdBits |= idBitsToAssign;
1937 }
1938 }
1939 }
1940
1941 // Dispatch to touch targets.
1942 if (mFirstTouchTarget == null) {
1943 // No touch targets so treat this as an ordinary view.
1944 handled = dispatchTransformedTouchEvent(ev, canceled, null,
1945 TouchTarget.ALL_POINTER_IDS);
1946 } else {
1947 // Dispatch to touch targets, excluding the new touch target if we already
1948 // dispatched to it. Cancel touch targets if necessary.
1949 TouchTarget predecessor = null;
1950 TouchTarget target = mFirstTouchTarget;
1951 while (target != null) {
1952 final TouchTarget next = target.next;
1953 if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) {
1954 handled = true;
1955 } else {
1956 final boolean cancelChild = resetCancelNextUpFlag(target.child)
Chet Haase9c17fe62013-03-22 17:05:55 -07001957 || intercepted;
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001958 if (dispatchTransformedTouchEvent(ev, cancelChild,
1959 target.child, target.pointerIdBits)) {
1960 handled = true;
1961 }
1962 if (cancelChild) {
1963 if (predecessor == null) {
1964 mFirstTouchTarget = next;
1965 } else {
1966 predecessor.next = next;
1967 }
1968 target.recycle();
1969 target = next;
Jeff Brown20e987b2010-08-23 12:01:02 -07001970 continue;
1971 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001972 }
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001973 predecessor = target;
1974 target = next;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001975 }
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001976 }
Jeff Brown20e987b2010-08-23 12:01:02 -07001977
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001978 // Update list of touch targets for pointer up or cancel, if needed.
1979 if (canceled
1980 || actionMasked == MotionEvent.ACTION_UP
1981 || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
1982 resetTouchState();
1983 } else if (split && actionMasked == MotionEvent.ACTION_POINTER_UP) {
1984 final int actionIndex = ev.getActionIndex();
1985 final int idBitsToRemove = 1 << ev.getPointerId(actionIndex);
1986 removePointersFromTouchTargets(idBitsToRemove);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001987 }
1988 }
Romain Guy8506ab42009-06-11 17:35:47 -07001989
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001990 if (!handled && mInputEventConsistencyVerifier != null) {
1991 mInputEventConsistencyVerifier.onUnhandledEvent(ev, 1);
Jeff Brown20e987b2010-08-23 12:01:02 -07001992 }
Jeff Brown20e987b2010-08-23 12:01:02 -07001993 return handled;
1994 }
1995
Romain Guy469b1db2010-10-05 11:49:57 -07001996 /**
1997 * Resets all touch state in preparation for a new cycle.
1998 */
1999 private void resetTouchState() {
Jeff Brown20e987b2010-08-23 12:01:02 -07002000 clearTouchTargets();
2001 resetCancelNextUpFlag(this);
2002 mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
2003 }
2004
Romain Guy469b1db2010-10-05 11:49:57 -07002005 /**
2006 * Resets the cancel next up flag.
2007 * Returns true if the flag was previously set.
2008 */
Romain Guya998dff2012-03-23 18:58:36 -07002009 private static boolean resetCancelNextUpFlag(View view) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07002010 if ((view.mPrivateFlags & PFLAG_CANCEL_NEXT_UP_EVENT) != 0) {
2011 view.mPrivateFlags &= ~PFLAG_CANCEL_NEXT_UP_EVENT;
Jeff Brown20e987b2010-08-23 12:01:02 -07002012 return true;
Adam Cohen9b073942010-08-19 16:49:52 -07002013 }
2014 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002015 }
2016
Romain Guy469b1db2010-10-05 11:49:57 -07002017 /**
2018 * Clears all touch targets.
2019 */
2020 private void clearTouchTargets() {
Jeff Brown20e987b2010-08-23 12:01:02 -07002021 TouchTarget target = mFirstTouchTarget;
2022 if (target != null) {
2023 do {
2024 TouchTarget next = target.next;
2025 target.recycle();
2026 target = next;
2027 } while (target != null);
2028 mFirstTouchTarget = null;
2029 }
2030 }
2031
Romain Guy469b1db2010-10-05 11:49:57 -07002032 /**
2033 * Cancels and clears all touch targets.
2034 */
2035 private void cancelAndClearTouchTargets(MotionEvent event) {
Jeff Brown20e987b2010-08-23 12:01:02 -07002036 if (mFirstTouchTarget != null) {
2037 boolean syntheticEvent = false;
2038 if (event == null) {
2039 final long now = SystemClock.uptimeMillis();
2040 event = MotionEvent.obtain(now, now,
2041 MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
Jeff Brown2fdbc5a2011-06-30 12:25:54 -07002042 event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
Jeff Brown20e987b2010-08-23 12:01:02 -07002043 syntheticEvent = true;
2044 }
2045
2046 for (TouchTarget target = mFirstTouchTarget; target != null; target = target.next) {
2047 resetCancelNextUpFlag(target.child);
2048 dispatchTransformedTouchEvent(event, true, target.child, target.pointerIdBits);
2049 }
2050 clearTouchTargets();
2051
2052 if (syntheticEvent) {
2053 event.recycle();
2054 }
2055 }
2056 }
2057
Romain Guy469b1db2010-10-05 11:49:57 -07002058 /**
2059 * Gets the touch target for specified child view.
2060 * Returns null if not found.
2061 */
2062 private TouchTarget getTouchTarget(View child) {
Jeff Brown20e987b2010-08-23 12:01:02 -07002063 for (TouchTarget target = mFirstTouchTarget; target != null; target = target.next) {
2064 if (target.child == child) {
2065 return target;
2066 }
2067 }
2068 return null;
2069 }
2070
Romain Guy469b1db2010-10-05 11:49:57 -07002071 /**
2072 * Adds a touch target for specified child to the beginning of the list.
2073 * Assumes the target child is not already present.
2074 */
2075 private TouchTarget addTouchTarget(View child, int pointerIdBits) {
Jeff Brown20e987b2010-08-23 12:01:02 -07002076 TouchTarget target = TouchTarget.obtain(child, pointerIdBits);
2077 target.next = mFirstTouchTarget;
2078 mFirstTouchTarget = target;
2079 return target;
2080 }
2081
Romain Guy469b1db2010-10-05 11:49:57 -07002082 /**
2083 * Removes the pointer ids from consideration.
2084 */
2085 private void removePointersFromTouchTargets(int pointerIdBits) {
Jeff Brown20e987b2010-08-23 12:01:02 -07002086 TouchTarget predecessor = null;
2087 TouchTarget target = mFirstTouchTarget;
2088 while (target != null) {
2089 final TouchTarget next = target.next;
2090 if ((target.pointerIdBits & pointerIdBits) != 0) {
2091 target.pointerIdBits &= ~pointerIdBits;
2092 if (target.pointerIdBits == 0) {
2093 if (predecessor == null) {
2094 mFirstTouchTarget = next;
2095 } else {
2096 predecessor.next = next;
2097 }
2098 target.recycle();
2099 target = next;
2100 continue;
2101 }
2102 }
2103 predecessor = target;
2104 target = next;
2105 }
2106 }
2107
Jeff Brown59a422e2012-04-19 15:19:19 -07002108 private void cancelTouchTarget(View view) {
2109 TouchTarget predecessor = null;
2110 TouchTarget target = mFirstTouchTarget;
2111 while (target != null) {
2112 final TouchTarget next = target.next;
2113 if (target.child == view) {
2114 if (predecessor == null) {
2115 mFirstTouchTarget = next;
2116 } else {
2117 predecessor.next = next;
2118 }
2119 target.recycle();
2120
2121 final long now = SystemClock.uptimeMillis();
2122 MotionEvent event = MotionEvent.obtain(now, now,
2123 MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
2124 event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
2125 view.dispatchTouchEvent(event);
2126 event.recycle();
2127 return;
2128 }
2129 predecessor = target;
2130 target = next;
2131 }
2132 }
2133
Romain Guy469b1db2010-10-05 11:49:57 -07002134 /**
Jeff Browna032cc02011-03-07 16:56:21 -08002135 * Returns true if a child view can receive pointer events.
2136 * @hide
2137 */
2138 private static boolean canViewReceivePointerEvents(View child) {
2139 return (child.mViewFlags & VISIBILITY_MASK) == VISIBLE
2140 || child.getAnimation() != null;
2141 }
2142
2143 /**
Romain Guy469b1db2010-10-05 11:49:57 -07002144 * Returns true if a child view contains the specified point when transformed
Jeff Brown20e987b2010-08-23 12:01:02 -07002145 * into its coordinate space.
Romain Guy469b1db2010-10-05 11:49:57 -07002146 * Child must not be null.
Adam Cohena32edd42010-10-26 10:35:01 -07002147 * @hide
Romain Guy469b1db2010-10-05 11:49:57 -07002148 */
Adam Cohena32edd42010-10-26 10:35:01 -07002149 protected boolean isTransformedTouchPointInView(float x, float y, View child,
Christopher Tate2c095f32010-10-04 14:13:40 -07002150 PointF outLocalPoint) {
Jeff Brown20e987b2010-08-23 12:01:02 -07002151 float localX = x + mScrollX - child.mLeft;
2152 float localY = y + mScrollY - child.mTop;
2153 if (! child.hasIdentityMatrix() && mAttachInfo != null) {
Adam Powell2b342f02010-08-18 18:14:13 -07002154 final float[] localXY = mAttachInfo.mTmpTransformLocation;
2155 localXY[0] = localX;
2156 localXY[1] = localY;
2157 child.getInverseMatrix().mapPoints(localXY);
2158 localX = localXY[0];
2159 localY = localXY[1];
2160 }
Christopher Tate2c095f32010-10-04 14:13:40 -07002161 final boolean isInView = child.pointInView(localX, localY);
2162 if (isInView && outLocalPoint != null) {
2163 outLocalPoint.set(localX, localY);
2164 }
2165 return isInView;
Adam Powell2b342f02010-08-18 18:14:13 -07002166 }
2167
Romain Guy469b1db2010-10-05 11:49:57 -07002168 /**
2169 * Transforms a motion event into the coordinate space of a particular child view,
Jeff Brown20e987b2010-08-23 12:01:02 -07002170 * filters out irrelevant pointer ids, and overrides its action if necessary.
Romain Guy469b1db2010-10-05 11:49:57 -07002171 * If child is null, assumes the MotionEvent will be sent to this ViewGroup instead.
2172 */
2173 private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,
Jeff Brown20e987b2010-08-23 12:01:02 -07002174 View child, int desiredPointerIdBits) {
2175 final boolean handled;
Adam Powell2b342f02010-08-18 18:14:13 -07002176
Jeff Brown20e987b2010-08-23 12:01:02 -07002177 // Canceling motions is a special case. We don't need to perform any transformations
2178 // or filtering. The important part is the action, not the contents.
2179 final int oldAction = event.getAction();
2180 if (cancel || oldAction == MotionEvent.ACTION_CANCEL) {
2181 event.setAction(MotionEvent.ACTION_CANCEL);
2182 if (child == null) {
2183 handled = super.dispatchTouchEvent(event);
2184 } else {
2185 handled = child.dispatchTouchEvent(event);
2186 }
2187 event.setAction(oldAction);
2188 return handled;
2189 }
Adam Powell2b342f02010-08-18 18:14:13 -07002190
Jeff Brown20e987b2010-08-23 12:01:02 -07002191 // Calculate the number of pointers to deliver.
Jeff Brownfe9f8ab2011-05-06 18:20:01 -07002192 final int oldPointerIdBits = event.getPointerIdBits();
2193 final int newPointerIdBits = oldPointerIdBits & desiredPointerIdBits;
Adam Powell2b342f02010-08-18 18:14:13 -07002194
Jeff Brown20e987b2010-08-23 12:01:02 -07002195 // If for some reason we ended up in an inconsistent state where it looks like we
2196 // might produce a motion event with no pointers in it, then drop the event.
Jeff Brownfe9f8ab2011-05-06 18:20:01 -07002197 if (newPointerIdBits == 0) {
Jeff Brown20e987b2010-08-23 12:01:02 -07002198 return false;
2199 }
Adam Powell2b342f02010-08-18 18:14:13 -07002200
Jeff Brown20e987b2010-08-23 12:01:02 -07002201 // If the number of pointers is the same and we don't need to perform any fancy
2202 // irreversible transformations, then we can reuse the motion event for this
2203 // dispatch as long as we are careful to revert any changes we make.
Jeff Brownfe9f8ab2011-05-06 18:20:01 -07002204 // Otherwise we need to make a copy.
2205 final MotionEvent transformedEvent;
2206 if (newPointerIdBits == oldPointerIdBits) {
2207 if (child == null || child.hasIdentityMatrix()) {
2208 if (child == null) {
2209 handled = super.dispatchTouchEvent(event);
2210 } else {
2211 final float offsetX = mScrollX - child.mLeft;
2212 final float offsetY = mScrollY - child.mTop;
2213 event.offsetLocation(offsetX, offsetY);
Adam Powell2b342f02010-08-18 18:14:13 -07002214
Jeff Brownfe9f8ab2011-05-06 18:20:01 -07002215 handled = child.dispatchTouchEvent(event);
Jeff Brown20e987b2010-08-23 12:01:02 -07002216
Jeff Brownfe9f8ab2011-05-06 18:20:01 -07002217 event.offsetLocation(-offsetX, -offsetY);
2218 }
2219 return handled;
Jeff Brown20e987b2010-08-23 12:01:02 -07002220 }
Jeff Brown20e987b2010-08-23 12:01:02 -07002221 transformedEvent = MotionEvent.obtain(event);
2222 } else {
Jeff Brownfe9f8ab2011-05-06 18:20:01 -07002223 transformedEvent = event.split(newPointerIdBits);
Adam Powell2b342f02010-08-18 18:14:13 -07002224 }
2225
Jeff Brown20e987b2010-08-23 12:01:02 -07002226 // Perform any necessary transformations and dispatch.
2227 if (child == null) {
2228 handled = super.dispatchTouchEvent(transformedEvent);
2229 } else {
2230 final float offsetX = mScrollX - child.mLeft;
2231 final float offsetY = mScrollY - child.mTop;
2232 transformedEvent.offsetLocation(offsetX, offsetY);
2233 if (! child.hasIdentityMatrix()) {
2234 transformedEvent.transform(child.getInverseMatrix());
Adam Powell2b342f02010-08-18 18:14:13 -07002235 }
2236
Jeff Brown20e987b2010-08-23 12:01:02 -07002237 handled = child.dispatchTouchEvent(transformedEvent);
Adam Powell2b342f02010-08-18 18:14:13 -07002238 }
2239
Jeff Brown20e987b2010-08-23 12:01:02 -07002240 // Done.
2241 transformedEvent.recycle();
Adam Powell2b342f02010-08-18 18:14:13 -07002242 return handled;
2243 }
2244
Romain Guy469b1db2010-10-05 11:49:57 -07002245 /**
Adam Powell2b342f02010-08-18 18:14:13 -07002246 * Enable or disable the splitting of MotionEvents to multiple children during touch event
Jeff Brown995e7742010-12-22 16:59:36 -08002247 * dispatch. This behavior is enabled by default for applications that target an
2248 * SDK version of {@link Build.VERSION_CODES#HONEYCOMB} or newer.
Adam Powell2b342f02010-08-18 18:14:13 -07002249 *
2250 * <p>When this option is enabled MotionEvents may be split and dispatched to different child
2251 * views depending on where each pointer initially went down. This allows for user interactions
2252 * such as scrolling two panes of content independently, chording of buttons, and performing
2253 * independent gestures on different pieces of content.
2254 *
2255 * @param split <code>true</code> to allow MotionEvents to be split and dispatched to multiple
2256 * child views. <code>false</code> to only allow one child view to be the target of
2257 * any MotionEvent received by this ViewGroup.
Scott Main27a85082013-06-10 10:39:48 -07002258 * @attr ref android.R.styleable#ViewGroup_splitMotionEvents
Adam Powell2b342f02010-08-18 18:14:13 -07002259 */
2260 public void setMotionEventSplittingEnabled(boolean split) {
2261 // TODO Applications really shouldn't change this setting mid-touch event,
2262 // but perhaps this should handle that case and send ACTION_CANCELs to any child views
2263 // with gestures in progress when this is changed.
2264 if (split) {
Adam Powell2b342f02010-08-18 18:14:13 -07002265 mGroupFlags |= FLAG_SPLIT_MOTION_EVENTS;
2266 } else {
2267 mGroupFlags &= ~FLAG_SPLIT_MOTION_EVENTS;
Adam Powell2b342f02010-08-18 18:14:13 -07002268 }
2269 }
2270
2271 /**
Jeff Brown995e7742010-12-22 16:59:36 -08002272 * Returns true if MotionEvents dispatched to this ViewGroup can be split to multiple children.
Adam Powell2b342f02010-08-18 18:14:13 -07002273 * @return true if MotionEvents dispatched to this ViewGroup can be split to multiple children.
2274 */
2275 public boolean isMotionEventSplittingEnabled() {
2276 return (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) == FLAG_SPLIT_MOTION_EVENTS;
2277 }
2278
2279 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002280 * {@inheritDoc}
2281 */
2282 public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
Romain Guy8506ab42009-06-11 17:35:47 -07002283
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002284 if (disallowIntercept == ((mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0)) {
2285 // We're already in this state, assume our ancestors are too
2286 return;
2287 }
Romain Guy8506ab42009-06-11 17:35:47 -07002288
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002289 if (disallowIntercept) {
2290 mGroupFlags |= FLAG_DISALLOW_INTERCEPT;
2291 } else {
2292 mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
2293 }
Romain Guy8506ab42009-06-11 17:35:47 -07002294
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002295 // Pass it up to our parent
2296 if (mParent != null) {
2297 mParent.requestDisallowInterceptTouchEvent(disallowIntercept);
2298 }
2299 }
2300
2301 /**
2302 * Implement this method to intercept all touch screen motion events. This
2303 * allows you to watch events as they are dispatched to your children, and
2304 * take ownership of the current gesture at any point.
2305 *
2306 * <p>Using this function takes some care, as it has a fairly complicated
2307 * interaction with {@link View#onTouchEvent(MotionEvent)
2308 * View.onTouchEvent(MotionEvent)}, and using it requires implementing
2309 * that method as well as this one in the correct way. Events will be
2310 * received in the following order:
2311 *
2312 * <ol>
2313 * <li> You will receive the down event here.
2314 * <li> The down event will be handled either by a child of this view
2315 * group, or given to your own onTouchEvent() method to handle; this means
2316 * you should implement onTouchEvent() to return true, so you will
2317 * continue to see the rest of the gesture (instead of looking for
2318 * a parent view to handle it). Also, by returning true from
2319 * onTouchEvent(), you will not receive any following
2320 * events in onInterceptTouchEvent() and all touch processing must
2321 * happen in onTouchEvent() like normal.
2322 * <li> For as long as you return false from this function, each following
2323 * event (up to and including the final up) will be delivered first here
2324 * and then to the target's onTouchEvent().
2325 * <li> If you return true from here, you will not receive any
2326 * following events: the target view will receive the same event but
2327 * with the action {@link MotionEvent#ACTION_CANCEL}, and all further
2328 * events will be delivered to your onTouchEvent() method and no longer
2329 * appear here.
2330 * </ol>
2331 *
2332 * @param ev The motion event being dispatched down the hierarchy.
2333 * @return Return true to steal motion events from the children and have
2334 * them dispatched to this ViewGroup through onTouchEvent().
2335 * The current target will receive an ACTION_CANCEL event, and no further
2336 * messages will be delivered here.
2337 */
2338 public boolean onInterceptTouchEvent(MotionEvent ev) {
2339 return false;
2340 }
2341
2342 /**
2343 * {@inheritDoc}
2344 *
2345 * Looks for a view to give focus to respecting the setting specified by
2346 * {@link #getDescendantFocusability()}.
2347 *
2348 * Uses {@link #onRequestFocusInDescendants(int, android.graphics.Rect)} to
2349 * find focus within the children of this group when appropriate.
2350 *
2351 * @see #FOCUS_BEFORE_DESCENDANTS
2352 * @see #FOCUS_AFTER_DESCENDANTS
2353 * @see #FOCUS_BLOCK_DESCENDANTS
Romain Guy02739a82011-05-16 11:43:18 -07002354 * @see #onRequestFocusInDescendants(int, android.graphics.Rect)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002355 */
2356 @Override
2357 public boolean requestFocus(int direction, Rect previouslyFocusedRect) {
2358 if (DBG) {
2359 System.out.println(this + " ViewGroup.requestFocus direction="
2360 + direction);
2361 }
2362 int descendantFocusability = getDescendantFocusability();
2363
2364 switch (descendantFocusability) {
2365 case FOCUS_BLOCK_DESCENDANTS:
2366 return super.requestFocus(direction, previouslyFocusedRect);
2367 case FOCUS_BEFORE_DESCENDANTS: {
2368 final boolean took = super.requestFocus(direction, previouslyFocusedRect);
2369 return took ? took : onRequestFocusInDescendants(direction, previouslyFocusedRect);
2370 }
2371 case FOCUS_AFTER_DESCENDANTS: {
2372 final boolean took = onRequestFocusInDescendants(direction, previouslyFocusedRect);
2373 return took ? took : super.requestFocus(direction, previouslyFocusedRect);
2374 }
2375 default:
2376 throw new IllegalStateException("descendant focusability must be "
2377 + "one of FOCUS_BEFORE_DESCENDANTS, FOCUS_AFTER_DESCENDANTS, FOCUS_BLOCK_DESCENDANTS "
2378 + "but is " + descendantFocusability);
2379 }
2380 }
2381
2382 /**
2383 * Look for a descendant to call {@link View#requestFocus} on.
2384 * Called by {@link ViewGroup#requestFocus(int, android.graphics.Rect)}
2385 * when it wants to request focus within its children. Override this to
2386 * customize how your {@link ViewGroup} requests focus within its children.
2387 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT
2388 * @param previouslyFocusedRect The rectangle (in this View's coordinate system)
2389 * to give a finer grained hint about where focus is coming from. May be null
2390 * if there is no hint.
2391 * @return Whether focus was taken.
2392 */
2393 @SuppressWarnings({"ConstantConditions"})
2394 protected boolean onRequestFocusInDescendants(int direction,
2395 Rect previouslyFocusedRect) {
2396 int index;
2397 int increment;
2398 int end;
2399 int count = mChildrenCount;
2400 if ((direction & FOCUS_FORWARD) != 0) {
2401 index = 0;
2402 increment = 1;
2403 end = count;
2404 } else {
2405 index = count - 1;
2406 increment = -1;
2407 end = -1;
2408 }
2409 final View[] children = mChildren;
2410 for (int i = index; i != end; i += increment) {
2411 View child = children[i];
2412 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
2413 if (child.requestFocus(direction, previouslyFocusedRect)) {
2414 return true;
2415 }
2416 }
2417 }
2418 return false;
2419 }
Chet Haase5c13d892010-10-08 08:37:55 -07002420
Romain Guya440b002010-02-24 15:57:54 -08002421 /**
2422 * {@inheritDoc}
Chet Haase5c13d892010-10-08 08:37:55 -07002423 *
Romain Guydcc490f2010-02-24 17:59:35 -08002424 * @hide
Romain Guya440b002010-02-24 15:57:54 -08002425 */
2426 @Override
2427 public void dispatchStartTemporaryDetach() {
2428 super.dispatchStartTemporaryDetach();
2429 final int count = mChildrenCount;
2430 final View[] children = mChildren;
2431 for (int i = 0; i < count; i++) {
2432 children[i].dispatchStartTemporaryDetach();
2433 }
2434 }
Chet Haase5c13d892010-10-08 08:37:55 -07002435
Romain Guya440b002010-02-24 15:57:54 -08002436 /**
2437 * {@inheritDoc}
Chet Haase5c13d892010-10-08 08:37:55 -07002438 *
Romain Guydcc490f2010-02-24 17:59:35 -08002439 * @hide
Romain Guya440b002010-02-24 15:57:54 -08002440 */
2441 @Override
2442 public void dispatchFinishTemporaryDetach() {
2443 super.dispatchFinishTemporaryDetach();
2444 final int count = mChildrenCount;
2445 final View[] children = mChildren;
2446 for (int i = 0; i < count; i++) {
2447 children[i].dispatchFinishTemporaryDetach();
2448 }
2449 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002450
2451 /**
2452 * {@inheritDoc}
2453 */
2454 @Override
2455 void dispatchAttachedToWindow(AttachInfo info, int visibility) {
Adam Powell4b867882011-09-16 12:59:46 -07002456 mGroupFlags |= FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002457 super.dispatchAttachedToWindow(info, visibility);
Adam Powell4b867882011-09-16 12:59:46 -07002458 mGroupFlags &= ~FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW;
2459
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002460 final int count = mChildrenCount;
2461 final View[] children = mChildren;
2462 for (int i = 0; i < count; i++) {
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07002463 final View child = children[i];
2464 child.dispatchAttachedToWindow(info,
Philip Milne7b757812012-09-19 18:13:44 -07002465 visibility | (child.mViewFlags & VISIBILITY_MASK));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002466 }
2467 }
2468
svetoslavganov75986cf2009-05-14 22:28:01 -07002469 @Override
Romain Guybb9908b2012-03-08 11:14:07 -08002470 void dispatchScreenStateChanged(int screenState) {
2471 super.dispatchScreenStateChanged(screenState);
2472
2473 final int count = mChildrenCount;
2474 final View[] children = mChildren;
2475 for (int i = 0; i < count; i++) {
2476 children[i].dispatchScreenStateChanged(screenState);
2477 }
2478 }
2479
2480 @Override
Svetoslav Ganov031d9c12011-09-09 16:41:13 -07002481 boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07002482 boolean handled = false;
2483 if (includeForAccessibility()) {
2484 handled = super.dispatchPopulateAccessibilityEventInternal(event);
2485 if (handled) {
2486 return handled;
2487 }
Svetoslav Ganovb84b94e2011-09-22 19:26:56 -07002488 }
Svetoslav Ganov736c2752011-04-22 18:30:36 -07002489 // Let our children have a shot in populating the event.
Svetoslav Ganov42138042012-03-20 11:51:39 -07002490 ChildListForAccessibility children = ChildListForAccessibility.obtain(this, true);
Svetoslav Ganov76f287e2012-04-23 11:02:36 -07002491 try {
2492 final int childCount = children.getChildCount();
2493 for (int i = 0; i < childCount; i++) {
2494 View child = children.getChildAt(i);
2495 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
2496 handled = child.dispatchPopulateAccessibilityEvent(event);
2497 if (handled) {
Svetoslav Ganov76f287e2012-04-23 11:02:36 -07002498 return handled;
2499 }
Svetoslav Ganov6179ea32011-06-28 01:12:41 -07002500 }
Svetoslav Ganov736c2752011-04-22 18:30:36 -07002501 }
Svetoslav Ganov76f287e2012-04-23 11:02:36 -07002502 } finally {
2503 children.recycle();
svetoslavganov75986cf2009-05-14 22:28:01 -07002504 }
Svetoslav Ganov736c2752011-04-22 18:30:36 -07002505 return false;
svetoslavganov75986cf2009-05-14 22:28:01 -07002506 }
2507
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002508 @Override
Svetoslav Ganov031d9c12011-09-09 16:41:13 -07002509 void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
2510 super.onInitializeAccessibilityNodeInfoInternal(info);
Svetoslav Ganov42138042012-03-20 11:51:39 -07002511 if (mAttachInfo != null) {
2512 ArrayList<View> childrenForAccessibility = mAttachInfo.mTempArrayList;
2513 childrenForAccessibility.clear();
2514 addChildrenForAccessibility(childrenForAccessibility);
2515 final int childrenForAccessibilityCount = childrenForAccessibility.size();
2516 for (int i = 0; i < childrenForAccessibilityCount; i++) {
2517 View child = childrenForAccessibility.get(i);
Svetoslav Ganovea1da3d2011-06-15 17:16:02 -07002518 info.addChild(child);
2519 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07002520 childrenForAccessibility.clear();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002521 }
2522 }
2523
Svetoslav Ganov8a78fd42012-01-17 14:36:46 -08002524 @Override
2525 void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
2526 super.onInitializeAccessibilityEventInternal(event);
2527 event.setClassName(ViewGroup.class.getName());
2528 }
2529
Svetoslav Ganov42138042012-03-20 11:51:39 -07002530 @Override
Alan Viverette77e9a282013-09-12 17:16:09 -07002531 public void notifySubtreeAccessibilityStateChanged(View child, View source, int changeType) {
2532 // If this is a live region, we should send a subtree change event
2533 // from this view. Otherwise, we can let it propagate up.
2534 if (getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE) {
2535 notifyViewAccessibilityStateChangedIfNeeded(changeType);
2536 } else if (mParent != null) {
Adam Powell504a10f2013-07-11 15:25:59 -07002537 try {
Alan Viverette77e9a282013-09-12 17:16:09 -07002538 mParent.notifySubtreeAccessibilityStateChanged(this, source, changeType);
Adam Powell504a10f2013-07-11 15:25:59 -07002539 } catch (AbstractMethodError e) {
2540 Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() +
2541 " does not fully implement ViewParent", e);
2542 }
Svetoslav6254f482013-06-04 17:22:14 -07002543 }
2544 }
2545
2546 @Override
2547 void resetSubtreeAccessibilityStateChanged() {
2548 super.resetSubtreeAccessibilityStateChanged();
Svetoslav Ganov42138042012-03-20 11:51:39 -07002549 View[] children = mChildren;
2550 final int childCount = mChildrenCount;
2551 for (int i = 0; i < childCount; i++) {
Svetoslav6254f482013-06-04 17:22:14 -07002552 children[i].resetSubtreeAccessibilityStateChanged();
Svetoslav Ganov42138042012-03-20 11:51:39 -07002553 }
2554 }
2555
2556 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002557 * {@inheritDoc}
2558 */
2559 @Override
2560 void dispatchDetachedFromWindow() {
Jeff Brown20e987b2010-08-23 12:01:02 -07002561 // If we still have a touch target, we are still in the process of
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002562 // dispatching motion events to a child; we need to get rid of that
2563 // child to avoid dispatching events to it after the window is torn
2564 // down. To make sure we keep the child in a consistent state, we
2565 // first send it an ACTION_CANCEL motion event.
Jeff Brown20e987b2010-08-23 12:01:02 -07002566 cancelAndClearTouchTargets(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002567
Jeff Brown59a422e2012-04-19 15:19:19 -07002568 // Similarly, set ACTION_EXIT to all hover targets and clear them.
2569 exitHoverTargets();
2570
Chet Haase9c087442011-01-12 16:20:16 -08002571 // In case view is detached while transition is running
Chet Haaseb9895022013-04-02 15:10:58 -07002572 mLayoutCalledWhileSuppressed = false;
Chet Haase9c087442011-01-12 16:20:16 -08002573
Christopher Tate86cab1b2011-01-13 20:28:55 -08002574 // Tear down our drag tracking
2575 mDragNotifiedChildren = null;
2576 if (mCurrentDrag != null) {
2577 mCurrentDrag.recycle();
2578 mCurrentDrag = null;
2579 }
2580
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002581 final int count = mChildrenCount;
2582 final View[] children = mChildren;
2583 for (int i = 0; i < count; i++) {
2584 children[i].dispatchDetachedFromWindow();
2585 }
2586 super.dispatchDetachedFromWindow();
2587 }
2588
Fabrice Di Meglio23c89fd2012-08-13 12:17:42 -07002589 /**
2590 * @hide
2591 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002592 @Override
Fabrice Di Meglio23c89fd2012-08-13 12:17:42 -07002593 protected void internalSetPadding(int left, int top, int right, int bottom) {
Romain Guy2440e672012-08-07 14:43:43 -07002594 super.internalSetPadding(left, top, right, bottom);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002595
Romain Guy13f35f32011-03-24 12:03:17 -07002596 if ((mPaddingLeft | mPaddingTop | mPaddingRight | mPaddingBottom) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002597 mGroupFlags |= FLAG_PADDING_NOT_NULL;
2598 } else {
2599 mGroupFlags &= ~FLAG_PADDING_NOT_NULL;
2600 }
2601 }
2602
2603 /**
2604 * {@inheritDoc}
2605 */
2606 @Override
2607 protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {
2608 super.dispatchSaveInstanceState(container);
2609 final int count = mChildrenCount;
2610 final View[] children = mChildren;
2611 for (int i = 0; i < count; i++) {
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07002612 View c = children[i];
2613 if ((c.mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED) {
2614 c.dispatchSaveInstanceState(container);
2615 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002616 }
2617 }
2618
2619 /**
Romain Guy9fc27812011-04-27 14:21:41 -07002620 * Perform dispatching of a {@link #saveHierarchyState(android.util.SparseArray)} freeze()}
2621 * to only this view, not to its children. For use when overriding
2622 * {@link #dispatchSaveInstanceState(android.util.SparseArray)} dispatchFreeze()} to allow
2623 * subclasses to freeze their own state but not the state of their children.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002624 *
2625 * @param container the container
2626 */
2627 protected void dispatchFreezeSelfOnly(SparseArray<Parcelable> container) {
2628 super.dispatchSaveInstanceState(container);
2629 }
2630
2631 /**
2632 * {@inheritDoc}
2633 */
2634 @Override
2635 protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {
2636 super.dispatchRestoreInstanceState(container);
2637 final int count = mChildrenCount;
2638 final View[] children = mChildren;
2639 for (int i = 0; i < count; i++) {
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07002640 View c = children[i];
2641 if ((c.mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED) {
2642 c.dispatchRestoreInstanceState(container);
2643 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002644 }
2645 }
2646
2647 /**
Romain Guy02739a82011-05-16 11:43:18 -07002648 * Perform dispatching of a {@link #restoreHierarchyState(android.util.SparseArray)}
2649 * to only this view, not to its children. For use when overriding
2650 * {@link #dispatchRestoreInstanceState(android.util.SparseArray)} to allow
2651 * subclasses to thaw their own state but not the state of their children.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002652 *
2653 * @param container the container
2654 */
2655 protected void dispatchThawSelfOnly(SparseArray<Parcelable> container) {
2656 super.dispatchRestoreInstanceState(container);
2657 }
2658
2659 /**
2660 * Enables or disables the drawing cache for each child of this view group.
2661 *
2662 * @param enabled true to enable the cache, false to dispose of it
2663 */
2664 protected void setChildrenDrawingCacheEnabled(boolean enabled) {
2665 if (enabled || (mPersistentDrawingCache & PERSISTENT_ALL_CACHES) != PERSISTENT_ALL_CACHES) {
2666 final View[] children = mChildren;
2667 final int count = mChildrenCount;
2668 for (int i = 0; i < count; i++) {
2669 children[i].setDrawingCacheEnabled(enabled);
2670 }
2671 }
2672 }
2673
2674 @Override
2675 protected void onAnimationStart() {
2676 super.onAnimationStart();
2677
2678 // When this ViewGroup's animation starts, build the cache for the children
2679 if ((mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE) {
2680 final int count = mChildrenCount;
2681 final View[] children = mChildren;
Romain Guy0d9275e2010-10-26 14:22:30 -07002682 final boolean buildCache = !isHardwareAccelerated();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002683
2684 for (int i = 0; i < count; i++) {
2685 final View child = children[i];
2686 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
2687 child.setDrawingCacheEnabled(true);
Romain Guy0d9275e2010-10-26 14:22:30 -07002688 if (buildCache) {
2689 child.buildDrawingCache(true);
2690 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002691 }
2692 }
2693
2694 mGroupFlags |= FLAG_CHILDREN_DRAWN_WITH_CACHE;
2695 }
2696 }
2697
2698 @Override
2699 protected void onAnimationEnd() {
2700 super.onAnimationEnd();
2701
2702 // When this ViewGroup's animation ends, destroy the cache of the children
2703 if ((mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE) {
2704 mGroupFlags &= ~FLAG_CHILDREN_DRAWN_WITH_CACHE;
2705
2706 if ((mPersistentDrawingCache & PERSISTENT_ANIMATION_CACHE) == 0) {
2707 setChildrenDrawingCacheEnabled(false);
2708 }
2709 }
2710 }
2711
Romain Guy223ff5c2010-03-02 17:07:47 -08002712 @Override
2713 Bitmap createSnapshot(Bitmap.Config quality, int backgroundColor, boolean skipChildren) {
Romain Guy65554f22010-03-22 18:58:21 -07002714 int count = mChildrenCount;
2715 int[] visibilities = null;
2716
Romain Guy223ff5c2010-03-02 17:07:47 -08002717 if (skipChildren) {
Romain Guy65554f22010-03-22 18:58:21 -07002718 visibilities = new int[count];
2719 for (int i = 0; i < count; i++) {
2720 View child = getChildAt(i);
2721 visibilities[i] = child.getVisibility();
2722 if (visibilities[i] == View.VISIBLE) {
2723 child.setVisibility(INVISIBLE);
2724 }
2725 }
Romain Guy223ff5c2010-03-02 17:07:47 -08002726 }
2727
2728 Bitmap b = super.createSnapshot(quality, backgroundColor, skipChildren);
Romain Guy65554f22010-03-22 18:58:21 -07002729
2730 if (skipChildren) {
2731 for (int i = 0; i < count; i++) {
2732 getChildAt(i).setVisibility(visibilities[i]);
Chet Haase5c13d892010-10-08 08:37:55 -07002733 }
Romain Guy65554f22010-03-22 18:58:21 -07002734 }
Romain Guy223ff5c2010-03-02 17:07:47 -08002735
2736 return b;
2737 }
2738
Philip Milne7b757812012-09-19 18:13:44 -07002739 /** Return true if this ViewGroup is laying out using optical bounds. */
2740 boolean isLayoutModeOptical() {
2741 return mLayoutMode == LAYOUT_MODE_OPTICAL_BOUNDS;
2742 }
Romain Guycbc67742012-04-27 16:12:57 -07002743
Philip Milne7b757812012-09-19 18:13:44 -07002744 Insets computeOpticalInsets() {
2745 if (isLayoutModeOptical()) {
2746 int left = 0;
2747 int top = 0;
2748 int right = 0;
2749 int bottom = 0;
2750 for (int i = 0; i < mChildrenCount; i++) {
2751 View child = getChildAt(i);
2752 if (child.getVisibility() == VISIBLE) {
2753 Insets insets = child.getOpticalInsets();
2754 left = Math.max(left, insets.left);
2755 top = Math.max(top, insets.top);
2756 right = Math.max(right, insets.right);
2757 bottom = Math.max(bottom, insets.bottom);
2758 }
2759 }
2760 return Insets.of(left, top, right, bottom);
2761 } else {
2762 return Insets.NONE;
2763 }
2764 }
2765
2766 private static void fillRect(Canvas canvas, Paint paint, int x1, int y1, int x2, int y2) {
2767 if (x1 != x2 && y1 != y2) {
2768 if (x1 > x2) {
2769 int tmp = x1; x1 = x2; x2 = tmp;
2770 }
2771 if (y1 > y2) {
2772 int tmp = y1; y1 = y2; y2 = tmp;
2773 }
2774 canvas.drawRect(x1, y1, x2, y2, paint);
2775 }
2776 }
2777
2778 private static int sign(int x) {
2779 return (x >= 0) ? 1 : -1;
2780 }
2781
2782 private static void drawCorner(Canvas c, Paint paint, int x1, int y1, int dx, int dy, int lw) {
2783 fillRect(c, paint, x1, y1, x1 + dx, y1 + lw * sign(dy));
2784 fillRect(c, paint, x1, y1, x1 + lw * sign(dx), y1 + dy);
2785 }
2786
2787 private int dipsToPixels(int dips) {
2788 float scale = getContext().getResources().getDisplayMetrics().density;
2789 return (int) (dips * scale + 0.5f);
2790 }
2791
Romain Guy6410c0a2013-06-17 11:21:58 -07002792 private static void drawRectCorners(Canvas canvas, int x1, int y1, int x2, int y2, Paint paint,
2793 int lineLength, int lineWidth) {
Philip Milne7b757812012-09-19 18:13:44 -07002794 drawCorner(canvas, paint, x1, y1, lineLength, lineLength, lineWidth);
2795 drawCorner(canvas, paint, x1, y2, lineLength, -lineLength, lineWidth);
2796 drawCorner(canvas, paint, x2, y1, -lineLength, lineLength, lineWidth);
2797 drawCorner(canvas, paint, x2, y2, -lineLength, -lineLength, lineWidth);
2798 }
2799
2800 private static void fillDifference(Canvas canvas,
2801 int x2, int y2, int x3, int y3,
2802 int dx1, int dy1, int dx2, int dy2, Paint paint) {
2803 int x1 = x2 - dx1;
2804 int y1 = y2 - dy1;
2805
2806 int x4 = x3 + dx2;
2807 int y4 = y3 + dy2;
2808
2809 fillRect(canvas, paint, x1, y1, x4, y2);
2810 fillRect(canvas, paint, x1, y2, x2, y3);
2811 fillRect(canvas, paint, x3, y2, x4, y3);
2812 fillRect(canvas, paint, x1, y3, x4, y4);
Philip Milne10ca24a2012-04-23 15:38:27 -07002813 }
2814
2815 /**
2816 * @hide
2817 */
Philip Milne7b757812012-09-19 18:13:44 -07002818 protected void onDebugDrawMargins(Canvas canvas, Paint paint) {
Philip Milne10ca24a2012-04-23 15:38:27 -07002819 for (int i = 0; i < getChildCount(); i++) {
2820 View c = getChildAt(i);
Philip Milne7b757812012-09-19 18:13:44 -07002821 c.getLayoutParams().onDebugDraw(c, canvas, paint);
Philip Milne10ca24a2012-04-23 15:38:27 -07002822 }
2823 }
2824
2825 /**
2826 * @hide
2827 */
2828 protected void onDebugDraw(Canvas canvas) {
Philip Milne7b757812012-09-19 18:13:44 -07002829 Paint paint = getDebugPaint();
2830
Philip Milne10ca24a2012-04-23 15:38:27 -07002831 // Draw optical bounds
Philip Milne7b757812012-09-19 18:13:44 -07002832 {
2833 paint.setColor(Color.RED);
2834 paint.setStyle(Paint.Style.STROKE);
Philip Milne7b757812012-09-19 18:13:44 -07002835
Philip Milne10ca24a2012-04-23 15:38:27 -07002836 for (int i = 0; i < getChildCount(); i++) {
2837 View c = getChildAt(i);
Philip Milne7a23b492012-04-24 22:12:36 -07002838 Insets insets = c.getOpticalInsets();
Philip Milne7b757812012-09-19 18:13:44 -07002839
2840 drawRect(canvas, paint,
2841 c.getLeft() + insets.left,
2842 c.getTop() + insets.top,
2843 c.getRight() - insets.right - 1,
2844 c.getBottom() - insets.bottom - 1);
Philip Milne10ca24a2012-04-23 15:38:27 -07002845 }
2846 }
2847
Philip Milne10ca24a2012-04-23 15:38:27 -07002848 // Draw margins
Philip Milne7b757812012-09-19 18:13:44 -07002849 {
2850 paint.setColor(Color.argb(63, 255, 0, 255));
2851 paint.setStyle(Paint.Style.FILL);
Philip Milne604f4402012-04-24 19:27:11 -07002852
Philip Milne7b757812012-09-19 18:13:44 -07002853 onDebugDrawMargins(canvas, paint);
2854 }
2855
2856 // Draw clip bounds
2857 {
2858 paint.setColor(Color.rgb(63, 127, 255));
2859 paint.setStyle(Paint.Style.FILL);
2860
2861 int lineLength = dipsToPixels(8);
2862 int lineWidth = dipsToPixels(1);
2863 for (int i = 0; i < getChildCount(); i++) {
2864 View c = getChildAt(i);
2865 drawRectCorners(canvas, c.getLeft(), c.getTop(), c.getRight(), c.getBottom(),
2866 paint, lineLength, lineWidth);
2867 }
Philip Milne604f4402012-04-24 19:27:11 -07002868 }
Philip Milne10ca24a2012-04-23 15:38:27 -07002869 }
2870
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002871 /**
2872 * {@inheritDoc}
2873 */
2874 @Override
2875 protected void dispatchDraw(Canvas canvas) {
2876 final int count = mChildrenCount;
2877 final View[] children = mChildren;
2878 int flags = mGroupFlags;
2879
2880 if ((flags & FLAG_RUN_ANIMATION) != 0 && canAnimate()) {
2881 final boolean cache = (mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE;
2882
Romain Guy0d9275e2010-10-26 14:22:30 -07002883 final boolean buildCache = !isHardwareAccelerated();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002884 for (int i = 0; i < count; i++) {
2885 final View child = children[i];
2886 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
2887 final LayoutParams params = child.getLayoutParams();
2888 attachLayoutAnimationParameters(child, params, i, count);
2889 bindLayoutAnimation(child);
2890 if (cache) {
2891 child.setDrawingCacheEnabled(true);
Romain Guy0d9275e2010-10-26 14:22:30 -07002892 if (buildCache) {
2893 child.buildDrawingCache(true);
2894 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002895 }
2896 }
2897 }
2898
2899 final LayoutAnimationController controller = mLayoutAnimationController;
2900 if (controller.willOverlap()) {
2901 mGroupFlags |= FLAG_OPTIMIZE_INVALIDATE;
2902 }
2903
2904 controller.start();
2905
2906 mGroupFlags &= ~FLAG_RUN_ANIMATION;
2907 mGroupFlags &= ~FLAG_ANIMATION_DONE;
2908
2909 if (cache) {
2910 mGroupFlags |= FLAG_CHILDREN_DRAWN_WITH_CACHE;
2911 }
2912
2913 if (mAnimationListener != null) {
2914 mAnimationListener.onAnimationStart(controller.getAnimation());
2915 }
2916 }
2917
2918 int saveCount = 0;
2919 final boolean clipToPadding = (flags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK;
2920 if (clipToPadding) {
2921 saveCount = canvas.save();
Romain Guy8f2d94f2009-03-25 18:04:42 -07002922 canvas.clipRect(mScrollX + mPaddingLeft, mScrollY + mPaddingTop,
2923 mScrollX + mRight - mLeft - mPaddingRight,
2924 mScrollY + mBottom - mTop - mPaddingBottom);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002925
2926 }
2927
2928 // We will draw our child's animation, let's reset the flag
Dianne Hackborn4702a852012-08-17 15:18:29 -07002929 mPrivateFlags &= ~PFLAG_DRAW_ANIMATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002930 mGroupFlags &= ~FLAG_INVALIDATE_REQUIRED;
2931
2932 boolean more = false;
2933 final long drawingTime = getDrawingTime();
2934
2935 if ((flags & FLAG_USE_CHILD_DRAWING_ORDER) == 0) {
2936 for (int i = 0; i < count; i++) {
2937 final View child = children[i];
2938 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
2939 more |= drawChild(canvas, child, drawingTime);
2940 }
2941 }
2942 } else {
2943 for (int i = 0; i < count; i++) {
2944 final View child = children[getChildDrawingOrder(count, i)];
2945 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
2946 more |= drawChild(canvas, child, drawingTime);
2947 }
2948 }
2949 }
2950
2951 // Draw any disappearing views that have animations
2952 if (mDisappearingChildren != null) {
2953 final ArrayList<View> disappearingChildren = mDisappearingChildren;
2954 final int disappearingCount = disappearingChildren.size() - 1;
2955 // Go backwards -- we may delete as animations finish
2956 for (int i = disappearingCount; i >= 0; i--) {
2957 final View child = disappearingChildren.get(i);
2958 more |= drawChild(canvas, child, drawingTime);
2959 }
2960 }
2961
Philip Milne10ca24a2012-04-23 15:38:27 -07002962 if (debugDraw()) {
2963 onDebugDraw(canvas);
2964 }
2965
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002966 if (clipToPadding) {
2967 canvas.restoreToCount(saveCount);
2968 }
2969
2970 // mGroupFlags might have been updated by drawChild()
2971 flags = mGroupFlags;
2972
2973 if ((flags & FLAG_INVALIDATE_REQUIRED) == FLAG_INVALIDATE_REQUIRED) {
Romain Guy849d0a32011-02-01 17:20:48 -08002974 invalidate(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002975 }
2976
2977 if ((flags & FLAG_ANIMATION_DONE) == 0 && (flags & FLAG_NOTIFY_ANIMATION_LISTENER) == 0 &&
2978 mLayoutAnimationController.isDone() && !more) {
2979 // We want to erase the drawing cache and notify the listener after the
2980 // next frame is drawn because one extra invalidate() is caused by
2981 // drawChild() after the animation is over
2982 mGroupFlags |= FLAG_NOTIFY_ANIMATION_LISTENER;
2983 final Runnable end = new Runnable() {
2984 public void run() {
2985 notifyAnimationListener();
2986 }
2987 };
2988 post(end);
2989 }
2990 }
Romain Guy8506ab42009-06-11 17:35:47 -07002991
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002992 /**
Chet Haaseedf6f4b2013-03-26 07:55:30 -07002993 * Returns the ViewGroupOverlay for this view group, creating it if it does
2994 * not yet exist. In addition to {@link ViewOverlay}'s support for drawables,
2995 * {@link ViewGroupOverlay} allows views to be added to the overlay. These
2996 * views, like overlay drawables, are visual-only; they do not receive input
2997 * events and should not be used as anything other than a temporary
2998 * representation of a view in a parent container, such as might be used
2999 * by an animation effect.
3000 *
Chet Haase95399492013-04-08 14:30:31 -07003001 * <p>Note: Overlays do not currently work correctly with {@link
3002 * SurfaceView} or {@link TextureView}; contents in overlays for these
3003 * types of views may not display correctly.</p>
3004 *
Chet Haaseedf6f4b2013-03-26 07:55:30 -07003005 * @return The ViewGroupOverlay object for this view.
3006 * @see ViewGroupOverlay
3007 */
3008 @Override
3009 public ViewGroupOverlay getOverlay() {
3010 if (mOverlay == null) {
3011 mOverlay = new ViewGroupOverlay(mContext, this);
3012 }
3013 return (ViewGroupOverlay) mOverlay;
3014 }
3015
3016 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003017 * Returns the index of the child to draw for this iteration. Override this
3018 * if you want to change the drawing order of children. By default, it
3019 * returns i.
3020 * <p>
Romain Guy293451e2009-11-04 13:59:48 -08003021 * NOTE: In order for this method to be called, you must enable child ordering
3022 * first by calling {@link #setChildrenDrawingOrderEnabled(boolean)}.
Romain Guy8506ab42009-06-11 17:35:47 -07003023 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003024 * @param i The current iteration.
3025 * @return The index of the child to draw this iteration.
Chet Haase5c13d892010-10-08 08:37:55 -07003026 *
Romain Guy293451e2009-11-04 13:59:48 -08003027 * @see #setChildrenDrawingOrderEnabled(boolean)
3028 * @see #isChildrenDrawingOrderEnabled()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003029 */
3030 protected int getChildDrawingOrder(int childCount, int i) {
3031 return i;
3032 }
Romain Guy8506ab42009-06-11 17:35:47 -07003033
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003034 private void notifyAnimationListener() {
3035 mGroupFlags &= ~FLAG_NOTIFY_ANIMATION_LISTENER;
3036 mGroupFlags |= FLAG_ANIMATION_DONE;
3037
3038 if (mAnimationListener != null) {
3039 final Runnable end = new Runnable() {
3040 public void run() {
3041 mAnimationListener.onAnimationEnd(mLayoutAnimationController.getAnimation());
3042 }
3043 };
3044 post(end);
3045 }
3046
3047 if ((mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE) {
3048 mGroupFlags &= ~FLAG_CHILDREN_DRAWN_WITH_CACHE;
3049 if ((mPersistentDrawingCache & PERSISTENT_ANIMATION_CACHE) == 0) {
3050 setChildrenDrawingCacheEnabled(false);
3051 }
3052 }
3053
Romain Guy849d0a32011-02-01 17:20:48 -08003054 invalidate(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003055 }
3056
3057 /**
Chet Haasedaf98e92011-01-10 14:10:36 -08003058 * This method is used to cause children of this ViewGroup to restore or recreate their
3059 * display lists. It is called by getDisplayList() when the parent ViewGroup does not need
3060 * to recreate its own display list, which would happen if it went through the normal
3061 * draw/dispatchDraw mechanisms.
3062 *
3063 * @hide
3064 */
3065 @Override
3066 protected void dispatchGetDisplayList() {
3067 final int count = mChildrenCount;
3068 final View[] children = mChildren;
3069 for (int i = 0; i < count; i++) {
3070 final View child = children[i];
Romain Guy59c7f802011-09-29 17:21:45 -07003071 if (((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) &&
3072 child.hasStaticLayer()) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07003073 child.mRecreateDisplayList = (child.mPrivateFlags & PFLAG_INVALIDATED)
3074 == PFLAG_INVALIDATED;
3075 child.mPrivateFlags &= ~PFLAG_INVALIDATED;
Romain Guy2f57ba52011-02-03 18:03:29 -08003076 child.getDisplayList();
3077 child.mRecreateDisplayList = false;
3078 }
Chet Haasedaf98e92011-01-10 14:10:36 -08003079 }
Chet Haase91cedf12013-03-11 07:56:30 -07003080 if (mOverlay != null) {
Chet Haaseedf6f4b2013-03-26 07:55:30 -07003081 View overlayView = mOverlay.getOverlayView();
3082 overlayView.mRecreateDisplayList = (overlayView.mPrivateFlags & PFLAG_INVALIDATED)
Chet Haase91cedf12013-03-11 07:56:30 -07003083 == PFLAG_INVALIDATED;
Chet Haaseedf6f4b2013-03-26 07:55:30 -07003084 overlayView.mPrivateFlags &= ~PFLAG_INVALIDATED;
3085 overlayView.getDisplayList();
3086 overlayView.mRecreateDisplayList = false;
Chet Haase91cedf12013-03-11 07:56:30 -07003087 }
Chet Haasedaf98e92011-01-10 14:10:36 -08003088 }
3089
3090 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003091 * Draw one child of this View Group. This method is responsible for getting
3092 * the canvas in the right state. This includes clipping, translating so
3093 * that the child's scrolled origin is at 0, 0, and applying any animation
3094 * transformations.
3095 *
3096 * @param canvas The canvas on which to draw the child
3097 * @param child Who to draw
Chet Haasebcca79a2012-02-14 08:45:14 -08003098 * @param drawingTime The time at which draw is occurring
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003099 * @return True if an invalidate() was issued
3100 */
3101 protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
Chet Haase64a48c12012-02-13 16:33:29 -08003102 return child.draw(canvas, this, drawingTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003103 }
3104
3105 /**
Chet Haase430742f2013-04-12 11:18:36 -07003106 * Returns whether ths group's children are clipped to their bounds before drawing.
3107 * The default value is true.
3108 * @see #setClipChildren(boolean)
3109 *
3110 * @return True if the group's children will be clipped to their bounds,
3111 * false otherwise.
3112 */
3113 public boolean getClipChildren() {
3114 return ((mGroupFlags & FLAG_CLIP_CHILDREN) != 0);
3115 }
3116
3117 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003118 * By default, children are clipped to their bounds before drawing. This
3119 * allows view groups to override this behavior for animations, etc.
3120 *
3121 * @param clipChildren true to clip children to their bounds,
3122 * false otherwise
3123 * @attr ref android.R.styleable#ViewGroup_clipChildren
3124 */
3125 public void setClipChildren(boolean clipChildren) {
Chet Haasea1cff502012-02-21 13:43:44 -08003126 boolean previousValue = (mGroupFlags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN;
3127 if (clipChildren != previousValue) {
3128 setBooleanFlag(FLAG_CLIP_CHILDREN, clipChildren);
Chet Haase1271e2c2012-04-20 09:54:27 -07003129 for (int i = 0; i < mChildrenCount; ++i) {
3130 View child = getChildAt(i);
3131 if (child.mDisplayList != null) {
Chet Haasedd671592013-04-19 14:54:34 -07003132 child.mDisplayList.setClipToBounds(clipChildren);
Chet Haasea1cff502012-02-21 13:43:44 -08003133 }
3134 }
3135 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003136 }
3137
3138 /**
3139 * By default, children are clipped to the padding of the ViewGroup. This
3140 * allows view groups to override this behavior
3141 *
3142 * @param clipToPadding true to clip children to the padding of the
3143 * group, false otherwise
3144 * @attr ref android.R.styleable#ViewGroup_clipToPadding
3145 */
3146 public void setClipToPadding(boolean clipToPadding) {
3147 setBooleanFlag(FLAG_CLIP_TO_PADDING, clipToPadding);
3148 }
3149
3150 /**
3151 * {@inheritDoc}
3152 */
3153 @Override
3154 public void dispatchSetSelected(boolean selected) {
3155 final View[] children = mChildren;
3156 final int count = mChildrenCount;
3157 for (int i = 0; i < count; i++) {
3158 children[i].setSelected(selected);
3159 }
3160 }
Romain Guy8506ab42009-06-11 17:35:47 -07003161
Dianne Hackbornd0fa3712010-09-14 18:57:14 -07003162 /**
3163 * {@inheritDoc}
3164 */
3165 @Override
3166 public void dispatchSetActivated(boolean activated) {
3167 final View[] children = mChildren;
3168 final int count = mChildrenCount;
3169 for (int i = 0; i < count; i++) {
Dianne Hackbornd0fa3712010-09-14 18:57:14 -07003170 children[i].setActivated(activated);
3171 }
3172 }
3173
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003174 @Override
3175 protected void dispatchSetPressed(boolean pressed) {
3176 final View[] children = mChildren;
3177 final int count = mChildrenCount;
3178 for (int i = 0; i < count; i++) {
Adam Powell035a1fc2012-02-27 15:23:50 -08003179 final View child = children[i];
3180 // Children that are clickable on their own should not
3181 // show a pressed state when their parent view does.
3182 // Clearing a pressed state always propagates.
3183 if (!pressed || (!child.isClickable() && !child.isLongClickable())) {
3184 child.setPressed(pressed);
3185 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003186 }
3187 }
3188
Adam Powell14874662013-07-18 19:42:41 -07003189 @Override
3190 void dispatchCancelPendingInputEvents() {
3191 super.dispatchCancelPendingInputEvents();
3192
3193 final View[] children = mChildren;
3194 final int count = mChildrenCount;
3195 for (int i = 0; i < count; i++) {
3196 children[i].dispatchCancelPendingInputEvents();
3197 }
3198 }
3199
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003200 /**
3201 * When this property is set to true, this ViewGroup supports static transformations on
3202 * children; this causes
3203 * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} to be
3204 * invoked when a child is drawn.
3205 *
3206 * Any subclass overriding
3207 * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} should
3208 * set this property to true.
3209 *
3210 * @param enabled True to enable static transformations on children, false otherwise.
3211 *
Chet Haase599913d2012-07-23 16:22:05 -07003212 * @see #getChildStaticTransformation(View, android.view.animation.Transformation)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003213 */
3214 protected void setStaticTransformationsEnabled(boolean enabled) {
3215 setBooleanFlag(FLAG_SUPPORT_STATIC_TRANSFORMATIONS, enabled);
3216 }
3217
3218 /**
Chet Haase2d46fcc2011-12-19 18:01:05 -08003219 * Sets <code>t</code> to be the static transformation of the child, if set, returning a
3220 * boolean to indicate whether a static transform was set. The default implementation
3221 * simply returns <code>false</code>; subclasses may override this method for different
Chet Haase599913d2012-07-23 16:22:05 -07003222 * behavior. {@link #setStaticTransformationsEnabled(boolean)} must be set to true
3223 * for this method to be called.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003224 *
Chet Haase2d46fcc2011-12-19 18:01:05 -08003225 * @param child The child view whose static transform is being requested
3226 * @param t The Transformation which will hold the result
3227 * @return true if the transformation was set, false otherwise
Romain Guy8506ab42009-06-11 17:35:47 -07003228 * @see #setStaticTransformationsEnabled(boolean)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003229 */
3230 protected boolean getChildStaticTransformation(View child, Transformation t) {
3231 return false;
3232 }
3233
Romain Guyf6991302013-06-05 17:19:01 -07003234 Transformation getChildTransformation() {
3235 if (mChildTransformation == null) {
3236 mChildTransformation = new Transformation();
3237 }
3238 return mChildTransformation;
3239 }
3240
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003241 /**
3242 * {@hide}
3243 */
3244 @Override
3245 protected View findViewTraversal(int id) {
3246 if (id == mID) {
3247 return this;
3248 }
3249
3250 final View[] where = mChildren;
3251 final int len = mChildrenCount;
3252
3253 for (int i = 0; i < len; i++) {
3254 View v = where[i];
3255
Dianne Hackborn4702a852012-08-17 15:18:29 -07003256 if ((v.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003257 v = v.findViewById(id);
3258
3259 if (v != null) {
3260 return v;
3261 }
3262 }
3263 }
3264
3265 return null;
3266 }
3267
3268 /**
3269 * {@hide}
3270 */
3271 @Override
3272 protected View findViewWithTagTraversal(Object tag) {
3273 if (tag != null && tag.equals(mTag)) {
3274 return this;
3275 }
3276
3277 final View[] where = mChildren;
3278 final int len = mChildrenCount;
3279
3280 for (int i = 0; i < len; i++) {
3281 View v = where[i];
3282
Dianne Hackborn4702a852012-08-17 15:18:29 -07003283 if ((v.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003284 v = v.findViewWithTag(tag);
3285
3286 if (v != null) {
3287 return v;
3288 }
3289 }
3290 }
3291
3292 return null;
3293 }
3294
3295 /**
Jeff Brown4e6319b2010-12-13 10:36:51 -08003296 * {@hide}
3297 */
3298 @Override
Jeff Brown4dfbec22011-08-15 14:55:37 -07003299 protected View findViewByPredicateTraversal(Predicate<View> predicate, View childToSkip) {
Jeff Brown4e6319b2010-12-13 10:36:51 -08003300 if (predicate.apply(this)) {
3301 return this;
3302 }
3303
3304 final View[] where = mChildren;
3305 final int len = mChildrenCount;
3306
3307 for (int i = 0; i < len; i++) {
3308 View v = where[i];
3309
Dianne Hackborn4702a852012-08-17 15:18:29 -07003310 if (v != childToSkip && (v.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) {
Jeff Brown4e6319b2010-12-13 10:36:51 -08003311 v = v.findViewByPredicate(predicate);
3312
3313 if (v != null) {
3314 return v;
3315 }
3316 }
3317 }
3318
3319 return null;
3320 }
3321
3322 /**
Romain Guy393a52c2012-05-22 20:21:08 -07003323 * <p>Adds a child view. If no layout parameters are already set on the child, the
3324 * default parameters for this ViewGroup are set on the child.</p>
3325 *
3326 * <p><strong>Note:</strong> do not invoke this method from
3327 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3328 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003329 *
3330 * @param child the child view to add
3331 *
3332 * @see #generateDefaultLayoutParams()
3333 */
3334 public void addView(View child) {
3335 addView(child, -1);
3336 }
3337
3338 /**
3339 * Adds a child view. If no layout parameters are already set on the child, the
3340 * default parameters for this ViewGroup are set on the child.
Romain Guy393a52c2012-05-22 20:21:08 -07003341 *
3342 * <p><strong>Note:</strong> do not invoke this method from
3343 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3344 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003345 *
3346 * @param child the child view to add
3347 * @param index the position at which to add the child
3348 *
3349 * @see #generateDefaultLayoutParams()
3350 */
3351 public void addView(View child, int index) {
3352 LayoutParams params = child.getLayoutParams();
3353 if (params == null) {
3354 params = generateDefaultLayoutParams();
3355 if (params == null) {
3356 throw new IllegalArgumentException("generateDefaultLayoutParams() cannot return null");
3357 }
3358 }
3359 addView(child, index, params);
3360 }
3361
3362 /**
3363 * Adds a child view with this ViewGroup's default layout parameters and the
3364 * specified width and height.
3365 *
Romain Guy393a52c2012-05-22 20:21:08 -07003366 * <p><strong>Note:</strong> do not invoke this method from
3367 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3368 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
3369 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003370 * @param child the child view to add
3371 */
3372 public void addView(View child, int width, int height) {
3373 final LayoutParams params = generateDefaultLayoutParams();
3374 params.width = width;
3375 params.height = height;
3376 addView(child, -1, params);
3377 }
3378
3379 /**
3380 * Adds a child view with the specified layout parameters.
3381 *
Romain Guy393a52c2012-05-22 20:21:08 -07003382 * <p><strong>Note:</strong> do not invoke this method from
3383 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3384 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
3385 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003386 * @param child the child view to add
3387 * @param params the layout parameters to set on the child
3388 */
3389 public void addView(View child, LayoutParams params) {
3390 addView(child, -1, params);
3391 }
3392
3393 /**
3394 * Adds a child view with the specified layout parameters.
3395 *
Romain Guy393a52c2012-05-22 20:21:08 -07003396 * <p><strong>Note:</strong> do not invoke this method from
3397 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3398 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
3399 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003400 * @param child the child view to add
3401 * @param index the position at which to add the child
3402 * @param params the layout parameters to set on the child
3403 */
3404 public void addView(View child, int index, LayoutParams params) {
3405 if (DBG) {
3406 System.out.println(this + " addView");
3407 }
3408
3409 // addViewInner() will call child.requestLayout() when setting the new LayoutParams
3410 // therefore, we call requestLayout() on ourselves before, so that the child's request
3411 // will be blocked at our level
3412 requestLayout();
Romain Guy849d0a32011-02-01 17:20:48 -08003413 invalidate(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003414 addViewInner(child, index, params, false);
3415 }
3416
3417 /**
3418 * {@inheritDoc}
3419 */
3420 public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
3421 if (!checkLayoutParams(params)) {
3422 throw new IllegalArgumentException("Invalid LayoutParams supplied to " + this);
3423 }
3424 if (view.mParent != this) {
3425 throw new IllegalArgumentException("Given view not a child of " + this);
3426 }
3427 view.setLayoutParams(params);
3428 }
3429
3430 /**
3431 * {@inheritDoc}
3432 */
3433 protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
3434 return p != null;
3435 }
3436
3437 /**
3438 * Interface definition for a callback to be invoked when the hierarchy
3439 * within this view changed. The hierarchy changes whenever a child is added
3440 * to or removed from this view.
3441 */
3442 public interface OnHierarchyChangeListener {
3443 /**
3444 * Called when a new child is added to a parent view.
3445 *
3446 * @param parent the view in which a child was added
3447 * @param child the new child view added in the hierarchy
3448 */
3449 void onChildViewAdded(View parent, View child);
3450
3451 /**
3452 * Called when a child is removed from a parent view.
3453 *
3454 * @param parent the view from which the child was removed
3455 * @param child the child removed from the hierarchy
3456 */
3457 void onChildViewRemoved(View parent, View child);
3458 }
3459
3460 /**
3461 * Register a callback to be invoked when a child is added to or removed
3462 * from this view.
3463 *
3464 * @param listener the callback to invoke on hierarchy change
3465 */
3466 public void setOnHierarchyChangeListener(OnHierarchyChangeListener listener) {
3467 mOnHierarchyChangeListener = listener;
3468 }
3469
3470 /**
Philip Milnef51d91c2011-07-18 16:12:19 -07003471 * @hide
3472 */
3473 protected void onViewAdded(View child) {
3474 if (mOnHierarchyChangeListener != null) {
3475 mOnHierarchyChangeListener.onChildViewAdded(this, child);
3476 }
3477 }
3478
3479 /**
3480 * @hide
3481 */
3482 protected void onViewRemoved(View child) {
3483 if (mOnHierarchyChangeListener != null) {
3484 mOnHierarchyChangeListener.onChildViewRemoved(this, child);
3485 }
3486 }
3487
Philip Milnecfb631b2012-10-26 10:51:46 -07003488 private void clearCachedLayoutMode() {
Svetoslav6254f482013-06-04 17:22:14 -07003489 if (!hasBooleanFlag(FLAG_LAYOUT_MODE_WAS_EXPLICITLY_SET)) {
Philip Milnecfb631b2012-10-26 10:51:46 -07003490 mLayoutMode = LAYOUT_MODE_UNDEFINED;
3491 }
3492 }
3493
3494 @Override
3495 protected void onAttachedToWindow() {
3496 super.onAttachedToWindow();
3497 clearCachedLayoutMode();
3498 }
3499
3500 @Override
3501 protected void onDetachedFromWindow() {
3502 super.onDetachedFromWindow();
3503 clearCachedLayoutMode();
3504 }
3505
Philip Milnef51d91c2011-07-18 16:12:19 -07003506 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003507 * Adds a view during layout. This is useful if in your onLayout() method,
3508 * you need to add more views (as does the list view for example).
3509 *
3510 * If index is negative, it means put it at the end of the list.
3511 *
3512 * @param child the view to add to the group
3513 * @param index the index at which the child must be added
3514 * @param params the layout parameters to associate with the child
3515 * @return true if the child was added, false otherwise
3516 */
3517 protected boolean addViewInLayout(View child, int index, LayoutParams params) {
3518 return addViewInLayout(child, index, params, false);
3519 }
3520
3521 /**
3522 * Adds a view during layout. This is useful if in your onLayout() method,
3523 * you need to add more views (as does the list view for example).
3524 *
3525 * If index is negative, it means put it at the end of the list.
3526 *
3527 * @param child the view to add to the group
3528 * @param index the index at which the child must be added
3529 * @param params the layout parameters to associate with the child
3530 * @param preventRequestLayout if true, calling this method will not trigger a
3531 * layout request on child
3532 * @return true if the child was added, false otherwise
3533 */
3534 protected boolean addViewInLayout(View child, int index, LayoutParams params,
3535 boolean preventRequestLayout) {
3536 child.mParent = null;
3537 addViewInner(child, index, params, preventRequestLayout);
Dianne Hackborn4702a852012-08-17 15:18:29 -07003538 child.mPrivateFlags = (child.mPrivateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003539 return true;
3540 }
3541
3542 /**
3543 * Prevents the specified child to be laid out during the next layout pass.
3544 *
3545 * @param child the child on which to perform the cleanup
3546 */
3547 protected void cleanupLayoutState(View child) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07003548 child.mPrivateFlags &= ~View.PFLAG_FORCE_LAYOUT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003549 }
3550
3551 private void addViewInner(View child, int index, LayoutParams params,
3552 boolean preventRequestLayout) {
3553
Chet Haasee8e45d32011-03-02 17:07:35 -08003554 if (mTransition != null) {
3555 // Don't prevent other add transitions from completing, but cancel remove
3556 // transitions to let them complete the process before we add to the container
3557 mTransition.cancel(LayoutTransition.DISAPPEARING);
Chet Haaseadd65772011-02-09 16:47:29 -08003558 }
3559
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003560 if (child.getParent() != null) {
3561 throw new IllegalStateException("The specified child already has a parent. " +
3562 "You must call removeView() on the child's parent first.");
3563 }
3564
Chet Haase21cd1382010-09-01 17:42:29 -07003565 if (mTransition != null) {
Chet Haase5e25c2c2010-09-16 11:15:56 -07003566 mTransition.addChild(this, child);
Chet Haase21cd1382010-09-01 17:42:29 -07003567 }
3568
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003569 if (!checkLayoutParams(params)) {
3570 params = generateLayoutParams(params);
3571 }
3572
3573 if (preventRequestLayout) {
3574 child.mLayoutParams = params;
3575 } else {
3576 child.setLayoutParams(params);
3577 }
3578
3579 if (index < 0) {
3580 index = mChildrenCount;
3581 }
3582
3583 addInArray(child, index);
3584
3585 // tell our children
3586 if (preventRequestLayout) {
3587 child.assignParent(this);
3588 } else {
3589 child.mParent = this;
3590 }
3591
3592 if (child.hasFocus()) {
3593 requestChildFocus(child, child.findFocus());
3594 }
Romain Guy8506ab42009-06-11 17:35:47 -07003595
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003596 AttachInfo ai = mAttachInfo;
Adam Powell4b867882011-09-16 12:59:46 -07003597 if (ai != null && (mGroupFlags & FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW) == 0) {
Romain Guy8506ab42009-06-11 17:35:47 -07003598 boolean lastKeepOn = ai.mKeepScreenOn;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003599 ai.mKeepScreenOn = false;
3600 child.dispatchAttachedToWindow(mAttachInfo, (mViewFlags&VISIBILITY_MASK));
3601 if (ai.mKeepScreenOn) {
3602 needGlobalAttributesUpdate(true);
3603 }
3604 ai.mKeepScreenOn = lastKeepOn;
3605 }
3606
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07003607 if (child.isLayoutDirectionInherited()) {
Fabrice Di Meglioa7e0bcd2012-10-16 19:55:01 -07003608 child.resetRtlProperties();
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07003609 }
3610
Philip Milnef51d91c2011-07-18 16:12:19 -07003611 onViewAdded(child);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003612
3613 if ((child.mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE) {
3614 mGroupFlags |= FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE;
3615 }
Adam Powell539ee872012-02-03 19:00:49 -08003616
3617 if (child.hasTransientState()) {
3618 childHasTransientStateChanged(child, true);
3619 }
Svetoslav6254f482013-06-04 17:22:14 -07003620
3621 if (child.isImportantForAccessibility() && child.getVisibility() != View.GONE) {
Svetoslav00dbe812013-06-10 12:51:09 -07003622 notifySubtreeAccessibilityStateChangedIfNeeded();
Svetoslav6254f482013-06-04 17:22:14 -07003623 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003624 }
3625
3626 private void addInArray(View child, int index) {
3627 View[] children = mChildren;
3628 final int count = mChildrenCount;
3629 final int size = children.length;
3630 if (index == count) {
3631 if (size == count) {
3632 mChildren = new View[size + ARRAY_CAPACITY_INCREMENT];
3633 System.arraycopy(children, 0, mChildren, 0, size);
3634 children = mChildren;
3635 }
3636 children[mChildrenCount++] = child;
3637 } else if (index < count) {
3638 if (size == count) {
3639 mChildren = new View[size + ARRAY_CAPACITY_INCREMENT];
3640 System.arraycopy(children, 0, mChildren, 0, index);
3641 System.arraycopy(children, index, mChildren, index + 1, count - index);
3642 children = mChildren;
3643 } else {
3644 System.arraycopy(children, index, children, index + 1, count - index);
3645 }
3646 children[index] = child;
3647 mChildrenCount++;
Joe Onorato03ab0c72011-01-06 15:46:27 -08003648 if (mLastTouchDownIndex >= index) {
3649 mLastTouchDownIndex++;
3650 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003651 } else {
3652 throw new IndexOutOfBoundsException("index=" + index + " count=" + count);
3653 }
3654 }
3655
3656 // This method also sets the child's mParent to null
3657 private void removeFromArray(int index) {
3658 final View[] children = mChildren;
Chet Haase21cd1382010-09-01 17:42:29 -07003659 if (!(mTransitioningViews != null && mTransitioningViews.contains(children[index]))) {
3660 children[index].mParent = null;
3661 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003662 final int count = mChildrenCount;
3663 if (index == count - 1) {
3664 children[--mChildrenCount] = null;
3665 } else if (index >= 0 && index < count) {
3666 System.arraycopy(children, index + 1, children, index, count - index - 1);
3667 children[--mChildrenCount] = null;
3668 } else {
3669 throw new IndexOutOfBoundsException();
3670 }
Joe Onorato03ab0c72011-01-06 15:46:27 -08003671 if (mLastTouchDownIndex == index) {
3672 mLastTouchDownTime = 0;
3673 mLastTouchDownIndex = -1;
3674 } else if (mLastTouchDownIndex > index) {
3675 mLastTouchDownIndex--;
3676 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003677 }
3678
3679 // This method also sets the children's mParent to null
3680 private void removeFromArray(int start, int count) {
3681 final View[] children = mChildren;
3682 final int childrenCount = mChildrenCount;
3683
3684 start = Math.max(0, start);
3685 final int end = Math.min(childrenCount, start + count);
3686
3687 if (start == end) {
3688 return;
3689 }
3690
3691 if (end == childrenCount) {
3692 for (int i = start; i < end; i++) {
3693 children[i].mParent = null;
3694 children[i] = null;
3695 }
3696 } else {
3697 for (int i = start; i < end; i++) {
3698 children[i].mParent = null;
3699 }
3700
3701 // Since we're looping above, we might as well do the copy, but is arraycopy()
3702 // faster than the extra 2 bounds checks we would do in the loop?
3703 System.arraycopy(children, end, children, start, childrenCount - end);
3704
3705 for (int i = childrenCount - (end - start); i < childrenCount; i++) {
3706 children[i] = null;
3707 }
3708 }
3709
3710 mChildrenCount -= (end - start);
3711 }
3712
3713 private void bindLayoutAnimation(View child) {
3714 Animation a = mLayoutAnimationController.getAnimationForView(child);
3715 child.setAnimation(a);
3716 }
3717
3718 /**
3719 * Subclasses should override this method to set layout animation
3720 * parameters on the supplied child.
3721 *
3722 * @param child the child to associate with animation parameters
3723 * @param params the child's layout parameters which hold the animation
3724 * parameters
3725 * @param index the index of the child in the view group
3726 * @param count the number of children in the view group
3727 */
3728 protected void attachLayoutAnimationParameters(View child,
3729 LayoutParams params, int index, int count) {
3730 LayoutAnimationController.AnimationParameters animationParams =
3731 params.layoutAnimationParameters;
3732 if (animationParams == null) {
3733 animationParams = new LayoutAnimationController.AnimationParameters();
3734 params.layoutAnimationParameters = animationParams;
3735 }
3736
3737 animationParams.count = count;
3738 animationParams.index = index;
3739 }
3740
3741 /**
3742 * {@inheritDoc}
Romain Guy393a52c2012-05-22 20:21:08 -07003743 *
3744 * <p><strong>Note:</strong> do not invoke this method from
3745 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3746 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003747 */
3748 public void removeView(View view) {
3749 removeViewInternal(view);
3750 requestLayout();
Romain Guy849d0a32011-02-01 17:20:48 -08003751 invalidate(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003752 }
3753
3754 /**
3755 * Removes a view during layout. This is useful if in your onLayout() method,
3756 * you need to remove more views.
3757 *
Romain Guy393a52c2012-05-22 20:21:08 -07003758 * <p><strong>Note:</strong> do not invoke this method from
3759 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3760 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
3761 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003762 * @param view the view to remove from the group
3763 */
3764 public void removeViewInLayout(View view) {
3765 removeViewInternal(view);
3766 }
3767
3768 /**
3769 * Removes a range of views during layout. This is useful if in your onLayout() method,
3770 * you need to remove more views.
3771 *
Romain Guy393a52c2012-05-22 20:21:08 -07003772 * <p><strong>Note:</strong> do not invoke this method from
3773 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3774 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
3775 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003776 * @param start the index of the first view to remove from the group
3777 * @param count the number of views to remove from the group
3778 */
3779 public void removeViewsInLayout(int start, int count) {
3780 removeViewsInternal(start, count);
3781 }
3782
3783 /**
3784 * Removes the view at the specified position in the group.
3785 *
Romain Guy393a52c2012-05-22 20:21:08 -07003786 * <p><strong>Note:</strong> do not invoke this method from
3787 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3788 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
3789 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003790 * @param index the position in the group of the view to remove
3791 */
3792 public void removeViewAt(int index) {
3793 removeViewInternal(index, getChildAt(index));
3794 requestLayout();
Romain Guy849d0a32011-02-01 17:20:48 -08003795 invalidate(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003796 }
3797
3798 /**
3799 * Removes the specified range of views from the group.
3800 *
Romain Guy393a52c2012-05-22 20:21:08 -07003801 * <p><strong>Note:</strong> do not invoke this method from
3802 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3803 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
3804 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003805 * @param start the first position in the group of the range of views to remove
3806 * @param count the number of views to remove
3807 */
3808 public void removeViews(int start, int count) {
3809 removeViewsInternal(start, count);
3810 requestLayout();
Romain Guy849d0a32011-02-01 17:20:48 -08003811 invalidate(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003812 }
3813
3814 private void removeViewInternal(View view) {
3815 final int index = indexOfChild(view);
3816 if (index >= 0) {
3817 removeViewInternal(index, view);
3818 }
3819 }
3820
3821 private void removeViewInternal(int index, View view) {
Chet Haase21cd1382010-09-01 17:42:29 -07003822
3823 if (mTransition != null) {
Chet Haase5e25c2c2010-09-16 11:15:56 -07003824 mTransition.removeChild(this, view);
Chet Haase21cd1382010-09-01 17:42:29 -07003825 }
3826
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003827 boolean clearChildFocus = false;
3828 if (view == mFocused) {
Svetoslav Ganov57cadf22012-04-04 16:44:39 -07003829 view.unFocus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003830 clearChildFocus = true;
3831 }
3832
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003833 if (view.isAccessibilityFocused()) {
3834 view.clearAccessibilityFocus();
3835 }
Svetoslav Ganov961bf0e2012-05-08 09:40:03 -07003836
Jeff Brown59a422e2012-04-19 15:19:19 -07003837 cancelTouchTarget(view);
3838 cancelHoverTarget(view);
3839
Chet Haase21cd1382010-09-01 17:42:29 -07003840 if (view.getAnimation() != null ||
3841 (mTransitioningViews != null && mTransitioningViews.contains(view))) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003842 addDisappearingView(view);
3843 } else if (view.mAttachInfo != null) {
3844 view.dispatchDetachedFromWindow();
3845 }
3846
Adam Powell539ee872012-02-03 19:00:49 -08003847 if (view.hasTransientState()) {
3848 childHasTransientStateChanged(view, false);
3849 }
3850
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003851 needGlobalAttributesUpdate(false);
Romain Guy8506ab42009-06-11 17:35:47 -07003852
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003853 removeFromArray(index);
3854
3855 if (clearChildFocus) {
3856 clearChildFocus(view);
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003857 if (!rootViewRequestFocus()) {
3858 notifyGlobalFocusCleared(this);
3859 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07003860 }
Romain Guy6fb05632012-11-29 10:50:33 -08003861
3862 onViewRemoved(view);
Svetoslav6254f482013-06-04 17:22:14 -07003863
3864 if (view.isImportantForAccessibility() && view.getVisibility() != View.GONE) {
Svetoslav00dbe812013-06-10 12:51:09 -07003865 notifySubtreeAccessibilityStateChangedIfNeeded();
Svetoslav6254f482013-06-04 17:22:14 -07003866 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003867 }
3868
Chet Haase21cd1382010-09-01 17:42:29 -07003869 /**
3870 * Sets the LayoutTransition object for this ViewGroup. If the LayoutTransition object is
3871 * not null, changes in layout which occur because of children being added to or removed from
3872 * the ViewGroup will be animated according to the animations defined in that LayoutTransition
3873 * object. By default, the transition object is null (so layout changes are not animated).
3874 *
Chet Haaseef3cbfd2013-08-21 14:01:02 -07003875 * <p>Replacing a non-null transition will cause that previous transition to be
3876 * canceled, if it is currently running, to restore this container to
3877 * its correct post-transition state.</p>
3878 *
Chet Haase21cd1382010-09-01 17:42:29 -07003879 * @param transition The LayoutTransition object that will animated changes in layout. A value
3880 * of <code>null</code> means no transition will run on layout changes.
Chet Haase13cc1202010-09-03 15:39:20 -07003881 * @attr ref android.R.styleable#ViewGroup_animateLayoutChanges
Chet Haase21cd1382010-09-01 17:42:29 -07003882 */
3883 public void setLayoutTransition(LayoutTransition transition) {
Chet Haaseb20db3e2010-09-10 13:07:30 -07003884 if (mTransition != null) {
Chet Haasefee6f2b2013-08-27 12:22:29 -07003885 LayoutTransition previousTransition = mTransition;
3886 previousTransition.cancel();
3887 previousTransition.removeTransitionListener(mLayoutTransitionListener);
Chet Haaseb20db3e2010-09-10 13:07:30 -07003888 }
Chet Haase21cd1382010-09-01 17:42:29 -07003889 mTransition = transition;
Chet Haase13cc1202010-09-03 15:39:20 -07003890 if (mTransition != null) {
3891 mTransition.addTransitionListener(mLayoutTransitionListener);
3892 }
3893 }
3894
3895 /**
3896 * Gets the LayoutTransition object for this ViewGroup. If the LayoutTransition object is
3897 * not null, changes in layout which occur because of children being added to or removed from
3898 * the ViewGroup will be animated according to the animations defined in that LayoutTransition
3899 * object. By default, the transition object is null (so layout changes are not animated).
3900 *
3901 * @return LayoutTranstion The LayoutTransition object that will animated changes in layout.
3902 * A value of <code>null</code> means no transition will run on layout changes.
3903 */
3904 public LayoutTransition getLayoutTransition() {
3905 return mTransition;
Chet Haase21cd1382010-09-01 17:42:29 -07003906 }
3907
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003908 private void removeViewsInternal(int start, int count) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003909 final View focused = mFocused;
3910 final boolean detach = mAttachInfo != null;
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003911 boolean clearChildFocus = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003912
3913 final View[] children = mChildren;
3914 final int end = start + count;
3915
3916 for (int i = start; i < end; i++) {
3917 final View view = children[i];
3918
Chet Haase21cd1382010-09-01 17:42:29 -07003919 if (mTransition != null) {
Chet Haase5e25c2c2010-09-16 11:15:56 -07003920 mTransition.removeChild(this, view);
Chet Haase21cd1382010-09-01 17:42:29 -07003921 }
3922
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003923 if (view == focused) {
Svetoslav Ganov57cadf22012-04-04 16:44:39 -07003924 view.unFocus();
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003925 clearChildFocus = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003926 }
3927
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003928 if (view.isAccessibilityFocused()) {
3929 view.clearAccessibilityFocus();
3930 }
Svetoslav Ganov961bf0e2012-05-08 09:40:03 -07003931
Jeff Brown59a422e2012-04-19 15:19:19 -07003932 cancelTouchTarget(view);
3933 cancelHoverTarget(view);
3934
Chet Haase21cd1382010-09-01 17:42:29 -07003935 if (view.getAnimation() != null ||
3936 (mTransitioningViews != null && mTransitioningViews.contains(view))) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003937 addDisappearingView(view);
3938 } else if (detach) {
3939 view.dispatchDetachedFromWindow();
3940 }
3941
Adam Powell539ee872012-02-03 19:00:49 -08003942 if (view.hasTransientState()) {
3943 childHasTransientStateChanged(view, false);
3944 }
3945
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003946 needGlobalAttributesUpdate(false);
Romain Guy8506ab42009-06-11 17:35:47 -07003947
Philip Milnef51d91c2011-07-18 16:12:19 -07003948 onViewRemoved(view);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003949 }
3950
3951 removeFromArray(start, count);
3952
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003953 if (clearChildFocus) {
3954 clearChildFocus(focused);
3955 if (!rootViewRequestFocus()) {
3956 notifyGlobalFocusCleared(focused);
3957 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003958 }
3959 }
3960
3961 /**
3962 * Call this method to remove all child views from the
3963 * ViewGroup.
Romain Guy393a52c2012-05-22 20:21:08 -07003964 *
3965 * <p><strong>Note:</strong> do not invoke this method from
3966 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3967 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003968 */
3969 public void removeAllViews() {
3970 removeAllViewsInLayout();
3971 requestLayout();
Romain Guy849d0a32011-02-01 17:20:48 -08003972 invalidate(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003973 }
3974
3975 /**
3976 * Called by a ViewGroup subclass to remove child views from itself,
3977 * when it must first know its size on screen before it can calculate how many
3978 * child views it will render. An example is a Gallery or a ListView, which
3979 * may "have" 50 children, but actually only render the number of children
3980 * that can currently fit inside the object on screen. Do not call
3981 * this method unless you are extending ViewGroup and understand the
3982 * view measuring and layout pipeline.
Romain Guy393a52c2012-05-22 20:21:08 -07003983 *
3984 * <p><strong>Note:</strong> do not invoke this method from
3985 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3986 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003987 */
3988 public void removeAllViewsInLayout() {
3989 final int count = mChildrenCount;
3990 if (count <= 0) {
3991 return;
3992 }
3993
3994 final View[] children = mChildren;
3995 mChildrenCount = 0;
3996
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003997 final View focused = mFocused;
3998 final boolean detach = mAttachInfo != null;
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003999 boolean clearChildFocus = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004000
4001 needGlobalAttributesUpdate(false);
Romain Guy8506ab42009-06-11 17:35:47 -07004002
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004003 for (int i = count - 1; i >= 0; i--) {
4004 final View view = children[i];
4005
Chet Haase21cd1382010-09-01 17:42:29 -07004006 if (mTransition != null) {
Chet Haase5e25c2c2010-09-16 11:15:56 -07004007 mTransition.removeChild(this, view);
Chet Haase21cd1382010-09-01 17:42:29 -07004008 }
4009
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004010 if (view == focused) {
Svetoslav Ganov57cadf22012-04-04 16:44:39 -07004011 view.unFocus();
Svetoslav Ganov149567f2013-01-08 15:23:34 -08004012 clearChildFocus = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004013 }
4014
Svetoslav Ganov149567f2013-01-08 15:23:34 -08004015 if (view.isAccessibilityFocused()) {
4016 view.clearAccessibilityFocus();
4017 }
Svetoslav Ganov961bf0e2012-05-08 09:40:03 -07004018
Jeff Brown59a422e2012-04-19 15:19:19 -07004019 cancelTouchTarget(view);
4020 cancelHoverTarget(view);
4021
Chet Haase21cd1382010-09-01 17:42:29 -07004022 if (view.getAnimation() != null ||
4023 (mTransitioningViews != null && mTransitioningViews.contains(view))) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004024 addDisappearingView(view);
4025 } else if (detach) {
4026 view.dispatchDetachedFromWindow();
4027 }
4028
Adam Powell539ee872012-02-03 19:00:49 -08004029 if (view.hasTransientState()) {
4030 childHasTransientStateChanged(view, false);
4031 }
4032
Philip Milnef51d91c2011-07-18 16:12:19 -07004033 onViewRemoved(view);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004034
4035 view.mParent = null;
4036 children[i] = null;
4037 }
4038
Svetoslav Ganov149567f2013-01-08 15:23:34 -08004039 if (clearChildFocus) {
4040 clearChildFocus(focused);
4041 if (!rootViewRequestFocus()) {
4042 notifyGlobalFocusCleared(focused);
4043 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004044 }
4045 }
4046
4047 /**
4048 * Finishes the removal of a detached view. This method will dispatch the detached from
4049 * window event and notify the hierarchy change listener.
Chet Haaseca479d42012-08-30 17:20:08 -07004050 * <p>
4051 * This method is intended to be lightweight and makes no assumptions about whether the
4052 * parent or child should be redrawn. Proper use of this method will include also making
4053 * any appropriate {@link #requestLayout()} or {@link #invalidate()} calls.
4054 * For example, callers can {@link #post(Runnable) post} a {@link Runnable}
4055 * which performs a {@link #requestLayout()} on the next frame, after all detach/remove
4056 * calls are finished, causing layout to be run prior to redrawing the view hierarchy.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004057 *
4058 * @param child the child to be definitely removed from the view hierarchy
4059 * @param animate if true and the view has an animation, the view is placed in the
4060 * disappearing views list, otherwise, it is detached from the window
4061 *
4062 * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
4063 * @see #detachAllViewsFromParent()
4064 * @see #detachViewFromParent(View)
4065 * @see #detachViewFromParent(int)
4066 */
4067 protected void removeDetachedView(View child, boolean animate) {
Chet Haase21cd1382010-09-01 17:42:29 -07004068 if (mTransition != null) {
Chet Haase5e25c2c2010-09-16 11:15:56 -07004069 mTransition.removeChild(this, child);
Chet Haase21cd1382010-09-01 17:42:29 -07004070 }
4071
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004072 if (child == mFocused) {
4073 child.clearFocus();
4074 }
Romain Guy8506ab42009-06-11 17:35:47 -07004075
Svetoslav Ganov961bf0e2012-05-08 09:40:03 -07004076 child.clearAccessibilityFocus();
4077
Jeff Brown59a422e2012-04-19 15:19:19 -07004078 cancelTouchTarget(child);
4079 cancelHoverTarget(child);
4080
Chet Haase21cd1382010-09-01 17:42:29 -07004081 if ((animate && child.getAnimation() != null) ||
4082 (mTransitioningViews != null && mTransitioningViews.contains(child))) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004083 addDisappearingView(child);
4084 } else if (child.mAttachInfo != null) {
4085 child.dispatchDetachedFromWindow();
4086 }
4087
Adam Powell539ee872012-02-03 19:00:49 -08004088 if (child.hasTransientState()) {
4089 childHasTransientStateChanged(child, false);
4090 }
4091
Philip Milnef51d91c2011-07-18 16:12:19 -07004092 onViewRemoved(child);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004093 }
4094
4095 /**
4096 * Attaches a view to this view group. Attaching a view assigns this group as the parent,
Chet Haaseca479d42012-08-30 17:20:08 -07004097 * sets the layout parameters and puts the view in the list of children so that
4098 * it can be retrieved by calling {@link #getChildAt(int)}.
4099 * <p>
4100 * This method is intended to be lightweight and makes no assumptions about whether the
4101 * parent or child should be redrawn. Proper use of this method will include also making
4102 * any appropriate {@link #requestLayout()} or {@link #invalidate()} calls.
4103 * For example, callers can {@link #post(Runnable) post} a {@link Runnable}
4104 * which performs a {@link #requestLayout()} on the next frame, after all detach/attach
4105 * calls are finished, causing layout to be run prior to redrawing the view hierarchy.
4106 * <p>
4107 * This method should be called only for views which were detached from their parent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004108 *
4109 * @param child the child to attach
4110 * @param index the index at which the child should be attached
4111 * @param params the layout parameters of the child
4112 *
4113 * @see #removeDetachedView(View, boolean)
4114 * @see #detachAllViewsFromParent()
4115 * @see #detachViewFromParent(View)
4116 * @see #detachViewFromParent(int)
4117 */
4118 protected void attachViewToParent(View child, int index, LayoutParams params) {
4119 child.mLayoutParams = params;
4120
4121 if (index < 0) {
4122 index = mChildrenCount;
4123 }
4124
4125 addInArray(child, index);
4126
4127 child.mParent = this;
Dianne Hackborn4702a852012-08-17 15:18:29 -07004128 child.mPrivateFlags = (child.mPrivateFlags & ~PFLAG_DIRTY_MASK
4129 & ~PFLAG_DRAWING_CACHE_VALID)
4130 | PFLAG_DRAWN | PFLAG_INVALIDATED;
4131 this.mPrivateFlags |= PFLAG_INVALIDATED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004132
4133 if (child.hasFocus()) {
4134 requestChildFocus(child, child.findFocus());
4135 }
4136 }
4137
4138 /**
Chet Haaseca479d42012-08-30 17:20:08 -07004139 * Detaches a view from its parent. Detaching a view should be followed
4140 * either by a call to
4141 * {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
4142 * or a call to {@link #removeDetachedView(View, boolean)}. Detachment should only be
4143 * temporary; reattachment or removal should happen within the same drawing cycle as
4144 * detachment. When a view is detached, its parent is null and cannot be retrieved by a
4145 * call to {@link #getChildAt(int)}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004146 *
4147 * @param child the child to detach
4148 *
4149 * @see #detachViewFromParent(int)
4150 * @see #detachViewsFromParent(int, int)
4151 * @see #detachAllViewsFromParent()
4152 * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
4153 * @see #removeDetachedView(View, boolean)
4154 */
4155 protected void detachViewFromParent(View child) {
4156 removeFromArray(indexOfChild(child));
4157 }
4158
4159 /**
Chet Haaseca479d42012-08-30 17:20:08 -07004160 * Detaches a view from its parent. Detaching a view should be followed
4161 * either by a call to
4162 * {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
4163 * or a call to {@link #removeDetachedView(View, boolean)}. Detachment should only be
4164 * temporary; reattachment or removal should happen within the same drawing cycle as
4165 * detachment. When a view is detached, its parent is null and cannot be retrieved by a
4166 * call to {@link #getChildAt(int)}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004167 *
4168 * @param index the index of the child to detach
4169 *
4170 * @see #detachViewFromParent(View)
4171 * @see #detachAllViewsFromParent()
4172 * @see #detachViewsFromParent(int, int)
4173 * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
4174 * @see #removeDetachedView(View, boolean)
4175 */
4176 protected void detachViewFromParent(int index) {
4177 removeFromArray(index);
4178 }
4179
4180 /**
Chet Haaseca479d42012-08-30 17:20:08 -07004181 * Detaches a range of views from their parents. Detaching a view should be followed
4182 * either by a call to
4183 * {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
4184 * or a call to {@link #removeDetachedView(View, boolean)}. Detachment should only be
4185 * temporary; reattachment or removal should happen within the same drawing cycle as
4186 * detachment. When a view is detached, its parent is null and cannot be retrieved by a
4187 * call to {@link #getChildAt(int)}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004188 *
4189 * @param start the first index of the childrend range to detach
4190 * @param count the number of children to detach
4191 *
4192 * @see #detachViewFromParent(View)
4193 * @see #detachViewFromParent(int)
4194 * @see #detachAllViewsFromParent()
4195 * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
4196 * @see #removeDetachedView(View, boolean)
4197 */
4198 protected void detachViewsFromParent(int start, int count) {
4199 removeFromArray(start, count);
4200 }
4201
4202 /**
Chet Haaseca479d42012-08-30 17:20:08 -07004203 * Detaches all views from the parent. Detaching a view should be followed
4204 * either by a call to
4205 * {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
4206 * or a call to {@link #removeDetachedView(View, boolean)}. Detachment should only be
4207 * temporary; reattachment or removal should happen within the same drawing cycle as
4208 * detachment. When a view is detached, its parent is null and cannot be retrieved by a
4209 * call to {@link #getChildAt(int)}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004210 *
4211 * @see #detachViewFromParent(View)
4212 * @see #detachViewFromParent(int)
4213 * @see #detachViewsFromParent(int, int)
4214 * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
4215 * @see #removeDetachedView(View, boolean)
4216 */
4217 protected void detachAllViewsFromParent() {
4218 final int count = mChildrenCount;
4219 if (count <= 0) {
4220 return;
4221 }
4222
4223 final View[] children = mChildren;
4224 mChildrenCount = 0;
4225
4226 for (int i = count - 1; i >= 0; i--) {
4227 children[i].mParent = null;
4228 children[i] = null;
4229 }
4230 }
4231
4232 /**
4233 * Don't call or override this method. It is used for the implementation of
4234 * the view hierarchy.
4235 */
4236 public final void invalidateChild(View child, final Rect dirty) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004237 ViewParent parent = this;
4238
4239 final AttachInfo attachInfo = mAttachInfo;
4240 if (attachInfo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004241 // If the child is drawing an animation, we want to copy this flag onto
4242 // ourselves and the parent to make sure the invalidate request goes
4243 // through
Dianne Hackborn4702a852012-08-17 15:18:29 -07004244 final boolean drawAnimation = (child.mPrivateFlags & PFLAG_DRAW_ANIMATION)
4245 == PFLAG_DRAW_ANIMATION;
Romain Guy24443ea2009-05-11 11:56:30 -07004246
Romain Guyfe455af2012-02-15 16:40:20 -08004247 // Check whether the child that requests the invalidate is fully opaque
4248 // Views being animated or transformed are not considered opaque because we may
4249 // be invalidating their old position and need the parent to paint behind them.
4250 Matrix childMatrix = child.getMatrix();
4251 final boolean isOpaque = child.isOpaque() && !drawAnimation &&
4252 child.getAnimation() == null && childMatrix.isIdentity();
4253 // Mark the child as dirty, using the appropriate flag
4254 // Make sure we do not set both flags at the same time
Dianne Hackborn4702a852012-08-17 15:18:29 -07004255 int opaqueFlag = isOpaque ? PFLAG_DIRTY_OPAQUE : PFLAG_DIRTY;
Romain Guyfe455af2012-02-15 16:40:20 -08004256
4257 if (child.mLayerType != LAYER_TYPE_NONE) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07004258 mPrivateFlags |= PFLAG_INVALIDATED;
4259 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
Romain Guyfe455af2012-02-15 16:40:20 -08004260 child.mLocalDirtyRect.union(dirty);
4261 }
4262
4263 final int[] location = attachInfo.mInvalidateChildLocation;
4264 location[CHILD_LEFT_INDEX] = child.mLeft;
4265 location[CHILD_TOP_INDEX] = child.mTop;
Chet Haase599913d2012-07-23 16:22:05 -07004266 if (!childMatrix.isIdentity() ||
4267 (mGroupFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) {
Romain Guyfe455af2012-02-15 16:40:20 -08004268 RectF boundingRect = attachInfo.mTmpTransformRect;
4269 boundingRect.set(dirty);
Chet Haase599913d2012-07-23 16:22:05 -07004270 Matrix transformMatrix;
4271 if ((mGroupFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) {
4272 Transformation t = attachInfo.mTmpTransformation;
4273 boolean transformed = getChildStaticTransformation(child, t);
4274 if (transformed) {
4275 transformMatrix = attachInfo.mTmpMatrix;
4276 transformMatrix.set(t.getMatrix());
4277 if (!childMatrix.isIdentity()) {
4278 transformMatrix.preConcat(childMatrix);
4279 }
4280 } else {
4281 transformMatrix = childMatrix;
4282 }
4283 } else {
4284 transformMatrix = childMatrix;
4285 }
4286 transformMatrix.mapRect(boundingRect);
Romain Guyfe455af2012-02-15 16:40:20 -08004287 dirty.set((int) (boundingRect.left - 0.5f),
4288 (int) (boundingRect.top - 0.5f),
4289 (int) (boundingRect.right + 0.5f),
4290 (int) (boundingRect.bottom + 0.5f));
4291 }
4292
4293 do {
4294 View view = null;
4295 if (parent instanceof View) {
4296 view = (View) parent;
Romain Guyfe455af2012-02-15 16:40:20 -08004297 }
4298
4299 if (drawAnimation) {
4300 if (view != null) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07004301 view.mPrivateFlags |= PFLAG_DRAW_ANIMATION;
Romain Guyfe455af2012-02-15 16:40:20 -08004302 } else if (parent instanceof ViewRootImpl) {
4303 ((ViewRootImpl) parent).mIsAnimating = true;
4304 }
4305 }
4306
4307 // If the parent is dirty opaque or not dirty, mark it dirty with the opaque
4308 // flag coming from the child that initiated the invalidate
4309 if (view != null) {
4310 if ((view.mViewFlags & FADING_EDGE_MASK) != 0 &&
4311 view.getSolidColor() == 0) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07004312 opaqueFlag = PFLAG_DIRTY;
Romain Guyfe455af2012-02-15 16:40:20 -08004313 }
Dianne Hackborn4702a852012-08-17 15:18:29 -07004314 if ((view.mPrivateFlags & PFLAG_DIRTY_MASK) != PFLAG_DIRTY) {
4315 view.mPrivateFlags = (view.mPrivateFlags & ~PFLAG_DIRTY_MASK) | opaqueFlag;
Romain Guyfe455af2012-02-15 16:40:20 -08004316 }
4317 }
4318
4319 parent = parent.invalidateChildInParent(location, dirty);
4320 if (view != null) {
4321 // Account for transform on current parent
4322 Matrix m = view.getMatrix();
4323 if (!m.isIdentity()) {
4324 RectF boundingRect = attachInfo.mTmpTransformRect;
4325 boundingRect.set(dirty);
4326 m.mapRect(boundingRect);
Romain Guye8585b12012-02-17 18:28:47 -08004327 dirty.set((int) (boundingRect.left - 0.5f),
4328 (int) (boundingRect.top - 0.5f),
Romain Guyfe455af2012-02-15 16:40:20 -08004329 (int) (boundingRect.right + 0.5f),
4330 (int) (boundingRect.bottom + 0.5f));
4331 }
4332 }
4333 } while (parent != null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004334 }
4335 }
4336
4337 /**
4338 * Don't call or override this method. It is used for the implementation of
4339 * the view hierarchy.
4340 *
4341 * This implementation returns null if this ViewGroup does not have a parent,
4342 * if this ViewGroup is already fully invalidated or if the dirty rectangle
4343 * does not intersect with this ViewGroup's bounds.
4344 */
4345 public ViewParent invalidateChildInParent(final int[] location, final Rect dirty) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07004346 if ((mPrivateFlags & PFLAG_DRAWN) == PFLAG_DRAWN ||
4347 (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004348 if ((mGroupFlags & (FLAG_OPTIMIZE_INVALIDATE | FLAG_ANIMATION_DONE)) !=
4349 FLAG_OPTIMIZE_INVALIDATE) {
4350 dirty.offset(location[CHILD_LEFT_INDEX] - mScrollX,
4351 location[CHILD_TOP_INDEX] - mScrollY);
Chet Haasea4f14eb2013-04-22 11:11:39 -07004352 if ((mGroupFlags & FLAG_CLIP_CHILDREN) == 0) {
4353 dirty.union(0, 0, mRight - mLeft, mBottom - mTop);
4354 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004355
4356 final int left = mLeft;
4357 final int top = mTop;
4358
Chet Haase05e91ed2012-07-03 14:17:57 -07004359 if ((mGroupFlags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN) {
4360 if (!dirty.intersect(0, 0, mRight - left, mBottom - top)) {
4361 dirty.setEmpty();
Romain Guy3a3133d2011-02-01 22:59:58 -08004362 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004363 }
Dianne Hackborn4702a852012-08-17 15:18:29 -07004364 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
Chet Haase05e91ed2012-07-03 14:17:57 -07004365
4366 location[CHILD_LEFT_INDEX] = left;
4367 location[CHILD_TOP_INDEX] = top;
4368
4369 if (mLayerType != LAYER_TYPE_NONE) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07004370 mPrivateFlags |= PFLAG_INVALIDATED;
Chet Haase05e91ed2012-07-03 14:17:57 -07004371 mLocalDirtyRect.union(dirty);
4372 }
4373
4374 return mParent;
4375
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004376 } else {
Dianne Hackborn4702a852012-08-17 15:18:29 -07004377 mPrivateFlags &= ~PFLAG_DRAWN & ~PFLAG_DRAWING_CACHE_VALID;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004378
4379 location[CHILD_LEFT_INDEX] = mLeft;
4380 location[CHILD_TOP_INDEX] = mTop;
Chet Haasea3db8662011-07-19 10:36:05 -07004381 if ((mGroupFlags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN) {
4382 dirty.set(0, 0, mRight - mLeft, mBottom - mTop);
4383 } else {
4384 // in case the dirty rect extends outside the bounds of this container
4385 dirty.union(0, 0, mRight - mLeft, mBottom - mTop);
4386 }
Romain Guy3a3133d2011-02-01 22:59:58 -08004387
4388 if (mLayerType != LAYER_TYPE_NONE) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07004389 mPrivateFlags |= PFLAG_INVALIDATED;
Romain Guy3a3133d2011-02-01 22:59:58 -08004390 mLocalDirtyRect.union(dirty);
4391 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004392
4393 return mParent;
4394 }
4395 }
4396
4397 return null;
4398 }
4399
4400 /**
Chet Haase9d1992d2012-03-13 11:03:25 -07004401 * Quick invalidation method called by View.invalidateViewProperty. This doesn't set the
4402 * DRAWN flags and doesn't handle the Animation logic that the default invalidation methods
4403 * do; all we want to do here is schedule a traversal with the appropriate dirty rect.
4404 *
4405 * @hide
4406 */
4407 public void invalidateChildFast(View child, final Rect dirty) {
4408 ViewParent parent = this;
4409
4410 final AttachInfo attachInfo = mAttachInfo;
4411 if (attachInfo != null) {
4412 if (child.mLayerType != LAYER_TYPE_NONE) {
4413 child.mLocalDirtyRect.union(dirty);
4414 }
4415
4416 int left = child.mLeft;
4417 int top = child.mTop;
4418 if (!child.getMatrix().isIdentity()) {
4419 child.transformRect(dirty);
4420 }
4421
4422 do {
4423 if (parent instanceof ViewGroup) {
4424 ViewGroup parentVG = (ViewGroup) parent;
Chet Haaseb85967b2012-03-26 14:37:51 -07004425 if (parentVG.mLayerType != LAYER_TYPE_NONE) {
4426 // Layered parents should be recreated, not just re-issued
4427 parentVG.invalidate();
4428 parent = null;
4429 } else {
4430 parent = parentVG.invalidateChildInParentFast(left, top, dirty);
4431 left = parentVG.mLeft;
4432 top = parentVG.mTop;
4433 }
Chet Haase9d1992d2012-03-13 11:03:25 -07004434 } else {
4435 // Reached the top; this calls into the usual invalidate method in
4436 // ViewRootImpl, which schedules a traversal
4437 final int[] location = attachInfo.mInvalidateChildLocation;
4438 location[0] = left;
4439 location[1] = top;
4440 parent = parent.invalidateChildInParent(location, dirty);
4441 }
4442 } while (parent != null);
4443 }
4444 }
4445
4446 /**
4447 * Quick invalidation method that simply transforms the dirty rect into the parent's
4448 * coordinate system, pruning the invalidation if the parent has already been invalidated.
Chet Haasee4a2d7c2013-06-21 17:49:36 -07004449 *
4450 * @hide
Chet Haase9d1992d2012-03-13 11:03:25 -07004451 */
Chet Haasee4a2d7c2013-06-21 17:49:36 -07004452 protected ViewParent invalidateChildInParentFast(int left, int top, final Rect dirty) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07004453 if ((mPrivateFlags & PFLAG_DRAWN) == PFLAG_DRAWN ||
4454 (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID) {
Chet Haase9d1992d2012-03-13 11:03:25 -07004455 dirty.offset(left - mScrollX, top - mScrollY);
Chet Haasea4f14eb2013-04-22 11:11:39 -07004456 if ((mGroupFlags & FLAG_CLIP_CHILDREN) == 0) {
4457 dirty.union(0, 0, mRight - mLeft, mBottom - mTop);
4458 }
Chet Haase9d1992d2012-03-13 11:03:25 -07004459
4460 if ((mGroupFlags & FLAG_CLIP_CHILDREN) == 0 ||
4461 dirty.intersect(0, 0, mRight - mLeft, mBottom - mTop)) {
4462
4463 if (mLayerType != LAYER_TYPE_NONE) {
4464 mLocalDirtyRect.union(dirty);
4465 }
4466 if (!getMatrix().isIdentity()) {
4467 transformRect(dirty);
4468 }
4469
4470 return mParent;
4471 }
4472 }
4473
4474 return null;
4475 }
4476
4477 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004478 * Offset a rectangle that is in a descendant's coordinate
4479 * space into our coordinate space.
4480 * @param descendant A descendant of this view
4481 * @param rect A rectangle defined in descendant's coordinate space.
4482 */
4483 public final void offsetDescendantRectToMyCoords(View descendant, Rect rect) {
4484 offsetRectBetweenParentAndChild(descendant, rect, true, false);
4485 }
4486
4487 /**
4488 * Offset a rectangle that is in our coordinate space into an ancestor's
4489 * coordinate space.
4490 * @param descendant A descendant of this view
4491 * @param rect A rectangle defined in descendant's coordinate space.
4492 */
4493 public final void offsetRectIntoDescendantCoords(View descendant, Rect rect) {
4494 offsetRectBetweenParentAndChild(descendant, rect, false, false);
4495 }
4496
4497 /**
4498 * Helper method that offsets a rect either from parent to descendant or
4499 * descendant to parent.
4500 */
4501 void offsetRectBetweenParentAndChild(View descendant, Rect rect,
4502 boolean offsetFromChildToParent, boolean clipToBounds) {
4503
4504 // already in the same coord system :)
4505 if (descendant == this) {
4506 return;
4507 }
4508
4509 ViewParent theParent = descendant.mParent;
4510
4511 // search and offset up to the parent
4512 while ((theParent != null)
4513 && (theParent instanceof View)
4514 && (theParent != this)) {
4515
4516 if (offsetFromChildToParent) {
4517 rect.offset(descendant.mLeft - descendant.mScrollX,
4518 descendant.mTop - descendant.mScrollY);
4519 if (clipToBounds) {
4520 View p = (View) theParent;
4521 rect.intersect(0, 0, p.mRight - p.mLeft, p.mBottom - p.mTop);
4522 }
4523 } else {
4524 if (clipToBounds) {
4525 View p = (View) theParent;
4526 rect.intersect(0, 0, p.mRight - p.mLeft, p.mBottom - p.mTop);
4527 }
4528 rect.offset(descendant.mScrollX - descendant.mLeft,
4529 descendant.mScrollY - descendant.mTop);
4530 }
4531
4532 descendant = (View) theParent;
4533 theParent = descendant.mParent;
4534 }
4535
4536 // now that we are up to this view, need to offset one more time
4537 // to get into our coordinate space
4538 if (theParent == this) {
4539 if (offsetFromChildToParent) {
4540 rect.offset(descendant.mLeft - descendant.mScrollX,
4541 descendant.mTop - descendant.mScrollY);
4542 } else {
4543 rect.offset(descendant.mScrollX - descendant.mLeft,
4544 descendant.mScrollY - descendant.mTop);
4545 }
4546 } else {
4547 throw new IllegalArgumentException("parameter must be a descendant of this view");
4548 }
4549 }
4550
4551 /**
4552 * Offset the vertical location of all children of this view by the specified number of pixels.
4553 *
4554 * @param offset the number of pixels to offset
4555 *
4556 * @hide
4557 */
4558 public void offsetChildrenTopAndBottom(int offset) {
4559 final int count = mChildrenCount;
4560 final View[] children = mChildren;
Romain Guy5549cb52013-05-06 18:42:08 -07004561 boolean invalidate = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004562
4563 for (int i = 0; i < count; i++) {
4564 final View v = children[i];
4565 v.mTop += offset;
4566 v.mBottom += offset;
Chet Haase1271e2c2012-04-20 09:54:27 -07004567 if (v.mDisplayList != null) {
Romain Guy5549cb52013-05-06 18:42:08 -07004568 invalidate = true;
Romain Guy52036b12013-02-14 18:03:37 -08004569 v.mDisplayList.offsetTopAndBottom(offset);
Chet Haasea1cff502012-02-21 13:43:44 -08004570 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004571 }
Romain Guy5549cb52013-05-06 18:42:08 -07004572
4573 if (invalidate) {
4574 invalidateViewProperty(false, false);
4575 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004576 }
4577
4578 /**
4579 * {@inheritDoc}
4580 */
4581 public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) {
Adam Powellf93bb6d2011-12-12 15:21:57 -08004582 // It doesn't make a whole lot of sense to call this on a view that isn't attached,
4583 // but for some simple tests it can be useful. If we don't have attach info this
4584 // will allocate memory.
4585 final RectF rect = mAttachInfo != null ? mAttachInfo.mTmpTransformRect : new RectF();
Gilles Debunnecea45132011-11-24 02:19:27 +01004586 rect.set(r);
4587
4588 if (!child.hasIdentityMatrix()) {
4589 child.getMatrix().mapRect(rect);
4590 }
4591
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004592 int dx = child.mLeft - mScrollX;
4593 int dy = child.mTop - mScrollY;
Gilles Debunnecea45132011-11-24 02:19:27 +01004594
4595 rect.offset(dx, dy);
4596
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004597 if (offset != null) {
Gilles Debunnecea45132011-11-24 02:19:27 +01004598 if (!child.hasIdentityMatrix()) {
Adam Powellf93bb6d2011-12-12 15:21:57 -08004599 float[] position = mAttachInfo != null ? mAttachInfo.mTmpTransformLocation
4600 : new float[2];
Gilles Debunnecea45132011-11-24 02:19:27 +01004601 position[0] = offset.x;
4602 position[1] = offset.y;
4603 child.getMatrix().mapPoints(position);
4604 offset.x = (int) (position[0] + 0.5f);
4605 offset.y = (int) (position[1] + 0.5f);
4606 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004607 offset.x += dx;
4608 offset.y += dy;
4609 }
Gilles Debunnecea45132011-11-24 02:19:27 +01004610
4611 if (rect.intersect(0, 0, mRight - mLeft, mBottom - mTop)) {
4612 if (mParent == null) return true;
4613 r.set((int) (rect.left + 0.5f), (int) (rect.top + 0.5f),
4614 (int) (rect.right + 0.5f), (int) (rect.bottom + 0.5f));
4615 return mParent.getChildVisibleRect(this, r, offset);
4616 }
4617
4618 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004619 }
4620
4621 /**
4622 * {@inheritDoc}
4623 */
4624 @Override
Chet Haase9c087442011-01-12 16:20:16 -08004625 public final void layout(int l, int t, int r, int b) {
Chet Haase430742f2013-04-12 11:18:36 -07004626 if (!mSuppressLayout && (mTransition == null || !mTransition.isChangingLayout())) {
Chet Haase7dd4a532012-04-16 13:35:09 -07004627 if (mTransition != null) {
4628 mTransition.layoutChange(this);
4629 }
Chet Haase9c087442011-01-12 16:20:16 -08004630 super.layout(l, t, r, b);
4631 } else {
4632 // record the fact that we noop'd it; request layout when transition finishes
Chet Haaseb9895022013-04-02 15:10:58 -07004633 mLayoutCalledWhileSuppressed = true;
Chet Haase9c087442011-01-12 16:20:16 -08004634 }
4635 }
4636
4637 /**
4638 * {@inheritDoc}
4639 */
4640 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004641 protected abstract void onLayout(boolean changed,
4642 int l, int t, int r, int b);
4643
4644 /**
4645 * Indicates whether the view group has the ability to animate its children
4646 * after the first layout.
4647 *
4648 * @return true if the children can be animated, false otherwise
4649 */
4650 protected boolean canAnimate() {
4651 return mLayoutAnimationController != null;
4652 }
4653
4654 /**
4655 * Runs the layout animation. Calling this method triggers a relayout of
4656 * this view group.
4657 */
4658 public void startLayoutAnimation() {
4659 if (mLayoutAnimationController != null) {
4660 mGroupFlags |= FLAG_RUN_ANIMATION;
4661 requestLayout();
4662 }
4663 }
4664
4665 /**
4666 * Schedules the layout animation to be played after the next layout pass
4667 * of this view group. This can be used to restart the layout animation
4668 * when the content of the view group changes or when the activity is
4669 * paused and resumed.
4670 */
4671 public void scheduleLayoutAnimation() {
4672 mGroupFlags |= FLAG_RUN_ANIMATION;
4673 }
4674
4675 /**
4676 * Sets the layout animation controller used to animate the group's
4677 * children after the first layout.
4678 *
4679 * @param controller the animation controller
4680 */
4681 public void setLayoutAnimation(LayoutAnimationController controller) {
4682 mLayoutAnimationController = controller;
4683 if (mLayoutAnimationController != null) {
4684 mGroupFlags |= FLAG_RUN_ANIMATION;
4685 }
4686 }
4687
4688 /**
4689 * Returns the layout animation controller used to animate the group's
4690 * children.
4691 *
4692 * @return the current animation controller
4693 */
4694 public LayoutAnimationController getLayoutAnimation() {
4695 return mLayoutAnimationController;
4696 }
4697
4698 /**
4699 * Indicates whether the children's drawing cache is used during a layout
4700 * animation. By default, the drawing cache is enabled but this will prevent
4701 * nested layout animations from working. To nest animations, you must disable
4702 * the cache.
4703 *
4704 * @return true if the animation cache is enabled, false otherwise
4705 *
4706 * @see #setAnimationCacheEnabled(boolean)
4707 * @see View#setDrawingCacheEnabled(boolean)
4708 */
4709 @ViewDebug.ExportedProperty
4710 public boolean isAnimationCacheEnabled() {
4711 return (mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE;
4712 }
4713
4714 /**
4715 * Enables or disables the children's drawing cache during a layout animation.
4716 * By default, the drawing cache is enabled but this will prevent nested
4717 * layout animations from working. To nest animations, you must disable the
4718 * cache.
4719 *
4720 * @param enabled true to enable the animation cache, false otherwise
4721 *
4722 * @see #isAnimationCacheEnabled()
4723 * @see View#setDrawingCacheEnabled(boolean)
4724 */
4725 public void setAnimationCacheEnabled(boolean enabled) {
4726 setBooleanFlag(FLAG_ANIMATION_CACHE, enabled);
4727 }
4728
4729 /**
4730 * Indicates whether this ViewGroup will always try to draw its children using their
4731 * drawing cache. By default this property is enabled.
4732 *
4733 * @return true if the animation cache is enabled, false otherwise
4734 *
4735 * @see #setAlwaysDrawnWithCacheEnabled(boolean)
4736 * @see #setChildrenDrawnWithCacheEnabled(boolean)
4737 * @see View#setDrawingCacheEnabled(boolean)
4738 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07004739 @ViewDebug.ExportedProperty(category = "drawing")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004740 public boolean isAlwaysDrawnWithCacheEnabled() {
4741 return (mGroupFlags & FLAG_ALWAYS_DRAWN_WITH_CACHE) == FLAG_ALWAYS_DRAWN_WITH_CACHE;
4742 }
4743
4744 /**
4745 * Indicates whether this ViewGroup will always try to draw its children using their
4746 * drawing cache. This property can be set to true when the cache rendering is
4747 * slightly different from the children's normal rendering. Renderings can be different,
4748 * for instance, when the cache's quality is set to low.
4749 *
4750 * When this property is disabled, the ViewGroup will use the drawing cache of its
4751 * children only when asked to. It's usually the task of subclasses to tell ViewGroup
4752 * when to start using the drawing cache and when to stop using it.
4753 *
4754 * @param always true to always draw with the drawing cache, false otherwise
4755 *
4756 * @see #isAlwaysDrawnWithCacheEnabled()
4757 * @see #setChildrenDrawnWithCacheEnabled(boolean)
4758 * @see View#setDrawingCacheEnabled(boolean)
4759 * @see View#setDrawingCacheQuality(int)
4760 */
4761 public void setAlwaysDrawnWithCacheEnabled(boolean always) {
4762 setBooleanFlag(FLAG_ALWAYS_DRAWN_WITH_CACHE, always);
4763 }
4764
4765 /**
4766 * Indicates whether the ViewGroup is currently drawing its children using
4767 * their drawing cache.
4768 *
4769 * @return true if children should be drawn with their cache, false otherwise
4770 *
4771 * @see #setAlwaysDrawnWithCacheEnabled(boolean)
4772 * @see #setChildrenDrawnWithCacheEnabled(boolean)
4773 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07004774 @ViewDebug.ExportedProperty(category = "drawing")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004775 protected boolean isChildrenDrawnWithCacheEnabled() {
4776 return (mGroupFlags & FLAG_CHILDREN_DRAWN_WITH_CACHE) == FLAG_CHILDREN_DRAWN_WITH_CACHE;
4777 }
4778
4779 /**
4780 * Tells the ViewGroup to draw its children using their drawing cache. This property
4781 * is ignored when {@link #isAlwaysDrawnWithCacheEnabled()} is true. A child's drawing cache
4782 * will be used only if it has been enabled.
4783 *
4784 * Subclasses should call this method to start and stop using the drawing cache when
4785 * they perform performance sensitive operations, like scrolling or animating.
4786 *
4787 * @param enabled true if children should be drawn with their cache, false otherwise
4788 *
4789 * @see #setAlwaysDrawnWithCacheEnabled(boolean)
4790 * @see #isChildrenDrawnWithCacheEnabled()
4791 */
4792 protected void setChildrenDrawnWithCacheEnabled(boolean enabled) {
4793 setBooleanFlag(FLAG_CHILDREN_DRAWN_WITH_CACHE, enabled);
4794 }
4795
Romain Guy293451e2009-11-04 13:59:48 -08004796 /**
4797 * Indicates whether the ViewGroup is drawing its children in the order defined by
4798 * {@link #getChildDrawingOrder(int, int)}.
4799 *
4800 * @return true if children drawing order is defined by {@link #getChildDrawingOrder(int, int)},
4801 * false otherwise
4802 *
4803 * @see #setChildrenDrawingOrderEnabled(boolean)
4804 * @see #getChildDrawingOrder(int, int)
4805 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07004806 @ViewDebug.ExportedProperty(category = "drawing")
Romain Guy293451e2009-11-04 13:59:48 -08004807 protected boolean isChildrenDrawingOrderEnabled() {
4808 return (mGroupFlags & FLAG_USE_CHILD_DRAWING_ORDER) == FLAG_USE_CHILD_DRAWING_ORDER;
4809 }
4810
4811 /**
4812 * Tells the ViewGroup whether to draw its children in the order defined by the method
4813 * {@link #getChildDrawingOrder(int, int)}.
4814 *
4815 * @param enabled true if the order of the children when drawing is determined by
4816 * {@link #getChildDrawingOrder(int, int)}, false otherwise
4817 *
4818 * @see #isChildrenDrawingOrderEnabled()
4819 * @see #getChildDrawingOrder(int, int)
4820 */
4821 protected void setChildrenDrawingOrderEnabled(boolean enabled) {
4822 setBooleanFlag(FLAG_USE_CHILD_DRAWING_ORDER, enabled);
4823 }
4824
Svetoslav6254f482013-06-04 17:22:14 -07004825 private boolean hasBooleanFlag(int flag) {
Philip Milnef091b662013-02-27 11:15:21 -08004826 return (mGroupFlags & flag) == flag;
4827 }
4828
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004829 private void setBooleanFlag(int flag, boolean value) {
4830 if (value) {
4831 mGroupFlags |= flag;
4832 } else {
4833 mGroupFlags &= ~flag;
4834 }
4835 }
4836
4837 /**
4838 * Returns an integer indicating what types of drawing caches are kept in memory.
4839 *
4840 * @see #setPersistentDrawingCache(int)
4841 * @see #setAnimationCacheEnabled(boolean)
4842 *
4843 * @return one or a combination of {@link #PERSISTENT_NO_CACHE},
4844 * {@link #PERSISTENT_ANIMATION_CACHE}, {@link #PERSISTENT_SCROLLING_CACHE}
4845 * and {@link #PERSISTENT_ALL_CACHES}
4846 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07004847 @ViewDebug.ExportedProperty(category = "drawing", mapping = {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004848 @ViewDebug.IntToString(from = PERSISTENT_NO_CACHE, to = "NONE"),
Romain Guy203688c2010-05-12 15:41:32 -07004849 @ViewDebug.IntToString(from = PERSISTENT_ANIMATION_CACHE, to = "ANIMATION"),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004850 @ViewDebug.IntToString(from = PERSISTENT_SCROLLING_CACHE, to = "SCROLLING"),
4851 @ViewDebug.IntToString(from = PERSISTENT_ALL_CACHES, to = "ALL")
4852 })
4853 public int getPersistentDrawingCache() {
4854 return mPersistentDrawingCache;
4855 }
4856
4857 /**
4858 * Indicates what types of drawing caches should be kept in memory after
4859 * they have been created.
4860 *
4861 * @see #getPersistentDrawingCache()
4862 * @see #setAnimationCacheEnabled(boolean)
4863 *
4864 * @param drawingCacheToKeep one or a combination of {@link #PERSISTENT_NO_CACHE},
4865 * {@link #PERSISTENT_ANIMATION_CACHE}, {@link #PERSISTENT_SCROLLING_CACHE}
4866 * and {@link #PERSISTENT_ALL_CACHES}
4867 */
4868 public void setPersistentDrawingCache(int drawingCacheToKeep) {
4869 mPersistentDrawingCache = drawingCacheToKeep & PERSISTENT_ALL_CACHES;
4870 }
4871
Philip Milnef091b662013-02-27 11:15:21 -08004872 private void setLayoutMode(int layoutMode, boolean explicitly) {
4873 mLayoutMode = layoutMode;
4874 setBooleanFlag(FLAG_LAYOUT_MODE_WAS_EXPLICITLY_SET, explicitly);
4875 }
4876
4877 /**
4878 * Recursively traverse the view hierarchy, resetting the layoutMode of any
4879 * descendants that had inherited a different layoutMode from a previous parent.
4880 * Recursion terminates when a descendant's mode is:
4881 * <ul>
4882 * <li>Undefined</li>
4883 * <li>The same as the root node's</li>
4884 * <li>A mode that had been explicitly set</li>
4885 * <ul/>
4886 * The first two clauses are optimizations.
4887 * @param layoutModeOfRoot
4888 */
4889 @Override
4890 void invalidateInheritedLayoutMode(int layoutModeOfRoot) {
4891 if (mLayoutMode == LAYOUT_MODE_UNDEFINED ||
4892 mLayoutMode == layoutModeOfRoot ||
Svetoslav6254f482013-06-04 17:22:14 -07004893 hasBooleanFlag(FLAG_LAYOUT_MODE_WAS_EXPLICITLY_SET)) {
Philip Milnef091b662013-02-27 11:15:21 -08004894 return;
4895 }
4896 setLayoutMode(LAYOUT_MODE_UNDEFINED, false);
4897
4898 // apply recursively
4899 for (int i = 0, N = getChildCount(); i < N; i++) {
4900 getChildAt(i).invalidateInheritedLayoutMode(layoutModeOfRoot);
4901 }
4902 }
4903
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004904 /**
Philip Milnecfb631b2012-10-26 10:51:46 -07004905 * Returns the basis of alignment during layout operations on this ViewGroup:
Philip Milne7b757812012-09-19 18:13:44 -07004906 * either {@link #LAYOUT_MODE_CLIP_BOUNDS} or {@link #LAYOUT_MODE_OPTICAL_BOUNDS}.
Philip Milnecfb631b2012-10-26 10:51:46 -07004907 * <p>
4908 * If no layoutMode was explicitly set, either programmatically or in an XML resource,
4909 * the method returns the layoutMode of the view's parent ViewGroup if such a parent exists,
4910 * otherwise the method returns a default value of {@link #LAYOUT_MODE_CLIP_BOUNDS}.
Philip Milne1557fd72012-04-04 23:41:34 -07004911 *
Philip Milnefcc6a0f2012-04-16 16:12:19 -07004912 * @return the layout mode to use during layout operations
Philip Milne1557fd72012-04-04 23:41:34 -07004913 *
4914 * @see #setLayoutMode(int)
4915 */
4916 public int getLayoutMode() {
Philip Milnecfb631b2012-10-26 10:51:46 -07004917 if (mLayoutMode == LAYOUT_MODE_UNDEFINED) {
Philip Milnef091b662013-02-27 11:15:21 -08004918 int inheritedLayoutMode = (mParent instanceof ViewGroup) ?
4919 ((ViewGroup) mParent).getLayoutMode() : LAYOUT_MODE_DEFAULT;
4920 setLayoutMode(inheritedLayoutMode, false);
Philip Milnecfb631b2012-10-26 10:51:46 -07004921 }
Philip Milne1557fd72012-04-04 23:41:34 -07004922 return mLayoutMode;
4923 }
4924
4925 /**
Philip Milnecfb631b2012-10-26 10:51:46 -07004926 * Sets the basis of alignment during the layout of this ViewGroup.
Philip Milne7b757812012-09-19 18:13:44 -07004927 * Valid values are either {@link #LAYOUT_MODE_CLIP_BOUNDS} or
4928 * {@link #LAYOUT_MODE_OPTICAL_BOUNDS}.
Philip Milne1557fd72012-04-04 23:41:34 -07004929 *
Philip Milnefcc6a0f2012-04-16 16:12:19 -07004930 * @param layoutMode the layout mode to use during layout operations
Philip Milne1557fd72012-04-04 23:41:34 -07004931 *
4932 * @see #getLayoutMode()
Scott Main27a85082013-06-10 10:39:48 -07004933 * @attr ref android.R.styleable#ViewGroup_layoutMode
Philip Milne1557fd72012-04-04 23:41:34 -07004934 */
4935 public void setLayoutMode(int layoutMode) {
4936 if (mLayoutMode != layoutMode) {
Philip Milnef091b662013-02-27 11:15:21 -08004937 invalidateInheritedLayoutMode(layoutMode);
4938 setLayoutMode(layoutMode, layoutMode != LAYOUT_MODE_UNDEFINED);
Philip Milne1557fd72012-04-04 23:41:34 -07004939 requestLayout();
4940 }
4941 }
4942
4943 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004944 * Returns a new set of layout parameters based on the supplied attributes set.
4945 *
4946 * @param attrs the attributes to build the layout parameters from
4947 *
4948 * @return an instance of {@link android.view.ViewGroup.LayoutParams} or one
4949 * of its descendants
4950 */
4951 public LayoutParams generateLayoutParams(AttributeSet attrs) {
4952 return new LayoutParams(getContext(), attrs);
4953 }
4954
4955 /**
4956 * Returns a safe set of layout parameters based on the supplied layout params.
4957 * When a ViewGroup is passed a View whose layout params do not pass the test of
4958 * {@link #checkLayoutParams(android.view.ViewGroup.LayoutParams)}, this method
4959 * is invoked. This method should return a new set of layout params suitable for
4960 * this ViewGroup, possibly by copying the appropriate attributes from the
4961 * specified set of layout params.
4962 *
4963 * @param p The layout parameters to convert into a suitable set of layout parameters
4964 * for this ViewGroup.
4965 *
4966 * @return an instance of {@link android.view.ViewGroup.LayoutParams} or one
4967 * of its descendants
4968 */
4969 protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
4970 return p;
4971 }
4972
4973 /**
4974 * Returns a set of default layout parameters. These parameters are requested
4975 * when the View passed to {@link #addView(View)} has no layout parameters
4976 * already set. If null is returned, an exception is thrown from addView.
4977 *
4978 * @return a set of default layout parameters or null
4979 */
4980 protected LayoutParams generateDefaultLayoutParams() {
4981 return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
4982 }
4983
4984 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004985 * {@inheritDoc}
4986 */
4987 @Override
4988 protected void debug(int depth) {
4989 super.debug(depth);
4990 String output;
4991
4992 if (mFocused != null) {
4993 output = debugIndent(depth);
4994 output += "mFocused";
4995 Log.d(VIEW_LOG_TAG, output);
4996 }
4997 if (mChildrenCount != 0) {
4998 output = debugIndent(depth);
4999 output += "{";
5000 Log.d(VIEW_LOG_TAG, output);
5001 }
5002 int count = mChildrenCount;
5003 for (int i = 0; i < count; i++) {
5004 View child = mChildren[i];
5005 child.debug(depth + 1);
5006 }
5007
5008 if (mChildrenCount != 0) {
5009 output = debugIndent(depth);
5010 output += "}";
5011 Log.d(VIEW_LOG_TAG, output);
5012 }
5013 }
5014
5015 /**
5016 * Returns the position in the group of the specified child view.
5017 *
5018 * @param child the view for which to get the position
5019 * @return a positive integer representing the position of the view in the
5020 * group, or -1 if the view does not exist in the group
5021 */
5022 public int indexOfChild(View child) {
5023 final int count = mChildrenCount;
5024 final View[] children = mChildren;
5025 for (int i = 0; i < count; i++) {
5026 if (children[i] == child) {
5027 return i;
5028 }
5029 }
5030 return -1;
5031 }
5032
5033 /**
5034 * Returns the number of children in the group.
5035 *
5036 * @return a positive integer representing the number of children in
5037 * the group
5038 */
5039 public int getChildCount() {
5040 return mChildrenCount;
5041 }
5042
5043 /**
5044 * Returns the view at the specified position in the group.
5045 *
5046 * @param index the position at which to get the view from
5047 * @return the view at the specified position or null if the position
5048 * does not exist within the group
5049 */
5050 public View getChildAt(int index) {
Adam Powell3ba8f5d2011-03-07 15:36:33 -08005051 if (index < 0 || index >= mChildrenCount) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005052 return null;
5053 }
Adam Powell3ba8f5d2011-03-07 15:36:33 -08005054 return mChildren[index];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005055 }
5056
5057 /**
5058 * Ask all of the children of this view to measure themselves, taking into
5059 * account both the MeasureSpec requirements for this view and its padding.
5060 * We skip children that are in the GONE state The heavy lifting is done in
5061 * getChildMeasureSpec.
5062 *
5063 * @param widthMeasureSpec The width requirements for this view
5064 * @param heightMeasureSpec The height requirements for this view
5065 */
5066 protected void measureChildren(int widthMeasureSpec, int heightMeasureSpec) {
5067 final int size = mChildrenCount;
5068 final View[] children = mChildren;
5069 for (int i = 0; i < size; ++i) {
5070 final View child = children[i];
5071 if ((child.mViewFlags & VISIBILITY_MASK) != GONE) {
5072 measureChild(child, widthMeasureSpec, heightMeasureSpec);
5073 }
5074 }
5075 }
5076
5077 /**
5078 * Ask one of the children of this view to measure itself, taking into
5079 * account both the MeasureSpec requirements for this view and its padding.
5080 * The heavy lifting is done in getChildMeasureSpec.
5081 *
5082 * @param child The child to measure
5083 * @param parentWidthMeasureSpec The width requirements for this view
5084 * @param parentHeightMeasureSpec The height requirements for this view
5085 */
5086 protected void measureChild(View child, int parentWidthMeasureSpec,
5087 int parentHeightMeasureSpec) {
5088 final LayoutParams lp = child.getLayoutParams();
5089
5090 final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
5091 mPaddingLeft + mPaddingRight, lp.width);
5092 final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
5093 mPaddingTop + mPaddingBottom, lp.height);
5094
5095 child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
5096 }
5097
5098 /**
5099 * Ask one of the children of this view to measure itself, taking into
5100 * account both the MeasureSpec requirements for this view and its padding
5101 * and margins. The child must have MarginLayoutParams The heavy lifting is
5102 * done in getChildMeasureSpec.
5103 *
5104 * @param child The child to measure
5105 * @param parentWidthMeasureSpec The width requirements for this view
5106 * @param widthUsed Extra space that has been used up by the parent
5107 * horizontally (possibly by other children of the parent)
5108 * @param parentHeightMeasureSpec The height requirements for this view
5109 * @param heightUsed Extra space that has been used up by the parent
5110 * vertically (possibly by other children of the parent)
5111 */
5112 protected void measureChildWithMargins(View child,
5113 int parentWidthMeasureSpec, int widthUsed,
5114 int parentHeightMeasureSpec, int heightUsed) {
5115 final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
5116
5117 final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
5118 mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin
5119 + widthUsed, lp.width);
5120 final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
5121 mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin
5122 + heightUsed, lp.height);
5123
5124 child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
5125 }
5126
5127 /**
5128 * Does the hard part of measureChildren: figuring out the MeasureSpec to
5129 * pass to a particular child. This method figures out the right MeasureSpec
5130 * for one dimension (height or width) of one child view.
5131 *
5132 * The goal is to combine information from our MeasureSpec with the
5133 * LayoutParams of the child to get the best possible results. For example,
5134 * if the this view knows its size (because its MeasureSpec has a mode of
5135 * EXACTLY), and the child has indicated in its LayoutParams that it wants
5136 * to be the same size as the parent, the parent should ask the child to
5137 * layout given an exact size.
5138 *
5139 * @param spec The requirements for this view
5140 * @param padding The padding of this view for the current dimension and
5141 * margins, if applicable
5142 * @param childDimension How big the child wants to be in the current
5143 * dimension
5144 * @return a MeasureSpec integer for the child
5145 */
5146 public static int getChildMeasureSpec(int spec, int padding, int childDimension) {
5147 int specMode = MeasureSpec.getMode(spec);
5148 int specSize = MeasureSpec.getSize(spec);
5149
5150 int size = Math.max(0, specSize - padding);
5151
5152 int resultSize = 0;
5153 int resultMode = 0;
5154
5155 switch (specMode) {
5156 // Parent has imposed an exact size on us
5157 case MeasureSpec.EXACTLY:
5158 if (childDimension >= 0) {
5159 resultSize = childDimension;
5160 resultMode = MeasureSpec.EXACTLY;
Romain Guy980a9382010-01-08 15:06:28 -08005161 } else if (childDimension == LayoutParams.MATCH_PARENT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005162 // Child wants to be our size. So be it.
5163 resultSize = size;
5164 resultMode = MeasureSpec.EXACTLY;
5165 } else if (childDimension == LayoutParams.WRAP_CONTENT) {
5166 // Child wants to determine its own size. It can't be
5167 // bigger than us.
5168 resultSize = size;
5169 resultMode = MeasureSpec.AT_MOST;
5170 }
5171 break;
5172
5173 // Parent has imposed a maximum size on us
5174 case MeasureSpec.AT_MOST:
5175 if (childDimension >= 0) {
5176 // Child wants a specific size... so be it
5177 resultSize = childDimension;
5178 resultMode = MeasureSpec.EXACTLY;
Romain Guy980a9382010-01-08 15:06:28 -08005179 } else if (childDimension == LayoutParams.MATCH_PARENT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005180 // Child wants to be our size, but our size is not fixed.
5181 // Constrain child to not be bigger than us.
5182 resultSize = size;
5183 resultMode = MeasureSpec.AT_MOST;
5184 } else if (childDimension == LayoutParams.WRAP_CONTENT) {
5185 // Child wants to determine its own size. It can't be
5186 // bigger than us.
5187 resultSize = size;
5188 resultMode = MeasureSpec.AT_MOST;
5189 }
5190 break;
5191
5192 // Parent asked to see how big we want to be
5193 case MeasureSpec.UNSPECIFIED:
5194 if (childDimension >= 0) {
5195 // Child wants a specific size... let him have it
5196 resultSize = childDimension;
5197 resultMode = MeasureSpec.EXACTLY;
Romain Guy980a9382010-01-08 15:06:28 -08005198 } else if (childDimension == LayoutParams.MATCH_PARENT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005199 // Child wants to be our size... find out how big it should
5200 // be
5201 resultSize = 0;
5202 resultMode = MeasureSpec.UNSPECIFIED;
5203 } else if (childDimension == LayoutParams.WRAP_CONTENT) {
5204 // Child wants to determine its own size.... find out how
5205 // big it should be
5206 resultSize = 0;
5207 resultMode = MeasureSpec.UNSPECIFIED;
5208 }
5209 break;
5210 }
5211 return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
5212 }
5213
5214
5215 /**
5216 * Removes any pending animations for views that have been removed. Call
5217 * this if you don't want animations for exiting views to stack up.
5218 */
5219 public void clearDisappearingChildren() {
5220 if (mDisappearingChildren != null) {
5221 mDisappearingChildren.clear();
Chet Haaseb85967b2012-03-26 14:37:51 -07005222 invalidate();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005223 }
5224 }
5225
5226 /**
5227 * Add a view which is removed from mChildren but still needs animation
5228 *
5229 * @param v View to add
5230 */
5231 private void addDisappearingView(View v) {
5232 ArrayList<View> disappearingChildren = mDisappearingChildren;
5233
5234 if (disappearingChildren == null) {
5235 disappearingChildren = mDisappearingChildren = new ArrayList<View>();
5236 }
5237
5238 disappearingChildren.add(v);
5239 }
5240
5241 /**
5242 * Cleanup a view when its animation is done. This may mean removing it from
5243 * the list of disappearing views.
5244 *
5245 * @param view The view whose animation has finished
5246 * @param animation The animation, cannot be null
5247 */
Chet Haase64a48c12012-02-13 16:33:29 -08005248 void finishAnimatingView(final View view, Animation animation) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005249 final ArrayList<View> disappearingChildren = mDisappearingChildren;
5250 if (disappearingChildren != null) {
5251 if (disappearingChildren.contains(view)) {
5252 disappearingChildren.remove(view);
5253
5254 if (view.mAttachInfo != null) {
5255 view.dispatchDetachedFromWindow();
5256 }
5257
5258 view.clearAnimation();
5259 mGroupFlags |= FLAG_INVALIDATE_REQUIRED;
5260 }
5261 }
5262
5263 if (animation != null && !animation.getFillAfter()) {
5264 view.clearAnimation();
5265 }
5266
Dianne Hackborn4702a852012-08-17 15:18:29 -07005267 if ((view.mPrivateFlags & PFLAG_ANIMATION_STARTED) == PFLAG_ANIMATION_STARTED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005268 view.onAnimationEnd();
5269 // Should be performed by onAnimationEnd() but this avoid an infinite loop,
5270 // so we'd rather be safe than sorry
Dianne Hackborn4702a852012-08-17 15:18:29 -07005271 view.mPrivateFlags &= ~PFLAG_ANIMATION_STARTED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005272 // Draw one more frame after the animation is done
5273 mGroupFlags |= FLAG_INVALIDATE_REQUIRED;
5274 }
5275 }
5276
Chet Haaseb20db3e2010-09-10 13:07:30 -07005277 /**
Chet Haaseaceafe62011-08-26 15:44:33 -07005278 * Utility function called by View during invalidation to determine whether a view that
5279 * is invisible or gone should still be invalidated because it is being transitioned (and
5280 * therefore still needs to be drawn).
5281 */
5282 boolean isViewTransitioning(View view) {
5283 return (mTransitioningViews != null && mTransitioningViews.contains(view));
5284 }
5285
5286 /**
Chet Haaseb20db3e2010-09-10 13:07:30 -07005287 * This method tells the ViewGroup that the given View object, which should have this
5288 * ViewGroup as its parent,
5289 * should be kept around (re-displayed when the ViewGroup draws its children) even if it
5290 * is removed from its parent. This allows animations, such as those used by
5291 * {@link android.app.Fragment} and {@link android.animation.LayoutTransition} to animate
5292 * the removal of views. A call to this method should always be accompanied by a later call
5293 * to {@link #endViewTransition(View)}, such as after an animation on the View has finished,
5294 * so that the View finally gets removed.
5295 *
5296 * @param view The View object to be kept visible even if it gets removed from its parent.
5297 */
5298 public void startViewTransition(View view) {
5299 if (view.mParent == this) {
5300 if (mTransitioningViews == null) {
5301 mTransitioningViews = new ArrayList<View>();
5302 }
5303 mTransitioningViews.add(view);
5304 }
5305 }
5306
5307 /**
5308 * This method should always be called following an earlier call to
5309 * {@link #startViewTransition(View)}. The given View is finally removed from its parent
5310 * and will no longer be displayed. Note that this method does not perform the functionality
5311 * of removing a view from its parent; it just discontinues the display of a View that
5312 * has previously been removed.
5313 *
5314 * @return view The View object that has been removed but is being kept around in the visible
5315 * hierarchy by an earlier call to {@link #startViewTransition(View)}.
5316 */
5317 public void endViewTransition(View view) {
5318 if (mTransitioningViews != null) {
5319 mTransitioningViews.remove(view);
5320 final ArrayList<View> disappearingChildren = mDisappearingChildren;
5321 if (disappearingChildren != null && disappearingChildren.contains(view)) {
5322 disappearingChildren.remove(view);
Chet Haase5e25c2c2010-09-16 11:15:56 -07005323 if (mVisibilityChangingChildren != null &&
5324 mVisibilityChangingChildren.contains(view)) {
5325 mVisibilityChangingChildren.remove(view);
5326 } else {
5327 if (view.mAttachInfo != null) {
5328 view.dispatchDetachedFromWindow();
5329 }
5330 if (view.mParent != null) {
5331 view.mParent = null;
5332 }
Chet Haaseb20db3e2010-09-10 13:07:30 -07005333 }
Chet Haaseb85967b2012-03-26 14:37:51 -07005334 invalidate();
Chet Haaseb20db3e2010-09-10 13:07:30 -07005335 }
5336 }
5337 }
5338
Chet Haase21cd1382010-09-01 17:42:29 -07005339 private LayoutTransition.TransitionListener mLayoutTransitionListener =
5340 new LayoutTransition.TransitionListener() {
5341 @Override
5342 public void startTransition(LayoutTransition transition, ViewGroup container,
5343 View view, int transitionType) {
5344 // We only care about disappearing items, since we need special logic to keep
5345 // those items visible after they've been 'removed'
5346 if (transitionType == LayoutTransition.DISAPPEARING) {
Chet Haaseb20db3e2010-09-10 13:07:30 -07005347 startViewTransition(view);
Chet Haase21cd1382010-09-01 17:42:29 -07005348 }
5349 }
5350
5351 @Override
5352 public void endTransition(LayoutTransition transition, ViewGroup container,
5353 View view, int transitionType) {
Chet Haaseb9895022013-04-02 15:10:58 -07005354 if (mLayoutCalledWhileSuppressed && !transition.isChangingLayout()) {
Chet Haase9c087442011-01-12 16:20:16 -08005355 requestLayout();
Chet Haaseb9895022013-04-02 15:10:58 -07005356 mLayoutCalledWhileSuppressed = false;
Chet Haase9c087442011-01-12 16:20:16 -08005357 }
Chet Haase21cd1382010-09-01 17:42:29 -07005358 if (transitionType == LayoutTransition.DISAPPEARING && mTransitioningViews != null) {
Chet Haaseb20db3e2010-09-10 13:07:30 -07005359 endViewTransition(view);
Chet Haase21cd1382010-09-01 17:42:29 -07005360 }
5361 }
5362 };
5363
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005364 /**
Chet Haaseb9895022013-04-02 15:10:58 -07005365 * Tells this ViewGroup to suppress all layout() calls until layout
5366 * suppression is disabled with a later call to suppressLayout(false).
5367 * When layout suppression is disabled, a requestLayout() call is sent
5368 * if layout() was attempted while layout was being suppressed.
5369 *
5370 * @hide
5371 */
5372 public void suppressLayout(boolean suppress) {
5373 mSuppressLayout = suppress;
5374 if (!suppress) {
5375 if (mLayoutCalledWhileSuppressed) {
5376 requestLayout();
5377 mLayoutCalledWhileSuppressed = false;
5378 }
5379 }
5380 }
5381
5382 /**
Chet Haase199acdf2013-07-24 18:40:55 -07005383 * Returns whether layout calls on this container are currently being
5384 * suppressed, due to an earlier call to {@link #suppressLayout(boolean)}.
5385 *
5386 * @return true if layout calls are currently suppressed, false otherwise.
5387 *
5388 * @hide
5389 */
5390 public boolean isLayoutSuppressed() {
5391 return mSuppressLayout;
5392 }
5393
5394 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005395 * {@inheritDoc}
5396 */
5397 @Override
5398 public boolean gatherTransparentRegion(Region region) {
5399 // If no transparent regions requested, we are always opaque.
Dianne Hackborn4702a852012-08-17 15:18:29 -07005400 final boolean meOpaque = (mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) == 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005401 if (meOpaque && region == null) {
5402 // The caller doesn't care about the region, so stop now.
5403 return true;
5404 }
5405 super.gatherTransparentRegion(region);
5406 final View[] children = mChildren;
5407 final int count = mChildrenCount;
5408 boolean noneOfTheChildrenAreTransparent = true;
5409 for (int i = 0; i < count; i++) {
5410 final View child = children[i];
Mathias Agopiane3381152010-12-02 15:19:36 -08005411 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005412 if (!child.gatherTransparentRegion(region)) {
5413 noneOfTheChildrenAreTransparent = false;
5414 }
5415 }
5416 }
5417 return meOpaque || noneOfTheChildrenAreTransparent;
5418 }
5419
5420 /**
5421 * {@inheritDoc}
5422 */
5423 public void requestTransparentRegion(View child) {
5424 if (child != null) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07005425 child.mPrivateFlags |= View.PFLAG_REQUEST_TRANSPARENT_REGIONS;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005426 if (mParent != null) {
5427 mParent.requestTransparentRegion(this);
5428 }
5429 }
5430 }
Romain Guy8506ab42009-06-11 17:35:47 -07005431
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005432
5433 @Override
5434 protected boolean fitSystemWindows(Rect insets) {
5435 boolean done = super.fitSystemWindows(insets);
5436 if (!done) {
5437 final int count = mChildrenCount;
5438 final View[] children = mChildren;
5439 for (int i = 0; i < count; i++) {
5440 done = children[i].fitSystemWindows(insets);
5441 if (done) {
5442 break;
5443 }
5444 }
5445 }
5446 return done;
5447 }
5448
5449 /**
5450 * Returns the animation listener to which layout animation events are
5451 * sent.
5452 *
5453 * @return an {@link android.view.animation.Animation.AnimationListener}
5454 */
5455 public Animation.AnimationListener getLayoutAnimationListener() {
5456 return mAnimationListener;
5457 }
5458
5459 @Override
5460 protected void drawableStateChanged() {
5461 super.drawableStateChanged();
5462
5463 if ((mGroupFlags & FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE) != 0) {
5464 if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0) {
5465 throw new IllegalStateException("addStateFromChildren cannot be enabled if a"
5466 + " child has duplicateParentState set to true");
5467 }
5468
5469 final View[] children = mChildren;
5470 final int count = mChildrenCount;
5471
5472 for (int i = 0; i < count; i++) {
5473 final View child = children[i];
5474 if ((child.mViewFlags & DUPLICATE_PARENT_STATE) != 0) {
5475 child.refreshDrawableState();
5476 }
5477 }
5478 }
5479 }
5480
5481 @Override
Dianne Hackborne2136772010-11-04 15:08:59 -07005482 public void jumpDrawablesToCurrentState() {
5483 super.jumpDrawablesToCurrentState();
5484 final View[] children = mChildren;
5485 final int count = mChildrenCount;
5486 for (int i = 0; i < count; i++) {
5487 children[i].jumpDrawablesToCurrentState();
5488 }
5489 }
5490
5491 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005492 protected int[] onCreateDrawableState(int extraSpace) {
5493 if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) == 0) {
5494 return super.onCreateDrawableState(extraSpace);
5495 }
5496
5497 int need = 0;
5498 int n = getChildCount();
5499 for (int i = 0; i < n; i++) {
5500 int[] childState = getChildAt(i).getDrawableState();
5501
5502 if (childState != null) {
5503 need += childState.length;
5504 }
5505 }
5506
5507 int[] state = super.onCreateDrawableState(extraSpace + need);
5508
5509 for (int i = 0; i < n; i++) {
5510 int[] childState = getChildAt(i).getDrawableState();
5511
5512 if (childState != null) {
5513 state = mergeDrawableStates(state, childState);
5514 }
5515 }
5516
5517 return state;
5518 }
5519
5520 /**
5521 * Sets whether this ViewGroup's drawable states also include
5522 * its children's drawable states. This is used, for example, to
5523 * make a group appear to be focused when its child EditText or button
5524 * is focused.
5525 */
5526 public void setAddStatesFromChildren(boolean addsStates) {
5527 if (addsStates) {
5528 mGroupFlags |= FLAG_ADD_STATES_FROM_CHILDREN;
5529 } else {
5530 mGroupFlags &= ~FLAG_ADD_STATES_FROM_CHILDREN;
5531 }
5532
5533 refreshDrawableState();
5534 }
5535
5536 /**
5537 * Returns whether this ViewGroup's drawable states also include
5538 * its children's drawable states. This is used, for example, to
5539 * make a group appear to be focused when its child EditText or button
5540 * is focused.
5541 */
5542 public boolean addStatesFromChildren() {
5543 return (mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0;
5544 }
5545
5546 /**
Jeff Smitha45746e2012-07-19 14:19:24 -05005547 * If {@link #addStatesFromChildren} is true, refreshes this group's
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005548 * drawable state (to include the states from its children).
5549 */
5550 public void childDrawableStateChanged(View child) {
5551 if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0) {
5552 refreshDrawableState();
5553 }
5554 }
5555
5556 /**
5557 * Specifies the animation listener to which layout animation events must
5558 * be sent. Only
5559 * {@link android.view.animation.Animation.AnimationListener#onAnimationStart(Animation)}
5560 * and
5561 * {@link android.view.animation.Animation.AnimationListener#onAnimationEnd(Animation)}
5562 * are invoked.
5563 *
5564 * @param animationListener the layout animation listener
5565 */
5566 public void setLayoutAnimationListener(Animation.AnimationListener animationListener) {
5567 mAnimationListener = animationListener;
5568 }
5569
5570 /**
Chet Haasecca2c982011-05-20 14:34:18 -07005571 * This method is called by LayoutTransition when there are 'changing' animations that need
5572 * to start after the layout/setup phase. The request is forwarded to the ViewAncestor, who
5573 * starts all pending transitions prior to the drawing phase in the current traversal.
5574 *
5575 * @param transition The LayoutTransition to be started on the next traversal.
5576 *
5577 * @hide
5578 */
5579 public void requestTransitionStart(LayoutTransition transition) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07005580 ViewRootImpl viewAncestor = getViewRootImpl();
Chet Haase1abf7fa2011-08-17 18:31:56 -07005581 if (viewAncestor != null) {
5582 viewAncestor.requestTransitionStart(transition);
5583 }
Chet Haasecca2c982011-05-20 14:34:18 -07005584 }
5585
Fabrice Di Meglio4457e852012-09-18 19:23:12 -07005586 /**
5587 * @hide
5588 */
Fabrice Di Meglio80dc53d2011-06-21 18:36:33 -07005589 @Override
Fabrice Di Meglio09ecb252013-05-03 16:51:55 -07005590 public boolean resolveRtlPropertiesIfNeeded() {
5591 final boolean result = super.resolveRtlPropertiesIfNeeded();
5592 // We dont need to resolve the children RTL properties if nothing has changed for the parent
5593 if (result) {
5594 int count = getChildCount();
5595 for (int i = 0; i < count; i++) {
5596 final View child = getChildAt(i);
5597 if (child.isLayoutDirectionInherited()) {
5598 child.resolveRtlPropertiesIfNeeded();
5599 }
Fabrice Di Meglio84ebb352012-10-11 16:27:37 -07005600 }
5601 }
Fabrice Di Meglio09ecb252013-05-03 16:51:55 -07005602 return result;
Fabrice Di Meglio84ebb352012-10-11 16:27:37 -07005603 }
5604
5605 /**
5606 * @hide
5607 */
5608 @Override
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07005609 public boolean resolveLayoutDirection() {
5610 final boolean result = super.resolveLayoutDirection();
5611 if (result) {
5612 int count = getChildCount();
5613 for (int i = 0; i < count; i++) {
5614 final View child = getChildAt(i);
5615 if (child.isLayoutDirectionInherited()) {
5616 child.resolveLayoutDirection();
5617 }
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07005618 }
5619 }
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07005620 return result;
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07005621 }
5622
5623 /**
5624 * @hide
5625 */
5626 @Override
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07005627 public boolean resolveTextDirection() {
5628 final boolean result = super.resolveTextDirection();
5629 if (result) {
5630 int count = getChildCount();
5631 for (int i = 0; i < count; i++) {
5632 final View child = getChildAt(i);
5633 if (child.isTextDirectionInherited()) {
5634 child.resolveTextDirection();
5635 }
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07005636 }
5637 }
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07005638 return result;
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07005639 }
5640
5641 /**
5642 * @hide
5643 */
5644 @Override
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07005645 public boolean resolveTextAlignment() {
5646 final boolean result = super.resolveTextAlignment();
5647 if (result) {
5648 int count = getChildCount();
5649 for (int i = 0; i < count; i++) {
5650 final View child = getChildAt(i);
5651 if (child.isTextAlignmentInherited()) {
5652 child.resolveTextAlignment();
5653 }
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07005654 }
5655 }
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07005656 return result;
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07005657 }
5658
5659 /**
5660 * @hide
5661 */
5662 @Override
Fabrice Di Meglio84ebb352012-10-11 16:27:37 -07005663 public void resolvePadding() {
5664 super.resolvePadding();
5665 int count = getChildCount();
5666 for (int i = 0; i < count; i++) {
5667 final View child = getChildAt(i);
5668 if (child.isLayoutDirectionInherited()) {
5669 child.resolvePadding();
5670 }
5671 }
5672 }
5673
5674 /**
5675 * @hide
5676 */
5677 @Override
5678 protected void resolveDrawables() {
5679 super.resolveDrawables();
5680 int count = getChildCount();
5681 for (int i = 0; i < count; i++) {
5682 final View child = getChildAt(i);
5683 if (child.isLayoutDirectionInherited()) {
5684 child.resolveDrawables();
5685 }
5686 }
5687 }
5688
Fabrice Di Meglio1e0ed6b2012-10-18 16:06:52 -07005689 /**
5690 * @hide
5691 */
Fabrice Di Megliofcc33482012-10-18 11:11:51 -07005692 @Override
5693 public void resolveLayoutParams() {
5694 super.resolveLayoutParams();
5695 int count = getChildCount();
5696 for (int i = 0; i < count; i++) {
5697 final View child = getChildAt(i);
5698 child.resolveLayoutParams();
5699 }
5700 }
5701
Fabrice Di Meglio84ebb352012-10-11 16:27:37 -07005702 /**
5703 * @hide
5704 */
5705 @Override
Fabrice Di Meglio4457e852012-09-18 19:23:12 -07005706 public void resetResolvedLayoutDirection() {
5707 super.resetResolvedLayoutDirection();
5708
Fabrice Di Meglio4457e852012-09-18 19:23:12 -07005709 int count = getChildCount();
Fabrice Di Meglio80dc53d2011-06-21 18:36:33 -07005710 for (int i = 0; i < count; i++) {
5711 final View child = getChildAt(i);
Fabrice Di Meglioe56ffdc2012-09-23 14:51:16 -07005712 if (child.isLayoutDirectionInherited()) {
Fabrice Di Meglio7f86c802011-07-01 15:09:24 -07005713 child.resetResolvedLayoutDirection();
Fabrice Di Meglio80dc53d2011-06-21 18:36:33 -07005714 }
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07005715 }
5716 }
5717
5718 /**
5719 * @hide
5720 */
5721 @Override
5722 public void resetResolvedTextDirection() {
5723 super.resetResolvedTextDirection();
5724
5725 int count = getChildCount();
5726 for (int i = 0; i < count; i++) {
5727 final View child = getChildAt(i);
Fabrice Di Meglio97e146c2012-09-23 15:45:16 -07005728 if (child.isTextDirectionInherited()) {
Fabrice Di Meglio22268862011-06-27 18:13:18 -07005729 child.resetResolvedTextDirection();
5730 }
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07005731 }
5732 }
5733
5734 /**
5735 * @hide
5736 */
5737 @Override
5738 public void resetResolvedTextAlignment() {
5739 super.resetResolvedTextAlignment();
5740
5741 int count = getChildCount();
5742 for (int i = 0; i < count; i++) {
5743 final View child = getChildAt(i);
Fabrice Di Meglio1a7d4872012-09-23 16:19:58 -07005744 if (child.isTextAlignmentInherited()) {
Fabrice Di Meglio9da0f8a2012-03-13 19:37:57 -07005745 child.resetResolvedTextAlignment();
5746 }
5747 }
5748 }
5749
Fabrice Di Meglio22268862011-06-27 18:13:18 -07005750 /**
Fabrice Di Meglio84ebb352012-10-11 16:27:37 -07005751 * @hide
5752 */
5753 @Override
5754 public void resetResolvedPadding() {
5755 super.resetResolvedPadding();
5756
5757 int count = getChildCount();
5758 for (int i = 0; i < count; i++) {
5759 final View child = getChildAt(i);
5760 if (child.isLayoutDirectionInherited()) {
5761 child.resetResolvedPadding();
5762 }
5763 }
5764 }
5765
5766 /**
5767 * @hide
5768 */
5769 @Override
5770 protected void resetResolvedDrawables() {
5771 super.resetResolvedDrawables();
5772
5773 int count = getChildCount();
5774 for (int i = 0; i < count; i++) {
5775 final View child = getChildAt(i);
5776 if (child.isLayoutDirectionInherited()) {
5777 child.resetResolvedDrawables();
5778 }
5779 }
5780 }
5781
5782 /**
Patrick Dubroye0a799a2011-05-04 16:19:22 -07005783 * Return true if the pressed state should be delayed for children or descendants of this
5784 * ViewGroup. Generally, this should be done for containers that can scroll, such as a List.
5785 * This prevents the pressed state from appearing when the user is actually trying to scroll
5786 * the content.
5787 *
5788 * The default implementation returns true for compatibility reasons. Subclasses that do
5789 * not scroll should generally override this method and return false.
5790 */
5791 public boolean shouldDelayChildPressedState() {
5792 return true;
5793 }
5794
Philip Milned7dd8902012-01-26 16:55:30 -08005795 /** @hide */
5796 protected void onSetLayoutParams(View child, LayoutParams layoutParams) {
5797 }
5798
Patrick Dubroye0a799a2011-05-04 16:19:22 -07005799 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005800 * LayoutParams are used by views to tell their parents how they want to be
5801 * laid out. See
5802 * {@link android.R.styleable#ViewGroup_Layout ViewGroup Layout Attributes}
5803 * for a list of all child view attributes that this class supports.
Romain Guy8506ab42009-06-11 17:35:47 -07005804 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005805 * <p>
5806 * The base LayoutParams class just describes how big the view wants to be
5807 * for both width and height. For each dimension, it can specify one of:
5808 * <ul>
Dirk Dougherty75c66da2010-03-25 16:33:33 -07005809 * <li>FILL_PARENT (renamed MATCH_PARENT in API Level 8 and higher), which
5810 * means that the view wants to be as big as its parent (minus padding)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005811 * <li> WRAP_CONTENT, which means that the view wants to be just big enough
5812 * to enclose its content (plus padding)
Dirk Dougherty75c66da2010-03-25 16:33:33 -07005813 * <li> an exact number
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005814 * </ul>
5815 * There are subclasses of LayoutParams for different subclasses of
5816 * ViewGroup. For example, AbsoluteLayout has its own subclass of
Joe Fernandez558459f2011-10-13 16:47:36 -07005817 * LayoutParams which adds an X and Y value.</p>
5818 *
5819 * <div class="special reference">
5820 * <h3>Developer Guides</h3>
5821 * <p>For more information about creating user interface layouts, read the
5822 * <a href="{@docRoot}guide/topics/ui/declaring-layout.html">XML Layouts</a> developer
5823 * guide.</p></div>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005824 *
5825 * @attr ref android.R.styleable#ViewGroup_Layout_layout_height
5826 * @attr ref android.R.styleable#ViewGroup_Layout_layout_width
5827 */
5828 public static class LayoutParams {
5829 /**
Dirk Dougherty75c66da2010-03-25 16:33:33 -07005830 * Special value for the height or width requested by a View.
5831 * FILL_PARENT means that the view wants to be as big as its parent,
5832 * minus the parent's padding, if any. This value is deprecated
5833 * starting in API Level 8 and replaced by {@link #MATCH_PARENT}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005834 */
Romain Guy980a9382010-01-08 15:06:28 -08005835 @SuppressWarnings({"UnusedDeclaration"})
5836 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005837 public static final int FILL_PARENT = -1;
5838
5839 /**
5840 * Special value for the height or width requested by a View.
Gilles Debunnef5c6eff2010-02-09 19:08:36 -08005841 * MATCH_PARENT means that the view wants to be as big as its parent,
Dirk Dougherty75c66da2010-03-25 16:33:33 -07005842 * minus the parent's padding, if any. Introduced in API Level 8.
Romain Guy980a9382010-01-08 15:06:28 -08005843 */
5844 public static final int MATCH_PARENT = -1;
5845
5846 /**
5847 * Special value for the height or width requested by a View.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005848 * WRAP_CONTENT means that the view wants to be just large enough to fit
5849 * its own internal content, taking its own padding into account.
5850 */
5851 public static final int WRAP_CONTENT = -2;
5852
5853 /**
Dirk Dougherty75c66da2010-03-25 16:33:33 -07005854 * Information about how wide the view wants to be. Can be one of the
5855 * constants FILL_PARENT (replaced by MATCH_PARENT ,
5856 * in API Level 8) or WRAP_CONTENT. or an exact size.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005857 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07005858 @ViewDebug.ExportedProperty(category = "layout", mapping = {
Romain Guy980a9382010-01-08 15:06:28 -08005859 @ViewDebug.IntToString(from = MATCH_PARENT, to = "MATCH_PARENT"),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005860 @ViewDebug.IntToString(from = WRAP_CONTENT, to = "WRAP_CONTENT")
5861 })
5862 public int width;
5863
5864 /**
Dirk Dougherty75c66da2010-03-25 16:33:33 -07005865 * Information about how tall the view wants to be. Can be one of the
5866 * constants FILL_PARENT (replaced by MATCH_PARENT ,
5867 * in API Level 8) or WRAP_CONTENT. or an exact size.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005868 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07005869 @ViewDebug.ExportedProperty(category = "layout", mapping = {
Romain Guy980a9382010-01-08 15:06:28 -08005870 @ViewDebug.IntToString(from = MATCH_PARENT, to = "MATCH_PARENT"),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005871 @ViewDebug.IntToString(from = WRAP_CONTENT, to = "WRAP_CONTENT")
5872 })
5873 public int height;
5874
5875 /**
5876 * Used to animate layouts.
5877 */
5878 public LayoutAnimationController.AnimationParameters layoutAnimationParameters;
5879
5880 /**
5881 * Creates a new set of layout parameters. The values are extracted from
5882 * the supplied attributes set and context. The XML attributes mapped
5883 * to this set of layout parameters are:
5884 *
5885 * <ul>
5886 * <li><code>layout_width</code>: the width, either an exact value,
Dirk Dougherty75c66da2010-03-25 16:33:33 -07005887 * {@link #WRAP_CONTENT}, or {@link #FILL_PARENT} (replaced by
5888 * {@link #MATCH_PARENT} in API Level 8)</li>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005889 * <li><code>layout_height</code>: the height, either an exact value,
Dirk Dougherty75c66da2010-03-25 16:33:33 -07005890 * {@link #WRAP_CONTENT}, or {@link #FILL_PARENT} (replaced by
5891 * {@link #MATCH_PARENT} in API Level 8)</li>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005892 * </ul>
5893 *
5894 * @param c the application environment
5895 * @param attrs the set of attributes from which to extract the layout
5896 * parameters' values
5897 */
5898 public LayoutParams(Context c, AttributeSet attrs) {
5899 TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.ViewGroup_Layout);
5900 setBaseAttributes(a,
5901 R.styleable.ViewGroup_Layout_layout_width,
5902 R.styleable.ViewGroup_Layout_layout_height);
5903 a.recycle();
5904 }
5905
5906 /**
5907 * Creates a new set of layout parameters with the specified width
5908 * and height.
5909 *
Dirk Dougherty75c66da2010-03-25 16:33:33 -07005910 * @param width the width, either {@link #WRAP_CONTENT},
5911 * {@link #FILL_PARENT} (replaced by {@link #MATCH_PARENT} in
5912 * API Level 8), or a fixed size in pixels
5913 * @param height the height, either {@link #WRAP_CONTENT},
5914 * {@link #FILL_PARENT} (replaced by {@link #MATCH_PARENT} in
5915 * API Level 8), or a fixed size in pixels
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005916 */
5917 public LayoutParams(int width, int height) {
5918 this.width = width;
5919 this.height = height;
5920 }
5921
5922 /**
5923 * Copy constructor. Clones the width and height values of the source.
5924 *
5925 * @param source The layout params to copy from.
5926 */
5927 public LayoutParams(LayoutParams source) {
5928 this.width = source.width;
5929 this.height = source.height;
5930 }
5931
5932 /**
5933 * Used internally by MarginLayoutParams.
5934 * @hide
5935 */
5936 LayoutParams() {
5937 }
5938
5939 /**
Dave Burke579e1402012-10-18 20:41:55 -07005940 * Extracts the layout parameters from the supplied attributes.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005941 *
5942 * @param a the style attributes to extract the parameters from
5943 * @param widthAttr the identifier of the width attribute
5944 * @param heightAttr the identifier of the height attribute
5945 */
5946 protected void setBaseAttributes(TypedArray a, int widthAttr, int heightAttr) {
Dave Burke579e1402012-10-18 20:41:55 -07005947 width = a.getLayoutDimension(widthAttr, "layout_width");
5948 height = a.getLayoutDimension(heightAttr, "layout_height");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005949 }
5950
5951 /**
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07005952 * Resolve layout parameters depending on the layout direction. Subclasses that care about
5953 * layoutDirection changes should override this method. The default implementation does
5954 * nothing.
5955 *
5956 * @param layoutDirection the direction of the layout
5957 *
5958 * {@link View#LAYOUT_DIRECTION_LTR}
5959 * {@link View#LAYOUT_DIRECTION_RTL}
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07005960 */
Fabrice Di Meglio2918ab62012-10-10 16:39:25 -07005961 public void resolveLayoutDirection(int layoutDirection) {
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07005962 }
5963
5964 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005965 * Returns a String representation of this set of layout parameters.
5966 *
5967 * @param output the String to prepend to the internal representation
5968 * @return a String with the following format: output +
5969 * "ViewGroup.LayoutParams={ width=WIDTH, height=HEIGHT }"
Romain Guy8506ab42009-06-11 17:35:47 -07005970 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005971 * @hide
5972 */
5973 public String debug(String output) {
5974 return output + "ViewGroup.LayoutParams={ width="
5975 + sizeToString(width) + ", height=" + sizeToString(height) + " }";
5976 }
5977
5978 /**
Philip Milne10ca24a2012-04-23 15:38:27 -07005979 * Use {@code canvas} to draw suitable debugging annotations for these LayoutParameters.
5980 *
5981 * @param view the view that contains these layout parameters
5982 * @param canvas the canvas on which to draw
5983 *
5984 * @hide
5985 */
Philip Milne7b757812012-09-19 18:13:44 -07005986 public void onDebugDraw(View view, Canvas canvas, Paint paint) {
Philip Milne10ca24a2012-04-23 15:38:27 -07005987 }
5988
5989 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005990 * Converts the specified size to a readable String.
5991 *
5992 * @param size the size to convert
5993 * @return a String instance representing the supplied size
Romain Guy8506ab42009-06-11 17:35:47 -07005994 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005995 * @hide
5996 */
5997 protected static String sizeToString(int size) {
5998 if (size == WRAP_CONTENT) {
5999 return "wrap-content";
6000 }
Romain Guy980a9382010-01-08 15:06:28 -08006001 if (size == MATCH_PARENT) {
6002 return "match-parent";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006003 }
6004 return String.valueOf(size);
6005 }
6006 }
6007
6008 /**
6009 * Per-child layout information for layouts that support margins.
6010 * See
6011 * {@link android.R.styleable#ViewGroup_MarginLayout ViewGroup Margin Layout Attributes}
6012 * for a list of all child view attributes that this class supports.
6013 */
6014 public static class MarginLayoutParams extends ViewGroup.LayoutParams {
6015 /**
Philip Milned7dd8902012-01-26 16:55:30 -08006016 * The left margin in pixels of the child.
6017 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
6018 * to this field.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006019 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07006020 @ViewDebug.ExportedProperty(category = "layout")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006021 public int leftMargin;
6022
6023 /**
Philip Milned7dd8902012-01-26 16:55:30 -08006024 * The top margin in pixels of the child.
6025 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
6026 * to this field.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006027 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07006028 @ViewDebug.ExportedProperty(category = "layout")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006029 public int topMargin;
6030
6031 /**
Philip Milned7dd8902012-01-26 16:55:30 -08006032 * The right margin in pixels of the child.
6033 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
6034 * to this field.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006035 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07006036 @ViewDebug.ExportedProperty(category = "layout")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006037 public int rightMargin;
6038
6039 /**
Philip Milned7dd8902012-01-26 16:55:30 -08006040 * The bottom margin in pixels of the child.
6041 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
6042 * to this field.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006043 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07006044 @ViewDebug.ExportedProperty(category = "layout")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006045 public int bottomMargin;
6046
6047 /**
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006048 * The start margin in pixels of the child.
Fabrice Di Meglio54546f22012-02-14 16:26:16 -08006049 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
6050 * to this field.
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006051 */
6052 @ViewDebug.ExportedProperty(category = "layout")
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006053 private int startMargin = DEFAULT_MARGIN_RELATIVE;
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006054
6055 /**
6056 * The end margin in pixels of the child.
Fabrice Di Meglio54546f22012-02-14 16:26:16 -08006057 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
6058 * to this field.
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006059 */
6060 @ViewDebug.ExportedProperty(category = "layout")
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006061 private int endMargin = DEFAULT_MARGIN_RELATIVE;
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006062
6063 /**
6064 * The default start and end margin.
Fabrice Di Megliof443f982012-07-13 20:24:03 -07006065 * @hide
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006066 */
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006067 public static final int DEFAULT_MARGIN_RELATIVE = Integer.MIN_VALUE;
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006068
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006069 /**
6070 * Bit 0: layout direction
6071 * Bit 1: layout direction
6072 * Bit 2: left margin undefined
6073 * Bit 3: right margin undefined
6074 * Bit 4: is RTL compatibility mode
6075 * Bit 5: need resolution
6076 *
6077 * Bit 6 to 7 not used
6078 *
6079 * @hide
6080 */
6081 @ViewDebug.ExportedProperty(category = "layout", flagMapping = {
6082 @ViewDebug.FlagToString(mask = LAYOUT_DIRECTION_MASK,
6083 equals = LAYOUT_DIRECTION_MASK, name = "LAYOUT_DIRECTION"),
6084 @ViewDebug.FlagToString(mask = LEFT_MARGIN_UNDEFINED_MASK,
6085 equals = LEFT_MARGIN_UNDEFINED_MASK, name = "LEFT_MARGIN_UNDEFINED_MASK"),
6086 @ViewDebug.FlagToString(mask = RIGHT_MARGIN_UNDEFINED_MASK,
6087 equals = RIGHT_MARGIN_UNDEFINED_MASK, name = "RIGHT_MARGIN_UNDEFINED_MASK"),
6088 @ViewDebug.FlagToString(mask = RTL_COMPATIBILITY_MODE_MASK,
6089 equals = RTL_COMPATIBILITY_MODE_MASK, name = "RTL_COMPATIBILITY_MODE_MASK"),
6090 @ViewDebug.FlagToString(mask = NEED_RESOLUTION_MASK,
6091 equals = NEED_RESOLUTION_MASK, name = "NEED_RESOLUTION_MASK")
6092 })
6093 byte mMarginFlags;
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07006094
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006095 private static final int LAYOUT_DIRECTION_MASK = 0x00000003;
6096 private static final int LEFT_MARGIN_UNDEFINED_MASK = 0x00000004;
6097 private static final int RIGHT_MARGIN_UNDEFINED_MASK = 0x00000008;
6098 private static final int RTL_COMPATIBILITY_MODE_MASK = 0x00000010;
6099 private static final int NEED_RESOLUTION_MASK = 0x00000020;
Fabrice Di Megliof443f982012-07-13 20:24:03 -07006100
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006101 private static final int DEFAULT_MARGIN_RESOLVED = 0;
6102 private static final int UNDEFINED_MARGIN = DEFAULT_MARGIN_RELATIVE;
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07006103
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006104 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006105 * Creates a new set of layout parameters. The values are extracted from
6106 * the supplied attributes set and context.
6107 *
6108 * @param c the application environment
6109 * @param attrs the set of attributes from which to extract the layout
6110 * parameters' values
6111 */
6112 public MarginLayoutParams(Context c, AttributeSet attrs) {
6113 super();
6114
6115 TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.ViewGroup_MarginLayout);
6116 setBaseAttributes(a,
6117 R.styleable.ViewGroup_MarginLayout_layout_width,
6118 R.styleable.ViewGroup_MarginLayout_layout_height);
6119
6120 int margin = a.getDimensionPixelSize(
6121 com.android.internal.R.styleable.ViewGroup_MarginLayout_layout_margin, -1);
6122 if (margin >= 0) {
6123 leftMargin = margin;
6124 topMargin = margin;
6125 rightMargin= margin;
6126 bottomMargin = margin;
6127 } else {
6128 leftMargin = a.getDimensionPixelSize(
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006129 R.styleable.ViewGroup_MarginLayout_layout_marginLeft,
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07006130 UNDEFINED_MARGIN);
6131 if (leftMargin == UNDEFINED_MARGIN) {
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006132 mMarginFlags |= LEFT_MARGIN_UNDEFINED_MASK;
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07006133 leftMargin = DEFAULT_MARGIN_RESOLVED;
6134 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006135 rightMargin = a.getDimensionPixelSize(
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006136 R.styleable.ViewGroup_MarginLayout_layout_marginRight,
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07006137 UNDEFINED_MARGIN);
6138 if (rightMargin == UNDEFINED_MARGIN) {
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006139 mMarginFlags |= RIGHT_MARGIN_UNDEFINED_MASK;
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07006140 rightMargin = DEFAULT_MARGIN_RESOLVED;
6141 }
6142
6143 topMargin = a.getDimensionPixelSize(
6144 R.styleable.ViewGroup_MarginLayout_layout_marginTop,
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006145 DEFAULT_MARGIN_RESOLVED);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006146 bottomMargin = a.getDimensionPixelSize(
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006147 R.styleable.ViewGroup_MarginLayout_layout_marginBottom,
6148 DEFAULT_MARGIN_RESOLVED);
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07006149
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006150 startMargin = a.getDimensionPixelSize(
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006151 R.styleable.ViewGroup_MarginLayout_layout_marginStart,
6152 DEFAULT_MARGIN_RELATIVE);
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006153 endMargin = a.getDimensionPixelSize(
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006154 R.styleable.ViewGroup_MarginLayout_layout_marginEnd,
6155 DEFAULT_MARGIN_RELATIVE);
6156
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006157 if (isMarginRelative()) {
6158 mMarginFlags |= NEED_RESOLUTION_MASK;
6159 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006160 }
6161
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006162 final boolean hasRtlSupport = c.getApplicationInfo().hasRtlSupport();
6163 final int targetSdkVersion = c.getApplicationInfo().targetSdkVersion;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006164 if (targetSdkVersion < JELLY_BEAN_MR1 || !hasRtlSupport) {
6165 mMarginFlags |= RTL_COMPATIBILITY_MODE_MASK;
6166 }
6167
6168 // Layout direction is LTR by default
6169 mMarginFlags |= LAYOUT_DIRECTION_LTR;
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07006170
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006171 a.recycle();
6172 }
6173
6174 /**
6175 * {@inheritDoc}
6176 */
6177 public MarginLayoutParams(int width, int height) {
6178 super(width, height);
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006179
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006180 mMarginFlags |= LEFT_MARGIN_UNDEFINED_MASK;
6181 mMarginFlags |= RIGHT_MARGIN_UNDEFINED_MASK;
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07006182
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006183 mMarginFlags &= ~NEED_RESOLUTION_MASK;
6184 mMarginFlags &= ~RTL_COMPATIBILITY_MODE_MASK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006185 }
6186
6187 /**
6188 * Copy constructor. Clones the width, height and margin values of the source.
6189 *
6190 * @param source The layout params to copy from.
6191 */
6192 public MarginLayoutParams(MarginLayoutParams source) {
6193 this.width = source.width;
6194 this.height = source.height;
6195
6196 this.leftMargin = source.leftMargin;
6197 this.topMargin = source.topMargin;
6198 this.rightMargin = source.rightMargin;
6199 this.bottomMargin = source.bottomMargin;
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006200 this.startMargin = source.startMargin;
6201 this.endMargin = source.endMargin;
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07006202
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006203 this.mMarginFlags = source.mMarginFlags;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006204 }
6205
6206 /**
6207 * {@inheritDoc}
6208 */
6209 public MarginLayoutParams(LayoutParams source) {
6210 super(source);
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006211
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006212 mMarginFlags |= LEFT_MARGIN_UNDEFINED_MASK;
6213 mMarginFlags |= RIGHT_MARGIN_UNDEFINED_MASK;
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07006214
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006215 mMarginFlags &= ~NEED_RESOLUTION_MASK;
6216 mMarginFlags &= ~RTL_COMPATIBILITY_MODE_MASK;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006217 }
6218
6219 /**
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006220 * Sets the margins, in pixels. A call to {@link android.view.View#requestLayout()} needs
6221 * to be done so that the new margins are taken into account. Left and right margins may be
6222 * overriden by {@link android.view.View#requestLayout()} depending on layout direction.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006223 *
6224 * @param left the left margin size
6225 * @param top the top margin size
6226 * @param right the right margin size
6227 * @param bottom the bottom margin size
6228 *
6229 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginLeft
6230 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginTop
6231 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginRight
6232 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginBottom
6233 */
6234 public void setMargins(int left, int top, int right, int bottom) {
6235 leftMargin = left;
6236 topMargin = top;
6237 rightMargin = right;
6238 bottomMargin = bottom;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006239 mMarginFlags &= ~LEFT_MARGIN_UNDEFINED_MASK;
6240 mMarginFlags &= ~RIGHT_MARGIN_UNDEFINED_MASK;
6241 if (isMarginRelative()) {
6242 mMarginFlags |= NEED_RESOLUTION_MASK;
6243 } else {
6244 mMarginFlags &= ~NEED_RESOLUTION_MASK;
6245 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006246 }
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006247
6248 /**
6249 * Sets the relative margins, in pixels. A call to {@link android.view.View#requestLayout()}
6250 * needs to be done so that the new relative margins are taken into account. Left and right
6251 * margins may be overriden by {@link android.view.View#requestLayout()} depending on layout
6252 * direction.
6253 *
6254 * @param start the start margin size
6255 * @param top the top margin size
6256 * @param end the right margin size
6257 * @param bottom the bottom margin size
6258 *
6259 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart
6260 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginTop
6261 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd
6262 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginBottom
6263 *
6264 * @hide
6265 */
6266 public void setMarginsRelative(int start, int top, int end, int bottom) {
6267 startMargin = start;
6268 topMargin = top;
6269 endMargin = end;
6270 bottomMargin = bottom;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006271 mMarginFlags |= NEED_RESOLUTION_MASK;
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006272 }
6273
6274 /**
Fabrice Di Meglioa40627d2012-09-11 16:47:21 -07006275 * Sets the relative start margin.
6276 *
Fabrice Di Meglio61a21772012-09-12 16:33:13 -07006277 * @param start the start margin size
Fabrice Di Meglioa40627d2012-09-11 16:47:21 -07006278 *
6279 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart
6280 */
6281 public void setMarginStart(int start) {
6282 startMargin = start;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006283 mMarginFlags |= NEED_RESOLUTION_MASK;
Fabrice Di Meglioa40627d2012-09-11 16:47:21 -07006284 }
6285
6286 /**
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006287 * Returns the start margin in pixels.
6288 *
6289 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart
6290 *
6291 * @return the start margin in pixels.
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006292 */
6293 public int getMarginStart() {
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006294 if (startMargin != DEFAULT_MARGIN_RELATIVE) return startMargin;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006295 if ((mMarginFlags & NEED_RESOLUTION_MASK) == NEED_RESOLUTION_MASK) {
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006296 doResolveMargins();
6297 }
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006298 switch(mMarginFlags & LAYOUT_DIRECTION_MASK) {
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07006299 case View.LAYOUT_DIRECTION_RTL:
6300 return rightMargin;
6301 case View.LAYOUT_DIRECTION_LTR:
6302 default:
6303 return leftMargin;
6304 }
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006305 }
6306
6307 /**
Fabrice Di Meglioa40627d2012-09-11 16:47:21 -07006308 * Sets the relative end margin.
6309 *
Fabrice Di Meglio61a21772012-09-12 16:33:13 -07006310 * @param end the end margin size
Fabrice Di Meglioa40627d2012-09-11 16:47:21 -07006311 *
6312 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd
6313 */
6314 public void setMarginEnd(int end) {
6315 endMargin = end;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006316 mMarginFlags |= NEED_RESOLUTION_MASK;
Fabrice Di Meglioa40627d2012-09-11 16:47:21 -07006317 }
6318
6319 /**
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006320 * Returns the end margin in pixels.
6321 *
6322 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd
6323 *
6324 * @return the end margin in pixels.
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006325 */
6326 public int getMarginEnd() {
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006327 if (endMargin != DEFAULT_MARGIN_RELATIVE) return endMargin;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006328 if ((mMarginFlags & NEED_RESOLUTION_MASK) == NEED_RESOLUTION_MASK) {
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006329 doResolveMargins();
6330 }
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006331 switch(mMarginFlags & LAYOUT_DIRECTION_MASK) {
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07006332 case View.LAYOUT_DIRECTION_RTL:
6333 return leftMargin;
6334 case View.LAYOUT_DIRECTION_LTR:
6335 default:
6336 return rightMargin;
6337 }
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006338 }
6339
6340 /**
6341 * Check if margins are relative.
6342 *
6343 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart
6344 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd
6345 *
Fabrice Di Megliof443f982012-07-13 20:24:03 -07006346 * @return true if either marginStart or marginEnd has been set.
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006347 */
6348 public boolean isMarginRelative() {
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006349 return (startMargin != DEFAULT_MARGIN_RELATIVE || endMargin != DEFAULT_MARGIN_RELATIVE);
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006350 }
6351
6352 /**
Fabrice Di Megliof443f982012-07-13 20:24:03 -07006353 * Set the layout direction
6354 * @param layoutDirection the layout direction.
6355 * Should be either {@link View#LAYOUT_DIRECTION_LTR}
6356 * or {@link View#LAYOUT_DIRECTION_RTL}.
6357 */
6358 public void setLayoutDirection(int layoutDirection) {
6359 if (layoutDirection != View.LAYOUT_DIRECTION_LTR &&
6360 layoutDirection != View.LAYOUT_DIRECTION_RTL) return;
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006361 if (layoutDirection != (mMarginFlags & LAYOUT_DIRECTION_MASK)) {
6362 mMarginFlags &= ~LAYOUT_DIRECTION_MASK;
6363 mMarginFlags |= (layoutDirection & LAYOUT_DIRECTION_MASK);
6364 if (isMarginRelative()) {
6365 mMarginFlags |= NEED_RESOLUTION_MASK;
6366 } else {
6367 mMarginFlags &= ~NEED_RESOLUTION_MASK;
6368 }
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006369 }
Fabrice Di Megliof443f982012-07-13 20:24:03 -07006370 }
6371
6372 /**
6373 * Retuns the layout direction. Can be either {@link View#LAYOUT_DIRECTION_LTR} or
6374 * {@link View#LAYOUT_DIRECTION_RTL}.
6375 *
6376 * @return the layout direction.
6377 */
6378 public int getLayoutDirection() {
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006379 return (mMarginFlags & LAYOUT_DIRECTION_MASK);
Fabrice Di Megliof443f982012-07-13 20:24:03 -07006380 }
6381
6382 /**
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006383 * This will be called by {@link android.view.View#requestLayout()}. Left and Right margins
Fabrice Di Meglio98aec1c2012-02-13 16:54:05 -08006384 * may be overridden depending on layout direction.
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006385 */
6386 @Override
Fabrice Di Meglio2918ab62012-10-10 16:39:25 -07006387 public void resolveLayoutDirection(int layoutDirection) {
Fabrice Di Megliof443f982012-07-13 20:24:03 -07006388 setLayoutDirection(layoutDirection);
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07006389
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006390 // No relative margin or pre JB-MR1 case or no need to resolve, just dont do anything
6391 // Will use the left and right margins if no relative margin is defined.
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006392 if (!isMarginRelative() ||
6393 (mMarginFlags & NEED_RESOLUTION_MASK) != NEED_RESOLUTION_MASK) return;
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07006394
Fabrice Di Meglio0072f642013-03-26 15:50:24 -07006395 // Proceed with resolution
6396 doResolveMargins();
6397 }
6398
6399 private void doResolveMargins() {
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006400 if ((mMarginFlags & RTL_COMPATIBILITY_MODE_MASK) == RTL_COMPATIBILITY_MODE_MASK) {
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07006401 // if left or right margins are not defined and if we have some start or end margin
6402 // defined then use those start and end margins.
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006403 if ((mMarginFlags & LEFT_MARGIN_UNDEFINED_MASK) == LEFT_MARGIN_UNDEFINED_MASK
6404 && startMargin > DEFAULT_MARGIN_RELATIVE) {
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07006405 leftMargin = startMargin;
6406 }
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006407 if ((mMarginFlags & RIGHT_MARGIN_UNDEFINED_MASK) == RIGHT_MARGIN_UNDEFINED_MASK
6408 && endMargin > DEFAULT_MARGIN_RELATIVE) {
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07006409 rightMargin = endMargin;
6410 }
6411 } else {
6412 // We have some relative margins (either the start one or the end one or both). So use
6413 // them and override what has been defined for left and right margins. If either start
6414 // or end margin is not defined, just set it to default "0".
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006415 switch(mMarginFlags & LAYOUT_DIRECTION_MASK) {
Fabrice Di Meglio02a7d562013-03-27 12:41:22 -07006416 case View.LAYOUT_DIRECTION_RTL:
6417 leftMargin = (endMargin > DEFAULT_MARGIN_RELATIVE) ?
6418 endMargin : DEFAULT_MARGIN_RESOLVED;
6419 rightMargin = (startMargin > DEFAULT_MARGIN_RELATIVE) ?
6420 startMargin : DEFAULT_MARGIN_RESOLVED;
6421 break;
6422 case View.LAYOUT_DIRECTION_LTR:
6423 default:
6424 leftMargin = (startMargin > DEFAULT_MARGIN_RELATIVE) ?
6425 startMargin : DEFAULT_MARGIN_RESOLVED;
6426 rightMargin = (endMargin > DEFAULT_MARGIN_RELATIVE) ?
6427 endMargin : DEFAULT_MARGIN_RESOLVED;
6428 break;
6429 }
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006430 }
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006431 mMarginFlags &= ~NEED_RESOLUTION_MASK;
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006432 }
Philip Milne10ca24a2012-04-23 15:38:27 -07006433
Fabrice Di Meglio03b8d3a2012-09-27 17:05:27 -07006434 /**
6435 * @hide
6436 */
6437 public boolean isLayoutRtl() {
Fabrice Di Megliob365f912013-03-27 16:36:21 -07006438 return ((mMarginFlags & LAYOUT_DIRECTION_MASK) == View.LAYOUT_DIRECTION_RTL);
Fabrice Di Megliof443f982012-07-13 20:24:03 -07006439 }
6440
Philip Milne10ca24a2012-04-23 15:38:27 -07006441 /**
6442 * @hide
6443 */
6444 @Override
Philip Milne7b757812012-09-19 18:13:44 -07006445 public void onDebugDraw(View view, Canvas canvas, Paint paint) {
6446 Insets oi = isLayoutModeOptical(view.mParent) ? view.getOpticalInsets() : Insets.NONE;
6447
6448 fillDifference(canvas,
6449 view.getLeft() + oi.left,
6450 view.getTop() + oi.top,
6451 view.getRight() - oi.right,
6452 view.getBottom() - oi.bottom,
6453 leftMargin,
6454 topMargin,
6455 rightMargin,
6456 bottomMargin,
6457 paint);
Philip Milne10ca24a2012-04-23 15:38:27 -07006458 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006459 }
Adam Powell2b342f02010-08-18 18:14:13 -07006460
Jeff Brown20e987b2010-08-23 12:01:02 -07006461 /* Describes a touched view and the ids of the pointers that it has captured.
6462 *
6463 * This code assumes that pointer ids are always in the range 0..31 such that
6464 * it can use a bitfield to track which pointer ids are present.
6465 * As it happens, the lower layers of the input dispatch pipeline also use the
6466 * same trick so the assumption should be safe here...
6467 */
6468 private static final class TouchTarget {
6469 private static final int MAX_RECYCLED = 32;
Romain Guy6410c0a2013-06-17 11:21:58 -07006470 private static final Object sRecycleLock = new Object[0];
Jeff Brown20e987b2010-08-23 12:01:02 -07006471 private static TouchTarget sRecycleBin;
6472 private static int sRecycledCount;
Adam Powell2b342f02010-08-18 18:14:13 -07006473
Jeff Brown20e987b2010-08-23 12:01:02 -07006474 public static final int ALL_POINTER_IDS = -1; // all ones
Adam Powell2b342f02010-08-18 18:14:13 -07006475
Jeff Brown20e987b2010-08-23 12:01:02 -07006476 // The touched child view.
6477 public View child;
6478
6479 // The combined bit mask of pointer ids for all pointers captured by the target.
6480 public int pointerIdBits;
6481
6482 // The next target in the target list.
6483 public TouchTarget next;
6484
6485 private TouchTarget() {
Adam Powell2b342f02010-08-18 18:14:13 -07006486 }
6487
Jeff Brown20e987b2010-08-23 12:01:02 -07006488 public static TouchTarget obtain(View child, int pointerIdBits) {
6489 final TouchTarget target;
6490 synchronized (sRecycleLock) {
Adam Powell816c3be2010-08-23 18:00:05 -07006491 if (sRecycleBin == null) {
Jeff Brown20e987b2010-08-23 12:01:02 -07006492 target = new TouchTarget();
Adam Powell816c3be2010-08-23 18:00:05 -07006493 } else {
Jeff Brown20e987b2010-08-23 12:01:02 -07006494 target = sRecycleBin;
6495 sRecycleBin = target.next;
6496 sRecycledCount--;
6497 target.next = null;
Adam Powell816c3be2010-08-23 18:00:05 -07006498 }
Adam Powell816c3be2010-08-23 18:00:05 -07006499 }
Jeff Brown20e987b2010-08-23 12:01:02 -07006500 target.child = child;
6501 target.pointerIdBits = pointerIdBits;
6502 return target;
6503 }
Adam Powell816c3be2010-08-23 18:00:05 -07006504
Jeff Brown20e987b2010-08-23 12:01:02 -07006505 public void recycle() {
6506 synchronized (sRecycleLock) {
6507 if (sRecycledCount < MAX_RECYCLED) {
6508 next = sRecycleBin;
6509 sRecycleBin = this;
6510 sRecycledCount += 1;
Patrick Dubroyfb0547d2010-10-19 17:36:18 -07006511 } else {
6512 next = null;
Adam Powell816c3be2010-08-23 18:00:05 -07006513 }
Patrick Dubroyfb0547d2010-10-19 17:36:18 -07006514 child = null;
Adam Powell816c3be2010-08-23 18:00:05 -07006515 }
6516 }
Adam Powell2b342f02010-08-18 18:14:13 -07006517 }
Jeff Brown87b7f802011-06-21 18:35:45 -07006518
6519 /* Describes a hovered view. */
6520 private static final class HoverTarget {
6521 private static final int MAX_RECYCLED = 32;
Romain Guy6410c0a2013-06-17 11:21:58 -07006522 private static final Object sRecycleLock = new Object[0];
Jeff Brown87b7f802011-06-21 18:35:45 -07006523 private static HoverTarget sRecycleBin;
6524 private static int sRecycledCount;
6525
6526 // The hovered child view.
6527 public View child;
6528
6529 // The next target in the target list.
6530 public HoverTarget next;
6531
6532 private HoverTarget() {
6533 }
6534
6535 public static HoverTarget obtain(View child) {
6536 final HoverTarget target;
6537 synchronized (sRecycleLock) {
6538 if (sRecycleBin == null) {
6539 target = new HoverTarget();
6540 } else {
6541 target = sRecycleBin;
6542 sRecycleBin = target.next;
6543 sRecycledCount--;
6544 target.next = null;
6545 }
6546 }
6547 target.child = child;
6548 return target;
6549 }
6550
6551 public void recycle() {
6552 synchronized (sRecycleLock) {
6553 if (sRecycledCount < MAX_RECYCLED) {
6554 next = sRecycleBin;
6555 sRecycleBin = this;
6556 sRecycledCount += 1;
6557 } else {
6558 next = null;
6559 }
6560 child = null;
6561 }
6562 }
6563 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07006564
6565 /**
6566 * Pooled class that orderes the children of a ViewGroup from start
6567 * to end based on how they are laid out and the layout direction.
6568 */
6569 static class ChildListForAccessibility {
6570
6571 private static final int MAX_POOL_SIZE = 32;
6572
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08006573 private static final SynchronizedPool<ChildListForAccessibility> sPool =
6574 new SynchronizedPool<ChildListForAccessibility>(MAX_POOL_SIZE);
Svetoslav Ganov42138042012-03-20 11:51:39 -07006575
6576 private final ArrayList<View> mChildren = new ArrayList<View>();
6577
6578 private final ArrayList<ViewLocationHolder> mHolders = new ArrayList<ViewLocationHolder>();
6579
6580 public static ChildListForAccessibility obtain(ViewGroup parent, boolean sort) {
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08006581 ChildListForAccessibility list = sPool.acquire();
6582 if (list == null) {
6583 list = new ChildListForAccessibility();
Svetoslav Ganov42138042012-03-20 11:51:39 -07006584 }
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08006585 list.init(parent, sort);
6586 return list;
Svetoslav Ganov42138042012-03-20 11:51:39 -07006587 }
6588
6589 public void recycle() {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006590 clear();
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08006591 sPool.release(this);
Svetoslav Ganov42138042012-03-20 11:51:39 -07006592 }
6593
6594 public int getChildCount() {
6595 return mChildren.size();
6596 }
6597
6598 public View getChildAt(int index) {
6599 return mChildren.get(index);
6600 }
6601
6602 public int getChildIndex(View child) {
6603 return mChildren.indexOf(child);
6604 }
6605
6606 private void init(ViewGroup parent, boolean sort) {
6607 ArrayList<View> children = mChildren;
6608 final int childCount = parent.getChildCount();
6609 for (int i = 0; i < childCount; i++) {
6610 View child = parent.getChildAt(i);
6611 children.add(child);
6612 }
6613 if (sort) {
6614 ArrayList<ViewLocationHolder> holders = mHolders;
6615 for (int i = 0; i < childCount; i++) {
6616 View child = children.get(i);
6617 ViewLocationHolder holder = ViewLocationHolder.obtain(parent, child);
6618 holders.add(holder);
6619 }
6620 Collections.sort(holders);
6621 for (int i = 0; i < childCount; i++) {
6622 ViewLocationHolder holder = holders.get(i);
6623 children.set(i, holder.mView);
6624 holder.recycle();
6625 }
6626 holders.clear();
6627 }
6628 }
6629
6630 private void clear() {
6631 mChildren.clear();
6632 }
6633 }
6634
6635 /**
6636 * Pooled class that holds a View and its location with respect to
6637 * a specified root. This enables sorting of views based on their
6638 * coordinates without recomputing the position relative to the root
6639 * on every comparison.
6640 */
6641 static class ViewLocationHolder implements Comparable<ViewLocationHolder> {
6642
6643 private static final int MAX_POOL_SIZE = 32;
6644
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08006645 private static final SynchronizedPool<ViewLocationHolder> sPool =
6646 new SynchronizedPool<ViewLocationHolder>(MAX_POOL_SIZE);
Svetoslav Ganov42138042012-03-20 11:51:39 -07006647
6648 private final Rect mLocation = new Rect();
6649
6650 public View mView;
6651
6652 private int mLayoutDirection;
6653
6654 public static ViewLocationHolder obtain(ViewGroup root, View view) {
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08006655 ViewLocationHolder holder = sPool.acquire();
6656 if (holder == null) {
6657 holder = new ViewLocationHolder();
Svetoslav Ganov42138042012-03-20 11:51:39 -07006658 }
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08006659 holder.init(root, view);
6660 return holder;
Svetoslav Ganov42138042012-03-20 11:51:39 -07006661 }
6662
6663 public void recycle() {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006664 clear();
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08006665 sPool.release(this);
Svetoslav Ganov42138042012-03-20 11:51:39 -07006666 }
6667
6668 @Override
6669 public int compareTo(ViewLocationHolder another) {
6670 // This instance is greater than an invalid argument.
6671 if (another == null) {
6672 return 1;
6673 }
6674 if (getClass() != another.getClass()) {
6675 return 1;
6676 }
6677 // First is above second.
6678 if (mLocation.bottom - another.mLocation.top <= 0) {
6679 return -1;
6680 }
6681 // First is below second.
6682 if (mLocation.top - another.mLocation.bottom >= 0) {
6683 return 1;
6684 }
6685 // LTR
6686 if (mLayoutDirection == LAYOUT_DIRECTION_LTR) {
6687 final int leftDifference = mLocation.left - another.mLocation.left;
6688 // First more to the left than second.
6689 if (leftDifference != 0) {
6690 return leftDifference;
6691 }
6692 } else { // RTL
6693 final int rightDifference = mLocation.right - another.mLocation.right;
6694 // First more to the right than second.
6695 if (rightDifference != 0) {
6696 return -rightDifference;
6697 }
6698 }
6699 // Break tie by top.
6700 final int topDiference = mLocation.top - another.mLocation.top;
6701 if (topDiference != 0) {
6702 return topDiference;
6703 }
6704 // Break tie by height.
6705 final int heightDiference = mLocation.height() - another.mLocation.height();
6706 if (heightDiference != 0) {
6707 return -heightDiference;
6708 }
6709 // Break tie by width.
6710 final int widthDiference = mLocation.width() - another.mLocation.width();
6711 if (widthDiference != 0) {
6712 return -widthDiference;
6713 }
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07006714 // Just break the tie somehow. The accessibliity ids are unique
6715 // and stable, hence this is deterministic tie breaking.
6716 return mView.getAccessibilityViewId() - another.mView.getAccessibilityViewId();
Svetoslav Ganov42138042012-03-20 11:51:39 -07006717 }
6718
6719 private void init(ViewGroup root, View view) {
6720 Rect viewLocation = mLocation;
6721 view.getDrawingRect(viewLocation);
6722 root.offsetDescendantRectToMyCoords(view, viewLocation);
6723 mView = view;
Fabrice Di Meglioe56ffdc2012-09-23 14:51:16 -07006724 mLayoutDirection = root.getLayoutDirection();
Svetoslav Ganov42138042012-03-20 11:51:39 -07006725 }
6726
6727 private void clear() {
6728 mView = null;
6729 mLocation.set(0, 0, 0, 0);
6730 }
6731 }
Romain Guycbc67742012-04-27 16:12:57 -07006732
6733 private static Paint getDebugPaint() {
6734 if (sDebugPaint == null) {
6735 sDebugPaint = new Paint();
6736 sDebugPaint.setAntiAlias(false);
6737 }
6738 return sDebugPaint;
6739 }
6740
Romain Guy6410c0a2013-06-17 11:21:58 -07006741 private static void drawRect(Canvas canvas, Paint paint, int x1, int y1, int x2, int y2) {
Romain Guycbc67742012-04-27 16:12:57 -07006742 if (sDebugLines== null) {
Romain Guy6410c0a2013-06-17 11:21:58 -07006743 // TODO: This won't work with multiple UI threads in a single process
Romain Guycbc67742012-04-27 16:12:57 -07006744 sDebugLines = new float[16];
6745 }
6746
Romain Guycbc67742012-04-27 16:12:57 -07006747 sDebugLines[0] = x1;
6748 sDebugLines[1] = y1;
6749 sDebugLines[2] = x2;
6750 sDebugLines[3] = y1;
6751
6752 sDebugLines[4] = x2;
6753 sDebugLines[5] = y1;
6754 sDebugLines[6] = x2;
Philip Milne7b757812012-09-19 18:13:44 -07006755 sDebugLines[7] = y2;
Romain Guycbc67742012-04-27 16:12:57 -07006756
Philip Milne7b757812012-09-19 18:13:44 -07006757 sDebugLines[8] = x2;
Romain Guycbc67742012-04-27 16:12:57 -07006758 sDebugLines[9] = y2;
6759 sDebugLines[10] = x1;
6760 sDebugLines[11] = y2;
6761
Philip Milne7b757812012-09-19 18:13:44 -07006762 sDebugLines[12] = x1;
6763 sDebugLines[13] = y2;
Romain Guycbc67742012-04-27 16:12:57 -07006764 sDebugLines[14] = x1;
6765 sDebugLines[15] = y1;
6766
Philip Milne7b757812012-09-19 18:13:44 -07006767 canvas.drawLines(sDebugLines, paint);
Romain Guycbc67742012-04-27 16:12:57 -07006768 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006769}