blob: 688e17e154a9dcbd0c60768849b235a09a7e241b [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;
Svetoslav Ganov8643aa02011-04-20 12:12:33 -070041import android.view.accessibility.AccessibilityNodeInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080042import android.view.animation.Animation;
43import android.view.animation.AnimationUtils;
44import android.view.animation.LayoutAnimationController;
45import android.view.animation.Transformation;
Doug Feltcb379122011-07-07 11:57:48 -070046
Romain Guy0211a0a2011-02-14 16:34:59 -080047import com.android.internal.R;
48import com.android.internal.util.Predicate;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049
50import java.util.ArrayList;
Svetoslav Ganov42138042012-03-20 11:51:39 -070051import java.util.Collections;
Christopher Tate86cab1b2011-01-13 20:28:55 -080052import java.util.HashSet;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053
54/**
55 * <p>
56 * A <code>ViewGroup</code> is a special view that can contain other views
57 * (called children.) The view group is the base class for layouts and views
58 * containers. This class also defines the
59 * {@link android.view.ViewGroup.LayoutParams} class which serves as the base
60 * class for layouts parameters.
61 * </p>
62 *
63 * <p>
64 * Also see {@link LayoutParams} for layout attributes.
65 * </p>
Romain Guyd6a463a2009-05-21 23:10:10 -070066 *
Joe Fernandez558459f2011-10-13 16:47:36 -070067 * <div class="special reference">
68 * <h3>Developer Guides</h3>
69 * <p>For more information about creating user interface layouts, read the
70 * <a href="{@docRoot}guide/topics/ui/declaring-layout.html">XML Layouts</a> developer
71 * guide.</p></div>
72 *
Dianne Hackborn7caab0f2013-03-06 13:47:04 -080073 * <p>Here is a complete implementation of a custom ViewGroup that implements
74 * a simple {@link android.widget.FrameLayout} along with the ability to stack
75 * children in left and right gutters.</p>
76 *
77 * {@sample development/samples/ApiDemos/src/com/example/android/apis/view/CustomLayout.java
78 * Complete}
79 *
80 * <p>If you are implementing XML layout attributes as shown in the example, this is the
81 * corresponding definition for them that would go in <code>res/values/attrs.xml</code>:</p>
82 *
83 * {@sample development/samples/ApiDemos/res/values/attrs.xml CustomLayout}
84 *
85 * <p>Finally the layout manager can be used in an XML layout like so:</p>
86 *
87 * {@sample development/samples/ApiDemos/res/layout/custom_layout.xml Complete}
88 *
Romain Guyd6a463a2009-05-21 23:10:10 -070089 * @attr ref android.R.styleable#ViewGroup_clipChildren
90 * @attr ref android.R.styleable#ViewGroup_clipToPadding
91 * @attr ref android.R.styleable#ViewGroup_layoutAnimation
92 * @attr ref android.R.styleable#ViewGroup_animationCache
93 * @attr ref android.R.styleable#ViewGroup_persistentDrawingCache
94 * @attr ref android.R.styleable#ViewGroup_alwaysDrawnWithCache
95 * @attr ref android.R.styleable#ViewGroup_addStatesFromChildren
96 * @attr ref android.R.styleable#ViewGroup_descendantFocusability
Chet Haase13cc1202010-09-03 15:39:20 -070097 * @attr ref android.R.styleable#ViewGroup_animateLayoutChanges
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080098 */
99public abstract class ViewGroup extends View implements ViewParent, ViewManager {
Adam Powell539ee872012-02-03 19:00:49 -0800100 private static final String TAG = "ViewGroup";
Chet Haase21cd1382010-09-01 17:42:29 -0700101
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800102 private static final boolean DBG = false;
Philip Milne7b757812012-09-19 18:13:44 -0700103 /** @hide */
104 public static boolean DEBUG_DRAW = false;
Gilles Debunnecea45132011-11-24 02:19:27 +0100105
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800106 /**
107 * Views which have been hidden or removed which need to be animated on
108 * their way out.
109 * This field should be made private, so it is hidden from the SDK.
110 * {@hide}
111 */
112 protected ArrayList<View> mDisappearingChildren;
113
114 /**
115 * Listener used to propagate events indicating when children are added
116 * and/or removed from a view group.
117 * This field should be made private, so it is hidden from the SDK.
118 * {@hide}
119 */
120 protected OnHierarchyChangeListener mOnHierarchyChangeListener;
121
122 // The view contained within this ViewGroup that has or contains focus.
123 private View mFocused;
124
Chet Haase48460322010-06-11 14:22:25 -0700125 /**
126 * A Transformation used when drawing children, to
127 * apply on the child being drawn.
128 */
Chet Haase64a48c12012-02-13 16:33:29 -0800129 final Transformation mChildTransformation = new Transformation();
Chet Haase48460322010-06-11 14:22:25 -0700130
131 /**
132 * Used to track the current invalidation region.
133 */
Chet Haase64a48c12012-02-13 16:33:29 -0800134 RectF mInvalidateRegion;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800135
Chet Haase48460322010-06-11 14:22:25 -0700136 /**
137 * A Transformation used to calculate a correct
138 * invalidation area when the application is autoscaled.
139 */
Chet Haase64a48c12012-02-13 16:33:29 -0800140 Transformation mInvalidationTransformation;
Chet Haase48460322010-06-11 14:22:25 -0700141
Christopher Tatea53146c2010-09-07 11:57:52 -0700142 // View currently under an ongoing drag
143 private View mCurrentDragView;
144
Christopher Tate86cab1b2011-01-13 20:28:55 -0800145 // Metadata about the ongoing drag
146 private DragEvent mCurrentDrag;
147 private HashSet<View> mDragNotifiedChildren;
148
Christopher Tatea53146c2010-09-07 11:57:52 -0700149 // Does this group have a child that can accept the current drag payload?
150 private boolean mChildAcceptsDrag;
151
152 // Used during drag dispatch
153 private final PointF mLocalPoint = new PointF();
154
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800155 // Layout animation
156 private LayoutAnimationController mLayoutAnimationController;
157 private Animation.AnimationListener mAnimationListener;
158
Jeff Brown20e987b2010-08-23 12:01:02 -0700159 // First touch target in the linked list of touch targets.
160 private TouchTarget mFirstTouchTarget;
161
Joe Onorato03ab0c72011-01-06 15:46:27 -0800162 // For debugging only. You can see these in hierarchyviewer.
Romain Guye95003e2011-01-09 13:53:06 -0800163 @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"})
Joe Onorato03ab0c72011-01-06 15:46:27 -0800164 @ViewDebug.ExportedProperty(category = "events")
165 private long mLastTouchDownTime;
166 @ViewDebug.ExportedProperty(category = "events")
167 private int mLastTouchDownIndex = -1;
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 float mLastTouchDownX;
Romain Guye95003e2011-01-09 13:53:06 -0800171 @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"})
Joe Onorato03ab0c72011-01-06 15:46:27 -0800172 @ViewDebug.ExportedProperty(category = "events")
173 private float mLastTouchDownY;
174
Jeff Brown87b7f802011-06-21 18:35:45 -0700175 // First hover target in the linked list of hover targets.
176 // The hover targets are children which have received ACTION_HOVER_ENTER.
177 // They might not have actually handled the hover event, but we will
178 // continue sending hover events to them as long as the pointer remains over
179 // their bounds and the view group does not intercept hover.
180 private HoverTarget mFirstHoverTarget;
Jeff Browna032cc02011-03-07 16:56:21 -0800181
Jeff Brown10b62902011-06-20 16:40:37 -0700182 // True if the view group itself received a hover event.
183 // It might not have actually handled the hover event.
184 private boolean mHoveredSelf;
185
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800186 /**
187 * Internal flags.
Romain Guy8506ab42009-06-11 17:35:47 -0700188 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800189 * This field should be made private, so it is hidden from the SDK.
190 * {@hide}
191 */
Romain Guy2440e672012-08-07 14:43:43 -0700192 @ViewDebug.ExportedProperty(flagMapping = {
193 @ViewDebug.FlagToString(mask = FLAG_CLIP_CHILDREN, equals = FLAG_CLIP_CHILDREN,
194 name = "CLIP_CHILDREN"),
195 @ViewDebug.FlagToString(mask = FLAG_CLIP_TO_PADDING, equals = FLAG_CLIP_TO_PADDING,
196 name = "CLIP_TO_PADDING"),
197 @ViewDebug.FlagToString(mask = FLAG_PADDING_NOT_NULL, equals = FLAG_PADDING_NOT_NULL,
198 name = "PADDING_NOT_NULL")
199 })
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800200 protected int mGroupFlags;
201
Philip Milne7b757812012-09-19 18:13:44 -0700202 /**
203 * Either {@link #LAYOUT_MODE_CLIP_BOUNDS} or {@link #LAYOUT_MODE_OPTICAL_BOUNDS}.
Philip Milne1557fd72012-04-04 23:41:34 -0700204 */
Philip Milne7b757812012-09-19 18:13:44 -0700205 private int mLayoutMode = DEFAULT_LAYOUT_MODE;
Philip Milne1557fd72012-04-04 23:41:34 -0700206
Romain Guy33f6beb2012-02-16 19:24:51 -0800207 /**
208 * NOTE: If you change the flags below make sure to reflect the changes
209 * the DisplayList class
210 */
211
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800212 // When set, ViewGroup invalidates only the child's rectangle
213 // Set by default
Chet Haase64a48c12012-02-13 16:33:29 -0800214 static final int FLAG_CLIP_CHILDREN = 0x1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800215
216 // When set, ViewGroup excludes the padding area from the invalidate rectangle
217 // Set by default
218 private static final int FLAG_CLIP_TO_PADDING = 0x2;
219
220 // When set, dispatchDraw() will invoke invalidate(); this is set by drawChild() when
221 // a child needs to be invalidated and FLAG_OPTIMIZE_INVALIDATE is set
Chet Haase64a48c12012-02-13 16:33:29 -0800222 static final int FLAG_INVALIDATE_REQUIRED = 0x4;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800223
224 // When set, dispatchDraw() will run the layout animation and unset the flag
225 private static final int FLAG_RUN_ANIMATION = 0x8;
226
227 // When set, there is either no layout animation on the ViewGroup or the layout
228 // animation is over
229 // Set by default
Chet Haase64a48c12012-02-13 16:33:29 -0800230 static final int FLAG_ANIMATION_DONE = 0x10;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800231
232 // If set, this ViewGroup has padding; if unset there is no padding and we don't need
233 // to clip it, even if FLAG_CLIP_TO_PADDING is set
234 private static final int FLAG_PADDING_NOT_NULL = 0x20;
235
236 // When set, this ViewGroup caches its children in a Bitmap before starting a layout animation
237 // Set by default
238 private static final int FLAG_ANIMATION_CACHE = 0x40;
239
240 // When set, this ViewGroup converts calls to invalidate(Rect) to invalidate() during a
241 // layout animation; this avoid clobbering the hierarchy
242 // Automatically set when the layout animation starts, depending on the animation's
243 // characteristics
Chet Haase64a48c12012-02-13 16:33:29 -0800244 static final int FLAG_OPTIMIZE_INVALIDATE = 0x80;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800245
246 // When set, the next call to drawChild() will clear mChildTransformation's matrix
Chet Haase64a48c12012-02-13 16:33:29 -0800247 static final int FLAG_CLEAR_TRANSFORMATION = 0x100;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800248
249 // When set, this ViewGroup invokes mAnimationListener.onAnimationEnd() and removes
250 // the children's Bitmap caches if necessary
251 // This flag is set when the layout animation is over (after FLAG_ANIMATION_DONE is set)
252 private static final int FLAG_NOTIFY_ANIMATION_LISTENER = 0x200;
253
254 /**
255 * When set, the drawing method will call {@link #getChildDrawingOrder(int, int)}
256 * to get the index of the child to draw for that iteration.
Romain Guy293451e2009-11-04 13:59:48 -0800257 *
258 * @hide
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800259 */
260 protected static final int FLAG_USE_CHILD_DRAWING_ORDER = 0x400;
Romain Guy8506ab42009-06-11 17:35:47 -0700261
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800262 /**
263 * When set, this ViewGroup supports static transformations on children; this causes
264 * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} to be
265 * invoked when a child is drawn.
266 *
267 * Any subclass overriding
268 * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} should
269 * set this flags in {@link #mGroupFlags}.
Romain Guy8506ab42009-06-11 17:35:47 -0700270 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800271 * {@hide}
272 */
273 protected static final int FLAG_SUPPORT_STATIC_TRANSFORMATIONS = 0x800;
274
275 // When the previous drawChild() invocation used an alpha value that was lower than
276 // 1.0 and set it in mCachePaint
Chet Haase64a48c12012-02-13 16:33:29 -0800277 static final int FLAG_ALPHA_LOWER_THAN_ONE = 0x1000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800278
279 /**
280 * When set, this ViewGroup's drawable states also include those
281 * of its children.
282 */
283 private static final int FLAG_ADD_STATES_FROM_CHILDREN = 0x2000;
284
285 /**
286 * When set, this ViewGroup tries to always draw its children using their drawing cache.
287 */
Chet Haase64a48c12012-02-13 16:33:29 -0800288 static final int FLAG_ALWAYS_DRAWN_WITH_CACHE = 0x4000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800289
290 /**
291 * When set, and if FLAG_ALWAYS_DRAWN_WITH_CACHE is not set, this ViewGroup will try to
292 * draw its children with their drawing cache.
293 */
Chet Haase64a48c12012-02-13 16:33:29 -0800294 static final int FLAG_CHILDREN_DRAWN_WITH_CACHE = 0x8000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800295
296 /**
297 * When set, this group will go through its list of children to notify them of
298 * any drawable state change.
299 */
300 private static final int FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE = 0x10000;
301
302 private static final int FLAG_MASK_FOCUSABILITY = 0x60000;
303
304 /**
305 * This view will get focus before any of its descendants.
306 */
307 public static final int FOCUS_BEFORE_DESCENDANTS = 0x20000;
308
309 /**
310 * This view will get focus only if none of its descendants want it.
311 */
312 public static final int FOCUS_AFTER_DESCENDANTS = 0x40000;
313
314 /**
315 * This view will block any of its descendants from getting focus, even
316 * if they are focusable.
317 */
318 public static final int FOCUS_BLOCK_DESCENDANTS = 0x60000;
319
320 /**
321 * Used to map between enum in attrubutes and flag values.
322 */
323 private static final int[] DESCENDANT_FOCUSABILITY_FLAGS =
324 {FOCUS_BEFORE_DESCENDANTS, FOCUS_AFTER_DESCENDANTS,
325 FOCUS_BLOCK_DESCENDANTS};
326
327 /**
328 * When set, this ViewGroup should not intercept touch events.
Adam Powell110486f2010-06-22 17:14:44 -0700329 * {@hide}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800330 */
Adam Powell110486f2010-06-22 17:14:44 -0700331 protected static final int FLAG_DISALLOW_INTERCEPT = 0x80000;
Romain Guy8506ab42009-06-11 17:35:47 -0700332
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800333 /**
Adam Powell2b342f02010-08-18 18:14:13 -0700334 * When set, this ViewGroup will split MotionEvents to multiple child Views when appropriate.
335 */
Adam Powellf37df072010-09-17 16:22:49 -0700336 private static final int FLAG_SPLIT_MOTION_EVENTS = 0x200000;
Adam Powell2b342f02010-08-18 18:14:13 -0700337
338 /**
Adam Powell4b867882011-09-16 12:59:46 -0700339 * When set, this ViewGroup will not dispatch onAttachedToWindow calls
340 * to children when adding new views. This is used to prevent multiple
341 * onAttached calls when a ViewGroup adds children in its own onAttached method.
342 */
343 private static final int FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW = 0x400000;
344
345 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800346 * Indicates which types of drawing caches are to be kept in memory.
347 * This field should be made private, so it is hidden from the SDK.
348 * {@hide}
349 */
350 protected int mPersistentDrawingCache;
351
352 /**
353 * Used to indicate that no drawing cache should be kept in memory.
354 */
355 public static final int PERSISTENT_NO_CACHE = 0x0;
356
357 /**
358 * Used to indicate that the animation drawing cache should be kept in memory.
359 */
360 public static final int PERSISTENT_ANIMATION_CACHE = 0x1;
361
362 /**
363 * Used to indicate that the scrolling drawing cache should be kept in memory.
364 */
365 public static final int PERSISTENT_SCROLLING_CACHE = 0x2;
366
367 /**
368 * Used to indicate that all drawing caches should be kept in memory.
369 */
370 public static final int PERSISTENT_ALL_CACHES = 0x3;
371
Philip Milne1557fd72012-04-04 23:41:34 -0700372 // Layout Modes
373
Philip Milne1557fd72012-04-04 23:41:34 -0700374 /**
375 * This constant is a {@link #setLayoutMode(int) layoutMode}.
Philip Milne7a23b492012-04-24 22:12:36 -0700376 * Clip bounds are the raw values of {@link #getLeft() left}, {@link #getTop() top},
Philip Milne1557fd72012-04-04 23:41:34 -0700377 * {@link #getRight() right} and {@link #getBottom() bottom}.
378 */
Philip Milne7b757812012-09-19 18:13:44 -0700379 public static final int LAYOUT_MODE_CLIP_BOUNDS = 0;
Philip Milne1557fd72012-04-04 23:41:34 -0700380
381 /**
382 * This constant is a {@link #setLayoutMode(int) layoutMode}.
Philip Milne7a23b492012-04-24 22:12:36 -0700383 * Optical bounds describe where a widget appears to be. They sit inside the clip
384 * bounds which need to cover a larger area to allow other effects,
385 * such as shadows and glows, to be drawn.
Philip Milne1557fd72012-04-04 23:41:34 -0700386 */
Philip Milne7b757812012-09-19 18:13:44 -0700387 public static final int LAYOUT_MODE_OPTICAL_BOUNDS = 1;
388
389 /** @hide */
390 public static int DEFAULT_LAYOUT_MODE = LAYOUT_MODE_CLIP_BOUNDS;
Philip Milne1557fd72012-04-04 23:41:34 -0700391
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800392 /**
393 * We clip to padding when FLAG_CLIP_TO_PADDING and FLAG_PADDING_NOT_NULL
394 * are set at the same time.
395 */
396 protected static final int CLIP_TO_PADDING_MASK = FLAG_CLIP_TO_PADDING | FLAG_PADDING_NOT_NULL;
397
398 // Index of the child's left position in the mLocation array
399 private static final int CHILD_LEFT_INDEX = 0;
400 // Index of the child's top position in the mLocation array
401 private static final int CHILD_TOP_INDEX = 1;
402
403 // Child views of this ViewGroup
404 private View[] mChildren;
405 // Number of valid children in the mChildren array, the rest should be null or not
406 // considered as children
Chet Haase9c087442011-01-12 16:20:16 -0800407
408 private boolean mLayoutSuppressed = false;
409
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800410 private int mChildrenCount;
411
412 private static final int ARRAY_INITIAL_CAPACITY = 12;
413 private static final int ARRAY_CAPACITY_INCREMENT = 12;
414
Romain Guycbc67742012-04-27 16:12:57 -0700415 private static Paint sDebugPaint;
416 private static float[] sDebugLines;
Philip Milne604f4402012-04-24 19:27:11 -0700417
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800418 // Used to draw cached views
Chet Haase64a48c12012-02-13 16:33:29 -0800419 Paint mCachePaint;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800420
Chet Haase21cd1382010-09-01 17:42:29 -0700421 // Used to animate add/remove changes in layout
422 private LayoutTransition mTransition;
423
424 // The set of views that are currently being transitioned. This list is used to track views
425 // being removed that should not actually be removed from the parent yet because they are
426 // being animated.
427 private ArrayList<View> mTransitioningViews;
428
Chet Haase5e25c2c2010-09-16 11:15:56 -0700429 // List of children changing visibility. This is used to potentially keep rendering
430 // views during a transition when they otherwise would have become gone/invisible
431 private ArrayList<View> mVisibilityChangingChildren;
432
Adam Powell539ee872012-02-03 19:00:49 -0800433 // Indicates how many of this container's child subtrees contain transient state
434 @ViewDebug.ExportedProperty(category = "layout")
435 private int mChildCountWithTransientState = 0;
436
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800437 public ViewGroup(Context context) {
438 super(context);
439 initViewGroup();
440 }
441
442 public ViewGroup(Context context, AttributeSet attrs) {
443 super(context, attrs);
444 initViewGroup();
445 initFromAttributes(context, attrs);
446 }
447
448 public ViewGroup(Context context, AttributeSet attrs, int defStyle) {
449 super(context, attrs, defStyle);
450 initViewGroup();
451 initFromAttributes(context, attrs);
452 }
453
Philip Milne10ca24a2012-04-23 15:38:27 -0700454 private boolean debugDraw() {
Philip Milne7b757812012-09-19 18:13:44 -0700455 return DEBUG_DRAW || mAttachInfo != null && mAttachInfo.mDebugLayout;
Philip Milne10ca24a2012-04-23 15:38:27 -0700456 }
457
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800458 private void initViewGroup() {
459 // ViewGroup doesn't draw by default
Philip Milne10ca24a2012-04-23 15:38:27 -0700460 if (!debugDraw()) {
461 setFlags(WILL_NOT_DRAW, DRAW_MASK);
462 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800463 mGroupFlags |= FLAG_CLIP_CHILDREN;
464 mGroupFlags |= FLAG_CLIP_TO_PADDING;
465 mGroupFlags |= FLAG_ANIMATION_DONE;
466 mGroupFlags |= FLAG_ANIMATION_CACHE;
467 mGroupFlags |= FLAG_ALWAYS_DRAWN_WITH_CACHE;
468
Jeff Brown995e7742010-12-22 16:59:36 -0800469 if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB) {
470 mGroupFlags |= FLAG_SPLIT_MOTION_EVENTS;
471 }
472
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800473 setDescendantFocusability(FOCUS_BEFORE_DESCENDANTS);
474
475 mChildren = new View[ARRAY_INITIAL_CAPACITY];
476 mChildrenCount = 0;
477
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800478 mPersistentDrawingCache = PERSISTENT_SCROLLING_CACHE;
479 }
480
481 private void initFromAttributes(Context context, AttributeSet attrs) {
482 TypedArray a = context.obtainStyledAttributes(attrs,
483 R.styleable.ViewGroup);
484
485 final int N = a.getIndexCount();
486 for (int i = 0; i < N; i++) {
487 int attr = a.getIndex(i);
488 switch (attr) {
489 case R.styleable.ViewGroup_clipChildren:
490 setClipChildren(a.getBoolean(attr, true));
491 break;
492 case R.styleable.ViewGroup_clipToPadding:
493 setClipToPadding(a.getBoolean(attr, true));
494 break;
495 case R.styleable.ViewGroup_animationCache:
496 setAnimationCacheEnabled(a.getBoolean(attr, true));
497 break;
498 case R.styleable.ViewGroup_persistentDrawingCache:
499 setPersistentDrawingCache(a.getInt(attr, PERSISTENT_SCROLLING_CACHE));
500 break;
501 case R.styleable.ViewGroup_addStatesFromChildren:
502 setAddStatesFromChildren(a.getBoolean(attr, false));
503 break;
504 case R.styleable.ViewGroup_alwaysDrawnWithCache:
505 setAlwaysDrawnWithCacheEnabled(a.getBoolean(attr, true));
506 break;
507 case R.styleable.ViewGroup_layoutAnimation:
508 int id = a.getResourceId(attr, -1);
509 if (id > 0) {
510 setLayoutAnimation(AnimationUtils.loadLayoutAnimation(mContext, id));
511 }
512 break;
513 case R.styleable.ViewGroup_descendantFocusability:
514 setDescendantFocusability(DESCENDANT_FOCUSABILITY_FLAGS[a.getInt(attr, 0)]);
515 break;
Adam Powell2b342f02010-08-18 18:14:13 -0700516 case R.styleable.ViewGroup_splitMotionEvents:
517 setMotionEventSplittingEnabled(a.getBoolean(attr, false));
518 break;
Chet Haase13cc1202010-09-03 15:39:20 -0700519 case R.styleable.ViewGroup_animateLayoutChanges:
520 boolean animateLayoutChanges = a.getBoolean(attr, false);
521 if (animateLayoutChanges) {
522 setLayoutTransition(new LayoutTransition());
523 }
524 break;
Philip Milne7b757812012-09-19 18:13:44 -0700525 case R.styleable.ViewGroup_layoutMode:
526 setLayoutMode(a.getInt(attr, DEFAULT_LAYOUT_MODE));
527 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800528 }
529 }
530
531 a.recycle();
532 }
533
534 /**
535 * Gets the descendant focusability of this view group. The descendant
536 * focusability defines the relationship between this view group and its
537 * descendants when looking for a view to take focus in
538 * {@link #requestFocus(int, android.graphics.Rect)}.
539 *
540 * @return one of {@link #FOCUS_BEFORE_DESCENDANTS}, {@link #FOCUS_AFTER_DESCENDANTS},
541 * {@link #FOCUS_BLOCK_DESCENDANTS}.
542 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -0700543 @ViewDebug.ExportedProperty(category = "focus", mapping = {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800544 @ViewDebug.IntToString(from = FOCUS_BEFORE_DESCENDANTS, to = "FOCUS_BEFORE_DESCENDANTS"),
545 @ViewDebug.IntToString(from = FOCUS_AFTER_DESCENDANTS, to = "FOCUS_AFTER_DESCENDANTS"),
546 @ViewDebug.IntToString(from = FOCUS_BLOCK_DESCENDANTS, to = "FOCUS_BLOCK_DESCENDANTS")
547 })
548 public int getDescendantFocusability() {
549 return mGroupFlags & FLAG_MASK_FOCUSABILITY;
550 }
551
552 /**
553 * Set the descendant focusability of this view group. This defines the relationship
554 * between this view group and its descendants when looking for a view to
555 * take focus in {@link #requestFocus(int, android.graphics.Rect)}.
556 *
557 * @param focusability one of {@link #FOCUS_BEFORE_DESCENDANTS}, {@link #FOCUS_AFTER_DESCENDANTS},
558 * {@link #FOCUS_BLOCK_DESCENDANTS}.
559 */
560 public void setDescendantFocusability(int focusability) {
561 switch (focusability) {
562 case FOCUS_BEFORE_DESCENDANTS:
563 case FOCUS_AFTER_DESCENDANTS:
564 case FOCUS_BLOCK_DESCENDANTS:
565 break;
566 default:
567 throw new IllegalArgumentException("must be one of FOCUS_BEFORE_DESCENDANTS, "
568 + "FOCUS_AFTER_DESCENDANTS, FOCUS_BLOCK_DESCENDANTS");
569 }
570 mGroupFlags &= ~FLAG_MASK_FOCUSABILITY;
571 mGroupFlags |= (focusability & FLAG_MASK_FOCUSABILITY);
572 }
573
574 /**
575 * {@inheritDoc}
576 */
577 @Override
578 void handleFocusGainInternal(int direction, Rect previouslyFocusedRect) {
579 if (mFocused != null) {
580 mFocused.unFocus();
581 mFocused = null;
582 }
583 super.handleFocusGainInternal(direction, previouslyFocusedRect);
584 }
585
586 /**
587 * {@inheritDoc}
588 */
589 public void requestChildFocus(View child, View focused) {
590 if (DBG) {
591 System.out.println(this + " requestChildFocus()");
592 }
593 if (getDescendantFocusability() == FOCUS_BLOCK_DESCENDANTS) {
594 return;
595 }
596
597 // Unfocus us, if necessary
598 super.unFocus();
599
600 // We had a previous notion of who had focus. Clear it.
601 if (mFocused != child) {
602 if (mFocused != null) {
603 mFocused.unFocus();
604 }
605
606 mFocused = child;
607 }
608 if (mParent != null) {
609 mParent.requestChildFocus(this, focused);
610 }
611 }
612
613 /**
614 * {@inheritDoc}
615 */
616 public void focusableViewAvailable(View v) {
617 if (mParent != null
618 // shortcut: don't report a new focusable view if we block our descendants from
619 // getting focus
620 && (getDescendantFocusability() != FOCUS_BLOCK_DESCENDANTS)
621 // shortcut: don't report a new focusable view if we already are focused
622 // (and we don't prefer our descendants)
623 //
624 // note: knowing that mFocused is non-null is not a good enough reason
625 // to break the traversal since in that case we'd actually have to find
626 // the focused view and make sure it wasn't FOCUS_AFTER_DESCENDANTS and
Joe Onoratoc6cc0f82011-04-12 11:53:13 -0700627 // an ancestor of v; this will get checked for at ViewAncestor
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800628 && !(isFocused() && getDescendantFocusability() != FOCUS_AFTER_DESCENDANTS)) {
629 mParent.focusableViewAvailable(v);
630 }
631 }
632
633 /**
634 * {@inheritDoc}
635 */
636 public boolean showContextMenuForChild(View originalView) {
637 return mParent != null && mParent.showContextMenuForChild(originalView);
638 }
639
640 /**
Adam Powell6e346362010-07-23 10:18:23 -0700641 * {@inheritDoc}
642 */
643 public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback) {
644 return mParent != null ? mParent.startActionModeForChild(originalView, callback) : null;
645 }
646
647 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800648 * Find the nearest view in the specified direction that wants to take
649 * focus.
650 *
651 * @param focused The view that currently has focus
652 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and
653 * FOCUS_RIGHT, or 0 for not applicable.
654 */
655 public View focusSearch(View focused, int direction) {
Svetoslav Ganov27e2da72012-07-02 18:12:00 -0700656 if (isRootNamespace()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800657 // root namespace means we should consider ourselves the top of the
658 // tree for focus searching; otherwise we could be focus searching
659 // into other tabs. see LocalActivityManager and TabHost for more info
660 return FocusFinder.getInstance().findNextFocus(this, focused, direction);
661 } else if (mParent != null) {
662 return mParent.focusSearch(focused, direction);
663 }
664 return null;
665 }
666
667 /**
668 * {@inheritDoc}
669 */
670 public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
671 return false;
672 }
673
674 /**
675 * {@inheritDoc}
676 */
Svetoslav Ganov42138042012-03-20 11:51:39 -0700677 @Override
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700678 public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event) {
Svetoslav Ganov42138042012-03-20 11:51:39 -0700679 ViewParent parent = mParent;
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700680 if (parent == null) {
681 return false;
682 }
683 final boolean propagate = onRequestSendAccessibilityEvent(child, event);
684 if (!propagate) {
685 return false;
686 }
687 return parent.requestSendAccessibilityEvent(this, event);
688 }
689
690 /**
691 * Called when a child has requested sending an {@link AccessibilityEvent} and
692 * gives an opportunity to its parent to augment the event.
Svetoslav Ganov031d9c12011-09-09 16:41:13 -0700693 * <p>
Adam Powell2fcbbd02011-09-28 18:56:43 -0700694 * If an {@link android.view.View.AccessibilityDelegate} has been specified via calling
695 * {@link android.view.View#setAccessibilityDelegate(android.view.View.AccessibilityDelegate)} its
696 * {@link android.view.View.AccessibilityDelegate#onRequestSendAccessibilityEvent(ViewGroup, View, AccessibilityEvent)}
Svetoslav Ganov031d9c12011-09-09 16:41:13 -0700697 * is responsible for handling this call.
698 * </p>
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700699 *
700 * @param child The child which requests sending the event.
701 * @param event The event to be sent.
702 * @return True if the event should be sent.
703 *
704 * @see #requestSendAccessibilityEvent(View, AccessibilityEvent)
705 */
706 public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
Svetoslav Ganov031d9c12011-09-09 16:41:13 -0700707 if (mAccessibilityDelegate != null) {
708 return mAccessibilityDelegate.onRequestSendAccessibilityEvent(this, child, event);
709 } else {
710 return onRequestSendAccessibilityEventInternal(child, event);
711 }
712 }
713
714 /**
715 * @see #onRequestSendAccessibilityEvent(View, AccessibilityEvent)
716 *
717 * Note: Called from the default {@link View.AccessibilityDelegate}.
718 */
719 boolean onRequestSendAccessibilityEventInternal(View child, AccessibilityEvent event) {
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700720 return true;
721 }
722
723 /**
Adam Powell539ee872012-02-03 19:00:49 -0800724 * Called when a child view has changed whether or not it is tracking transient state.
725 *
726 * @hide
727 */
728 public void childHasTransientStateChanged(View child, boolean childHasTransientState) {
729 final boolean oldHasTransientState = hasTransientState();
730 if (childHasTransientState) {
731 mChildCountWithTransientState++;
732 } else {
733 mChildCountWithTransientState--;
734 }
735
736 final boolean newHasTransientState = hasTransientState();
737 if (mParent != null && oldHasTransientState != newHasTransientState) {
738 try {
739 mParent.childHasTransientStateChanged(this, newHasTransientState);
740 } catch (AbstractMethodError e) {
741 Log.e(TAG, mParent.getClass().getSimpleName() +
742 " does not fully implement ViewParent", e);
743 }
744 }
745 }
746
747 /**
748 * @hide
749 */
750 @Override
751 public boolean hasTransientState() {
752 return mChildCountWithTransientState > 0 || super.hasTransientState();
753 }
754
755 /**
Svetoslav Ganov736c2752011-04-22 18:30:36 -0700756 * {@inheritDoc}
757 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800758 @Override
759 public boolean dispatchUnhandledMove(View focused, int direction) {
760 return mFocused != null &&
761 mFocused.dispatchUnhandledMove(focused, direction);
762 }
763
764 /**
765 * {@inheritDoc}
766 */
767 public void clearChildFocus(View child) {
768 if (DBG) {
769 System.out.println(this + " clearChildFocus()");
770 }
771
772 mFocused = null;
773 if (mParent != null) {
774 mParent.clearChildFocus(this);
775 }
776 }
777
778 /**
779 * {@inheritDoc}
780 */
781 @Override
782 public void clearFocus() {
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -0800783 if (DBG) {
784 System.out.println(this + " clearFocus()");
785 }
786 if (mFocused == null) {
787 super.clearFocus();
788 } else {
Svetoslav Ganovb552d892012-06-02 14:35:02 -0700789 View focused = mFocused;
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -0800790 mFocused = null;
Svetoslav Ganovb552d892012-06-02 14:35:02 -0700791 focused.clearFocus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800792 }
793 }
794
795 /**
796 * {@inheritDoc}
797 */
798 @Override
799 void unFocus() {
800 if (DBG) {
801 System.out.println(this + " unFocus()");
802 }
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -0800803 if (mFocused == null) {
804 super.unFocus();
805 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800806 mFocused.unFocus();
Svetoslav Ganovb36a0ac2012-02-14 17:46:47 -0800807 mFocused = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800808 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800809 }
810
811 /**
812 * Returns the focused child of this view, if any. The child may have focus
813 * or contain focus.
814 *
815 * @return the focused child or null.
816 */
817 public View getFocusedChild() {
818 return mFocused;
819 }
820
821 /**
822 * Returns true if this view has or contains focus
823 *
824 * @return true if this view has or contains focus
825 */
826 @Override
827 public boolean hasFocus() {
Dianne Hackborn4702a852012-08-17 15:18:29 -0700828 return (mPrivateFlags & PFLAG_FOCUSED) != 0 || mFocused != null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800829 }
830
831 /*
832 * (non-Javadoc)
833 *
834 * @see android.view.View#findFocus()
835 */
836 @Override
837 public View findFocus() {
838 if (DBG) {
839 System.out.println("Find focus in " + this + ": flags="
840 + isFocused() + ", child=" + mFocused);
841 }
842
843 if (isFocused()) {
844 return this;
845 }
846
847 if (mFocused != null) {
848 return mFocused.findFocus();
849 }
850 return null;
851 }
852
853 /**
854 * {@inheritDoc}
855 */
856 @Override
857 public boolean hasFocusable() {
858 if ((mViewFlags & VISIBILITY_MASK) != VISIBLE) {
859 return false;
860 }
861
862 if (isFocusable()) {
863 return true;
864 }
865
866 final int descendantFocusability = getDescendantFocusability();
867 if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS) {
868 final int count = mChildrenCount;
869 final View[] children = mChildren;
870
871 for (int i = 0; i < count; i++) {
872 final View child = children[i];
873 if (child.hasFocusable()) {
874 return true;
875 }
876 }
877 }
878
879 return false;
880 }
881
882 /**
883 * {@inheritDoc}
884 */
885 @Override
svetoslavganov75986cf2009-05-14 22:28:01 -0700886 public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800887 final int focusableCount = views.size();
888
889 final int descendantFocusability = getDescendantFocusability();
890
Svetoslav Ganov27e2da72012-07-02 18:12:00 -0700891 if (descendantFocusability != FOCUS_BLOCK_DESCENDANTS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800892 final int count = mChildrenCount;
893 final View[] children = mChildren;
894
895 for (int i = 0; i < count; i++) {
896 final View child = children[i];
897 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
svetoslavganov75986cf2009-05-14 22:28:01 -0700898 child.addFocusables(views, direction, focusableMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800899 }
900 }
901 }
902
903 // we add ourselves (if focusable) in all cases except for when we are
904 // FOCUS_AFTER_DESCENDANTS and there are some descendants focusable. this is
905 // to avoid the focus search finding layouts when a more precise search
906 // among the focusable children would be more interesting.
Svetoslav Ganove5dfa472012-05-08 15:58:32 -0700907 if (descendantFocusability != FOCUS_AFTER_DESCENDANTS
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800908 // No focusable descendants
Svetoslav Ganov27e2da72012-07-02 18:12:00 -0700909 || (focusableCount == views.size())) {
svetoslavganov75986cf2009-05-14 22:28:01 -0700910 super.addFocusables(views, direction, focusableMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800911 }
912 }
913
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700914 @Override
Svetoslav Ganovea515ae2011-09-14 18:15:32 -0700915 public void findViewsWithText(ArrayList<View> outViews, CharSequence text, int flags) {
916 super.findViewsWithText(outViews, text, flags);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700917 final int childrenCount = mChildrenCount;
918 final View[] children = mChildren;
919 for (int i = 0; i < childrenCount; i++) {
920 View child = children[i];
Svetoslav Ganovea515ae2011-09-14 18:15:32 -0700921 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE
Dianne Hackborn4702a852012-08-17 15:18:29 -0700922 && (child.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) {
Svetoslav Ganovea515ae2011-09-14 18:15:32 -0700923 child.findViewsWithText(outViews, text, flags);
Svetoslav Ganov8643aa02011-04-20 12:12:33 -0700924 }
925 }
926 }
927
Svetoslav Ganov2cdedff2011-10-03 14:18:42 -0700928 @Override
929 View findViewByAccessibilityIdTraversal(int accessibilityId) {
930 View foundView = super.findViewByAccessibilityIdTraversal(accessibilityId);
931 if (foundView != null) {
932 return foundView;
933 }
934 final int childrenCount = mChildrenCount;
935 final View[] children = mChildren;
936 for (int i = 0; i < childrenCount; i++) {
937 View child = children[i];
938 foundView = child.findViewByAccessibilityIdTraversal(accessibilityId);
939 if (foundView != null) {
940 return foundView;
941 }
942 }
943 return null;
944 }
945
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800946 /**
947 * {@inheritDoc}
948 */
949 @Override
950 public void dispatchWindowFocusChanged(boolean hasFocus) {
951 super.dispatchWindowFocusChanged(hasFocus);
952 final int count = mChildrenCount;
953 final View[] children = mChildren;
954 for (int i = 0; i < count; i++) {
955 children[i].dispatchWindowFocusChanged(hasFocus);
956 }
957 }
958
959 /**
960 * {@inheritDoc}
961 */
962 @Override
963 public void addTouchables(ArrayList<View> views) {
964 super.addTouchables(views);
965
966 final int count = mChildrenCount;
967 final View[] children = mChildren;
968
969 for (int i = 0; i < count; i++) {
970 final View child = children[i];
971 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
972 child.addTouchables(views);
973 }
974 }
975 }
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -0700976
977 /**
978 * @hide
979 */
980 @Override
981 public void makeOptionalFitsSystemWindows() {
982 super.makeOptionalFitsSystemWindows();
983 final int count = mChildrenCount;
984 final View[] children = mChildren;
985 for (int i = 0; i < count; i++) {
986 children[i].makeOptionalFitsSystemWindows();
987 }
988 }
989
Romain Guy43c9cdf2010-01-27 13:53:55 -0800990 /**
991 * {@inheritDoc}
992 */
993 @Override
994 public void dispatchDisplayHint(int hint) {
995 super.dispatchDisplayHint(hint);
996 final int count = mChildrenCount;
997 final View[] children = mChildren;
998 for (int i = 0; i < count; i++) {
999 children[i].dispatchDisplayHint(hint);
1000 }
1001 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001002
1003 /**
Chet Haase0d299362012-01-26 10:51:48 -08001004 * Called when a view's visibility has changed. Notify the parent to take any appropriate
1005 * action.
1006 *
1007 * @param child The view whose visibility has changed
1008 * @param oldVisibility The previous visibility value (GONE, INVISIBLE, or VISIBLE).
1009 * @param newVisibility The new visibility value (GONE, INVISIBLE, or VISIBLE).
Chet Haase5e25c2c2010-09-16 11:15:56 -07001010 * @hide
Chet Haase5e25c2c2010-09-16 11:15:56 -07001011 */
Chet Haase0d299362012-01-26 10:51:48 -08001012 protected void onChildVisibilityChanged(View child, int oldVisibility, int newVisibility) {
Chet Haase5e25c2c2010-09-16 11:15:56 -07001013 if (mTransition != null) {
Chet Haase0d299362012-01-26 10:51:48 -08001014 if (newVisibility == VISIBLE) {
1015 mTransition.showChild(this, child, oldVisibility);
Chet Haase5e25c2c2010-09-16 11:15:56 -07001016 } else {
Chet Haase0d299362012-01-26 10:51:48 -08001017 mTransition.hideChild(this, child, newVisibility);
Chet Haase5e25c2c2010-09-16 11:15:56 -07001018 if (mTransitioningViews != null && mTransitioningViews.contains(child)) {
Chet Haaseddbb3462012-06-19 13:54:29 -07001019 // Only track this on disappearing views - appearing views are already visible
1020 // and don't need special handling during drawChild()
1021 if (mVisibilityChangingChildren == null) {
1022 mVisibilityChangingChildren = new ArrayList<View>();
1023 }
1024 mVisibilityChangingChildren.add(child);
Chet Haase5e25c2c2010-09-16 11:15:56 -07001025 addDisappearingView(child);
1026 }
1027 }
1028 }
Christopher Tate86cab1b2011-01-13 20:28:55 -08001029
1030 // in all cases, for drags
1031 if (mCurrentDrag != null) {
Chet Haase0d299362012-01-26 10:51:48 -08001032 if (newVisibility == VISIBLE) {
Christopher Tate86cab1b2011-01-13 20:28:55 -08001033 notifyChildOfDrag(child);
1034 }
1035 }
Chet Haase5e25c2c2010-09-16 11:15:56 -07001036 }
1037
1038 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001039 * {@inheritDoc}
1040 */
1041 @Override
Adam Powell326d8082009-12-09 15:10:07 -08001042 protected void dispatchVisibilityChanged(View changedView, int visibility) {
1043 super.dispatchVisibilityChanged(changedView, visibility);
1044 final int count = mChildrenCount;
1045 final View[] children = mChildren;
1046 for (int i = 0; i < count; i++) {
1047 children[i].dispatchVisibilityChanged(changedView, visibility);
1048 }
1049 }
1050
1051 /**
1052 * {@inheritDoc}
1053 */
1054 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001055 public void dispatchWindowVisibilityChanged(int visibility) {
1056 super.dispatchWindowVisibilityChanged(visibility);
1057 final int count = mChildrenCount;
1058 final View[] children = mChildren;
1059 for (int i = 0; i < count; i++) {
1060 children[i].dispatchWindowVisibilityChanged(visibility);
1061 }
1062 }
1063
1064 /**
1065 * {@inheritDoc}
1066 */
Dianne Hackborne36d6e22010-02-17 19:46:25 -08001067 @Override
1068 public void dispatchConfigurationChanged(Configuration newConfig) {
1069 super.dispatchConfigurationChanged(newConfig);
1070 final int count = mChildrenCount;
1071 final View[] children = mChildren;
1072 for (int i = 0; i < count; i++) {
1073 children[i].dispatchConfigurationChanged(newConfig);
1074 }
1075 }
1076
1077 /**
1078 * {@inheritDoc}
1079 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001080 public void recomputeViewAttributes(View child) {
Joe Onorato664644d2011-01-23 17:53:23 -08001081 if (mAttachInfo != null && !mAttachInfo.mRecomputeGlobalAttributes) {
1082 ViewParent parent = mParent;
1083 if (parent != null) parent.recomputeViewAttributes(this);
1084 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001085 }
Romain Guy8506ab42009-06-11 17:35:47 -07001086
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001087 @Override
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001088 void dispatchCollectViewAttributes(AttachInfo attachInfo, int visibility) {
1089 if ((visibility & VISIBILITY_MASK) == VISIBLE) {
1090 super.dispatchCollectViewAttributes(attachInfo, visibility);
1091 final int count = mChildrenCount;
1092 final View[] children = mChildren;
1093 for (int i = 0; i < count; i++) {
1094 final View child = children[i];
1095 child.dispatchCollectViewAttributes(attachInfo,
1096 visibility | (child.mViewFlags&VISIBILITY_MASK));
1097 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001098 }
1099 }
1100
1101 /**
1102 * {@inheritDoc}
1103 */
1104 public void bringChildToFront(View child) {
1105 int index = indexOfChild(child);
1106 if (index >= 0) {
1107 removeFromArray(index);
1108 addInArray(child, mChildrenCount);
1109 child.mParent = this;
1110 }
1111 }
1112
1113 /**
1114 * {@inheritDoc}
Christopher Tatea53146c2010-09-07 11:57:52 -07001115 */
Steve Block8a7259b2012-03-01 11:24:41 +00001116 // TODO: Write real docs
Christopher Tatea53146c2010-09-07 11:57:52 -07001117 @Override
1118 public boolean dispatchDragEvent(DragEvent event) {
1119 boolean retval = false;
1120 final float tx = event.mX;
1121 final float ty = event.mY;
1122
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07001123 ViewRootImpl root = getViewRootImpl();
Christopher Tatea53146c2010-09-07 11:57:52 -07001124
1125 // Dispatch down the view hierarchy
1126 switch (event.mAction) {
1127 case DragEvent.ACTION_DRAG_STARTED: {
1128 // clear state to recalculate which views we drag over
Chris Tate9d1ab882010-11-02 15:55:39 -07001129 mCurrentDragView = null;
Christopher Tatea53146c2010-09-07 11:57:52 -07001130
Christopher Tate86cab1b2011-01-13 20:28:55 -08001131 // Set up our tracking of drag-started notifications
1132 mCurrentDrag = DragEvent.obtain(event);
1133 if (mDragNotifiedChildren == null) {
1134 mDragNotifiedChildren = new HashSet<View>();
1135 } else {
1136 mDragNotifiedChildren.clear();
1137 }
1138
Christopher Tatea53146c2010-09-07 11:57:52 -07001139 // Now dispatch down to our children, caching the responses
1140 mChildAcceptsDrag = false;
1141 final int count = mChildrenCount;
1142 final View[] children = mChildren;
1143 for (int i = 0; i < count; i++) {
Christopher Tate2c095f32010-10-04 14:13:40 -07001144 final View child = children[i];
Christopher Tate3d4bf172011-03-28 16:16:46 -07001145 child.mPrivateFlags2 &= ~View.DRAG_MASK;
Christopher Tate2c095f32010-10-04 14:13:40 -07001146 if (child.getVisibility() == VISIBLE) {
Christopher Tate86cab1b2011-01-13 20:28:55 -08001147 final boolean handled = notifyChildOfDrag(children[i]);
Christopher Tate2c095f32010-10-04 14:13:40 -07001148 if (handled) {
1149 mChildAcceptsDrag = true;
1150 }
Christopher Tatea53146c2010-09-07 11:57:52 -07001151 }
1152 }
1153
1154 // Return HANDLED if one of our children can accept the drag
1155 if (mChildAcceptsDrag) {
1156 retval = true;
1157 }
1158 } break;
1159
1160 case DragEvent.ACTION_DRAG_ENDED: {
Christopher Tate86cab1b2011-01-13 20:28:55 -08001161 // Release the bookkeeping now that the drag lifecycle has ended
Christopher Tate1fc014f2011-01-19 12:56:26 -08001162 if (mDragNotifiedChildren != null) {
1163 for (View child : mDragNotifiedChildren) {
1164 // If a child was notified about an ongoing drag, it's told that it's over
1165 child.dispatchDragEvent(event);
Christopher Tate3d4bf172011-03-28 16:16:46 -07001166 child.mPrivateFlags2 &= ~View.DRAG_MASK;
1167 child.refreshDrawableState();
Christopher Tate1fc014f2011-01-19 12:56:26 -08001168 }
1169
1170 mDragNotifiedChildren.clear();
Christopher Tate267097b2013-03-04 12:57:23 -08001171 if (mCurrentDrag != null) {
1172 mCurrentDrag.recycle();
1173 mCurrentDrag = null;
1174 }
Christopher Tate1fc014f2011-01-19 12:56:26 -08001175 }
Christopher Tate86cab1b2011-01-13 20:28:55 -08001176
Christopher Tatea53146c2010-09-07 11:57:52 -07001177 // We consider drag-ended to have been handled if one of our children
1178 // had offered to handle the drag.
1179 if (mChildAcceptsDrag) {
1180 retval = true;
1181 }
1182 } break;
1183
1184 case DragEvent.ACTION_DRAG_LOCATION: {
1185 // Find the [possibly new] drag target
1186 final View target = findFrontmostDroppableChildAt(event.mX, event.mY, mLocalPoint);
1187
1188 // If we've changed apparent drag target, tell the view root which view
Chris Tate9d1ab882010-11-02 15:55:39 -07001189 // we're over now [for purposes of the eventual drag-recipient-changed
1190 // notifications to the framework] and tell the new target that the drag
1191 // has entered its bounds. The root will see setDragFocus() calls all
1192 // the way down to the final leaf view that is handling the LOCATION event
1193 // before reporting the new potential recipient to the framework.
Christopher Tatea53146c2010-09-07 11:57:52 -07001194 if (mCurrentDragView != target) {
Chris Tate9d1ab882010-11-02 15:55:39 -07001195 root.setDragFocus(target);
1196
1197 final int action = event.mAction;
1198 // If we've dragged off of a child view, send it the EXITED message
1199 if (mCurrentDragView != null) {
Christopher Tate3d4bf172011-03-28 16:16:46 -07001200 final View view = mCurrentDragView;
Chris Tate9d1ab882010-11-02 15:55:39 -07001201 event.mAction = DragEvent.ACTION_DRAG_EXITED;
Christopher Tate3d4bf172011-03-28 16:16:46 -07001202 view.dispatchDragEvent(event);
Dianne Hackborn4702a852012-08-17 15:18:29 -07001203 view.mPrivateFlags2 &= ~View.PFLAG2_DRAG_HOVERED;
Christopher Tate3d4bf172011-03-28 16:16:46 -07001204 view.refreshDrawableState();
Chris Tate9d1ab882010-11-02 15:55:39 -07001205 }
Christopher Tatea53146c2010-09-07 11:57:52 -07001206 mCurrentDragView = target;
Chris Tate9d1ab882010-11-02 15:55:39 -07001207
1208 // If we've dragged over a new child view, send it the ENTERED message
1209 if (target != null) {
1210 event.mAction = DragEvent.ACTION_DRAG_ENTERED;
1211 target.dispatchDragEvent(event);
Dianne Hackborn4702a852012-08-17 15:18:29 -07001212 target.mPrivateFlags2 |= View.PFLAG2_DRAG_HOVERED;
Christopher Tate3d4bf172011-03-28 16:16:46 -07001213 target.refreshDrawableState();
Chris Tate9d1ab882010-11-02 15:55:39 -07001214 }
1215 event.mAction = action; // restore the event's original state
Christopher Tatea53146c2010-09-07 11:57:52 -07001216 }
Christopher Tate2c095f32010-10-04 14:13:40 -07001217
Christopher Tatea53146c2010-09-07 11:57:52 -07001218 // Dispatch the actual drag location notice, localized into its coordinates
1219 if (target != null) {
1220 event.mX = mLocalPoint.x;
1221 event.mY = mLocalPoint.y;
1222
1223 retval = target.dispatchDragEvent(event);
1224
1225 event.mX = tx;
1226 event.mY = ty;
1227 }
1228 } break;
1229
Chris Tate9d1ab882010-11-02 15:55:39 -07001230 /* Entered / exited dispatch
1231 *
1232 * DRAG_ENTERED is not dispatched downwards from ViewGroup. The reason for this is
1233 * that we're about to get the corresponding LOCATION event, which we will use to
1234 * determine which of our children is the new target; at that point we will
1235 * push a DRAG_ENTERED down to the new target child [which may itself be a ViewGroup].
1236 *
1237 * DRAG_EXITED *is* dispatched all the way down immediately: once we know the
1238 * drag has left this ViewGroup, we know by definition that every contained subview
1239 * is also no longer under the drag point.
1240 */
1241
1242 case DragEvent.ACTION_DRAG_EXITED: {
1243 if (mCurrentDragView != null) {
Christopher Tate3d4bf172011-03-28 16:16:46 -07001244 final View view = mCurrentDragView;
1245 view.dispatchDragEvent(event);
Dianne Hackborn4702a852012-08-17 15:18:29 -07001246 view.mPrivateFlags2 &= ~View.PFLAG2_DRAG_HOVERED;
Christopher Tate3d4bf172011-03-28 16:16:46 -07001247 view.refreshDrawableState();
1248
Chris Tate9d1ab882010-11-02 15:55:39 -07001249 mCurrentDragView = null;
1250 }
1251 } break;
1252
Christopher Tatea53146c2010-09-07 11:57:52 -07001253 case DragEvent.ACTION_DROP: {
Christopher Tate2c095f32010-10-04 14:13:40 -07001254 if (ViewDebug.DEBUG_DRAG) Log.d(View.VIEW_LOG_TAG, "Drop event: " + event);
Christopher Tatea53146c2010-09-07 11:57:52 -07001255 View target = findFrontmostDroppableChildAt(event.mX, event.mY, mLocalPoint);
1256 if (target != null) {
Christopher Tate5ada6cb2010-10-05 14:15:29 -07001257 if (ViewDebug.DEBUG_DRAG) Log.d(View.VIEW_LOG_TAG, " dispatch drop to " + target);
Christopher Tatea53146c2010-09-07 11:57:52 -07001258 event.mX = mLocalPoint.x;
1259 event.mY = mLocalPoint.y;
1260 retval = target.dispatchDragEvent(event);
1261 event.mX = tx;
1262 event.mY = ty;
Christopher Tate5ada6cb2010-10-05 14:15:29 -07001263 } else {
1264 if (ViewDebug.DEBUG_DRAG) {
1265 Log.d(View.VIEW_LOG_TAG, " not dropped on an accepting view");
1266 }
Christopher Tatea53146c2010-09-07 11:57:52 -07001267 }
1268 } break;
1269 }
1270
1271 // If none of our children could handle the event, try here
1272 if (!retval) {
Chris Tate32affef2010-10-18 15:29:21 -07001273 // Call up to the View implementation that dispatches to installed listeners
1274 retval = super.dispatchDragEvent(event);
Christopher Tatea53146c2010-09-07 11:57:52 -07001275 }
1276 return retval;
1277 }
1278
1279 // Find the frontmost child view that lies under the given point, and calculate
1280 // the position within its own local coordinate system.
1281 View findFrontmostDroppableChildAt(float x, float y, PointF outLocalPoint) {
Christopher Tatea53146c2010-09-07 11:57:52 -07001282 final int count = mChildrenCount;
1283 final View[] children = mChildren;
1284 for (int i = count - 1; i >= 0; i--) {
1285 final View child = children[i];
Christopher Tate3d4bf172011-03-28 16:16:46 -07001286 if (!child.canAcceptDrag()) {
Christopher Tatea53146c2010-09-07 11:57:52 -07001287 continue;
1288 }
1289
Christopher Tate2c095f32010-10-04 14:13:40 -07001290 if (isTransformedTouchPointInView(x, y, child, outLocalPoint)) {
Christopher Tatea53146c2010-09-07 11:57:52 -07001291 return child;
1292 }
1293 }
1294 return null;
1295 }
1296
Christopher Tate86cab1b2011-01-13 20:28:55 -08001297 boolean notifyChildOfDrag(View child) {
1298 if (ViewDebug.DEBUG_DRAG) {
1299 Log.d(View.VIEW_LOG_TAG, "Sending drag-started to view: " + child);
1300 }
1301
Christopher Tate3d4bf172011-03-28 16:16:46 -07001302 boolean canAccept = false;
Christopher Tate86cab1b2011-01-13 20:28:55 -08001303 if (! mDragNotifiedChildren.contains(child)) {
1304 mDragNotifiedChildren.add(child);
Christopher Tate3d4bf172011-03-28 16:16:46 -07001305 canAccept = child.dispatchDragEvent(mCurrentDrag);
1306 if (canAccept && !child.canAcceptDrag()) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07001307 child.mPrivateFlags2 |= View.PFLAG2_DRAG_CAN_ACCEPT;
Christopher Tate3d4bf172011-03-28 16:16:46 -07001308 child.refreshDrawableState();
1309 }
Christopher Tate86cab1b2011-01-13 20:28:55 -08001310 }
Christopher Tate3d4bf172011-03-28 16:16:46 -07001311 return canAccept;
Christopher Tate86cab1b2011-01-13 20:28:55 -08001312 }
1313
Joe Onorato664644d2011-01-23 17:53:23 -08001314 @Override
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07001315 public void dispatchWindowSystemUiVisiblityChanged(int visible) {
1316 super.dispatchWindowSystemUiVisiblityChanged(visible);
1317
1318 final int count = mChildrenCount;
1319 final View[] children = mChildren;
1320 for (int i=0; i <count; i++) {
1321 final View child = children[i];
1322 child.dispatchWindowSystemUiVisiblityChanged(visible);
1323 }
1324 }
1325
1326 @Override
Joe Onorato664644d2011-01-23 17:53:23 -08001327 public void dispatchSystemUiVisibilityChanged(int visible) {
1328 super.dispatchSystemUiVisibilityChanged(visible);
1329
1330 final int count = mChildrenCount;
1331 final View[] children = mChildren;
1332 for (int i=0; i <count; i++) {
1333 final View child = children[i];
1334 child.dispatchSystemUiVisibilityChanged(visible);
1335 }
1336 }
1337
Dianne Hackborn9a230e02011-10-06 11:51:27 -07001338 @Override
Dianne Hackborncf675782012-05-10 15:07:24 -07001339 boolean updateLocalSystemUiVisibility(int localValue, int localChanges) {
1340 boolean changed = super.updateLocalSystemUiVisibility(localValue, localChanges);
Dianne Hackborn9a230e02011-10-06 11:51:27 -07001341
1342 final int count = mChildrenCount;
1343 final View[] children = mChildren;
1344 for (int i=0; i <count; i++) {
1345 final View child = children[i];
Dianne Hackborncf675782012-05-10 15:07:24 -07001346 changed |= child.updateLocalSystemUiVisibility(localValue, localChanges);
Dianne Hackborn9a230e02011-10-06 11:51:27 -07001347 }
Dianne Hackborncf675782012-05-10 15:07:24 -07001348 return changed;
Dianne Hackborn9a230e02011-10-06 11:51:27 -07001349 }
1350
Christopher Tatea53146c2010-09-07 11:57:52 -07001351 /**
1352 * {@inheritDoc}
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001353 */
1354 @Override
1355 public boolean dispatchKeyEventPreIme(KeyEvent event) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07001356 if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
1357 == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001358 return super.dispatchKeyEventPreIme(event);
Dianne Hackborn4702a852012-08-17 15:18:29 -07001359 } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
1360 == PFLAG_HAS_BOUNDS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001361 return mFocused.dispatchKeyEventPreIme(event);
1362 }
1363 return false;
1364 }
1365
1366 /**
1367 * {@inheritDoc}
1368 */
1369 @Override
1370 public boolean dispatchKeyEvent(KeyEvent event) {
Jeff Brown21bc5c92011-02-28 18:27:14 -08001371 if (mInputEventConsistencyVerifier != null) {
1372 mInputEventConsistencyVerifier.onKeyEvent(event, 1);
1373 }
1374
Dianne Hackborn4702a852012-08-17 15:18:29 -07001375 if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
1376 == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001377 if (super.dispatchKeyEvent(event)) {
1378 return true;
1379 }
Dianne Hackborn4702a852012-08-17 15:18:29 -07001380 } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
1381 == PFLAG_HAS_BOUNDS) {
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001382 if (mFocused.dispatchKeyEvent(event)) {
1383 return true;
1384 }
1385 }
1386
1387 if (mInputEventConsistencyVerifier != null) {
1388 mInputEventConsistencyVerifier.onUnhandledEvent(event, 1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001389 }
1390 return false;
1391 }
1392
1393 /**
1394 * {@inheritDoc}
1395 */
1396 @Override
1397 public boolean dispatchKeyShortcutEvent(KeyEvent event) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07001398 if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
1399 == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001400 return super.dispatchKeyShortcutEvent(event);
Dianne Hackborn4702a852012-08-17 15:18:29 -07001401 } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
1402 == PFLAG_HAS_BOUNDS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001403 return mFocused.dispatchKeyShortcutEvent(event);
1404 }
1405 return false;
1406 }
1407
1408 /**
1409 * {@inheritDoc}
1410 */
1411 @Override
1412 public boolean dispatchTrackballEvent(MotionEvent event) {
Jeff Brown21bc5c92011-02-28 18:27:14 -08001413 if (mInputEventConsistencyVerifier != null) {
1414 mInputEventConsistencyVerifier.onTrackballEvent(event, 1);
1415 }
1416
Dianne Hackborn4702a852012-08-17 15:18:29 -07001417 if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
1418 == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001419 if (super.dispatchTrackballEvent(event)) {
1420 return true;
1421 }
Dianne Hackborn4702a852012-08-17 15:18:29 -07001422 } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
1423 == PFLAG_HAS_BOUNDS) {
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001424 if (mFocused.dispatchTrackballEvent(event)) {
1425 return true;
1426 }
1427 }
1428
1429 if (mInputEventConsistencyVerifier != null) {
1430 mInputEventConsistencyVerifier.onUnhandledEvent(event, 1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001431 }
1432 return false;
1433 }
1434
Jeff Brown10b62902011-06-20 16:40:37 -07001435 /**
1436 * {@inheritDoc}
1437 */
Romain Guya9489272011-06-22 20:58:11 -07001438 @SuppressWarnings({"ConstantConditions"})
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001439 @Override
Jeff Browna032cc02011-03-07 16:56:21 -08001440 protected boolean dispatchHoverEvent(MotionEvent event) {
Jeff Browna032cc02011-03-07 16:56:21 -08001441 final int action = event.getAction();
Jeff Browna032cc02011-03-07 16:56:21 -08001442
Jeff Brown10b62902011-06-20 16:40:37 -07001443 // First check whether the view group wants to intercept the hover event.
1444 final boolean interceptHover = onInterceptHoverEvent(event);
1445 event.setAction(action); // restore action in case it was changed
1446
Jeff Brown87b7f802011-06-21 18:35:45 -07001447 MotionEvent eventNoHistory = event;
1448 boolean handled = false;
1449
1450 // Send events to the hovered children and build a new list of hover targets until
1451 // one is found that handles the event.
1452 HoverTarget firstOldHoverTarget = mFirstHoverTarget;
1453 mFirstHoverTarget = null;
Jeff Brown10b62902011-06-20 16:40:37 -07001454 if (!interceptHover && action != MotionEvent.ACTION_HOVER_EXIT) {
Jeff Browna032cc02011-03-07 16:56:21 -08001455 final float x = event.getX();
1456 final float y = event.getY();
Jeff Brown33bbfd22011-02-24 20:55:35 -08001457 final int childrenCount = mChildrenCount;
1458 if (childrenCount != 0) {
1459 final View[] children = mChildren;
Jeff Brown87b7f802011-06-21 18:35:45 -07001460 HoverTarget lastHoverTarget = null;
Jeff Brown33bbfd22011-02-24 20:55:35 -08001461 for (int i = childrenCount - 1; i >= 0; i--) {
1462 final View child = children[i];
Jeff Brown87b7f802011-06-21 18:35:45 -07001463 if (!canViewReceivePointerEvents(child)
1464 || !isTransformedTouchPointInView(x, y, child, null)) {
1465 continue;
1466 }
1467
1468 // Obtain a hover target for this child. Dequeue it from the
1469 // old hover target list if the child was previously hovered.
1470 HoverTarget hoverTarget = firstOldHoverTarget;
1471 final boolean wasHovered;
1472 for (HoverTarget predecessor = null; ;) {
1473 if (hoverTarget == null) {
1474 hoverTarget = HoverTarget.obtain(child);
1475 wasHovered = false;
1476 break;
1477 }
1478
1479 if (hoverTarget.child == child) {
1480 if (predecessor != null) {
1481 predecessor.next = hoverTarget.next;
1482 } else {
1483 firstOldHoverTarget = hoverTarget.next;
1484 }
1485 hoverTarget.next = null;
1486 wasHovered = true;
1487 break;
1488 }
1489
1490 predecessor = hoverTarget;
1491 hoverTarget = hoverTarget.next;
1492 }
1493
1494 // Enqueue the hover target onto the new hover target list.
1495 if (lastHoverTarget != null) {
1496 lastHoverTarget.next = hoverTarget;
1497 } else {
1498 lastHoverTarget = hoverTarget;
1499 mFirstHoverTarget = hoverTarget;
1500 }
1501
1502 // Dispatch the event to the child.
1503 if (action == MotionEvent.ACTION_HOVER_ENTER) {
1504 if (!wasHovered) {
1505 // Send the enter as is.
1506 handled |= dispatchTransformedGenericPointerEvent(
1507 event, child); // enter
1508 }
1509 } else if (action == MotionEvent.ACTION_HOVER_MOVE) {
1510 if (!wasHovered) {
1511 // Synthesize an enter from a move.
1512 eventNoHistory = obtainMotionEventNoHistoryOrSelf(eventNoHistory);
1513 eventNoHistory.setAction(MotionEvent.ACTION_HOVER_ENTER);
1514 handled |= dispatchTransformedGenericPointerEvent(
1515 eventNoHistory, child); // enter
1516 eventNoHistory.setAction(action);
1517
1518 handled |= dispatchTransformedGenericPointerEvent(
1519 eventNoHistory, child); // move
1520 } else {
1521 // Send the move as is.
1522 handled |= dispatchTransformedGenericPointerEvent(event, child);
1523 }
1524 }
1525 if (handled) {
Jeff Brown10b62902011-06-20 16:40:37 -07001526 break;
Jeff Brown33bbfd22011-02-24 20:55:35 -08001527 }
Jeff Brown10b62902011-06-20 16:40:37 -07001528 }
1529 }
1530 }
Jeff Brown33bbfd22011-02-24 20:55:35 -08001531
Jeff Brown87b7f802011-06-21 18:35:45 -07001532 // Send exit events to all previously hovered children that are no longer hovered.
1533 while (firstOldHoverTarget != null) {
1534 final View child = firstOldHoverTarget.child;
Jeff Brown10b62902011-06-20 16:40:37 -07001535
Jeff Brown87b7f802011-06-21 18:35:45 -07001536 // Exit the old hovered child.
1537 if (action == MotionEvent.ACTION_HOVER_EXIT) {
1538 // Send the exit as is.
1539 handled |= dispatchTransformedGenericPointerEvent(
1540 event, child); // exit
1541 } else {
1542 // Synthesize an exit from a move or enter.
1543 // Ignore the result because hover focus has moved to a different view.
1544 if (action == MotionEvent.ACTION_HOVER_MOVE) {
Jeff Brown10b62902011-06-20 16:40:37 -07001545 dispatchTransformedGenericPointerEvent(
Jeff Brown87b7f802011-06-21 18:35:45 -07001546 event, child); // move
Jeff Brown10b62902011-06-20 16:40:37 -07001547 }
Jeff Brown87b7f802011-06-21 18:35:45 -07001548 eventNoHistory = obtainMotionEventNoHistoryOrSelf(eventNoHistory);
1549 eventNoHistory.setAction(MotionEvent.ACTION_HOVER_EXIT);
1550 dispatchTransformedGenericPointerEvent(
1551 eventNoHistory, child); // exit
1552 eventNoHistory.setAction(action);
Jeff Brown10b62902011-06-20 16:40:37 -07001553 }
1554
Jeff Brown87b7f802011-06-21 18:35:45 -07001555 final HoverTarget nextOldHoverTarget = firstOldHoverTarget.next;
1556 firstOldHoverTarget.recycle();
1557 firstOldHoverTarget = nextOldHoverTarget;
Jeff Brown10b62902011-06-20 16:40:37 -07001558 }
1559
Jeff Brown87b7f802011-06-21 18:35:45 -07001560 // Send events to the view group itself if no children have handled it.
Jeff Brown10b62902011-06-20 16:40:37 -07001561 boolean newHoveredSelf = !handled;
1562 if (newHoveredSelf == mHoveredSelf) {
1563 if (newHoveredSelf) {
1564 // Send event to the view group as before.
1565 handled |= super.dispatchHoverEvent(event);
1566 }
1567 } else {
1568 if (mHoveredSelf) {
1569 // Exit the view group.
1570 if (action == MotionEvent.ACTION_HOVER_EXIT) {
1571 // Send the exit as is.
1572 handled |= super.dispatchHoverEvent(event); // exit
1573 } else {
1574 // Synthesize an exit from a move or enter.
1575 // Ignore the result because hover focus is moving to a different view.
1576 if (action == MotionEvent.ACTION_HOVER_MOVE) {
1577 super.dispatchHoverEvent(event); // move
1578 }
1579 eventNoHistory = obtainMotionEventNoHistoryOrSelf(eventNoHistory);
1580 eventNoHistory.setAction(MotionEvent.ACTION_HOVER_EXIT);
1581 super.dispatchHoverEvent(eventNoHistory); // exit
1582 eventNoHistory.setAction(action);
1583 }
1584 mHoveredSelf = false;
1585 }
1586
1587 if (newHoveredSelf) {
1588 // Enter the view group.
1589 if (action == MotionEvent.ACTION_HOVER_ENTER) {
1590 // Send the enter as is.
1591 handled |= super.dispatchHoverEvent(event); // enter
1592 mHoveredSelf = true;
1593 } else if (action == MotionEvent.ACTION_HOVER_MOVE) {
1594 // Synthesize an enter from a move.
1595 eventNoHistory = obtainMotionEventNoHistoryOrSelf(eventNoHistory);
1596 eventNoHistory.setAction(MotionEvent.ACTION_HOVER_ENTER);
1597 handled |= super.dispatchHoverEvent(eventNoHistory); // enter
1598 eventNoHistory.setAction(action);
1599
1600 handled |= super.dispatchHoverEvent(eventNoHistory); // move
1601 mHoveredSelf = true;
Jeff Brown33bbfd22011-02-24 20:55:35 -08001602 }
1603 }
Jeff Brown33bbfd22011-02-24 20:55:35 -08001604 }
1605
Jeff Browna032cc02011-03-07 16:56:21 -08001606 // Recycle the copy of the event that we made.
1607 if (eventNoHistory != event) {
1608 eventNoHistory.recycle();
1609 }
1610
Jeff Browna032cc02011-03-07 16:56:21 -08001611 // Done.
1612 return handled;
1613 }
1614
Jeff Brown59a422e2012-04-19 15:19:19 -07001615 private void exitHoverTargets() {
1616 if (mHoveredSelf || mFirstHoverTarget != null) {
1617 final long now = SystemClock.uptimeMillis();
1618 MotionEvent event = MotionEvent.obtain(now, now,
1619 MotionEvent.ACTION_HOVER_EXIT, 0.0f, 0.0f, 0);
1620 event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
1621 dispatchHoverEvent(event);
1622 event.recycle();
1623 }
1624 }
1625
1626 private void cancelHoverTarget(View view) {
1627 HoverTarget predecessor = null;
1628 HoverTarget target = mFirstHoverTarget;
1629 while (target != null) {
1630 final HoverTarget next = target.next;
1631 if (target.child == view) {
1632 if (predecessor == null) {
1633 mFirstHoverTarget = next;
1634 } else {
1635 predecessor.next = next;
1636 }
1637 target.recycle();
1638
1639 final long now = SystemClock.uptimeMillis();
1640 MotionEvent event = MotionEvent.obtain(now, now,
1641 MotionEvent.ACTION_HOVER_EXIT, 0.0f, 0.0f, 0);
1642 event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
1643 view.dispatchHoverEvent(event);
1644 event.recycle();
1645 return;
1646 }
1647 predecessor = target;
1648 target = next;
1649 }
1650 }
1651
Jeff Brown87b7f802011-06-21 18:35:45 -07001652 /** @hide */
1653 @Override
1654 protected boolean hasHoveredChild() {
1655 return mFirstHoverTarget != null;
1656 }
1657
Svetoslav Ganov42138042012-03-20 11:51:39 -07001658 @Override
1659 public void addChildrenForAccessibility(ArrayList<View> childrenForAccessibility) {
Svetoslav Ganov76f287e2012-04-23 11:02:36 -07001660 ChildListForAccessibility children = ChildListForAccessibility.obtain(this, true);
1661 try {
1662 final int childrenCount = children.getChildCount();
1663 for (int i = 0; i < childrenCount; i++) {
1664 View child = children.getChildAt(i);
Svetoslav Ganovc406be92012-05-11 16:12:32 -07001665 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
Svetoslav Ganov76f287e2012-04-23 11:02:36 -07001666 if (child.includeForAccessibility()) {
1667 childrenForAccessibility.add(child);
1668 } else {
1669 child.addChildrenForAccessibility(childrenForAccessibility);
1670 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07001671 }
1672 }
Svetoslav Ganov76f287e2012-04-23 11:02:36 -07001673 } finally {
1674 children.recycle();
Svetoslav Ganov42138042012-03-20 11:51:39 -07001675 }
1676 }
1677
1678 /**
1679 * @hide
1680 */
1681 @Override
1682 public void childAccessibilityStateChanged(View child) {
1683 if (mParent != null) {
1684 mParent.childAccessibilityStateChanged(child);
1685 }
1686 }
1687
Jeff Brown10b62902011-06-20 16:40:37 -07001688 /**
1689 * Implement this method to intercept hover events before they are handled
1690 * by child views.
1691 * <p>
1692 * This method is called before dispatching a hover event to a child of
1693 * the view group or to the view group's own {@link #onHoverEvent} to allow
1694 * the view group a chance to intercept the hover event.
1695 * This method can also be used to watch all pointer motions that occur within
1696 * the bounds of the view group even when the pointer is hovering over
1697 * a child of the view group rather than over the view group itself.
1698 * </p><p>
1699 * The view group can prevent its children from receiving hover events by
1700 * implementing this method and returning <code>true</code> to indicate
1701 * that it would like to intercept hover events. The view group must
1702 * continuously return <code>true</code> from {@link #onInterceptHoverEvent}
1703 * for as long as it wishes to continue intercepting hover events from
1704 * its children.
1705 * </p><p>
1706 * Interception preserves the invariant that at most one view can be
1707 * hovered at a time by transferring hover focus from the currently hovered
1708 * child to the view group or vice-versa as needed.
1709 * </p><p>
1710 * If this method returns <code>true</code> and a child is already hovered, then the
1711 * child view will first receive a hover exit event and then the view group
1712 * itself will receive a hover enter event in {@link #onHoverEvent}.
1713 * Likewise, if this method had previously returned <code>true</code> to intercept hover
1714 * events and instead returns <code>false</code> while the pointer is hovering
1715 * within the bounds of one of a child, then the view group will first receive a
1716 * hover exit event in {@link #onHoverEvent} and then the hovered child will
1717 * receive a hover enter event.
1718 * </p><p>
1719 * The default implementation always returns false.
1720 * </p>
1721 *
1722 * @param event The motion event that describes the hover.
1723 * @return True if the view group would like to intercept the hover event
1724 * and prevent its children from receiving it.
1725 */
1726 public boolean onInterceptHoverEvent(MotionEvent event) {
Svetoslav Ganov736c2752011-04-22 18:30:36 -07001727 return false;
1728 }
1729
Jeff Browna032cc02011-03-07 16:56:21 -08001730 private static MotionEvent obtainMotionEventNoHistoryOrSelf(MotionEvent event) {
1731 if (event.getHistorySize() == 0) {
1732 return event;
1733 }
1734 return MotionEvent.obtainNoHistory(event);
1735 }
1736
Jeff Brown10b62902011-06-20 16:40:37 -07001737 /**
1738 * {@inheritDoc}
1739 */
Jeff Browna032cc02011-03-07 16:56:21 -08001740 @Override
1741 protected boolean dispatchGenericPointerEvent(MotionEvent event) {
1742 // Send the event to the child under the pointer.
1743 final int childrenCount = mChildrenCount;
1744 if (childrenCount != 0) {
1745 final View[] children = mChildren;
1746 final float x = event.getX();
1747 final float y = event.getY();
1748
Adam Powella6478a32012-08-17 16:40:00 -07001749 final boolean customOrder = isChildrenDrawingOrderEnabled();
Jeff Browna032cc02011-03-07 16:56:21 -08001750 for (int i = childrenCount - 1; i >= 0; i--) {
Adam Powella6478a32012-08-17 16:40:00 -07001751 final int childIndex = customOrder ? getChildDrawingOrder(childrenCount, i) : i;
1752 final View child = children[childIndex];
Jeff Browna032cc02011-03-07 16:56:21 -08001753 if (!canViewReceivePointerEvents(child)
1754 || !isTransformedTouchPointInView(x, y, child, null)) {
1755 continue;
1756 }
1757
1758 if (dispatchTransformedGenericPointerEvent(event, child)) {
1759 return true;
1760 }
1761 }
1762 }
1763
1764 // No child handled the event. Send it to this view group.
1765 return super.dispatchGenericPointerEvent(event);
1766 }
1767
Jeff Brown10b62902011-06-20 16:40:37 -07001768 /**
1769 * {@inheritDoc}
1770 */
Jeff Browna032cc02011-03-07 16:56:21 -08001771 @Override
1772 protected boolean dispatchGenericFocusedEvent(MotionEvent event) {
Jeff Brown33bbfd22011-02-24 20:55:35 -08001773 // Send the event to the focused child or to this view group if it has focus.
Dianne Hackborn4702a852012-08-17 15:18:29 -07001774 if ((mPrivateFlags & (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS))
1775 == (PFLAG_FOCUSED | PFLAG_HAS_BOUNDS)) {
Jeff Browna032cc02011-03-07 16:56:21 -08001776 return super.dispatchGenericFocusedEvent(event);
Dianne Hackborn4702a852012-08-17 15:18:29 -07001777 } else if (mFocused != null && (mFocused.mPrivateFlags & PFLAG_HAS_BOUNDS)
1778 == PFLAG_HAS_BOUNDS) {
Jeff Browncb1404e2011-01-15 18:14:15 -08001779 return mFocused.dispatchGenericMotionEvent(event);
1780 }
1781 return false;
1782 }
1783
1784 /**
Jeff Browna032cc02011-03-07 16:56:21 -08001785 * Dispatches a generic pointer event to a child, taking into account
1786 * transformations that apply to the child.
1787 *
1788 * @param event The event to send.
1789 * @param child The view to send the event to.
1790 * @return {@code true} if the child handled the event.
1791 */
1792 private boolean dispatchTransformedGenericPointerEvent(MotionEvent event, View child) {
1793 final float offsetX = mScrollX - child.mLeft;
1794 final float offsetY = mScrollY - child.mTop;
1795
1796 boolean handled;
1797 if (!child.hasIdentityMatrix()) {
1798 MotionEvent transformedEvent = MotionEvent.obtain(event);
1799 transformedEvent.offsetLocation(offsetX, offsetY);
1800 transformedEvent.transform(child.getInverseMatrix());
1801 handled = child.dispatchGenericMotionEvent(transformedEvent);
1802 transformedEvent.recycle();
1803 } else {
1804 event.offsetLocation(offsetX, offsetY);
1805 handled = child.dispatchGenericMotionEvent(event);
1806 event.offsetLocation(-offsetX, -offsetY);
1807 }
1808 return handled;
1809 }
1810
1811 /**
Jeff Browncb1404e2011-01-15 18:14:15 -08001812 * {@inheritDoc}
1813 */
1814 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001815 public boolean dispatchTouchEvent(MotionEvent ev) {
Jeff Brown21bc5c92011-02-28 18:27:14 -08001816 if (mInputEventConsistencyVerifier != null) {
1817 mInputEventConsistencyVerifier.onTouchEvent(ev, 1);
1818 }
1819
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001820 boolean handled = false;
1821 if (onFilterTouchEventForSecurity(ev)) {
1822 final int action = ev.getAction();
1823 final int actionMasked = action & MotionEvent.ACTION_MASK;
Jeff Brown85a31762010-09-01 17:01:00 -07001824
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001825 // Handle an initial down.
1826 if (actionMasked == MotionEvent.ACTION_DOWN) {
1827 // Throw away all previous state when starting a new touch gesture.
1828 // The framework may have dropped the up or cancel event for the previous gesture
1829 // due to an app switch, ANR, or some other state change.
1830 cancelAndClearTouchTargets(ev);
1831 resetTouchState();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001832 }
Adam Powellb08013c2010-09-16 16:28:11 -07001833
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001834 // Check for interception.
1835 final boolean intercepted;
Jeff Brown20e987b2010-08-23 12:01:02 -07001836 if (actionMasked == MotionEvent.ACTION_DOWN
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001837 || mFirstTouchTarget != null) {
1838 final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
1839 if (!disallowIntercept) {
1840 intercepted = onInterceptTouchEvent(ev);
1841 ev.setAction(action); // restore action in case it was changed
1842 } else {
1843 intercepted = false;
1844 }
1845 } else {
1846 // There are no touch targets and this action is not an initial down
1847 // so this view group continues to intercept touches.
1848 intercepted = true;
1849 }
Jeff Brown20e987b2010-08-23 12:01:02 -07001850
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001851 // Check for cancelation.
1852 final boolean canceled = resetCancelNextUpFlag(this)
1853 || actionMasked == MotionEvent.ACTION_CANCEL;
Jeff Brown20e987b2010-08-23 12:01:02 -07001854
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001855 // Update list of touch targets for pointer down, if needed.
1856 final boolean split = (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) != 0;
1857 TouchTarget newTouchTarget = null;
1858 boolean alreadyDispatchedToNewTouchTarget = false;
1859 if (!canceled && !intercepted) {
1860 if (actionMasked == MotionEvent.ACTION_DOWN
1861 || (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN)
1862 || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
1863 final int actionIndex = ev.getActionIndex(); // always 0 for down
1864 final int idBitsToAssign = split ? 1 << ev.getPointerId(actionIndex)
1865 : TouchTarget.ALL_POINTER_IDS;
Jeff Brown20e987b2010-08-23 12:01:02 -07001866
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001867 // Clean up earlier touch targets for this pointer id in case they
1868 // have become out of sync.
1869 removePointersFromTouchTargets(idBitsToAssign);
1870
Chet Haase9c17fe62013-03-22 17:05:55 -07001871 final float x = ev.getX(actionIndex);
1872 final float y = ev.getY(actionIndex);
1873
1874 if (mOverlay != null) {
1875 ViewOverlay overlay = (ViewOverlay) mOverlay;
1876 // Check to see whether the overlay can handle the event
1877 final View child = mOverlay;
1878 if (canViewReceivePointerEvents(child) &&
1879 isTransformedTouchPointInView(x, y, child, null)) {
1880 newTouchTarget = getTouchTarget(child);
1881 if (newTouchTarget != null) {
1882 newTouchTarget.pointerIdBits |= idBitsToAssign;
1883 } else {
1884 resetCancelNextUpFlag(child);
1885 if (dispatchTransformedTouchEvent(ev, false, child,
1886 idBitsToAssign)) {
1887 mLastTouchDownTime = ev.getDownTime();
1888 mLastTouchDownX = ev.getX();
1889 mLastTouchDownY = ev.getY();
1890 newTouchTarget = addTouchTarget(child, idBitsToAssign);
1891 alreadyDispatchedToNewTouchTarget = true;
1892 }
1893 }
1894 }
1895 }
1896
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001897 final int childrenCount = mChildrenCount;
Chet Haase9c17fe62013-03-22 17:05:55 -07001898 if (newTouchTarget == null && childrenCount != 0) {
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001899 // Find a child that can receive the event.
1900 // Scan children from front to back.
1901 final View[] children = mChildren;
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001902
Adam Powella6478a32012-08-17 16:40:00 -07001903 final boolean customOrder = isChildrenDrawingOrderEnabled();
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001904 for (int i = childrenCount - 1; i >= 0; i--) {
Adam Powella6478a32012-08-17 16:40:00 -07001905 final int childIndex = customOrder ?
1906 getChildDrawingOrder(childrenCount, i) : i;
1907 final View child = children[childIndex];
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001908 if (!canViewReceivePointerEvents(child)
1909 || !isTransformedTouchPointInView(x, y, child, null)) {
1910 continue;
1911 }
1912
1913 newTouchTarget = getTouchTarget(child);
1914 if (newTouchTarget != null) {
1915 // Child is already receiving touch within its bounds.
1916 // Give it the new pointer in addition to the ones it is handling.
1917 newTouchTarget.pointerIdBits |= idBitsToAssign;
1918 break;
1919 }
1920
1921 resetCancelNextUpFlag(child);
1922 if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
1923 // Child wants to receive touch within its bounds.
1924 mLastTouchDownTime = ev.getDownTime();
Adam Powella6478a32012-08-17 16:40:00 -07001925 mLastTouchDownIndex = childIndex;
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001926 mLastTouchDownX = ev.getX();
1927 mLastTouchDownY = ev.getY();
1928 newTouchTarget = addTouchTarget(child, idBitsToAssign);
1929 alreadyDispatchedToNewTouchTarget = true;
1930 break;
1931 }
1932 }
1933 }
1934
1935 if (newTouchTarget == null && mFirstTouchTarget != null) {
1936 // Did not find a child to receive the event.
1937 // Assign the pointer to the least recently added target.
1938 newTouchTarget = mFirstTouchTarget;
1939 while (newTouchTarget.next != null) {
1940 newTouchTarget = newTouchTarget.next;
1941 }
1942 newTouchTarget.pointerIdBits |= idBitsToAssign;
1943 }
1944 }
1945 }
1946
1947 // Dispatch to touch targets.
1948 if (mFirstTouchTarget == null) {
1949 // No touch targets so treat this as an ordinary view.
1950 handled = dispatchTransformedTouchEvent(ev, canceled, null,
1951 TouchTarget.ALL_POINTER_IDS);
1952 } else {
1953 // Dispatch to touch targets, excluding the new touch target if we already
1954 // dispatched to it. Cancel touch targets if necessary.
1955 TouchTarget predecessor = null;
1956 TouchTarget target = mFirstTouchTarget;
1957 while (target != null) {
1958 final TouchTarget next = target.next;
1959 if (alreadyDispatchedToNewTouchTarget && target == newTouchTarget) {
1960 handled = true;
1961 } else {
1962 final boolean cancelChild = resetCancelNextUpFlag(target.child)
Chet Haase9c17fe62013-03-22 17:05:55 -07001963 || intercepted;
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001964 if (dispatchTransformedTouchEvent(ev, cancelChild,
1965 target.child, target.pointerIdBits)) {
1966 handled = true;
1967 }
1968 if (cancelChild) {
1969 if (predecessor == null) {
1970 mFirstTouchTarget = next;
1971 } else {
1972 predecessor.next = next;
1973 }
1974 target.recycle();
1975 target = next;
Jeff Brown20e987b2010-08-23 12:01:02 -07001976 continue;
1977 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001978 }
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001979 predecessor = target;
1980 target = next;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001981 }
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001982 }
Jeff Brown20e987b2010-08-23 12:01:02 -07001983
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001984 // Update list of touch targets for pointer up or cancel, if needed.
1985 if (canceled
1986 || actionMasked == MotionEvent.ACTION_UP
1987 || actionMasked == MotionEvent.ACTION_HOVER_MOVE) {
1988 resetTouchState();
1989 } else if (split && actionMasked == MotionEvent.ACTION_POINTER_UP) {
1990 final int actionIndex = ev.getActionIndex();
1991 final int idBitsToRemove = 1 << ev.getPointerId(actionIndex);
1992 removePointersFromTouchTargets(idBitsToRemove);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001993 }
1994 }
Romain Guy8506ab42009-06-11 17:35:47 -07001995
Jeff Brownbbdc50b2011-04-19 23:46:52 -07001996 if (!handled && mInputEventConsistencyVerifier != null) {
1997 mInputEventConsistencyVerifier.onUnhandledEvent(ev, 1);
Jeff Brown20e987b2010-08-23 12:01:02 -07001998 }
Jeff Brown20e987b2010-08-23 12:01:02 -07001999 return handled;
2000 }
2001
Romain Guy469b1db2010-10-05 11:49:57 -07002002 /**
2003 * Resets all touch state in preparation for a new cycle.
2004 */
2005 private void resetTouchState() {
Jeff Brown20e987b2010-08-23 12:01:02 -07002006 clearTouchTargets();
2007 resetCancelNextUpFlag(this);
2008 mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
2009 }
2010
Romain Guy469b1db2010-10-05 11:49:57 -07002011 /**
2012 * Resets the cancel next up flag.
2013 * Returns true if the flag was previously set.
2014 */
Romain Guya998dff2012-03-23 18:58:36 -07002015 private static boolean resetCancelNextUpFlag(View view) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07002016 if ((view.mPrivateFlags & PFLAG_CANCEL_NEXT_UP_EVENT) != 0) {
2017 view.mPrivateFlags &= ~PFLAG_CANCEL_NEXT_UP_EVENT;
Jeff Brown20e987b2010-08-23 12:01:02 -07002018 return true;
Adam Cohen9b073942010-08-19 16:49:52 -07002019 }
2020 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002021 }
2022
Romain Guy469b1db2010-10-05 11:49:57 -07002023 /**
2024 * Clears all touch targets.
2025 */
2026 private void clearTouchTargets() {
Jeff Brown20e987b2010-08-23 12:01:02 -07002027 TouchTarget target = mFirstTouchTarget;
2028 if (target != null) {
2029 do {
2030 TouchTarget next = target.next;
2031 target.recycle();
2032 target = next;
2033 } while (target != null);
2034 mFirstTouchTarget = null;
2035 }
2036 }
2037
Romain Guy469b1db2010-10-05 11:49:57 -07002038 /**
2039 * Cancels and clears all touch targets.
2040 */
2041 private void cancelAndClearTouchTargets(MotionEvent event) {
Jeff Brown20e987b2010-08-23 12:01:02 -07002042 if (mFirstTouchTarget != null) {
2043 boolean syntheticEvent = false;
2044 if (event == null) {
2045 final long now = SystemClock.uptimeMillis();
2046 event = MotionEvent.obtain(now, now,
2047 MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
Jeff Brown2fdbc5a2011-06-30 12:25:54 -07002048 event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
Jeff Brown20e987b2010-08-23 12:01:02 -07002049 syntheticEvent = true;
2050 }
2051
2052 for (TouchTarget target = mFirstTouchTarget; target != null; target = target.next) {
2053 resetCancelNextUpFlag(target.child);
2054 dispatchTransformedTouchEvent(event, true, target.child, target.pointerIdBits);
2055 }
2056 clearTouchTargets();
2057
2058 if (syntheticEvent) {
2059 event.recycle();
2060 }
2061 }
2062 }
2063
Romain Guy469b1db2010-10-05 11:49:57 -07002064 /**
2065 * Gets the touch target for specified child view.
2066 * Returns null if not found.
2067 */
2068 private TouchTarget getTouchTarget(View child) {
Jeff Brown20e987b2010-08-23 12:01:02 -07002069 for (TouchTarget target = mFirstTouchTarget; target != null; target = target.next) {
2070 if (target.child == child) {
2071 return target;
2072 }
2073 }
2074 return null;
2075 }
2076
Romain Guy469b1db2010-10-05 11:49:57 -07002077 /**
2078 * Adds a touch target for specified child to the beginning of the list.
2079 * Assumes the target child is not already present.
2080 */
2081 private TouchTarget addTouchTarget(View child, int pointerIdBits) {
Jeff Brown20e987b2010-08-23 12:01:02 -07002082 TouchTarget target = TouchTarget.obtain(child, pointerIdBits);
2083 target.next = mFirstTouchTarget;
2084 mFirstTouchTarget = target;
2085 return target;
2086 }
2087
Romain Guy469b1db2010-10-05 11:49:57 -07002088 /**
2089 * Removes the pointer ids from consideration.
2090 */
2091 private void removePointersFromTouchTargets(int pointerIdBits) {
Jeff Brown20e987b2010-08-23 12:01:02 -07002092 TouchTarget predecessor = null;
2093 TouchTarget target = mFirstTouchTarget;
2094 while (target != null) {
2095 final TouchTarget next = target.next;
2096 if ((target.pointerIdBits & pointerIdBits) != 0) {
2097 target.pointerIdBits &= ~pointerIdBits;
2098 if (target.pointerIdBits == 0) {
2099 if (predecessor == null) {
2100 mFirstTouchTarget = next;
2101 } else {
2102 predecessor.next = next;
2103 }
2104 target.recycle();
2105 target = next;
2106 continue;
2107 }
2108 }
2109 predecessor = target;
2110 target = next;
2111 }
2112 }
2113
Jeff Brown59a422e2012-04-19 15:19:19 -07002114 private void cancelTouchTarget(View view) {
2115 TouchTarget predecessor = null;
2116 TouchTarget target = mFirstTouchTarget;
2117 while (target != null) {
2118 final TouchTarget next = target.next;
2119 if (target.child == view) {
2120 if (predecessor == null) {
2121 mFirstTouchTarget = next;
2122 } else {
2123 predecessor.next = next;
2124 }
2125 target.recycle();
2126
2127 final long now = SystemClock.uptimeMillis();
2128 MotionEvent event = MotionEvent.obtain(now, now,
2129 MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
2130 event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
2131 view.dispatchTouchEvent(event);
2132 event.recycle();
2133 return;
2134 }
2135 predecessor = target;
2136 target = next;
2137 }
2138 }
2139
Romain Guy469b1db2010-10-05 11:49:57 -07002140 /**
Jeff Browna032cc02011-03-07 16:56:21 -08002141 * Returns true if a child view can receive pointer events.
2142 * @hide
2143 */
2144 private static boolean canViewReceivePointerEvents(View child) {
2145 return (child.mViewFlags & VISIBILITY_MASK) == VISIBLE
2146 || child.getAnimation() != null;
2147 }
2148
2149 /**
Romain Guy469b1db2010-10-05 11:49:57 -07002150 * Returns true if a child view contains the specified point when transformed
Jeff Brown20e987b2010-08-23 12:01:02 -07002151 * into its coordinate space.
Romain Guy469b1db2010-10-05 11:49:57 -07002152 * Child must not be null.
Adam Cohena32edd42010-10-26 10:35:01 -07002153 * @hide
Romain Guy469b1db2010-10-05 11:49:57 -07002154 */
Adam Cohena32edd42010-10-26 10:35:01 -07002155 protected boolean isTransformedTouchPointInView(float x, float y, View child,
Christopher Tate2c095f32010-10-04 14:13:40 -07002156 PointF outLocalPoint) {
Jeff Brown20e987b2010-08-23 12:01:02 -07002157 float localX = x + mScrollX - child.mLeft;
2158 float localY = y + mScrollY - child.mTop;
2159 if (! child.hasIdentityMatrix() && mAttachInfo != null) {
Adam Powell2b342f02010-08-18 18:14:13 -07002160 final float[] localXY = mAttachInfo.mTmpTransformLocation;
2161 localXY[0] = localX;
2162 localXY[1] = localY;
2163 child.getInverseMatrix().mapPoints(localXY);
2164 localX = localXY[0];
2165 localY = localXY[1];
2166 }
Christopher Tate2c095f32010-10-04 14:13:40 -07002167 final boolean isInView = child.pointInView(localX, localY);
2168 if (isInView && outLocalPoint != null) {
2169 outLocalPoint.set(localX, localY);
2170 }
2171 return isInView;
Adam Powell2b342f02010-08-18 18:14:13 -07002172 }
2173
Romain Guy469b1db2010-10-05 11:49:57 -07002174 /**
2175 * Transforms a motion event into the coordinate space of a particular child view,
Jeff Brown20e987b2010-08-23 12:01:02 -07002176 * filters out irrelevant pointer ids, and overrides its action if necessary.
Romain Guy469b1db2010-10-05 11:49:57 -07002177 * If child is null, assumes the MotionEvent will be sent to this ViewGroup instead.
2178 */
2179 private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,
Jeff Brown20e987b2010-08-23 12:01:02 -07002180 View child, int desiredPointerIdBits) {
2181 final boolean handled;
Adam Powell2b342f02010-08-18 18:14:13 -07002182
Jeff Brown20e987b2010-08-23 12:01:02 -07002183 // Canceling motions is a special case. We don't need to perform any transformations
2184 // or filtering. The important part is the action, not the contents.
2185 final int oldAction = event.getAction();
2186 if (cancel || oldAction == MotionEvent.ACTION_CANCEL) {
2187 event.setAction(MotionEvent.ACTION_CANCEL);
2188 if (child == null) {
2189 handled = super.dispatchTouchEvent(event);
2190 } else {
2191 handled = child.dispatchTouchEvent(event);
2192 }
2193 event.setAction(oldAction);
2194 return handled;
2195 }
Adam Powell2b342f02010-08-18 18:14:13 -07002196
Jeff Brown20e987b2010-08-23 12:01:02 -07002197 // Calculate the number of pointers to deliver.
Jeff Brownfe9f8ab2011-05-06 18:20:01 -07002198 final int oldPointerIdBits = event.getPointerIdBits();
2199 final int newPointerIdBits = oldPointerIdBits & desiredPointerIdBits;
Adam Powell2b342f02010-08-18 18:14:13 -07002200
Jeff Brown20e987b2010-08-23 12:01:02 -07002201 // If for some reason we ended up in an inconsistent state where it looks like we
2202 // might produce a motion event with no pointers in it, then drop the event.
Jeff Brownfe9f8ab2011-05-06 18:20:01 -07002203 if (newPointerIdBits == 0) {
Jeff Brown20e987b2010-08-23 12:01:02 -07002204 return false;
2205 }
Adam Powell2b342f02010-08-18 18:14:13 -07002206
Jeff Brown20e987b2010-08-23 12:01:02 -07002207 // If the number of pointers is the same and we don't need to perform any fancy
2208 // irreversible transformations, then we can reuse the motion event for this
2209 // dispatch as long as we are careful to revert any changes we make.
Jeff Brownfe9f8ab2011-05-06 18:20:01 -07002210 // Otherwise we need to make a copy.
2211 final MotionEvent transformedEvent;
2212 if (newPointerIdBits == oldPointerIdBits) {
2213 if (child == null || child.hasIdentityMatrix()) {
2214 if (child == null) {
2215 handled = super.dispatchTouchEvent(event);
2216 } else {
2217 final float offsetX = mScrollX - child.mLeft;
2218 final float offsetY = mScrollY - child.mTop;
2219 event.offsetLocation(offsetX, offsetY);
Adam Powell2b342f02010-08-18 18:14:13 -07002220
Jeff Brownfe9f8ab2011-05-06 18:20:01 -07002221 handled = child.dispatchTouchEvent(event);
Jeff Brown20e987b2010-08-23 12:01:02 -07002222
Jeff Brownfe9f8ab2011-05-06 18:20:01 -07002223 event.offsetLocation(-offsetX, -offsetY);
2224 }
2225 return handled;
Jeff Brown20e987b2010-08-23 12:01:02 -07002226 }
Jeff Brown20e987b2010-08-23 12:01:02 -07002227 transformedEvent = MotionEvent.obtain(event);
2228 } else {
Jeff Brownfe9f8ab2011-05-06 18:20:01 -07002229 transformedEvent = event.split(newPointerIdBits);
Adam Powell2b342f02010-08-18 18:14:13 -07002230 }
2231
Jeff Brown20e987b2010-08-23 12:01:02 -07002232 // Perform any necessary transformations and dispatch.
2233 if (child == null) {
2234 handled = super.dispatchTouchEvent(transformedEvent);
2235 } else {
2236 final float offsetX = mScrollX - child.mLeft;
2237 final float offsetY = mScrollY - child.mTop;
2238 transformedEvent.offsetLocation(offsetX, offsetY);
2239 if (! child.hasIdentityMatrix()) {
2240 transformedEvent.transform(child.getInverseMatrix());
Adam Powell2b342f02010-08-18 18:14:13 -07002241 }
2242
Jeff Brown20e987b2010-08-23 12:01:02 -07002243 handled = child.dispatchTouchEvent(transformedEvent);
Adam Powell2b342f02010-08-18 18:14:13 -07002244 }
2245
Jeff Brown20e987b2010-08-23 12:01:02 -07002246 // Done.
2247 transformedEvent.recycle();
Adam Powell2b342f02010-08-18 18:14:13 -07002248 return handled;
2249 }
2250
Romain Guy469b1db2010-10-05 11:49:57 -07002251 /**
Adam Powell2b342f02010-08-18 18:14:13 -07002252 * Enable or disable the splitting of MotionEvents to multiple children during touch event
Jeff Brown995e7742010-12-22 16:59:36 -08002253 * dispatch. This behavior is enabled by default for applications that target an
2254 * SDK version of {@link Build.VERSION_CODES#HONEYCOMB} or newer.
Adam Powell2b342f02010-08-18 18:14:13 -07002255 *
2256 * <p>When this option is enabled MotionEvents may be split and dispatched to different child
2257 * views depending on where each pointer initially went down. This allows for user interactions
2258 * such as scrolling two panes of content independently, chording of buttons, and performing
2259 * independent gestures on different pieces of content.
2260 *
2261 * @param split <code>true</code> to allow MotionEvents to be split and dispatched to multiple
2262 * child views. <code>false</code> to only allow one child view to be the target of
2263 * any MotionEvent received by this ViewGroup.
2264 */
2265 public void setMotionEventSplittingEnabled(boolean split) {
2266 // TODO Applications really shouldn't change this setting mid-touch event,
2267 // but perhaps this should handle that case and send ACTION_CANCELs to any child views
2268 // with gestures in progress when this is changed.
2269 if (split) {
Adam Powell2b342f02010-08-18 18:14:13 -07002270 mGroupFlags |= FLAG_SPLIT_MOTION_EVENTS;
2271 } else {
2272 mGroupFlags &= ~FLAG_SPLIT_MOTION_EVENTS;
Adam Powell2b342f02010-08-18 18:14:13 -07002273 }
2274 }
2275
2276 /**
Jeff Brown995e7742010-12-22 16:59:36 -08002277 * Returns true if MotionEvents dispatched to this ViewGroup can be split to multiple children.
Adam Powell2b342f02010-08-18 18:14:13 -07002278 * @return true if MotionEvents dispatched to this ViewGroup can be split to multiple children.
2279 */
2280 public boolean isMotionEventSplittingEnabled() {
2281 return (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) == FLAG_SPLIT_MOTION_EVENTS;
2282 }
2283
2284 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002285 * {@inheritDoc}
2286 */
2287 public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
Romain Guy8506ab42009-06-11 17:35:47 -07002288
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002289 if (disallowIntercept == ((mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0)) {
2290 // We're already in this state, assume our ancestors are too
2291 return;
2292 }
Romain Guy8506ab42009-06-11 17:35:47 -07002293
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002294 if (disallowIntercept) {
2295 mGroupFlags |= FLAG_DISALLOW_INTERCEPT;
2296 } else {
2297 mGroupFlags &= ~FLAG_DISALLOW_INTERCEPT;
2298 }
Romain Guy8506ab42009-06-11 17:35:47 -07002299
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002300 // Pass it up to our parent
2301 if (mParent != null) {
2302 mParent.requestDisallowInterceptTouchEvent(disallowIntercept);
2303 }
2304 }
2305
2306 /**
2307 * Implement this method to intercept all touch screen motion events. This
2308 * allows you to watch events as they are dispatched to your children, and
2309 * take ownership of the current gesture at any point.
2310 *
2311 * <p>Using this function takes some care, as it has a fairly complicated
2312 * interaction with {@link View#onTouchEvent(MotionEvent)
2313 * View.onTouchEvent(MotionEvent)}, and using it requires implementing
2314 * that method as well as this one in the correct way. Events will be
2315 * received in the following order:
2316 *
2317 * <ol>
2318 * <li> You will receive the down event here.
2319 * <li> The down event will be handled either by a child of this view
2320 * group, or given to your own onTouchEvent() method to handle; this means
2321 * you should implement onTouchEvent() to return true, so you will
2322 * continue to see the rest of the gesture (instead of looking for
2323 * a parent view to handle it). Also, by returning true from
2324 * onTouchEvent(), you will not receive any following
2325 * events in onInterceptTouchEvent() and all touch processing must
2326 * happen in onTouchEvent() like normal.
2327 * <li> For as long as you return false from this function, each following
2328 * event (up to and including the final up) will be delivered first here
2329 * and then to the target's onTouchEvent().
2330 * <li> If you return true from here, you will not receive any
2331 * following events: the target view will receive the same event but
2332 * with the action {@link MotionEvent#ACTION_CANCEL}, and all further
2333 * events will be delivered to your onTouchEvent() method and no longer
2334 * appear here.
2335 * </ol>
2336 *
2337 * @param ev The motion event being dispatched down the hierarchy.
2338 * @return Return true to steal motion events from the children and have
2339 * them dispatched to this ViewGroup through onTouchEvent().
2340 * The current target will receive an ACTION_CANCEL event, and no further
2341 * messages will be delivered here.
2342 */
2343 public boolean onInterceptTouchEvent(MotionEvent ev) {
2344 return false;
2345 }
2346
2347 /**
2348 * {@inheritDoc}
2349 *
2350 * Looks for a view to give focus to respecting the setting specified by
2351 * {@link #getDescendantFocusability()}.
2352 *
2353 * Uses {@link #onRequestFocusInDescendants(int, android.graphics.Rect)} to
2354 * find focus within the children of this group when appropriate.
2355 *
2356 * @see #FOCUS_BEFORE_DESCENDANTS
2357 * @see #FOCUS_AFTER_DESCENDANTS
2358 * @see #FOCUS_BLOCK_DESCENDANTS
Romain Guy02739a82011-05-16 11:43:18 -07002359 * @see #onRequestFocusInDescendants(int, android.graphics.Rect)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002360 */
2361 @Override
2362 public boolean requestFocus(int direction, Rect previouslyFocusedRect) {
2363 if (DBG) {
2364 System.out.println(this + " ViewGroup.requestFocus direction="
2365 + direction);
2366 }
2367 int descendantFocusability = getDescendantFocusability();
2368
2369 switch (descendantFocusability) {
2370 case FOCUS_BLOCK_DESCENDANTS:
2371 return super.requestFocus(direction, previouslyFocusedRect);
2372 case FOCUS_BEFORE_DESCENDANTS: {
2373 final boolean took = super.requestFocus(direction, previouslyFocusedRect);
2374 return took ? took : onRequestFocusInDescendants(direction, previouslyFocusedRect);
2375 }
2376 case FOCUS_AFTER_DESCENDANTS: {
2377 final boolean took = onRequestFocusInDescendants(direction, previouslyFocusedRect);
2378 return took ? took : super.requestFocus(direction, previouslyFocusedRect);
2379 }
2380 default:
2381 throw new IllegalStateException("descendant focusability must be "
2382 + "one of FOCUS_BEFORE_DESCENDANTS, FOCUS_AFTER_DESCENDANTS, FOCUS_BLOCK_DESCENDANTS "
2383 + "but is " + descendantFocusability);
2384 }
2385 }
2386
2387 /**
2388 * Look for a descendant to call {@link View#requestFocus} on.
2389 * Called by {@link ViewGroup#requestFocus(int, android.graphics.Rect)}
2390 * when it wants to request focus within its children. Override this to
2391 * customize how your {@link ViewGroup} requests focus within its children.
2392 * @param direction One of FOCUS_UP, FOCUS_DOWN, FOCUS_LEFT, and FOCUS_RIGHT
2393 * @param previouslyFocusedRect The rectangle (in this View's coordinate system)
2394 * to give a finer grained hint about where focus is coming from. May be null
2395 * if there is no hint.
2396 * @return Whether focus was taken.
2397 */
2398 @SuppressWarnings({"ConstantConditions"})
2399 protected boolean onRequestFocusInDescendants(int direction,
2400 Rect previouslyFocusedRect) {
2401 int index;
2402 int increment;
2403 int end;
2404 int count = mChildrenCount;
2405 if ((direction & FOCUS_FORWARD) != 0) {
2406 index = 0;
2407 increment = 1;
2408 end = count;
2409 } else {
2410 index = count - 1;
2411 increment = -1;
2412 end = -1;
2413 }
2414 final View[] children = mChildren;
2415 for (int i = index; i != end; i += increment) {
2416 View child = children[i];
2417 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
2418 if (child.requestFocus(direction, previouslyFocusedRect)) {
2419 return true;
2420 }
2421 }
2422 }
2423 return false;
2424 }
Chet Haase5c13d892010-10-08 08:37:55 -07002425
Romain Guya440b002010-02-24 15:57:54 -08002426 /**
2427 * {@inheritDoc}
Chet Haase5c13d892010-10-08 08:37:55 -07002428 *
Romain Guydcc490f2010-02-24 17:59:35 -08002429 * @hide
Romain Guya440b002010-02-24 15:57:54 -08002430 */
2431 @Override
2432 public void dispatchStartTemporaryDetach() {
2433 super.dispatchStartTemporaryDetach();
2434 final int count = mChildrenCount;
2435 final View[] children = mChildren;
2436 for (int i = 0; i < count; i++) {
2437 children[i].dispatchStartTemporaryDetach();
2438 }
2439 }
Chet Haase5c13d892010-10-08 08:37:55 -07002440
Romain Guya440b002010-02-24 15:57:54 -08002441 /**
2442 * {@inheritDoc}
Chet Haase5c13d892010-10-08 08:37:55 -07002443 *
Romain Guydcc490f2010-02-24 17:59:35 -08002444 * @hide
Romain Guya440b002010-02-24 15:57:54 -08002445 */
2446 @Override
2447 public void dispatchFinishTemporaryDetach() {
2448 super.dispatchFinishTemporaryDetach();
2449 final int count = mChildrenCount;
2450 final View[] children = mChildren;
2451 for (int i = 0; i < count; i++) {
2452 children[i].dispatchFinishTemporaryDetach();
2453 }
2454 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002455
2456 /**
2457 * {@inheritDoc}
2458 */
2459 @Override
2460 void dispatchAttachedToWindow(AttachInfo info, int visibility) {
Adam Powell4b867882011-09-16 12:59:46 -07002461 mGroupFlags |= FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002462 super.dispatchAttachedToWindow(info, visibility);
Adam Powell4b867882011-09-16 12:59:46 -07002463 mGroupFlags &= ~FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW;
2464
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002465 final int count = mChildrenCount;
2466 final View[] children = mChildren;
2467 for (int i = 0; i < count; i++) {
Dianne Hackborn3a3a6cf2012-03-26 10:24:04 -07002468 final View child = children[i];
2469 child.dispatchAttachedToWindow(info,
Philip Milne7b757812012-09-19 18:13:44 -07002470 visibility | (child.mViewFlags & VISIBILITY_MASK));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002471 }
2472 }
2473
svetoslavganov75986cf2009-05-14 22:28:01 -07002474 @Override
Romain Guybb9908b2012-03-08 11:14:07 -08002475 void dispatchScreenStateChanged(int screenState) {
2476 super.dispatchScreenStateChanged(screenState);
2477
2478 final int count = mChildrenCount;
2479 final View[] children = mChildren;
2480 for (int i = 0; i < count; i++) {
2481 children[i].dispatchScreenStateChanged(screenState);
2482 }
2483 }
2484
2485 @Override
Svetoslav Ganov031d9c12011-09-09 16:41:13 -07002486 boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) {
Svetoslav Ganov42138042012-03-20 11:51:39 -07002487 boolean handled = false;
2488 if (includeForAccessibility()) {
2489 handled = super.dispatchPopulateAccessibilityEventInternal(event);
2490 if (handled) {
2491 return handled;
2492 }
Svetoslav Ganovb84b94e2011-09-22 19:26:56 -07002493 }
Svetoslav Ganov736c2752011-04-22 18:30:36 -07002494 // Let our children have a shot in populating the event.
Svetoslav Ganov42138042012-03-20 11:51:39 -07002495 ChildListForAccessibility children = ChildListForAccessibility.obtain(this, true);
Svetoslav Ganov76f287e2012-04-23 11:02:36 -07002496 try {
2497 final int childCount = children.getChildCount();
2498 for (int i = 0; i < childCount; i++) {
2499 View child = children.getChildAt(i);
2500 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
2501 handled = child.dispatchPopulateAccessibilityEvent(event);
2502 if (handled) {
Svetoslav Ganov76f287e2012-04-23 11:02:36 -07002503 return handled;
2504 }
Svetoslav Ganov6179ea32011-06-28 01:12:41 -07002505 }
Svetoslav Ganov736c2752011-04-22 18:30:36 -07002506 }
Svetoslav Ganov76f287e2012-04-23 11:02:36 -07002507 } finally {
2508 children.recycle();
svetoslavganov75986cf2009-05-14 22:28:01 -07002509 }
Svetoslav Ganov736c2752011-04-22 18:30:36 -07002510 return false;
svetoslavganov75986cf2009-05-14 22:28:01 -07002511 }
2512
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002513 @Override
Svetoslav Ganov031d9c12011-09-09 16:41:13 -07002514 void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
2515 super.onInitializeAccessibilityNodeInfoInternal(info);
Svetoslav Ganov42138042012-03-20 11:51:39 -07002516 if (mAttachInfo != null) {
2517 ArrayList<View> childrenForAccessibility = mAttachInfo.mTempArrayList;
2518 childrenForAccessibility.clear();
2519 addChildrenForAccessibility(childrenForAccessibility);
2520 final int childrenForAccessibilityCount = childrenForAccessibility.size();
2521 for (int i = 0; i < childrenForAccessibilityCount; i++) {
2522 View child = childrenForAccessibility.get(i);
Svetoslav Ganovea1da3d2011-06-15 17:16:02 -07002523 info.addChild(child);
2524 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07002525 childrenForAccessibility.clear();
Svetoslav Ganov8643aa02011-04-20 12:12:33 -07002526 }
2527 }
2528
Svetoslav Ganov8a78fd42012-01-17 14:36:46 -08002529 @Override
2530 void onInitializeAccessibilityEventInternal(AccessibilityEvent event) {
2531 super.onInitializeAccessibilityEventInternal(event);
2532 event.setClassName(ViewGroup.class.getName());
2533 }
2534
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002535 /**
Svetoslav Ganov42138042012-03-20 11:51:39 -07002536 * @hide
2537 */
2538 @Override
2539 public void resetAccessibilityStateChanged() {
2540 super.resetAccessibilityStateChanged();
2541 View[] children = mChildren;
2542 final int childCount = mChildrenCount;
2543 for (int i = 0; i < childCount; i++) {
2544 View child = children[i];
2545 child.resetAccessibilityStateChanged();
2546 }
2547 }
2548
2549 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002550 * {@inheritDoc}
2551 */
2552 @Override
2553 void dispatchDetachedFromWindow() {
Jeff Brown20e987b2010-08-23 12:01:02 -07002554 // If we still have a touch target, we are still in the process of
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002555 // dispatching motion events to a child; we need to get rid of that
2556 // child to avoid dispatching events to it after the window is torn
2557 // down. To make sure we keep the child in a consistent state, we
2558 // first send it an ACTION_CANCEL motion event.
Jeff Brown20e987b2010-08-23 12:01:02 -07002559 cancelAndClearTouchTargets(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002560
Jeff Brown59a422e2012-04-19 15:19:19 -07002561 // Similarly, set ACTION_EXIT to all hover targets and clear them.
2562 exitHoverTargets();
2563
Chet Haase9c087442011-01-12 16:20:16 -08002564 // In case view is detached while transition is running
2565 mLayoutSuppressed = false;
2566
Christopher Tate86cab1b2011-01-13 20:28:55 -08002567 // Tear down our drag tracking
2568 mDragNotifiedChildren = null;
2569 if (mCurrentDrag != null) {
2570 mCurrentDrag.recycle();
2571 mCurrentDrag = null;
2572 }
2573
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002574 final int count = mChildrenCount;
2575 final View[] children = mChildren;
2576 for (int i = 0; i < count; i++) {
2577 children[i].dispatchDetachedFromWindow();
2578 }
2579 super.dispatchDetachedFromWindow();
2580 }
2581
Fabrice Di Meglio23c89fd2012-08-13 12:17:42 -07002582 /**
2583 * @hide
2584 */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002585 @Override
Fabrice Di Meglio23c89fd2012-08-13 12:17:42 -07002586 protected void internalSetPadding(int left, int top, int right, int bottom) {
Romain Guy2440e672012-08-07 14:43:43 -07002587 super.internalSetPadding(left, top, right, bottom);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002588
Romain Guy13f35f32011-03-24 12:03:17 -07002589 if ((mPaddingLeft | mPaddingTop | mPaddingRight | mPaddingBottom) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002590 mGroupFlags |= FLAG_PADDING_NOT_NULL;
2591 } else {
2592 mGroupFlags &= ~FLAG_PADDING_NOT_NULL;
2593 }
2594 }
2595
2596 /**
2597 * {@inheritDoc}
2598 */
2599 @Override
2600 protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {
2601 super.dispatchSaveInstanceState(container);
2602 final int count = mChildrenCount;
2603 final View[] children = mChildren;
2604 for (int i = 0; i < count; i++) {
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07002605 View c = children[i];
2606 if ((c.mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED) {
2607 c.dispatchSaveInstanceState(container);
2608 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002609 }
2610 }
2611
2612 /**
Romain Guy9fc27812011-04-27 14:21:41 -07002613 * Perform dispatching of a {@link #saveHierarchyState(android.util.SparseArray)} freeze()}
2614 * to only this view, not to its children. For use when overriding
2615 * {@link #dispatchSaveInstanceState(android.util.SparseArray)} dispatchFreeze()} to allow
2616 * subclasses to freeze their own state but not the state of their children.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002617 *
2618 * @param container the container
2619 */
2620 protected void dispatchFreezeSelfOnly(SparseArray<Parcelable> container) {
2621 super.dispatchSaveInstanceState(container);
2622 }
2623
2624 /**
2625 * {@inheritDoc}
2626 */
2627 @Override
2628 protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {
2629 super.dispatchRestoreInstanceState(container);
2630 final int count = mChildrenCount;
2631 final View[] children = mChildren;
2632 for (int i = 0; i < count; i++) {
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07002633 View c = children[i];
2634 if ((c.mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED) {
2635 c.dispatchRestoreInstanceState(container);
2636 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002637 }
2638 }
2639
2640 /**
Romain Guy02739a82011-05-16 11:43:18 -07002641 * Perform dispatching of a {@link #restoreHierarchyState(android.util.SparseArray)}
2642 * to only this view, not to its children. For use when overriding
2643 * {@link #dispatchRestoreInstanceState(android.util.SparseArray)} to allow
2644 * subclasses to thaw their own state but not the state of their children.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002645 *
2646 * @param container the container
2647 */
2648 protected void dispatchThawSelfOnly(SparseArray<Parcelable> container) {
2649 super.dispatchRestoreInstanceState(container);
2650 }
2651
2652 /**
2653 * Enables or disables the drawing cache for each child of this view group.
2654 *
2655 * @param enabled true to enable the cache, false to dispose of it
2656 */
2657 protected void setChildrenDrawingCacheEnabled(boolean enabled) {
2658 if (enabled || (mPersistentDrawingCache & PERSISTENT_ALL_CACHES) != PERSISTENT_ALL_CACHES) {
2659 final View[] children = mChildren;
2660 final int count = mChildrenCount;
2661 for (int i = 0; i < count; i++) {
2662 children[i].setDrawingCacheEnabled(enabled);
2663 }
2664 }
2665 }
2666
2667 @Override
2668 protected void onAnimationStart() {
2669 super.onAnimationStart();
2670
2671 // When this ViewGroup's animation starts, build the cache for the children
2672 if ((mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE) {
2673 final int count = mChildrenCount;
2674 final View[] children = mChildren;
Romain Guy0d9275e2010-10-26 14:22:30 -07002675 final boolean buildCache = !isHardwareAccelerated();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002676
2677 for (int i = 0; i < count; i++) {
2678 final View child = children[i];
2679 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
2680 child.setDrawingCacheEnabled(true);
Romain Guy0d9275e2010-10-26 14:22:30 -07002681 if (buildCache) {
2682 child.buildDrawingCache(true);
2683 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002684 }
2685 }
2686
2687 mGroupFlags |= FLAG_CHILDREN_DRAWN_WITH_CACHE;
2688 }
2689 }
2690
2691 @Override
2692 protected void onAnimationEnd() {
2693 super.onAnimationEnd();
2694
2695 // When this ViewGroup's animation ends, destroy the cache of the children
2696 if ((mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE) {
2697 mGroupFlags &= ~FLAG_CHILDREN_DRAWN_WITH_CACHE;
2698
2699 if ((mPersistentDrawingCache & PERSISTENT_ANIMATION_CACHE) == 0) {
2700 setChildrenDrawingCacheEnabled(false);
2701 }
2702 }
2703 }
2704
Romain Guy223ff5c2010-03-02 17:07:47 -08002705 @Override
2706 Bitmap createSnapshot(Bitmap.Config quality, int backgroundColor, boolean skipChildren) {
Romain Guy65554f22010-03-22 18:58:21 -07002707 int count = mChildrenCount;
2708 int[] visibilities = null;
2709
Romain Guy223ff5c2010-03-02 17:07:47 -08002710 if (skipChildren) {
Romain Guy65554f22010-03-22 18:58:21 -07002711 visibilities = new int[count];
2712 for (int i = 0; i < count; i++) {
2713 View child = getChildAt(i);
2714 visibilities[i] = child.getVisibility();
2715 if (visibilities[i] == View.VISIBLE) {
2716 child.setVisibility(INVISIBLE);
2717 }
2718 }
Romain Guy223ff5c2010-03-02 17:07:47 -08002719 }
2720
2721 Bitmap b = super.createSnapshot(quality, backgroundColor, skipChildren);
Romain Guy65554f22010-03-22 18:58:21 -07002722
2723 if (skipChildren) {
2724 for (int i = 0; i < count; i++) {
2725 getChildAt(i).setVisibility(visibilities[i]);
Chet Haase5c13d892010-10-08 08:37:55 -07002726 }
Romain Guy65554f22010-03-22 18:58:21 -07002727 }
Romain Guy223ff5c2010-03-02 17:07:47 -08002728
2729 return b;
2730 }
2731
Philip Milne7b757812012-09-19 18:13:44 -07002732 /** Return true if this ViewGroup is laying out using optical bounds. */
2733 boolean isLayoutModeOptical() {
2734 return mLayoutMode == LAYOUT_MODE_OPTICAL_BOUNDS;
2735 }
Romain Guycbc67742012-04-27 16:12:57 -07002736
Philip Milne7b757812012-09-19 18:13:44 -07002737 Insets computeOpticalInsets() {
2738 if (isLayoutModeOptical()) {
2739 int left = 0;
2740 int top = 0;
2741 int right = 0;
2742 int bottom = 0;
2743 for (int i = 0; i < mChildrenCount; i++) {
2744 View child = getChildAt(i);
2745 if (child.getVisibility() == VISIBLE) {
2746 Insets insets = child.getOpticalInsets();
2747 left = Math.max(left, insets.left);
2748 top = Math.max(top, insets.top);
2749 right = Math.max(right, insets.right);
2750 bottom = Math.max(bottom, insets.bottom);
2751 }
2752 }
2753 return Insets.of(left, top, right, bottom);
2754 } else {
2755 return Insets.NONE;
2756 }
2757 }
2758
2759 private static void fillRect(Canvas canvas, Paint paint, int x1, int y1, int x2, int y2) {
2760 if (x1 != x2 && y1 != y2) {
2761 if (x1 > x2) {
2762 int tmp = x1; x1 = x2; x2 = tmp;
2763 }
2764 if (y1 > y2) {
2765 int tmp = y1; y1 = y2; y2 = tmp;
2766 }
2767 canvas.drawRect(x1, y1, x2, y2, paint);
2768 }
2769 }
2770
2771 private static int sign(int x) {
2772 return (x >= 0) ? 1 : -1;
2773 }
2774
2775 private static void drawCorner(Canvas c, Paint paint, int x1, int y1, int dx, int dy, int lw) {
2776 fillRect(c, paint, x1, y1, x1 + dx, y1 + lw * sign(dy));
2777 fillRect(c, paint, x1, y1, x1 + lw * sign(dx), y1 + dy);
2778 }
2779
2780 private int dipsToPixels(int dips) {
2781 float scale = getContext().getResources().getDisplayMetrics().density;
2782 return (int) (dips * scale + 0.5f);
2783 }
2784
2785 private void drawRectCorners(Canvas canvas, int x1, int y1, int x2, int y2, Paint paint,
2786 int lineLength, int lineWidth) {
2787 drawCorner(canvas, paint, x1, y1, lineLength, lineLength, lineWidth);
2788 drawCorner(canvas, paint, x1, y2, lineLength, -lineLength, lineWidth);
2789 drawCorner(canvas, paint, x2, y1, -lineLength, lineLength, lineWidth);
2790 drawCorner(canvas, paint, x2, y2, -lineLength, -lineLength, lineWidth);
2791 }
2792
2793 private static void fillDifference(Canvas canvas,
2794 int x2, int y2, int x3, int y3,
2795 int dx1, int dy1, int dx2, int dy2, Paint paint) {
2796 int x1 = x2 - dx1;
2797 int y1 = y2 - dy1;
2798
2799 int x4 = x3 + dx2;
2800 int y4 = y3 + dy2;
2801
2802 fillRect(canvas, paint, x1, y1, x4, y2);
2803 fillRect(canvas, paint, x1, y2, x2, y3);
2804 fillRect(canvas, paint, x3, y2, x4, y3);
2805 fillRect(canvas, paint, x1, y3, x4, y4);
Philip Milne10ca24a2012-04-23 15:38:27 -07002806 }
2807
2808 /**
2809 * @hide
2810 */
Philip Milne7b757812012-09-19 18:13:44 -07002811 protected void onDebugDrawMargins(Canvas canvas, Paint paint) {
Philip Milne10ca24a2012-04-23 15:38:27 -07002812 for (int i = 0; i < getChildCount(); i++) {
2813 View c = getChildAt(i);
Philip Milne7b757812012-09-19 18:13:44 -07002814 c.getLayoutParams().onDebugDraw(c, canvas, paint);
Philip Milne10ca24a2012-04-23 15:38:27 -07002815 }
2816 }
2817
2818 /**
2819 * @hide
2820 */
2821 protected void onDebugDraw(Canvas canvas) {
Philip Milne7b757812012-09-19 18:13:44 -07002822 Paint paint = getDebugPaint();
2823
Philip Milne10ca24a2012-04-23 15:38:27 -07002824 // Draw optical bounds
Philip Milne7b757812012-09-19 18:13:44 -07002825 {
2826 paint.setColor(Color.RED);
2827 paint.setStyle(Paint.Style.STROKE);
Philip Milne7b757812012-09-19 18:13:44 -07002828
Philip Milne10ca24a2012-04-23 15:38:27 -07002829 for (int i = 0; i < getChildCount(); i++) {
2830 View c = getChildAt(i);
Philip Milne7a23b492012-04-24 22:12:36 -07002831 Insets insets = c.getOpticalInsets();
Philip Milne7b757812012-09-19 18:13:44 -07002832
2833 drawRect(canvas, paint,
2834 c.getLeft() + insets.left,
2835 c.getTop() + insets.top,
2836 c.getRight() - insets.right - 1,
2837 c.getBottom() - insets.bottom - 1);
Philip Milne10ca24a2012-04-23 15:38:27 -07002838 }
2839 }
2840
Philip Milne10ca24a2012-04-23 15:38:27 -07002841 // Draw margins
Philip Milne7b757812012-09-19 18:13:44 -07002842 {
2843 paint.setColor(Color.argb(63, 255, 0, 255));
2844 paint.setStyle(Paint.Style.FILL);
Philip Milne604f4402012-04-24 19:27:11 -07002845
Philip Milne7b757812012-09-19 18:13:44 -07002846 onDebugDrawMargins(canvas, paint);
2847 }
2848
2849 // Draw clip bounds
2850 {
2851 paint.setColor(Color.rgb(63, 127, 255));
2852 paint.setStyle(Paint.Style.FILL);
2853
2854 int lineLength = dipsToPixels(8);
2855 int lineWidth = dipsToPixels(1);
2856 for (int i = 0; i < getChildCount(); i++) {
2857 View c = getChildAt(i);
2858 drawRectCorners(canvas, c.getLeft(), c.getTop(), c.getRight(), c.getBottom(),
2859 paint, lineLength, lineWidth);
2860 }
Philip Milne604f4402012-04-24 19:27:11 -07002861 }
Philip Milne10ca24a2012-04-23 15:38:27 -07002862 }
2863
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002864 /**
2865 * {@inheritDoc}
2866 */
2867 @Override
2868 protected void dispatchDraw(Canvas canvas) {
2869 final int count = mChildrenCount;
2870 final View[] children = mChildren;
2871 int flags = mGroupFlags;
2872
2873 if ((flags & FLAG_RUN_ANIMATION) != 0 && canAnimate()) {
2874 final boolean cache = (mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE;
2875
Romain Guy0d9275e2010-10-26 14:22:30 -07002876 final boolean buildCache = !isHardwareAccelerated();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002877 for (int i = 0; i < count; i++) {
2878 final View child = children[i];
2879 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
2880 final LayoutParams params = child.getLayoutParams();
2881 attachLayoutAnimationParameters(child, params, i, count);
2882 bindLayoutAnimation(child);
2883 if (cache) {
2884 child.setDrawingCacheEnabled(true);
Romain Guy0d9275e2010-10-26 14:22:30 -07002885 if (buildCache) {
2886 child.buildDrawingCache(true);
2887 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002888 }
2889 }
2890 }
2891
2892 final LayoutAnimationController controller = mLayoutAnimationController;
2893 if (controller.willOverlap()) {
2894 mGroupFlags |= FLAG_OPTIMIZE_INVALIDATE;
2895 }
2896
2897 controller.start();
2898
2899 mGroupFlags &= ~FLAG_RUN_ANIMATION;
2900 mGroupFlags &= ~FLAG_ANIMATION_DONE;
2901
2902 if (cache) {
2903 mGroupFlags |= FLAG_CHILDREN_DRAWN_WITH_CACHE;
2904 }
2905
2906 if (mAnimationListener != null) {
2907 mAnimationListener.onAnimationStart(controller.getAnimation());
2908 }
2909 }
2910
2911 int saveCount = 0;
2912 final boolean clipToPadding = (flags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK;
2913 if (clipToPadding) {
2914 saveCount = canvas.save();
Romain Guy8f2d94f2009-03-25 18:04:42 -07002915 canvas.clipRect(mScrollX + mPaddingLeft, mScrollY + mPaddingTop,
2916 mScrollX + mRight - mLeft - mPaddingRight,
2917 mScrollY + mBottom - mTop - mPaddingBottom);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002918
2919 }
2920
2921 // We will draw our child's animation, let's reset the flag
Dianne Hackborn4702a852012-08-17 15:18:29 -07002922 mPrivateFlags &= ~PFLAG_DRAW_ANIMATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002923 mGroupFlags &= ~FLAG_INVALIDATE_REQUIRED;
2924
2925 boolean more = false;
2926 final long drawingTime = getDrawingTime();
2927
2928 if ((flags & FLAG_USE_CHILD_DRAWING_ORDER) == 0) {
2929 for (int i = 0; i < count; i++) {
2930 final View child = children[i];
2931 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
2932 more |= drawChild(canvas, child, drawingTime);
2933 }
2934 }
2935 } else {
2936 for (int i = 0; i < count; i++) {
2937 final View child = children[getChildDrawingOrder(count, i)];
2938 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
2939 more |= drawChild(canvas, child, drawingTime);
2940 }
2941 }
2942 }
2943
2944 // Draw any disappearing views that have animations
2945 if (mDisappearingChildren != null) {
2946 final ArrayList<View> disappearingChildren = mDisappearingChildren;
2947 final int disappearingCount = disappearingChildren.size() - 1;
2948 // Go backwards -- we may delete as animations finish
2949 for (int i = disappearingCount; i >= 0; i--) {
2950 final View child = disappearingChildren.get(i);
2951 more |= drawChild(canvas, child, drawingTime);
2952 }
2953 }
2954
Philip Milne10ca24a2012-04-23 15:38:27 -07002955 if (debugDraw()) {
2956 onDebugDraw(canvas);
2957 }
2958
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002959 if (clipToPadding) {
2960 canvas.restoreToCount(saveCount);
2961 }
2962
2963 // mGroupFlags might have been updated by drawChild()
2964 flags = mGroupFlags;
2965
2966 if ((flags & FLAG_INVALIDATE_REQUIRED) == FLAG_INVALIDATE_REQUIRED) {
Romain Guy849d0a32011-02-01 17:20:48 -08002967 invalidate(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002968 }
2969
2970 if ((flags & FLAG_ANIMATION_DONE) == 0 && (flags & FLAG_NOTIFY_ANIMATION_LISTENER) == 0 &&
2971 mLayoutAnimationController.isDone() && !more) {
2972 // We want to erase the drawing cache and notify the listener after the
2973 // next frame is drawn because one extra invalidate() is caused by
2974 // drawChild() after the animation is over
2975 mGroupFlags |= FLAG_NOTIFY_ANIMATION_LISTENER;
2976 final Runnable end = new Runnable() {
2977 public void run() {
2978 notifyAnimationListener();
2979 }
2980 };
2981 post(end);
2982 }
2983 }
Romain Guy8506ab42009-06-11 17:35:47 -07002984
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002985 /**
2986 * Returns the index of the child to draw for this iteration. Override this
2987 * if you want to change the drawing order of children. By default, it
2988 * returns i.
2989 * <p>
Romain Guy293451e2009-11-04 13:59:48 -08002990 * NOTE: In order for this method to be called, you must enable child ordering
2991 * first by calling {@link #setChildrenDrawingOrderEnabled(boolean)}.
Romain Guy8506ab42009-06-11 17:35:47 -07002992 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002993 * @param i The current iteration.
2994 * @return The index of the child to draw this iteration.
Chet Haase5c13d892010-10-08 08:37:55 -07002995 *
Romain Guy293451e2009-11-04 13:59:48 -08002996 * @see #setChildrenDrawingOrderEnabled(boolean)
2997 * @see #isChildrenDrawingOrderEnabled()
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002998 */
2999 protected int getChildDrawingOrder(int childCount, int i) {
3000 return i;
3001 }
Romain Guy8506ab42009-06-11 17:35:47 -07003002
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003003 private void notifyAnimationListener() {
3004 mGroupFlags &= ~FLAG_NOTIFY_ANIMATION_LISTENER;
3005 mGroupFlags |= FLAG_ANIMATION_DONE;
3006
3007 if (mAnimationListener != null) {
3008 final Runnable end = new Runnable() {
3009 public void run() {
3010 mAnimationListener.onAnimationEnd(mLayoutAnimationController.getAnimation());
3011 }
3012 };
3013 post(end);
3014 }
3015
3016 if ((mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE) {
3017 mGroupFlags &= ~FLAG_CHILDREN_DRAWN_WITH_CACHE;
3018 if ((mPersistentDrawingCache & PERSISTENT_ANIMATION_CACHE) == 0) {
3019 setChildrenDrawingCacheEnabled(false);
3020 }
3021 }
3022
Romain Guy849d0a32011-02-01 17:20:48 -08003023 invalidate(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003024 }
3025
3026 /**
Chet Haasedaf98e92011-01-10 14:10:36 -08003027 * This method is used to cause children of this ViewGroup to restore or recreate their
3028 * display lists. It is called by getDisplayList() when the parent ViewGroup does not need
3029 * to recreate its own display list, which would happen if it went through the normal
3030 * draw/dispatchDraw mechanisms.
3031 *
3032 * @hide
3033 */
3034 @Override
3035 protected void dispatchGetDisplayList() {
3036 final int count = mChildrenCount;
3037 final View[] children = mChildren;
3038 for (int i = 0; i < count; i++) {
3039 final View child = children[i];
Romain Guy59c7f802011-09-29 17:21:45 -07003040 if (((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) &&
3041 child.hasStaticLayer()) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07003042 child.mRecreateDisplayList = (child.mPrivateFlags & PFLAG_INVALIDATED)
3043 == PFLAG_INVALIDATED;
3044 child.mPrivateFlags &= ~PFLAG_INVALIDATED;
Romain Guy2f57ba52011-02-03 18:03:29 -08003045 child.getDisplayList();
3046 child.mRecreateDisplayList = false;
3047 }
Chet Haasedaf98e92011-01-10 14:10:36 -08003048 }
Chet Haase91cedf12013-03-11 07:56:30 -07003049 if (mOverlay != null) {
3050 mOverlay.mRecreateDisplayList = (mOverlay.mPrivateFlags & PFLAG_INVALIDATED)
3051 == PFLAG_INVALIDATED;
3052 mOverlay.mPrivateFlags &= ~PFLAG_INVALIDATED;
3053 mOverlay.getDisplayList();
3054 mOverlay.mRecreateDisplayList = false;
3055 }
Chet Haasedaf98e92011-01-10 14:10:36 -08003056 }
3057
3058 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003059 * Draw one child of this View Group. This method is responsible for getting
3060 * the canvas in the right state. This includes clipping, translating so
3061 * that the child's scrolled origin is at 0, 0, and applying any animation
3062 * transformations.
3063 *
3064 * @param canvas The canvas on which to draw the child
3065 * @param child Who to draw
Chet Haasebcca79a2012-02-14 08:45:14 -08003066 * @param drawingTime The time at which draw is occurring
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003067 * @return True if an invalidate() was issued
3068 */
3069 protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
Chet Haase64a48c12012-02-13 16:33:29 -08003070 return child.draw(canvas, this, drawingTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003071 }
3072
3073 /**
3074 * By default, children are clipped to their bounds before drawing. This
3075 * allows view groups to override this behavior for animations, etc.
3076 *
3077 * @param clipChildren true to clip children to their bounds,
3078 * false otherwise
3079 * @attr ref android.R.styleable#ViewGroup_clipChildren
3080 */
3081 public void setClipChildren(boolean clipChildren) {
Chet Haasea1cff502012-02-21 13:43:44 -08003082 boolean previousValue = (mGroupFlags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN;
3083 if (clipChildren != previousValue) {
3084 setBooleanFlag(FLAG_CLIP_CHILDREN, clipChildren);
Chet Haase1271e2c2012-04-20 09:54:27 -07003085 for (int i = 0; i < mChildrenCount; ++i) {
3086 View child = getChildAt(i);
3087 if (child.mDisplayList != null) {
3088 child.mDisplayList.setClipChildren(clipChildren);
Chet Haasea1cff502012-02-21 13:43:44 -08003089 }
3090 }
3091 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003092 }
3093
3094 /**
3095 * By default, children are clipped to the padding of the ViewGroup. This
3096 * allows view groups to override this behavior
3097 *
3098 * @param clipToPadding true to clip children to the padding of the
3099 * group, false otherwise
3100 * @attr ref android.R.styleable#ViewGroup_clipToPadding
3101 */
3102 public void setClipToPadding(boolean clipToPadding) {
3103 setBooleanFlag(FLAG_CLIP_TO_PADDING, clipToPadding);
3104 }
3105
3106 /**
3107 * {@inheritDoc}
3108 */
3109 @Override
3110 public void dispatchSetSelected(boolean selected) {
3111 final View[] children = mChildren;
3112 final int count = mChildrenCount;
3113 for (int i = 0; i < count; i++) {
3114 children[i].setSelected(selected);
3115 }
3116 }
Romain Guy8506ab42009-06-11 17:35:47 -07003117
Dianne Hackbornd0fa3712010-09-14 18:57:14 -07003118 /**
3119 * {@inheritDoc}
3120 */
3121 @Override
3122 public void dispatchSetActivated(boolean activated) {
3123 final View[] children = mChildren;
3124 final int count = mChildrenCount;
3125 for (int i = 0; i < count; i++) {
Dianne Hackbornd0fa3712010-09-14 18:57:14 -07003126 children[i].setActivated(activated);
3127 }
3128 }
3129
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003130 @Override
3131 protected void dispatchSetPressed(boolean pressed) {
3132 final View[] children = mChildren;
3133 final int count = mChildrenCount;
3134 for (int i = 0; i < count; i++) {
Adam Powell035a1fc2012-02-27 15:23:50 -08003135 final View child = children[i];
3136 // Children that are clickable on their own should not
3137 // show a pressed state when their parent view does.
3138 // Clearing a pressed state always propagates.
3139 if (!pressed || (!child.isClickable() && !child.isLongClickable())) {
3140 child.setPressed(pressed);
3141 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003142 }
3143 }
3144
3145 /**
3146 * When this property is set to true, this ViewGroup supports static transformations on
3147 * children; this causes
3148 * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} to be
3149 * invoked when a child is drawn.
3150 *
3151 * Any subclass overriding
3152 * {@link #getChildStaticTransformation(View, android.view.animation.Transformation)} should
3153 * set this property to true.
3154 *
3155 * @param enabled True to enable static transformations on children, false otherwise.
3156 *
Chet Haase599913d2012-07-23 16:22:05 -07003157 * @see #getChildStaticTransformation(View, android.view.animation.Transformation)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003158 */
3159 protected void setStaticTransformationsEnabled(boolean enabled) {
3160 setBooleanFlag(FLAG_SUPPORT_STATIC_TRANSFORMATIONS, enabled);
3161 }
3162
3163 /**
Chet Haase2d46fcc2011-12-19 18:01:05 -08003164 * Sets <code>t</code> to be the static transformation of the child, if set, returning a
3165 * boolean to indicate whether a static transform was set. The default implementation
3166 * simply returns <code>false</code>; subclasses may override this method for different
Chet Haase599913d2012-07-23 16:22:05 -07003167 * behavior. {@link #setStaticTransformationsEnabled(boolean)} must be set to true
3168 * for this method to be called.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003169 *
Chet Haase2d46fcc2011-12-19 18:01:05 -08003170 * @param child The child view whose static transform is being requested
3171 * @param t The Transformation which will hold the result
3172 * @return true if the transformation was set, false otherwise
Romain Guy8506ab42009-06-11 17:35:47 -07003173 * @see #setStaticTransformationsEnabled(boolean)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003174 */
3175 protected boolean getChildStaticTransformation(View child, Transformation t) {
3176 return false;
3177 }
3178
3179 /**
3180 * {@hide}
3181 */
3182 @Override
3183 protected View findViewTraversal(int id) {
3184 if (id == mID) {
3185 return this;
3186 }
3187
3188 final View[] where = mChildren;
3189 final int len = mChildrenCount;
3190
3191 for (int i = 0; i < len; i++) {
3192 View v = where[i];
3193
Dianne Hackborn4702a852012-08-17 15:18:29 -07003194 if ((v.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003195 v = v.findViewById(id);
3196
3197 if (v != null) {
3198 return v;
3199 }
3200 }
3201 }
3202
3203 return null;
3204 }
3205
3206 /**
3207 * {@hide}
3208 */
3209 @Override
3210 protected View findViewWithTagTraversal(Object tag) {
3211 if (tag != null && tag.equals(mTag)) {
3212 return this;
3213 }
3214
3215 final View[] where = mChildren;
3216 final int len = mChildrenCount;
3217
3218 for (int i = 0; i < len; i++) {
3219 View v = where[i];
3220
Dianne Hackborn4702a852012-08-17 15:18:29 -07003221 if ((v.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003222 v = v.findViewWithTag(tag);
3223
3224 if (v != null) {
3225 return v;
3226 }
3227 }
3228 }
3229
3230 return null;
3231 }
3232
3233 /**
Jeff Brown4e6319b2010-12-13 10:36:51 -08003234 * {@hide}
3235 */
3236 @Override
Jeff Brown4dfbec22011-08-15 14:55:37 -07003237 protected View findViewByPredicateTraversal(Predicate<View> predicate, View childToSkip) {
Jeff Brown4e6319b2010-12-13 10:36:51 -08003238 if (predicate.apply(this)) {
3239 return this;
3240 }
3241
3242 final View[] where = mChildren;
3243 final int len = mChildrenCount;
3244
3245 for (int i = 0; i < len; i++) {
3246 View v = where[i];
3247
Dianne Hackborn4702a852012-08-17 15:18:29 -07003248 if (v != childToSkip && (v.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) {
Jeff Brown4e6319b2010-12-13 10:36:51 -08003249 v = v.findViewByPredicate(predicate);
3250
3251 if (v != null) {
3252 return v;
3253 }
3254 }
3255 }
3256
3257 return null;
3258 }
3259
3260 /**
Romain Guy393a52c2012-05-22 20:21:08 -07003261 * <p>Adds a child view. If no layout parameters are already set on the child, the
3262 * default parameters for this ViewGroup are set on the child.</p>
3263 *
3264 * <p><strong>Note:</strong> do not invoke this method from
3265 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3266 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003267 *
3268 * @param child the child view to add
3269 *
3270 * @see #generateDefaultLayoutParams()
3271 */
3272 public void addView(View child) {
3273 addView(child, -1);
3274 }
3275
3276 /**
3277 * Adds a child view. If no layout parameters are already set on the child, the
3278 * default parameters for this ViewGroup are set on the child.
Romain Guy393a52c2012-05-22 20:21:08 -07003279 *
3280 * <p><strong>Note:</strong> do not invoke this method from
3281 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3282 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003283 *
3284 * @param child the child view to add
3285 * @param index the position at which to add the child
3286 *
3287 * @see #generateDefaultLayoutParams()
3288 */
3289 public void addView(View child, int index) {
3290 LayoutParams params = child.getLayoutParams();
3291 if (params == null) {
3292 params = generateDefaultLayoutParams();
3293 if (params == null) {
3294 throw new IllegalArgumentException("generateDefaultLayoutParams() cannot return null");
3295 }
3296 }
3297 addView(child, index, params);
3298 }
3299
3300 /**
3301 * Adds a child view with this ViewGroup's default layout parameters and the
3302 * specified width and height.
3303 *
Romain Guy393a52c2012-05-22 20:21:08 -07003304 * <p><strong>Note:</strong> do not invoke this method from
3305 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3306 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
3307 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003308 * @param child the child view to add
3309 */
3310 public void addView(View child, int width, int height) {
3311 final LayoutParams params = generateDefaultLayoutParams();
3312 params.width = width;
3313 params.height = height;
3314 addView(child, -1, params);
3315 }
3316
3317 /**
3318 * Adds a child view with the specified layout parameters.
3319 *
Romain Guy393a52c2012-05-22 20:21:08 -07003320 * <p><strong>Note:</strong> do not invoke this method from
3321 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3322 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
3323 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003324 * @param child the child view to add
3325 * @param params the layout parameters to set on the child
3326 */
3327 public void addView(View child, LayoutParams params) {
3328 addView(child, -1, params);
3329 }
3330
3331 /**
3332 * Adds a child view with the specified layout parameters.
3333 *
Romain Guy393a52c2012-05-22 20:21:08 -07003334 * <p><strong>Note:</strong> do not invoke this method from
3335 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3336 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
3337 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003338 * @param child the child view to add
3339 * @param index the position at which to add the child
3340 * @param params the layout parameters to set on the child
3341 */
3342 public void addView(View child, int index, LayoutParams params) {
3343 if (DBG) {
3344 System.out.println(this + " addView");
3345 }
3346
3347 // addViewInner() will call child.requestLayout() when setting the new LayoutParams
3348 // therefore, we call requestLayout() on ourselves before, so that the child's request
3349 // will be blocked at our level
3350 requestLayout();
Romain Guy849d0a32011-02-01 17:20:48 -08003351 invalidate(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003352 addViewInner(child, index, params, false);
3353 }
3354
3355 /**
3356 * {@inheritDoc}
3357 */
3358 public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
3359 if (!checkLayoutParams(params)) {
3360 throw new IllegalArgumentException("Invalid LayoutParams supplied to " + this);
3361 }
3362 if (view.mParent != this) {
3363 throw new IllegalArgumentException("Given view not a child of " + this);
3364 }
3365 view.setLayoutParams(params);
3366 }
3367
3368 /**
3369 * {@inheritDoc}
3370 */
3371 protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
3372 return p != null;
3373 }
3374
3375 /**
3376 * Interface definition for a callback to be invoked when the hierarchy
3377 * within this view changed. The hierarchy changes whenever a child is added
3378 * to or removed from this view.
3379 */
3380 public interface OnHierarchyChangeListener {
3381 /**
3382 * Called when a new child is added to a parent view.
3383 *
3384 * @param parent the view in which a child was added
3385 * @param child the new child view added in the hierarchy
3386 */
3387 void onChildViewAdded(View parent, View child);
3388
3389 /**
3390 * Called when a child is removed from a parent view.
3391 *
3392 * @param parent the view from which the child was removed
3393 * @param child the child removed from the hierarchy
3394 */
3395 void onChildViewRemoved(View parent, View child);
3396 }
3397
3398 /**
3399 * Register a callback to be invoked when a child is added to or removed
3400 * from this view.
3401 *
3402 * @param listener the callback to invoke on hierarchy change
3403 */
3404 public void setOnHierarchyChangeListener(OnHierarchyChangeListener listener) {
3405 mOnHierarchyChangeListener = listener;
3406 }
3407
3408 /**
Philip Milnef51d91c2011-07-18 16:12:19 -07003409 * @hide
3410 */
3411 protected void onViewAdded(View child) {
3412 if (mOnHierarchyChangeListener != null) {
3413 mOnHierarchyChangeListener.onChildViewAdded(this, child);
3414 }
3415 }
3416
3417 /**
3418 * @hide
3419 */
3420 protected void onViewRemoved(View child) {
3421 if (mOnHierarchyChangeListener != null) {
3422 mOnHierarchyChangeListener.onChildViewRemoved(this, child);
3423 }
3424 }
3425
3426 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003427 * Adds a view during layout. This is useful if in your onLayout() method,
3428 * you need to add more views (as does the list view for example).
3429 *
3430 * If index is negative, it means put it at the end of the list.
3431 *
3432 * @param child the view to add to the group
3433 * @param index the index at which the child must be added
3434 * @param params the layout parameters to associate with the child
3435 * @return true if the child was added, false otherwise
3436 */
3437 protected boolean addViewInLayout(View child, int index, LayoutParams params) {
3438 return addViewInLayout(child, index, params, false);
3439 }
3440
3441 /**
3442 * Adds a view during layout. This is useful if in your onLayout() method,
3443 * you need to add more views (as does the list view for example).
3444 *
3445 * If index is negative, it means put it at the end of the list.
3446 *
3447 * @param child the view to add to the group
3448 * @param index the index at which the child must be added
3449 * @param params the layout parameters to associate with the child
3450 * @param preventRequestLayout if true, calling this method will not trigger a
3451 * layout request on child
3452 * @return true if the child was added, false otherwise
3453 */
3454 protected boolean addViewInLayout(View child, int index, LayoutParams params,
3455 boolean preventRequestLayout) {
3456 child.mParent = null;
3457 addViewInner(child, index, params, preventRequestLayout);
Dianne Hackborn4702a852012-08-17 15:18:29 -07003458 child.mPrivateFlags = (child.mPrivateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003459 return true;
3460 }
3461
3462 /**
3463 * Prevents the specified child to be laid out during the next layout pass.
3464 *
3465 * @param child the child on which to perform the cleanup
3466 */
3467 protected void cleanupLayoutState(View child) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07003468 child.mPrivateFlags &= ~View.PFLAG_FORCE_LAYOUT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003469 }
3470
3471 private void addViewInner(View child, int index, LayoutParams params,
3472 boolean preventRequestLayout) {
3473
Chet Haasee8e45d32011-03-02 17:07:35 -08003474 if (mTransition != null) {
3475 // Don't prevent other add transitions from completing, but cancel remove
3476 // transitions to let them complete the process before we add to the container
3477 mTransition.cancel(LayoutTransition.DISAPPEARING);
Chet Haaseadd65772011-02-09 16:47:29 -08003478 }
3479
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003480 if (child.getParent() != null) {
3481 throw new IllegalStateException("The specified child already has a parent. " +
3482 "You must call removeView() on the child's parent first.");
3483 }
3484
Chet Haase21cd1382010-09-01 17:42:29 -07003485 if (mTransition != null) {
Chet Haase5e25c2c2010-09-16 11:15:56 -07003486 mTransition.addChild(this, child);
Chet Haase21cd1382010-09-01 17:42:29 -07003487 }
3488
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003489 if (!checkLayoutParams(params)) {
3490 params = generateLayoutParams(params);
3491 }
3492
3493 if (preventRequestLayout) {
3494 child.mLayoutParams = params;
3495 } else {
3496 child.setLayoutParams(params);
3497 }
3498
3499 if (index < 0) {
3500 index = mChildrenCount;
3501 }
3502
3503 addInArray(child, index);
3504
3505 // tell our children
3506 if (preventRequestLayout) {
3507 child.assignParent(this);
3508 } else {
3509 child.mParent = this;
3510 }
3511
3512 if (child.hasFocus()) {
3513 requestChildFocus(child, child.findFocus());
3514 }
Romain Guy8506ab42009-06-11 17:35:47 -07003515
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003516 AttachInfo ai = mAttachInfo;
Adam Powell4b867882011-09-16 12:59:46 -07003517 if (ai != null && (mGroupFlags & FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW) == 0) {
Romain Guy8506ab42009-06-11 17:35:47 -07003518 boolean lastKeepOn = ai.mKeepScreenOn;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003519 ai.mKeepScreenOn = false;
3520 child.dispatchAttachedToWindow(mAttachInfo, (mViewFlags&VISIBILITY_MASK));
3521 if (ai.mKeepScreenOn) {
3522 needGlobalAttributesUpdate(true);
3523 }
3524 ai.mKeepScreenOn = lastKeepOn;
3525 }
3526
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07003527 if (child.isLayoutDirectionInherited()) {
Fabrice Di Meglioa7e0bcd2012-10-16 19:55:01 -07003528 child.resetRtlProperties();
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07003529 }
3530
Philip Milnef51d91c2011-07-18 16:12:19 -07003531 onViewAdded(child);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003532
3533 if ((child.mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE) {
3534 mGroupFlags |= FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE;
3535 }
Adam Powell539ee872012-02-03 19:00:49 -08003536
3537 if (child.hasTransientState()) {
3538 childHasTransientStateChanged(child, true);
3539 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003540 }
3541
3542 private void addInArray(View child, int index) {
3543 View[] children = mChildren;
3544 final int count = mChildrenCount;
3545 final int size = children.length;
3546 if (index == count) {
3547 if (size == count) {
3548 mChildren = new View[size + ARRAY_CAPACITY_INCREMENT];
3549 System.arraycopy(children, 0, mChildren, 0, size);
3550 children = mChildren;
3551 }
3552 children[mChildrenCount++] = child;
3553 } else if (index < count) {
3554 if (size == count) {
3555 mChildren = new View[size + ARRAY_CAPACITY_INCREMENT];
3556 System.arraycopy(children, 0, mChildren, 0, index);
3557 System.arraycopy(children, index, mChildren, index + 1, count - index);
3558 children = mChildren;
3559 } else {
3560 System.arraycopy(children, index, children, index + 1, count - index);
3561 }
3562 children[index] = child;
3563 mChildrenCount++;
Joe Onorato03ab0c72011-01-06 15:46:27 -08003564 if (mLastTouchDownIndex >= index) {
3565 mLastTouchDownIndex++;
3566 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003567 } else {
3568 throw new IndexOutOfBoundsException("index=" + index + " count=" + count);
3569 }
3570 }
3571
3572 // This method also sets the child's mParent to null
3573 private void removeFromArray(int index) {
3574 final View[] children = mChildren;
Chet Haase21cd1382010-09-01 17:42:29 -07003575 if (!(mTransitioningViews != null && mTransitioningViews.contains(children[index]))) {
3576 children[index].mParent = null;
3577 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003578 final int count = mChildrenCount;
3579 if (index == count - 1) {
3580 children[--mChildrenCount] = null;
3581 } else if (index >= 0 && index < count) {
3582 System.arraycopy(children, index + 1, children, index, count - index - 1);
3583 children[--mChildrenCount] = null;
3584 } else {
3585 throw new IndexOutOfBoundsException();
3586 }
Joe Onorato03ab0c72011-01-06 15:46:27 -08003587 if (mLastTouchDownIndex == index) {
3588 mLastTouchDownTime = 0;
3589 mLastTouchDownIndex = -1;
3590 } else if (mLastTouchDownIndex > index) {
3591 mLastTouchDownIndex--;
3592 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003593 }
3594
3595 // This method also sets the children's mParent to null
3596 private void removeFromArray(int start, int count) {
3597 final View[] children = mChildren;
3598 final int childrenCount = mChildrenCount;
3599
3600 start = Math.max(0, start);
3601 final int end = Math.min(childrenCount, start + count);
3602
3603 if (start == end) {
3604 return;
3605 }
3606
3607 if (end == childrenCount) {
3608 for (int i = start; i < end; i++) {
3609 children[i].mParent = null;
3610 children[i] = null;
3611 }
3612 } else {
3613 for (int i = start; i < end; i++) {
3614 children[i].mParent = null;
3615 }
3616
3617 // Since we're looping above, we might as well do the copy, but is arraycopy()
3618 // faster than the extra 2 bounds checks we would do in the loop?
3619 System.arraycopy(children, end, children, start, childrenCount - end);
3620
3621 for (int i = childrenCount - (end - start); i < childrenCount; i++) {
3622 children[i] = null;
3623 }
3624 }
3625
3626 mChildrenCount -= (end - start);
3627 }
3628
3629 private void bindLayoutAnimation(View child) {
3630 Animation a = mLayoutAnimationController.getAnimationForView(child);
3631 child.setAnimation(a);
3632 }
3633
3634 /**
3635 * Subclasses should override this method to set layout animation
3636 * parameters on the supplied child.
3637 *
3638 * @param child the child to associate with animation parameters
3639 * @param params the child's layout parameters which hold the animation
3640 * parameters
3641 * @param index the index of the child in the view group
3642 * @param count the number of children in the view group
3643 */
3644 protected void attachLayoutAnimationParameters(View child,
3645 LayoutParams params, int index, int count) {
3646 LayoutAnimationController.AnimationParameters animationParams =
3647 params.layoutAnimationParameters;
3648 if (animationParams == null) {
3649 animationParams = new LayoutAnimationController.AnimationParameters();
3650 params.layoutAnimationParameters = animationParams;
3651 }
3652
3653 animationParams.count = count;
3654 animationParams.index = index;
3655 }
3656
3657 /**
3658 * {@inheritDoc}
Romain Guy393a52c2012-05-22 20:21:08 -07003659 *
3660 * <p><strong>Note:</strong> do not invoke this method from
3661 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3662 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003663 */
3664 public void removeView(View view) {
3665 removeViewInternal(view);
3666 requestLayout();
Romain Guy849d0a32011-02-01 17:20:48 -08003667 invalidate(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003668 }
3669
3670 /**
3671 * Removes a view during layout. This is useful if in your onLayout() method,
3672 * you need to remove more views.
3673 *
Romain Guy393a52c2012-05-22 20:21:08 -07003674 * <p><strong>Note:</strong> do not invoke this method from
3675 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3676 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
3677 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003678 * @param view the view to remove from the group
3679 */
3680 public void removeViewInLayout(View view) {
3681 removeViewInternal(view);
3682 }
3683
3684 /**
3685 * Removes a range of views during layout. This is useful if in your onLayout() method,
3686 * you need to remove more views.
3687 *
Romain Guy393a52c2012-05-22 20:21:08 -07003688 * <p><strong>Note:</strong> do not invoke this method from
3689 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3690 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
3691 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003692 * @param start the index of the first view to remove from the group
3693 * @param count the number of views to remove from the group
3694 */
3695 public void removeViewsInLayout(int start, int count) {
3696 removeViewsInternal(start, count);
3697 }
3698
3699 /**
3700 * Removes the view at the specified position in the group.
3701 *
Romain Guy393a52c2012-05-22 20:21:08 -07003702 * <p><strong>Note:</strong> do not invoke this method from
3703 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3704 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
3705 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003706 * @param index the position in the group of the view to remove
3707 */
3708 public void removeViewAt(int index) {
3709 removeViewInternal(index, getChildAt(index));
3710 requestLayout();
Romain Guy849d0a32011-02-01 17:20:48 -08003711 invalidate(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003712 }
3713
3714 /**
3715 * Removes the specified range of views from the group.
3716 *
Romain Guy393a52c2012-05-22 20:21:08 -07003717 * <p><strong>Note:</strong> do not invoke this method from
3718 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3719 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
3720 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003721 * @param start the first position in the group of the range of views to remove
3722 * @param count the number of views to remove
3723 */
3724 public void removeViews(int start, int count) {
3725 removeViewsInternal(start, count);
3726 requestLayout();
Romain Guy849d0a32011-02-01 17:20:48 -08003727 invalidate(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003728 }
3729
3730 private void removeViewInternal(View view) {
3731 final int index = indexOfChild(view);
3732 if (index >= 0) {
3733 removeViewInternal(index, view);
3734 }
3735 }
3736
3737 private void removeViewInternal(int index, View view) {
Chet Haase21cd1382010-09-01 17:42:29 -07003738
3739 if (mTransition != null) {
Chet Haase5e25c2c2010-09-16 11:15:56 -07003740 mTransition.removeChild(this, view);
Chet Haase21cd1382010-09-01 17:42:29 -07003741 }
3742
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003743 boolean clearChildFocus = false;
3744 if (view == mFocused) {
Svetoslav Ganov57cadf22012-04-04 16:44:39 -07003745 view.unFocus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003746 clearChildFocus = true;
3747 }
3748
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003749 if (view.isAccessibilityFocused()) {
3750 view.clearAccessibilityFocus();
3751 }
Svetoslav Ganov961bf0e2012-05-08 09:40:03 -07003752
Jeff Brown59a422e2012-04-19 15:19:19 -07003753 cancelTouchTarget(view);
3754 cancelHoverTarget(view);
3755
Chet Haase21cd1382010-09-01 17:42:29 -07003756 if (view.getAnimation() != null ||
3757 (mTransitioningViews != null && mTransitioningViews.contains(view))) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003758 addDisappearingView(view);
3759 } else if (view.mAttachInfo != null) {
3760 view.dispatchDetachedFromWindow();
3761 }
3762
Adam Powell539ee872012-02-03 19:00:49 -08003763 if (view.hasTransientState()) {
3764 childHasTransientStateChanged(view, false);
3765 }
3766
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003767 needGlobalAttributesUpdate(false);
Romain Guy8506ab42009-06-11 17:35:47 -07003768
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003769 removeFromArray(index);
3770
3771 if (clearChildFocus) {
3772 clearChildFocus(view);
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003773 if (!rootViewRequestFocus()) {
3774 notifyGlobalFocusCleared(this);
3775 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07003776 }
Romain Guy6fb05632012-11-29 10:50:33 -08003777
3778 onViewRemoved(view);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003779 }
3780
Chet Haase21cd1382010-09-01 17:42:29 -07003781 /**
3782 * Sets the LayoutTransition object for this ViewGroup. If the LayoutTransition object is
3783 * not null, changes in layout which occur because of children being added to or removed from
3784 * the ViewGroup will be animated according to the animations defined in that LayoutTransition
3785 * object. By default, the transition object is null (so layout changes are not animated).
3786 *
3787 * @param transition The LayoutTransition object that will animated changes in layout. A value
3788 * of <code>null</code> means no transition will run on layout changes.
Chet Haase13cc1202010-09-03 15:39:20 -07003789 * @attr ref android.R.styleable#ViewGroup_animateLayoutChanges
Chet Haase21cd1382010-09-01 17:42:29 -07003790 */
3791 public void setLayoutTransition(LayoutTransition transition) {
Chet Haaseb20db3e2010-09-10 13:07:30 -07003792 if (mTransition != null) {
3793 mTransition.removeTransitionListener(mLayoutTransitionListener);
3794 }
Chet Haase21cd1382010-09-01 17:42:29 -07003795 mTransition = transition;
Chet Haase13cc1202010-09-03 15:39:20 -07003796 if (mTransition != null) {
3797 mTransition.addTransitionListener(mLayoutTransitionListener);
3798 }
3799 }
3800
3801 /**
3802 * Gets the LayoutTransition object for this ViewGroup. If the LayoutTransition object is
3803 * not null, changes in layout which occur because of children being added to or removed from
3804 * the ViewGroup will be animated according to the animations defined in that LayoutTransition
3805 * object. By default, the transition object is null (so layout changes are not animated).
3806 *
3807 * @return LayoutTranstion The LayoutTransition object that will animated changes in layout.
3808 * A value of <code>null</code> means no transition will run on layout changes.
3809 */
3810 public LayoutTransition getLayoutTransition() {
3811 return mTransition;
Chet Haase21cd1382010-09-01 17:42:29 -07003812 }
3813
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003814 private void removeViewsInternal(int start, int count) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003815 final View focused = mFocused;
3816 final boolean detach = mAttachInfo != null;
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003817 boolean clearChildFocus = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003818
3819 final View[] children = mChildren;
3820 final int end = start + count;
3821
3822 for (int i = start; i < end; i++) {
3823 final View view = children[i];
3824
Chet Haase21cd1382010-09-01 17:42:29 -07003825 if (mTransition != null) {
Chet Haase5e25c2c2010-09-16 11:15:56 -07003826 mTransition.removeChild(this, view);
Chet Haase21cd1382010-09-01 17:42:29 -07003827 }
3828
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003829 if (view == focused) {
Svetoslav Ganov57cadf22012-04-04 16:44:39 -07003830 view.unFocus();
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003831 clearChildFocus = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003832 }
3833
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003834 if (view.isAccessibilityFocused()) {
3835 view.clearAccessibilityFocus();
3836 }
Svetoslav Ganov961bf0e2012-05-08 09:40:03 -07003837
Jeff Brown59a422e2012-04-19 15:19:19 -07003838 cancelTouchTarget(view);
3839 cancelHoverTarget(view);
3840
Chet Haase21cd1382010-09-01 17:42:29 -07003841 if (view.getAnimation() != null ||
3842 (mTransitioningViews != null && mTransitioningViews.contains(view))) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003843 addDisappearingView(view);
3844 } else if (detach) {
3845 view.dispatchDetachedFromWindow();
3846 }
3847
Adam Powell539ee872012-02-03 19:00:49 -08003848 if (view.hasTransientState()) {
3849 childHasTransientStateChanged(view, false);
3850 }
3851
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003852 needGlobalAttributesUpdate(false);
Romain Guy8506ab42009-06-11 17:35:47 -07003853
Philip Milnef51d91c2011-07-18 16:12:19 -07003854 onViewRemoved(view);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003855 }
3856
3857 removeFromArray(start, count);
3858
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003859 if (clearChildFocus) {
3860 clearChildFocus(focused);
3861 if (!rootViewRequestFocus()) {
3862 notifyGlobalFocusCleared(focused);
3863 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003864 }
3865 }
3866
3867 /**
3868 * Call this method to remove all child views from the
3869 * ViewGroup.
Romain Guy393a52c2012-05-22 20:21:08 -07003870 *
3871 * <p><strong>Note:</strong> do not invoke this method from
3872 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3873 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003874 */
3875 public void removeAllViews() {
3876 removeAllViewsInLayout();
3877 requestLayout();
Romain Guy849d0a32011-02-01 17:20:48 -08003878 invalidate(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003879 }
3880
3881 /**
3882 * Called by a ViewGroup subclass to remove child views from itself,
3883 * when it must first know its size on screen before it can calculate how many
3884 * child views it will render. An example is a Gallery or a ListView, which
3885 * may "have" 50 children, but actually only render the number of children
3886 * that can currently fit inside the object on screen. Do not call
3887 * this method unless you are extending ViewGroup and understand the
3888 * view measuring and layout pipeline.
Romain Guy393a52c2012-05-22 20:21:08 -07003889 *
3890 * <p><strong>Note:</strong> do not invoke this method from
3891 * {@link #draw(android.graphics.Canvas)}, {@link #onDraw(android.graphics.Canvas)},
3892 * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003893 */
3894 public void removeAllViewsInLayout() {
3895 final int count = mChildrenCount;
3896 if (count <= 0) {
3897 return;
3898 }
3899
3900 final View[] children = mChildren;
3901 mChildrenCount = 0;
3902
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003903 final View focused = mFocused;
3904 final boolean detach = mAttachInfo != null;
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003905 boolean clearChildFocus = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003906
3907 needGlobalAttributesUpdate(false);
Romain Guy8506ab42009-06-11 17:35:47 -07003908
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003909 for (int i = count - 1; i >= 0; i--) {
3910 final View view = children[i];
3911
Chet Haase21cd1382010-09-01 17:42:29 -07003912 if (mTransition != null) {
Chet Haase5e25c2c2010-09-16 11:15:56 -07003913 mTransition.removeChild(this, view);
Chet Haase21cd1382010-09-01 17:42:29 -07003914 }
3915
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003916 if (view == focused) {
Svetoslav Ganov57cadf22012-04-04 16:44:39 -07003917 view.unFocus();
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003918 clearChildFocus = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003919 }
3920
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003921 if (view.isAccessibilityFocused()) {
3922 view.clearAccessibilityFocus();
3923 }
Svetoslav Ganov961bf0e2012-05-08 09:40:03 -07003924
Jeff Brown59a422e2012-04-19 15:19:19 -07003925 cancelTouchTarget(view);
3926 cancelHoverTarget(view);
3927
Chet Haase21cd1382010-09-01 17:42:29 -07003928 if (view.getAnimation() != null ||
3929 (mTransitioningViews != null && mTransitioningViews.contains(view))) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003930 addDisappearingView(view);
3931 } else if (detach) {
3932 view.dispatchDetachedFromWindow();
3933 }
3934
Adam Powell539ee872012-02-03 19:00:49 -08003935 if (view.hasTransientState()) {
3936 childHasTransientStateChanged(view, false);
3937 }
3938
Philip Milnef51d91c2011-07-18 16:12:19 -07003939 onViewRemoved(view);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003940
3941 view.mParent = null;
3942 children[i] = null;
3943 }
3944
Svetoslav Ganov149567f2013-01-08 15:23:34 -08003945 if (clearChildFocus) {
3946 clearChildFocus(focused);
3947 if (!rootViewRequestFocus()) {
3948 notifyGlobalFocusCleared(focused);
3949 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003950 }
3951 }
3952
3953 /**
3954 * Finishes the removal of a detached view. This method will dispatch the detached from
3955 * window event and notify the hierarchy change listener.
Chet Haaseca479d42012-08-30 17:20:08 -07003956 * <p>
3957 * This method is intended to be lightweight and makes no assumptions about whether the
3958 * parent or child should be redrawn. Proper use of this method will include also making
3959 * any appropriate {@link #requestLayout()} or {@link #invalidate()} calls.
3960 * For example, callers can {@link #post(Runnable) post} a {@link Runnable}
3961 * which performs a {@link #requestLayout()} on the next frame, after all detach/remove
3962 * calls are finished, causing layout to be run prior to redrawing the view hierarchy.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003963 *
3964 * @param child the child to be definitely removed from the view hierarchy
3965 * @param animate if true and the view has an animation, the view is placed in the
3966 * disappearing views list, otherwise, it is detached from the window
3967 *
3968 * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
3969 * @see #detachAllViewsFromParent()
3970 * @see #detachViewFromParent(View)
3971 * @see #detachViewFromParent(int)
3972 */
3973 protected void removeDetachedView(View child, boolean animate) {
Chet Haase21cd1382010-09-01 17:42:29 -07003974 if (mTransition != null) {
Chet Haase5e25c2c2010-09-16 11:15:56 -07003975 mTransition.removeChild(this, child);
Chet Haase21cd1382010-09-01 17:42:29 -07003976 }
3977
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003978 if (child == mFocused) {
3979 child.clearFocus();
3980 }
Romain Guy8506ab42009-06-11 17:35:47 -07003981
Svetoslav Ganov961bf0e2012-05-08 09:40:03 -07003982 child.clearAccessibilityFocus();
3983
Jeff Brown59a422e2012-04-19 15:19:19 -07003984 cancelTouchTarget(child);
3985 cancelHoverTarget(child);
3986
Chet Haase21cd1382010-09-01 17:42:29 -07003987 if ((animate && child.getAnimation() != null) ||
3988 (mTransitioningViews != null && mTransitioningViews.contains(child))) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003989 addDisappearingView(child);
3990 } else if (child.mAttachInfo != null) {
3991 child.dispatchDetachedFromWindow();
3992 }
3993
Adam Powell539ee872012-02-03 19:00:49 -08003994 if (child.hasTransientState()) {
3995 childHasTransientStateChanged(child, false);
3996 }
3997
Philip Milnef51d91c2011-07-18 16:12:19 -07003998 onViewRemoved(child);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003999 }
4000
4001 /**
4002 * Attaches a view to this view group. Attaching a view assigns this group as the parent,
Chet Haaseca479d42012-08-30 17:20:08 -07004003 * sets the layout parameters and puts the view in the list of children so that
4004 * it can be retrieved by calling {@link #getChildAt(int)}.
4005 * <p>
4006 * This method is intended to be lightweight and makes no assumptions about whether the
4007 * parent or child should be redrawn. Proper use of this method will include also making
4008 * any appropriate {@link #requestLayout()} or {@link #invalidate()} calls.
4009 * For example, callers can {@link #post(Runnable) post} a {@link Runnable}
4010 * which performs a {@link #requestLayout()} on the next frame, after all detach/attach
4011 * calls are finished, causing layout to be run prior to redrawing the view hierarchy.
4012 * <p>
4013 * This method should be called only for views which were detached from their parent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004014 *
4015 * @param child the child to attach
4016 * @param index the index at which the child should be attached
4017 * @param params the layout parameters of the child
4018 *
4019 * @see #removeDetachedView(View, boolean)
4020 * @see #detachAllViewsFromParent()
4021 * @see #detachViewFromParent(View)
4022 * @see #detachViewFromParent(int)
4023 */
4024 protected void attachViewToParent(View child, int index, LayoutParams params) {
4025 child.mLayoutParams = params;
4026
4027 if (index < 0) {
4028 index = mChildrenCount;
4029 }
4030
4031 addInArray(child, index);
4032
4033 child.mParent = this;
Dianne Hackborn4702a852012-08-17 15:18:29 -07004034 child.mPrivateFlags = (child.mPrivateFlags & ~PFLAG_DIRTY_MASK
4035 & ~PFLAG_DRAWING_CACHE_VALID)
4036 | PFLAG_DRAWN | PFLAG_INVALIDATED;
4037 this.mPrivateFlags |= PFLAG_INVALIDATED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004038
4039 if (child.hasFocus()) {
4040 requestChildFocus(child, child.findFocus());
4041 }
4042 }
4043
4044 /**
Chet Haaseca479d42012-08-30 17:20:08 -07004045 * Detaches a view from its parent. Detaching a view should be followed
4046 * either by a call to
4047 * {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
4048 * or a call to {@link #removeDetachedView(View, boolean)}. Detachment should only be
4049 * temporary; reattachment or removal should happen within the same drawing cycle as
4050 * detachment. When a view is detached, its parent is null and cannot be retrieved by a
4051 * call to {@link #getChildAt(int)}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004052 *
4053 * @param child the child to detach
4054 *
4055 * @see #detachViewFromParent(int)
4056 * @see #detachViewsFromParent(int, int)
4057 * @see #detachAllViewsFromParent()
4058 * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
4059 * @see #removeDetachedView(View, boolean)
4060 */
4061 protected void detachViewFromParent(View child) {
4062 removeFromArray(indexOfChild(child));
4063 }
4064
4065 /**
Chet Haaseca479d42012-08-30 17:20:08 -07004066 * Detaches a view from its parent. Detaching a view should be followed
4067 * either by a call to
4068 * {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
4069 * or a call to {@link #removeDetachedView(View, boolean)}. Detachment should only be
4070 * temporary; reattachment or removal should happen within the same drawing cycle as
4071 * detachment. When a view is detached, its parent is null and cannot be retrieved by a
4072 * call to {@link #getChildAt(int)}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004073 *
4074 * @param index the index of the child to detach
4075 *
4076 * @see #detachViewFromParent(View)
4077 * @see #detachAllViewsFromParent()
4078 * @see #detachViewsFromParent(int, int)
4079 * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
4080 * @see #removeDetachedView(View, boolean)
4081 */
4082 protected void detachViewFromParent(int index) {
4083 removeFromArray(index);
4084 }
4085
4086 /**
Chet Haaseca479d42012-08-30 17:20:08 -07004087 * Detaches a range of views from their parents. Detaching a view should be followed
4088 * either by a call to
4089 * {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
4090 * or a call to {@link #removeDetachedView(View, boolean)}. Detachment should only be
4091 * temporary; reattachment or removal should happen within the same drawing cycle as
4092 * detachment. When a view is detached, its parent is null and cannot be retrieved by a
4093 * call to {@link #getChildAt(int)}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004094 *
4095 * @param start the first index of the childrend range to detach
4096 * @param count the number of children to detach
4097 *
4098 * @see #detachViewFromParent(View)
4099 * @see #detachViewFromParent(int)
4100 * @see #detachAllViewsFromParent()
4101 * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
4102 * @see #removeDetachedView(View, boolean)
4103 */
4104 protected void detachViewsFromParent(int start, int count) {
4105 removeFromArray(start, count);
4106 }
4107
4108 /**
Chet Haaseca479d42012-08-30 17:20:08 -07004109 * Detaches all views from the parent. Detaching a view should be followed
4110 * either by a call to
4111 * {@link #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)}
4112 * or a call to {@link #removeDetachedView(View, boolean)}. Detachment should only be
4113 * temporary; reattachment or removal should happen within the same drawing cycle as
4114 * detachment. When a view is detached, its parent is null and cannot be retrieved by a
4115 * call to {@link #getChildAt(int)}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004116 *
4117 * @see #detachViewFromParent(View)
4118 * @see #detachViewFromParent(int)
4119 * @see #detachViewsFromParent(int, int)
4120 * @see #attachViewToParent(View, int, android.view.ViewGroup.LayoutParams)
4121 * @see #removeDetachedView(View, boolean)
4122 */
4123 protected void detachAllViewsFromParent() {
4124 final int count = mChildrenCount;
4125 if (count <= 0) {
4126 return;
4127 }
4128
4129 final View[] children = mChildren;
4130 mChildrenCount = 0;
4131
4132 for (int i = count - 1; i >= 0; i--) {
4133 children[i].mParent = null;
4134 children[i] = null;
4135 }
4136 }
4137
4138 /**
4139 * Don't call or override this method. It is used for the implementation of
4140 * the view hierarchy.
4141 */
4142 public final void invalidateChild(View child, final Rect dirty) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004143 ViewParent parent = this;
4144
4145 final AttachInfo attachInfo = mAttachInfo;
4146 if (attachInfo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004147 // If the child is drawing an animation, we want to copy this flag onto
4148 // ourselves and the parent to make sure the invalidate request goes
4149 // through
Dianne Hackborn4702a852012-08-17 15:18:29 -07004150 final boolean drawAnimation = (child.mPrivateFlags & PFLAG_DRAW_ANIMATION)
4151 == PFLAG_DRAW_ANIMATION;
Romain Guy24443ea2009-05-11 11:56:30 -07004152
Romain Guyfe455af2012-02-15 16:40:20 -08004153 // Check whether the child that requests the invalidate is fully opaque
4154 // Views being animated or transformed are not considered opaque because we may
4155 // be invalidating their old position and need the parent to paint behind them.
4156 Matrix childMatrix = child.getMatrix();
4157 final boolean isOpaque = child.isOpaque() && !drawAnimation &&
4158 child.getAnimation() == null && childMatrix.isIdentity();
4159 // Mark the child as dirty, using the appropriate flag
4160 // Make sure we do not set both flags at the same time
Dianne Hackborn4702a852012-08-17 15:18:29 -07004161 int opaqueFlag = isOpaque ? PFLAG_DIRTY_OPAQUE : PFLAG_DIRTY;
Romain Guyfe455af2012-02-15 16:40:20 -08004162
4163 if (child.mLayerType != LAYER_TYPE_NONE) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07004164 mPrivateFlags |= PFLAG_INVALIDATED;
4165 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
Romain Guyfe455af2012-02-15 16:40:20 -08004166 child.mLocalDirtyRect.union(dirty);
4167 }
4168
4169 final int[] location = attachInfo.mInvalidateChildLocation;
4170 location[CHILD_LEFT_INDEX] = child.mLeft;
4171 location[CHILD_TOP_INDEX] = child.mTop;
Chet Haase599913d2012-07-23 16:22:05 -07004172 if (!childMatrix.isIdentity() ||
4173 (mGroupFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) {
Romain Guyfe455af2012-02-15 16:40:20 -08004174 RectF boundingRect = attachInfo.mTmpTransformRect;
4175 boundingRect.set(dirty);
Chet Haase599913d2012-07-23 16:22:05 -07004176 Matrix transformMatrix;
4177 if ((mGroupFlags & ViewGroup.FLAG_SUPPORT_STATIC_TRANSFORMATIONS) != 0) {
4178 Transformation t = attachInfo.mTmpTransformation;
4179 boolean transformed = getChildStaticTransformation(child, t);
4180 if (transformed) {
4181 transformMatrix = attachInfo.mTmpMatrix;
4182 transformMatrix.set(t.getMatrix());
4183 if (!childMatrix.isIdentity()) {
4184 transformMatrix.preConcat(childMatrix);
4185 }
4186 } else {
4187 transformMatrix = childMatrix;
4188 }
4189 } else {
4190 transformMatrix = childMatrix;
4191 }
4192 transformMatrix.mapRect(boundingRect);
Romain Guyfe455af2012-02-15 16:40:20 -08004193 dirty.set((int) (boundingRect.left - 0.5f),
4194 (int) (boundingRect.top - 0.5f),
4195 (int) (boundingRect.right + 0.5f),
4196 (int) (boundingRect.bottom + 0.5f));
4197 }
4198
4199 do {
4200 View view = null;
4201 if (parent instanceof View) {
4202 view = (View) parent;
Romain Guyfe455af2012-02-15 16:40:20 -08004203 }
4204
4205 if (drawAnimation) {
4206 if (view != null) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07004207 view.mPrivateFlags |= PFLAG_DRAW_ANIMATION;
Romain Guyfe455af2012-02-15 16:40:20 -08004208 } else if (parent instanceof ViewRootImpl) {
4209 ((ViewRootImpl) parent).mIsAnimating = true;
4210 }
4211 }
4212
4213 // If the parent is dirty opaque or not dirty, mark it dirty with the opaque
4214 // flag coming from the child that initiated the invalidate
4215 if (view != null) {
4216 if ((view.mViewFlags & FADING_EDGE_MASK) != 0 &&
4217 view.getSolidColor() == 0) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07004218 opaqueFlag = PFLAG_DIRTY;
Romain Guyfe455af2012-02-15 16:40:20 -08004219 }
Dianne Hackborn4702a852012-08-17 15:18:29 -07004220 if ((view.mPrivateFlags & PFLAG_DIRTY_MASK) != PFLAG_DIRTY) {
4221 view.mPrivateFlags = (view.mPrivateFlags & ~PFLAG_DIRTY_MASK) | opaqueFlag;
Romain Guyfe455af2012-02-15 16:40:20 -08004222 }
4223 }
4224
4225 parent = parent.invalidateChildInParent(location, dirty);
4226 if (view != null) {
4227 // Account for transform on current parent
4228 Matrix m = view.getMatrix();
4229 if (!m.isIdentity()) {
4230 RectF boundingRect = attachInfo.mTmpTransformRect;
4231 boundingRect.set(dirty);
4232 m.mapRect(boundingRect);
Romain Guye8585b12012-02-17 18:28:47 -08004233 dirty.set((int) (boundingRect.left - 0.5f),
4234 (int) (boundingRect.top - 0.5f),
Romain Guyfe455af2012-02-15 16:40:20 -08004235 (int) (boundingRect.right + 0.5f),
4236 (int) (boundingRect.bottom + 0.5f));
4237 }
4238 }
4239 } while (parent != null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004240 }
4241 }
4242
4243 /**
4244 * Don't call or override this method. It is used for the implementation of
4245 * the view hierarchy.
4246 *
4247 * This implementation returns null if this ViewGroup does not have a parent,
4248 * if this ViewGroup is already fully invalidated or if the dirty rectangle
4249 * does not intersect with this ViewGroup's bounds.
4250 */
4251 public ViewParent invalidateChildInParent(final int[] location, final Rect dirty) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07004252 if ((mPrivateFlags & PFLAG_DRAWN) == PFLAG_DRAWN ||
4253 (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004254 if ((mGroupFlags & (FLAG_OPTIMIZE_INVALIDATE | FLAG_ANIMATION_DONE)) !=
4255 FLAG_OPTIMIZE_INVALIDATE) {
4256 dirty.offset(location[CHILD_LEFT_INDEX] - mScrollX,
4257 location[CHILD_TOP_INDEX] - mScrollY);
4258
4259 final int left = mLeft;
4260 final int top = mTop;
4261
Chet Haase05e91ed2012-07-03 14:17:57 -07004262 if ((mGroupFlags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN) {
4263 if (!dirty.intersect(0, 0, mRight - left, mBottom - top)) {
4264 dirty.setEmpty();
Romain Guy3a3133d2011-02-01 22:59:58 -08004265 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004266 }
Dianne Hackborn4702a852012-08-17 15:18:29 -07004267 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
Chet Haase05e91ed2012-07-03 14:17:57 -07004268
4269 location[CHILD_LEFT_INDEX] = left;
4270 location[CHILD_TOP_INDEX] = top;
4271
4272 if (mLayerType != LAYER_TYPE_NONE) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07004273 mPrivateFlags |= PFLAG_INVALIDATED;
Chet Haase05e91ed2012-07-03 14:17:57 -07004274 mLocalDirtyRect.union(dirty);
4275 }
4276
4277 return mParent;
4278
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004279 } else {
Dianne Hackborn4702a852012-08-17 15:18:29 -07004280 mPrivateFlags &= ~PFLAG_DRAWN & ~PFLAG_DRAWING_CACHE_VALID;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004281
4282 location[CHILD_LEFT_INDEX] = mLeft;
4283 location[CHILD_TOP_INDEX] = mTop;
Chet Haasea3db8662011-07-19 10:36:05 -07004284 if ((mGroupFlags & FLAG_CLIP_CHILDREN) == FLAG_CLIP_CHILDREN) {
4285 dirty.set(0, 0, mRight - mLeft, mBottom - mTop);
4286 } else {
4287 // in case the dirty rect extends outside the bounds of this container
4288 dirty.union(0, 0, mRight - mLeft, mBottom - mTop);
4289 }
Romain Guy3a3133d2011-02-01 22:59:58 -08004290
4291 if (mLayerType != LAYER_TYPE_NONE) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07004292 mPrivateFlags |= PFLAG_INVALIDATED;
Romain Guy3a3133d2011-02-01 22:59:58 -08004293 mLocalDirtyRect.union(dirty);
4294 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004295
4296 return mParent;
4297 }
4298 }
4299
4300 return null;
4301 }
4302
4303 /**
Chet Haase9d1992d2012-03-13 11:03:25 -07004304 * Quick invalidation method called by View.invalidateViewProperty. This doesn't set the
4305 * DRAWN flags and doesn't handle the Animation logic that the default invalidation methods
4306 * do; all we want to do here is schedule a traversal with the appropriate dirty rect.
4307 *
4308 * @hide
4309 */
4310 public void invalidateChildFast(View child, final Rect dirty) {
4311 ViewParent parent = this;
4312
4313 final AttachInfo attachInfo = mAttachInfo;
4314 if (attachInfo != null) {
4315 if (child.mLayerType != LAYER_TYPE_NONE) {
4316 child.mLocalDirtyRect.union(dirty);
4317 }
4318
4319 int left = child.mLeft;
4320 int top = child.mTop;
4321 if (!child.getMatrix().isIdentity()) {
4322 child.transformRect(dirty);
4323 }
4324
4325 do {
4326 if (parent instanceof ViewGroup) {
4327 ViewGroup parentVG = (ViewGroup) parent;
Chet Haaseb85967b2012-03-26 14:37:51 -07004328 if (parentVG.mLayerType != LAYER_TYPE_NONE) {
4329 // Layered parents should be recreated, not just re-issued
4330 parentVG.invalidate();
4331 parent = null;
4332 } else {
4333 parent = parentVG.invalidateChildInParentFast(left, top, dirty);
4334 left = parentVG.mLeft;
4335 top = parentVG.mTop;
4336 }
Chet Haase9d1992d2012-03-13 11:03:25 -07004337 } else {
4338 // Reached the top; this calls into the usual invalidate method in
4339 // ViewRootImpl, which schedules a traversal
4340 final int[] location = attachInfo.mInvalidateChildLocation;
4341 location[0] = left;
4342 location[1] = top;
4343 parent = parent.invalidateChildInParent(location, dirty);
4344 }
4345 } while (parent != null);
4346 }
4347 }
4348
4349 /**
4350 * Quick invalidation method that simply transforms the dirty rect into the parent's
4351 * coordinate system, pruning the invalidation if the parent has already been invalidated.
4352 */
4353 private ViewParent invalidateChildInParentFast(int left, int top, final Rect dirty) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07004354 if ((mPrivateFlags & PFLAG_DRAWN) == PFLAG_DRAWN ||
4355 (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID) {
Chet Haase9d1992d2012-03-13 11:03:25 -07004356 dirty.offset(left - mScrollX, top - mScrollY);
4357
4358 if ((mGroupFlags & FLAG_CLIP_CHILDREN) == 0 ||
4359 dirty.intersect(0, 0, mRight - mLeft, mBottom - mTop)) {
4360
4361 if (mLayerType != LAYER_TYPE_NONE) {
4362 mLocalDirtyRect.union(dirty);
4363 }
4364 if (!getMatrix().isIdentity()) {
4365 transformRect(dirty);
4366 }
4367
4368 return mParent;
4369 }
4370 }
4371
4372 return null;
4373 }
4374
4375 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004376 * Offset a rectangle that is in a descendant's coordinate
4377 * space into our coordinate space.
4378 * @param descendant A descendant of this view
4379 * @param rect A rectangle defined in descendant's coordinate space.
4380 */
4381 public final void offsetDescendantRectToMyCoords(View descendant, Rect rect) {
4382 offsetRectBetweenParentAndChild(descendant, rect, true, false);
4383 }
4384
4385 /**
4386 * Offset a rectangle that is in our coordinate space into an ancestor's
4387 * coordinate space.
4388 * @param descendant A descendant of this view
4389 * @param rect A rectangle defined in descendant's coordinate space.
4390 */
4391 public final void offsetRectIntoDescendantCoords(View descendant, Rect rect) {
4392 offsetRectBetweenParentAndChild(descendant, rect, false, false);
4393 }
4394
4395 /**
4396 * Helper method that offsets a rect either from parent to descendant or
4397 * descendant to parent.
4398 */
4399 void offsetRectBetweenParentAndChild(View descendant, Rect rect,
4400 boolean offsetFromChildToParent, boolean clipToBounds) {
4401
4402 // already in the same coord system :)
4403 if (descendant == this) {
4404 return;
4405 }
4406
4407 ViewParent theParent = descendant.mParent;
4408
4409 // search and offset up to the parent
4410 while ((theParent != null)
4411 && (theParent instanceof View)
4412 && (theParent != this)) {
4413
4414 if (offsetFromChildToParent) {
4415 rect.offset(descendant.mLeft - descendant.mScrollX,
4416 descendant.mTop - descendant.mScrollY);
4417 if (clipToBounds) {
4418 View p = (View) theParent;
4419 rect.intersect(0, 0, p.mRight - p.mLeft, p.mBottom - p.mTop);
4420 }
4421 } else {
4422 if (clipToBounds) {
4423 View p = (View) theParent;
4424 rect.intersect(0, 0, p.mRight - p.mLeft, p.mBottom - p.mTop);
4425 }
4426 rect.offset(descendant.mScrollX - descendant.mLeft,
4427 descendant.mScrollY - descendant.mTop);
4428 }
4429
4430 descendant = (View) theParent;
4431 theParent = descendant.mParent;
4432 }
4433
4434 // now that we are up to this view, need to offset one more time
4435 // to get into our coordinate space
4436 if (theParent == this) {
4437 if (offsetFromChildToParent) {
4438 rect.offset(descendant.mLeft - descendant.mScrollX,
4439 descendant.mTop - descendant.mScrollY);
4440 } else {
4441 rect.offset(descendant.mScrollX - descendant.mLeft,
4442 descendant.mScrollY - descendant.mTop);
4443 }
4444 } else {
4445 throw new IllegalArgumentException("parameter must be a descendant of this view");
4446 }
4447 }
4448
4449 /**
4450 * Offset the vertical location of all children of this view by the specified number of pixels.
4451 *
4452 * @param offset the number of pixels to offset
4453 *
4454 * @hide
4455 */
4456 public void offsetChildrenTopAndBottom(int offset) {
4457 final int count = mChildrenCount;
4458 final View[] children = mChildren;
4459
4460 for (int i = 0; i < count; i++) {
4461 final View v = children[i];
4462 v.mTop += offset;
4463 v.mBottom += offset;
Chet Haase1271e2c2012-04-20 09:54:27 -07004464 if (v.mDisplayList != null) {
Romain Guy52036b12013-02-14 18:03:37 -08004465 v.mDisplayList.offsetTopAndBottom(offset);
Chet Haase9d1992d2012-03-13 11:03:25 -07004466 invalidateViewProperty(false, false);
Chet Haasea1cff502012-02-21 13:43:44 -08004467 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004468 }
4469 }
4470
4471 /**
4472 * {@inheritDoc}
4473 */
4474 public boolean getChildVisibleRect(View child, Rect r, android.graphics.Point offset) {
Adam Powellf93bb6d2011-12-12 15:21:57 -08004475 // It doesn't make a whole lot of sense to call this on a view that isn't attached,
4476 // but for some simple tests it can be useful. If we don't have attach info this
4477 // will allocate memory.
4478 final RectF rect = mAttachInfo != null ? mAttachInfo.mTmpTransformRect : new RectF();
Gilles Debunnecea45132011-11-24 02:19:27 +01004479 rect.set(r);
4480
4481 if (!child.hasIdentityMatrix()) {
4482 child.getMatrix().mapRect(rect);
4483 }
4484
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004485 int dx = child.mLeft - mScrollX;
4486 int dy = child.mTop - mScrollY;
Gilles Debunnecea45132011-11-24 02:19:27 +01004487
4488 rect.offset(dx, dy);
4489
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004490 if (offset != null) {
Gilles Debunnecea45132011-11-24 02:19:27 +01004491 if (!child.hasIdentityMatrix()) {
Adam Powellf93bb6d2011-12-12 15:21:57 -08004492 float[] position = mAttachInfo != null ? mAttachInfo.mTmpTransformLocation
4493 : new float[2];
Gilles Debunnecea45132011-11-24 02:19:27 +01004494 position[0] = offset.x;
4495 position[1] = offset.y;
4496 child.getMatrix().mapPoints(position);
4497 offset.x = (int) (position[0] + 0.5f);
4498 offset.y = (int) (position[1] + 0.5f);
4499 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004500 offset.x += dx;
4501 offset.y += dy;
4502 }
Gilles Debunnecea45132011-11-24 02:19:27 +01004503
4504 if (rect.intersect(0, 0, mRight - mLeft, mBottom - mTop)) {
4505 if (mParent == null) return true;
4506 r.set((int) (rect.left + 0.5f), (int) (rect.top + 0.5f),
4507 (int) (rect.right + 0.5f), (int) (rect.bottom + 0.5f));
4508 return mParent.getChildVisibleRect(this, r, offset);
4509 }
4510
4511 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004512 }
4513
4514 /**
4515 * {@inheritDoc}
4516 */
4517 @Override
Chet Haase9c087442011-01-12 16:20:16 -08004518 public final void layout(int l, int t, int r, int b) {
4519 if (mTransition == null || !mTransition.isChangingLayout()) {
Chet Haase7dd4a532012-04-16 13:35:09 -07004520 if (mTransition != null) {
4521 mTransition.layoutChange(this);
4522 }
Chet Haase9c087442011-01-12 16:20:16 -08004523 super.layout(l, t, r, b);
4524 } else {
4525 // record the fact that we noop'd it; request layout when transition finishes
4526 mLayoutSuppressed = true;
4527 }
4528 }
4529
4530 /**
4531 * {@inheritDoc}
4532 */
4533 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004534 protected abstract void onLayout(boolean changed,
4535 int l, int t, int r, int b);
4536
4537 /**
4538 * Indicates whether the view group has the ability to animate its children
4539 * after the first layout.
4540 *
4541 * @return true if the children can be animated, false otherwise
4542 */
4543 protected boolean canAnimate() {
4544 return mLayoutAnimationController != null;
4545 }
4546
4547 /**
4548 * Runs the layout animation. Calling this method triggers a relayout of
4549 * this view group.
4550 */
4551 public void startLayoutAnimation() {
4552 if (mLayoutAnimationController != null) {
4553 mGroupFlags |= FLAG_RUN_ANIMATION;
4554 requestLayout();
4555 }
4556 }
4557
4558 /**
4559 * Schedules the layout animation to be played after the next layout pass
4560 * of this view group. This can be used to restart the layout animation
4561 * when the content of the view group changes or when the activity is
4562 * paused and resumed.
4563 */
4564 public void scheduleLayoutAnimation() {
4565 mGroupFlags |= FLAG_RUN_ANIMATION;
4566 }
4567
4568 /**
4569 * Sets the layout animation controller used to animate the group's
4570 * children after the first layout.
4571 *
4572 * @param controller the animation controller
4573 */
4574 public void setLayoutAnimation(LayoutAnimationController controller) {
4575 mLayoutAnimationController = controller;
4576 if (mLayoutAnimationController != null) {
4577 mGroupFlags |= FLAG_RUN_ANIMATION;
4578 }
4579 }
4580
4581 /**
4582 * Returns the layout animation controller used to animate the group's
4583 * children.
4584 *
4585 * @return the current animation controller
4586 */
4587 public LayoutAnimationController getLayoutAnimation() {
4588 return mLayoutAnimationController;
4589 }
4590
4591 /**
4592 * Indicates whether the children's drawing cache is used during a layout
4593 * animation. By default, the drawing cache is enabled but this will prevent
4594 * nested layout animations from working. To nest animations, you must disable
4595 * the cache.
4596 *
4597 * @return true if the animation cache is enabled, false otherwise
4598 *
4599 * @see #setAnimationCacheEnabled(boolean)
4600 * @see View#setDrawingCacheEnabled(boolean)
4601 */
4602 @ViewDebug.ExportedProperty
4603 public boolean isAnimationCacheEnabled() {
4604 return (mGroupFlags & FLAG_ANIMATION_CACHE) == FLAG_ANIMATION_CACHE;
4605 }
4606
4607 /**
4608 * Enables or disables the children's drawing cache during a layout animation.
4609 * By default, the drawing cache is enabled but this will prevent nested
4610 * layout animations from working. To nest animations, you must disable the
4611 * cache.
4612 *
4613 * @param enabled true to enable the animation cache, false otherwise
4614 *
4615 * @see #isAnimationCacheEnabled()
4616 * @see View#setDrawingCacheEnabled(boolean)
4617 */
4618 public void setAnimationCacheEnabled(boolean enabled) {
4619 setBooleanFlag(FLAG_ANIMATION_CACHE, enabled);
4620 }
4621
4622 /**
4623 * Indicates whether this ViewGroup will always try to draw its children using their
4624 * drawing cache. By default this property is enabled.
4625 *
4626 * @return true if the animation cache is enabled, false otherwise
4627 *
4628 * @see #setAlwaysDrawnWithCacheEnabled(boolean)
4629 * @see #setChildrenDrawnWithCacheEnabled(boolean)
4630 * @see View#setDrawingCacheEnabled(boolean)
4631 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07004632 @ViewDebug.ExportedProperty(category = "drawing")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004633 public boolean isAlwaysDrawnWithCacheEnabled() {
4634 return (mGroupFlags & FLAG_ALWAYS_DRAWN_WITH_CACHE) == FLAG_ALWAYS_DRAWN_WITH_CACHE;
4635 }
4636
4637 /**
4638 * Indicates whether this ViewGroup will always try to draw its children using their
4639 * drawing cache. This property can be set to true when the cache rendering is
4640 * slightly different from the children's normal rendering. Renderings can be different,
4641 * for instance, when the cache's quality is set to low.
4642 *
4643 * When this property is disabled, the ViewGroup will use the drawing cache of its
4644 * children only when asked to. It's usually the task of subclasses to tell ViewGroup
4645 * when to start using the drawing cache and when to stop using it.
4646 *
4647 * @param always true to always draw with the drawing cache, false otherwise
4648 *
4649 * @see #isAlwaysDrawnWithCacheEnabled()
4650 * @see #setChildrenDrawnWithCacheEnabled(boolean)
4651 * @see View#setDrawingCacheEnabled(boolean)
4652 * @see View#setDrawingCacheQuality(int)
4653 */
4654 public void setAlwaysDrawnWithCacheEnabled(boolean always) {
4655 setBooleanFlag(FLAG_ALWAYS_DRAWN_WITH_CACHE, always);
4656 }
4657
4658 /**
4659 * Indicates whether the ViewGroup is currently drawing its children using
4660 * their drawing cache.
4661 *
4662 * @return true if children should be drawn with their cache, false otherwise
4663 *
4664 * @see #setAlwaysDrawnWithCacheEnabled(boolean)
4665 * @see #setChildrenDrawnWithCacheEnabled(boolean)
4666 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07004667 @ViewDebug.ExportedProperty(category = "drawing")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004668 protected boolean isChildrenDrawnWithCacheEnabled() {
4669 return (mGroupFlags & FLAG_CHILDREN_DRAWN_WITH_CACHE) == FLAG_CHILDREN_DRAWN_WITH_CACHE;
4670 }
4671
4672 /**
4673 * Tells the ViewGroup to draw its children using their drawing cache. This property
4674 * is ignored when {@link #isAlwaysDrawnWithCacheEnabled()} is true. A child's drawing cache
4675 * will be used only if it has been enabled.
4676 *
4677 * Subclasses should call this method to start and stop using the drawing cache when
4678 * they perform performance sensitive operations, like scrolling or animating.
4679 *
4680 * @param enabled true if children should be drawn with their cache, false otherwise
4681 *
4682 * @see #setAlwaysDrawnWithCacheEnabled(boolean)
4683 * @see #isChildrenDrawnWithCacheEnabled()
4684 */
4685 protected void setChildrenDrawnWithCacheEnabled(boolean enabled) {
4686 setBooleanFlag(FLAG_CHILDREN_DRAWN_WITH_CACHE, enabled);
4687 }
4688
Romain Guy293451e2009-11-04 13:59:48 -08004689 /**
4690 * Indicates whether the ViewGroup is drawing its children in the order defined by
4691 * {@link #getChildDrawingOrder(int, int)}.
4692 *
4693 * @return true if children drawing order is defined by {@link #getChildDrawingOrder(int, int)},
4694 * false otherwise
4695 *
4696 * @see #setChildrenDrawingOrderEnabled(boolean)
4697 * @see #getChildDrawingOrder(int, int)
4698 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07004699 @ViewDebug.ExportedProperty(category = "drawing")
Romain Guy293451e2009-11-04 13:59:48 -08004700 protected boolean isChildrenDrawingOrderEnabled() {
4701 return (mGroupFlags & FLAG_USE_CHILD_DRAWING_ORDER) == FLAG_USE_CHILD_DRAWING_ORDER;
4702 }
4703
4704 /**
4705 * Tells the ViewGroup whether to draw its children in the order defined by the method
4706 * {@link #getChildDrawingOrder(int, int)}.
4707 *
4708 * @param enabled true if the order of the children when drawing is determined by
4709 * {@link #getChildDrawingOrder(int, int)}, false otherwise
4710 *
4711 * @see #isChildrenDrawingOrderEnabled()
4712 * @see #getChildDrawingOrder(int, int)
4713 */
4714 protected void setChildrenDrawingOrderEnabled(boolean enabled) {
4715 setBooleanFlag(FLAG_USE_CHILD_DRAWING_ORDER, enabled);
4716 }
4717
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004718 private void setBooleanFlag(int flag, boolean value) {
4719 if (value) {
4720 mGroupFlags |= flag;
4721 } else {
4722 mGroupFlags &= ~flag;
4723 }
4724 }
4725
4726 /**
4727 * Returns an integer indicating what types of drawing caches are kept in memory.
4728 *
4729 * @see #setPersistentDrawingCache(int)
4730 * @see #setAnimationCacheEnabled(boolean)
4731 *
4732 * @return one or a combination of {@link #PERSISTENT_NO_CACHE},
4733 * {@link #PERSISTENT_ANIMATION_CACHE}, {@link #PERSISTENT_SCROLLING_CACHE}
4734 * and {@link #PERSISTENT_ALL_CACHES}
4735 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07004736 @ViewDebug.ExportedProperty(category = "drawing", mapping = {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004737 @ViewDebug.IntToString(from = PERSISTENT_NO_CACHE, to = "NONE"),
Romain Guy203688c2010-05-12 15:41:32 -07004738 @ViewDebug.IntToString(from = PERSISTENT_ANIMATION_CACHE, to = "ANIMATION"),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004739 @ViewDebug.IntToString(from = PERSISTENT_SCROLLING_CACHE, to = "SCROLLING"),
4740 @ViewDebug.IntToString(from = PERSISTENT_ALL_CACHES, to = "ALL")
4741 })
4742 public int getPersistentDrawingCache() {
4743 return mPersistentDrawingCache;
4744 }
4745
4746 /**
4747 * Indicates what types of drawing caches should be kept in memory after
4748 * they have been created.
4749 *
4750 * @see #getPersistentDrawingCache()
4751 * @see #setAnimationCacheEnabled(boolean)
4752 *
4753 * @param drawingCacheToKeep one or a combination of {@link #PERSISTENT_NO_CACHE},
4754 * {@link #PERSISTENT_ANIMATION_CACHE}, {@link #PERSISTENT_SCROLLING_CACHE}
4755 * and {@link #PERSISTENT_ALL_CACHES}
4756 */
4757 public void setPersistentDrawingCache(int drawingCacheToKeep) {
4758 mPersistentDrawingCache = drawingCacheToKeep & PERSISTENT_ALL_CACHES;
4759 }
4760
4761 /**
Philip Milne7a23b492012-04-24 22:12:36 -07004762 * Returns the basis of alignment during layout operations on this view group:
Philip Milne7b757812012-09-19 18:13:44 -07004763 * either {@link #LAYOUT_MODE_CLIP_BOUNDS} or {@link #LAYOUT_MODE_OPTICAL_BOUNDS}.
Philip Milne1557fd72012-04-04 23:41:34 -07004764 *
Philip Milnefcc6a0f2012-04-16 16:12:19 -07004765 * @return the layout mode to use during layout operations
Philip Milne1557fd72012-04-04 23:41:34 -07004766 *
4767 * @see #setLayoutMode(int)
4768 */
4769 public int getLayoutMode() {
Philip Milne1557fd72012-04-04 23:41:34 -07004770 return mLayoutMode;
4771 }
4772
4773 /**
Philip Milne7a23b492012-04-24 22:12:36 -07004774 * Sets the basis of alignment during the layout of this view group.
Philip Milne7b757812012-09-19 18:13:44 -07004775 * Valid values are either {@link #LAYOUT_MODE_CLIP_BOUNDS} or
4776 * {@link #LAYOUT_MODE_OPTICAL_BOUNDS}.
Philip Milne1557fd72012-04-04 23:41:34 -07004777 * <p>
Philip Milne7b757812012-09-19 18:13:44 -07004778 * The default is {@link #LAYOUT_MODE_CLIP_BOUNDS}.
Philip Milne1557fd72012-04-04 23:41:34 -07004779 *
Philip Milnefcc6a0f2012-04-16 16:12:19 -07004780 * @param layoutMode the layout mode to use during layout operations
Philip Milne1557fd72012-04-04 23:41:34 -07004781 *
4782 * @see #getLayoutMode()
4783 */
4784 public void setLayoutMode(int layoutMode) {
4785 if (mLayoutMode != layoutMode) {
4786 mLayoutMode = layoutMode;
4787 requestLayout();
4788 }
4789 }
4790
4791 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004792 * Returns a new set of layout parameters based on the supplied attributes set.
4793 *
4794 * @param attrs the attributes to build the layout parameters from
4795 *
4796 * @return an instance of {@link android.view.ViewGroup.LayoutParams} or one
4797 * of its descendants
4798 */
4799 public LayoutParams generateLayoutParams(AttributeSet attrs) {
4800 return new LayoutParams(getContext(), attrs);
4801 }
4802
4803 /**
4804 * Returns a safe set of layout parameters based on the supplied layout params.
4805 * When a ViewGroup is passed a View whose layout params do not pass the test of
4806 * {@link #checkLayoutParams(android.view.ViewGroup.LayoutParams)}, this method
4807 * is invoked. This method should return a new set of layout params suitable for
4808 * this ViewGroup, possibly by copying the appropriate attributes from the
4809 * specified set of layout params.
4810 *
4811 * @param p The layout parameters to convert into a suitable set of layout parameters
4812 * for this ViewGroup.
4813 *
4814 * @return an instance of {@link android.view.ViewGroup.LayoutParams} or one
4815 * of its descendants
4816 */
4817 protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
4818 return p;
4819 }
4820
4821 /**
4822 * Returns a set of default layout parameters. These parameters are requested
4823 * when the View passed to {@link #addView(View)} has no layout parameters
4824 * already set. If null is returned, an exception is thrown from addView.
4825 *
4826 * @return a set of default layout parameters or null
4827 */
4828 protected LayoutParams generateDefaultLayoutParams() {
4829 return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
4830 }
4831
4832 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004833 * {@inheritDoc}
4834 */
4835 @Override
4836 protected void debug(int depth) {
4837 super.debug(depth);
4838 String output;
4839
4840 if (mFocused != null) {
4841 output = debugIndent(depth);
4842 output += "mFocused";
4843 Log.d(VIEW_LOG_TAG, output);
4844 }
4845 if (mChildrenCount != 0) {
4846 output = debugIndent(depth);
4847 output += "{";
4848 Log.d(VIEW_LOG_TAG, output);
4849 }
4850 int count = mChildrenCount;
4851 for (int i = 0; i < count; i++) {
4852 View child = mChildren[i];
4853 child.debug(depth + 1);
4854 }
4855
4856 if (mChildrenCount != 0) {
4857 output = debugIndent(depth);
4858 output += "}";
4859 Log.d(VIEW_LOG_TAG, output);
4860 }
4861 }
4862
4863 /**
4864 * Returns the position in the group of the specified child view.
4865 *
4866 * @param child the view for which to get the position
4867 * @return a positive integer representing the position of the view in the
4868 * group, or -1 if the view does not exist in the group
4869 */
4870 public int indexOfChild(View child) {
4871 final int count = mChildrenCount;
4872 final View[] children = mChildren;
4873 for (int i = 0; i < count; i++) {
4874 if (children[i] == child) {
4875 return i;
4876 }
4877 }
4878 return -1;
4879 }
4880
4881 /**
4882 * Returns the number of children in the group.
4883 *
4884 * @return a positive integer representing the number of children in
4885 * the group
4886 */
4887 public int getChildCount() {
4888 return mChildrenCount;
4889 }
4890
4891 /**
4892 * Returns the view at the specified position in the group.
4893 *
4894 * @param index the position at which to get the view from
4895 * @return the view at the specified position or null if the position
4896 * does not exist within the group
4897 */
4898 public View getChildAt(int index) {
Adam Powell3ba8f5d2011-03-07 15:36:33 -08004899 if (index < 0 || index >= mChildrenCount) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004900 return null;
4901 }
Adam Powell3ba8f5d2011-03-07 15:36:33 -08004902 return mChildren[index];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004903 }
4904
4905 /**
4906 * Ask all of the children of this view to measure themselves, taking into
4907 * account both the MeasureSpec requirements for this view and its padding.
4908 * We skip children that are in the GONE state The heavy lifting is done in
4909 * getChildMeasureSpec.
4910 *
4911 * @param widthMeasureSpec The width requirements for this view
4912 * @param heightMeasureSpec The height requirements for this view
4913 */
4914 protected void measureChildren(int widthMeasureSpec, int heightMeasureSpec) {
4915 final int size = mChildrenCount;
4916 final View[] children = mChildren;
4917 for (int i = 0; i < size; ++i) {
4918 final View child = children[i];
4919 if ((child.mViewFlags & VISIBILITY_MASK) != GONE) {
4920 measureChild(child, widthMeasureSpec, heightMeasureSpec);
4921 }
4922 }
4923 }
4924
4925 /**
4926 * Ask one of the children of this view to measure itself, taking into
4927 * account both the MeasureSpec requirements for this view and its padding.
4928 * The heavy lifting is done in getChildMeasureSpec.
4929 *
4930 * @param child The child to measure
4931 * @param parentWidthMeasureSpec The width requirements for this view
4932 * @param parentHeightMeasureSpec The height requirements for this view
4933 */
4934 protected void measureChild(View child, int parentWidthMeasureSpec,
4935 int parentHeightMeasureSpec) {
4936 final LayoutParams lp = child.getLayoutParams();
4937
4938 final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
4939 mPaddingLeft + mPaddingRight, lp.width);
4940 final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
4941 mPaddingTop + mPaddingBottom, lp.height);
4942
4943 child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
4944 }
4945
4946 /**
4947 * Ask one of the children of this view to measure itself, taking into
4948 * account both the MeasureSpec requirements for this view and its padding
4949 * and margins. The child must have MarginLayoutParams The heavy lifting is
4950 * done in getChildMeasureSpec.
4951 *
4952 * @param child The child to measure
4953 * @param parentWidthMeasureSpec The width requirements for this view
4954 * @param widthUsed Extra space that has been used up by the parent
4955 * horizontally (possibly by other children of the parent)
4956 * @param parentHeightMeasureSpec The height requirements for this view
4957 * @param heightUsed Extra space that has been used up by the parent
4958 * vertically (possibly by other children of the parent)
4959 */
4960 protected void measureChildWithMargins(View child,
4961 int parentWidthMeasureSpec, int widthUsed,
4962 int parentHeightMeasureSpec, int heightUsed) {
4963 final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
4964
4965 final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec,
4966 mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin
4967 + widthUsed, lp.width);
4968 final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec,
4969 mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin
4970 + heightUsed, lp.height);
4971
4972 child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
4973 }
4974
4975 /**
4976 * Does the hard part of measureChildren: figuring out the MeasureSpec to
4977 * pass to a particular child. This method figures out the right MeasureSpec
4978 * for one dimension (height or width) of one child view.
4979 *
4980 * The goal is to combine information from our MeasureSpec with the
4981 * LayoutParams of the child to get the best possible results. For example,
4982 * if the this view knows its size (because its MeasureSpec has a mode of
4983 * EXACTLY), and the child has indicated in its LayoutParams that it wants
4984 * to be the same size as the parent, the parent should ask the child to
4985 * layout given an exact size.
4986 *
4987 * @param spec The requirements for this view
4988 * @param padding The padding of this view for the current dimension and
4989 * margins, if applicable
4990 * @param childDimension How big the child wants to be in the current
4991 * dimension
4992 * @return a MeasureSpec integer for the child
4993 */
4994 public static int getChildMeasureSpec(int spec, int padding, int childDimension) {
4995 int specMode = MeasureSpec.getMode(spec);
4996 int specSize = MeasureSpec.getSize(spec);
4997
4998 int size = Math.max(0, specSize - padding);
4999
5000 int resultSize = 0;
5001 int resultMode = 0;
5002
5003 switch (specMode) {
5004 // Parent has imposed an exact size on us
5005 case MeasureSpec.EXACTLY:
5006 if (childDimension >= 0) {
5007 resultSize = childDimension;
5008 resultMode = MeasureSpec.EXACTLY;
Romain Guy980a9382010-01-08 15:06:28 -08005009 } else if (childDimension == LayoutParams.MATCH_PARENT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005010 // Child wants to be our size. So be it.
5011 resultSize = size;
5012 resultMode = MeasureSpec.EXACTLY;
5013 } else if (childDimension == LayoutParams.WRAP_CONTENT) {
5014 // Child wants to determine its own size. It can't be
5015 // bigger than us.
5016 resultSize = size;
5017 resultMode = MeasureSpec.AT_MOST;
5018 }
5019 break;
5020
5021 // Parent has imposed a maximum size on us
5022 case MeasureSpec.AT_MOST:
5023 if (childDimension >= 0) {
5024 // Child wants a specific size... so be it
5025 resultSize = childDimension;
5026 resultMode = MeasureSpec.EXACTLY;
Romain Guy980a9382010-01-08 15:06:28 -08005027 } else if (childDimension == LayoutParams.MATCH_PARENT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005028 // Child wants to be our size, but our size is not fixed.
5029 // Constrain child to not be bigger than us.
5030 resultSize = size;
5031 resultMode = MeasureSpec.AT_MOST;
5032 } else if (childDimension == LayoutParams.WRAP_CONTENT) {
5033 // Child wants to determine its own size. It can't be
5034 // bigger than us.
5035 resultSize = size;
5036 resultMode = MeasureSpec.AT_MOST;
5037 }
5038 break;
5039
5040 // Parent asked to see how big we want to be
5041 case MeasureSpec.UNSPECIFIED:
5042 if (childDimension >= 0) {
5043 // Child wants a specific size... let him have it
5044 resultSize = childDimension;
5045 resultMode = MeasureSpec.EXACTLY;
Romain Guy980a9382010-01-08 15:06:28 -08005046 } else if (childDimension == LayoutParams.MATCH_PARENT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005047 // Child wants to be our size... find out how big it should
5048 // be
5049 resultSize = 0;
5050 resultMode = MeasureSpec.UNSPECIFIED;
5051 } else if (childDimension == LayoutParams.WRAP_CONTENT) {
5052 // Child wants to determine its own size.... find out how
5053 // big it should be
5054 resultSize = 0;
5055 resultMode = MeasureSpec.UNSPECIFIED;
5056 }
5057 break;
5058 }
5059 return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
5060 }
5061
5062
5063 /**
5064 * Removes any pending animations for views that have been removed. Call
5065 * this if you don't want animations for exiting views to stack up.
5066 */
5067 public void clearDisappearingChildren() {
5068 if (mDisappearingChildren != null) {
5069 mDisappearingChildren.clear();
Chet Haaseb85967b2012-03-26 14:37:51 -07005070 invalidate();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005071 }
5072 }
5073
5074 /**
5075 * Add a view which is removed from mChildren but still needs animation
5076 *
5077 * @param v View to add
5078 */
5079 private void addDisappearingView(View v) {
5080 ArrayList<View> disappearingChildren = mDisappearingChildren;
5081
5082 if (disappearingChildren == null) {
5083 disappearingChildren = mDisappearingChildren = new ArrayList<View>();
5084 }
5085
5086 disappearingChildren.add(v);
5087 }
5088
5089 /**
5090 * Cleanup a view when its animation is done. This may mean removing it from
5091 * the list of disappearing views.
5092 *
5093 * @param view The view whose animation has finished
5094 * @param animation The animation, cannot be null
5095 */
Chet Haase64a48c12012-02-13 16:33:29 -08005096 void finishAnimatingView(final View view, Animation animation) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005097 final ArrayList<View> disappearingChildren = mDisappearingChildren;
5098 if (disappearingChildren != null) {
5099 if (disappearingChildren.contains(view)) {
5100 disappearingChildren.remove(view);
5101
5102 if (view.mAttachInfo != null) {
5103 view.dispatchDetachedFromWindow();
5104 }
5105
5106 view.clearAnimation();
5107 mGroupFlags |= FLAG_INVALIDATE_REQUIRED;
5108 }
5109 }
5110
5111 if (animation != null && !animation.getFillAfter()) {
5112 view.clearAnimation();
5113 }
5114
Dianne Hackborn4702a852012-08-17 15:18:29 -07005115 if ((view.mPrivateFlags & PFLAG_ANIMATION_STARTED) == PFLAG_ANIMATION_STARTED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005116 view.onAnimationEnd();
5117 // Should be performed by onAnimationEnd() but this avoid an infinite loop,
5118 // so we'd rather be safe than sorry
Dianne Hackborn4702a852012-08-17 15:18:29 -07005119 view.mPrivateFlags &= ~PFLAG_ANIMATION_STARTED;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005120 // Draw one more frame after the animation is done
5121 mGroupFlags |= FLAG_INVALIDATE_REQUIRED;
5122 }
5123 }
5124
Chet Haaseb20db3e2010-09-10 13:07:30 -07005125 /**
Chet Haaseaceafe62011-08-26 15:44:33 -07005126 * Utility function called by View during invalidation to determine whether a view that
5127 * is invisible or gone should still be invalidated because it is being transitioned (and
5128 * therefore still needs to be drawn).
5129 */
5130 boolean isViewTransitioning(View view) {
5131 return (mTransitioningViews != null && mTransitioningViews.contains(view));
5132 }
5133
5134 /**
Chet Haaseb20db3e2010-09-10 13:07:30 -07005135 * This method tells the ViewGroup that the given View object, which should have this
5136 * ViewGroup as its parent,
5137 * should be kept around (re-displayed when the ViewGroup draws its children) even if it
5138 * is removed from its parent. This allows animations, such as those used by
5139 * {@link android.app.Fragment} and {@link android.animation.LayoutTransition} to animate
5140 * the removal of views. A call to this method should always be accompanied by a later call
5141 * to {@link #endViewTransition(View)}, such as after an animation on the View has finished,
5142 * so that the View finally gets removed.
5143 *
5144 * @param view The View object to be kept visible even if it gets removed from its parent.
5145 */
5146 public void startViewTransition(View view) {
5147 if (view.mParent == this) {
5148 if (mTransitioningViews == null) {
5149 mTransitioningViews = new ArrayList<View>();
5150 }
5151 mTransitioningViews.add(view);
5152 }
5153 }
5154
5155 /**
5156 * This method should always be called following an earlier call to
5157 * {@link #startViewTransition(View)}. The given View is finally removed from its parent
5158 * and will no longer be displayed. Note that this method does not perform the functionality
5159 * of removing a view from its parent; it just discontinues the display of a View that
5160 * has previously been removed.
5161 *
5162 * @return view The View object that has been removed but is being kept around in the visible
5163 * hierarchy by an earlier call to {@link #startViewTransition(View)}.
5164 */
5165 public void endViewTransition(View view) {
5166 if (mTransitioningViews != null) {
5167 mTransitioningViews.remove(view);
5168 final ArrayList<View> disappearingChildren = mDisappearingChildren;
5169 if (disappearingChildren != null && disappearingChildren.contains(view)) {
5170 disappearingChildren.remove(view);
Chet Haase5e25c2c2010-09-16 11:15:56 -07005171 if (mVisibilityChangingChildren != null &&
5172 mVisibilityChangingChildren.contains(view)) {
5173 mVisibilityChangingChildren.remove(view);
5174 } else {
5175 if (view.mAttachInfo != null) {
5176 view.dispatchDetachedFromWindow();
5177 }
5178 if (view.mParent != null) {
5179 view.mParent = null;
5180 }
Chet Haaseb20db3e2010-09-10 13:07:30 -07005181 }
Chet Haaseb85967b2012-03-26 14:37:51 -07005182 invalidate();
Chet Haaseb20db3e2010-09-10 13:07:30 -07005183 }
5184 }
5185 }
5186
Chet Haase21cd1382010-09-01 17:42:29 -07005187 private LayoutTransition.TransitionListener mLayoutTransitionListener =
5188 new LayoutTransition.TransitionListener() {
5189 @Override
5190 public void startTransition(LayoutTransition transition, ViewGroup container,
5191 View view, int transitionType) {
5192 // We only care about disappearing items, since we need special logic to keep
5193 // those items visible after they've been 'removed'
5194 if (transitionType == LayoutTransition.DISAPPEARING) {
Chet Haaseb20db3e2010-09-10 13:07:30 -07005195 startViewTransition(view);
Chet Haase21cd1382010-09-01 17:42:29 -07005196 }
5197 }
5198
5199 @Override
5200 public void endTransition(LayoutTransition transition, ViewGroup container,
5201 View view, int transitionType) {
Chet Haase9c087442011-01-12 16:20:16 -08005202 if (mLayoutSuppressed && !transition.isChangingLayout()) {
5203 requestLayout();
5204 mLayoutSuppressed = false;
5205 }
Chet Haase21cd1382010-09-01 17:42:29 -07005206 if (transitionType == LayoutTransition.DISAPPEARING && mTransitioningViews != null) {
Chet Haaseb20db3e2010-09-10 13:07:30 -07005207 endViewTransition(view);
Chet Haase21cd1382010-09-01 17:42:29 -07005208 }
5209 }
5210 };
5211
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005212 /**
5213 * {@inheritDoc}
5214 */
5215 @Override
5216 public boolean gatherTransparentRegion(Region region) {
5217 // If no transparent regions requested, we are always opaque.
Dianne Hackborn4702a852012-08-17 15:18:29 -07005218 final boolean meOpaque = (mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) == 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005219 if (meOpaque && region == null) {
5220 // The caller doesn't care about the region, so stop now.
5221 return true;
5222 }
5223 super.gatherTransparentRegion(region);
5224 final View[] children = mChildren;
5225 final int count = mChildrenCount;
5226 boolean noneOfTheChildrenAreTransparent = true;
5227 for (int i = 0; i < count; i++) {
5228 final View child = children[i];
Mathias Agopiane3381152010-12-02 15:19:36 -08005229 if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005230 if (!child.gatherTransparentRegion(region)) {
5231 noneOfTheChildrenAreTransparent = false;
5232 }
5233 }
5234 }
5235 return meOpaque || noneOfTheChildrenAreTransparent;
5236 }
5237
5238 /**
5239 * {@inheritDoc}
5240 */
5241 public void requestTransparentRegion(View child) {
5242 if (child != null) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07005243 child.mPrivateFlags |= View.PFLAG_REQUEST_TRANSPARENT_REGIONS;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005244 if (mParent != null) {
5245 mParent.requestTransparentRegion(this);
5246 }
5247 }
5248 }
Romain Guy8506ab42009-06-11 17:35:47 -07005249
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005250
5251 @Override
5252 protected boolean fitSystemWindows(Rect insets) {
5253 boolean done = super.fitSystemWindows(insets);
5254 if (!done) {
5255 final int count = mChildrenCount;
5256 final View[] children = mChildren;
5257 for (int i = 0; i < count; i++) {
5258 done = children[i].fitSystemWindows(insets);
5259 if (done) {
5260 break;
5261 }
5262 }
5263 }
5264 return done;
5265 }
5266
5267 /**
5268 * Returns the animation listener to which layout animation events are
5269 * sent.
5270 *
5271 * @return an {@link android.view.animation.Animation.AnimationListener}
5272 */
5273 public Animation.AnimationListener getLayoutAnimationListener() {
5274 return mAnimationListener;
5275 }
5276
5277 @Override
5278 protected void drawableStateChanged() {
5279 super.drawableStateChanged();
5280
5281 if ((mGroupFlags & FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE) != 0) {
5282 if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0) {
5283 throw new IllegalStateException("addStateFromChildren cannot be enabled if a"
5284 + " child has duplicateParentState set to true");
5285 }
5286
5287 final View[] children = mChildren;
5288 final int count = mChildrenCount;
5289
5290 for (int i = 0; i < count; i++) {
5291 final View child = children[i];
5292 if ((child.mViewFlags & DUPLICATE_PARENT_STATE) != 0) {
5293 child.refreshDrawableState();
5294 }
5295 }
5296 }
5297 }
5298
5299 @Override
Dianne Hackborne2136772010-11-04 15:08:59 -07005300 public void jumpDrawablesToCurrentState() {
5301 super.jumpDrawablesToCurrentState();
5302 final View[] children = mChildren;
5303 final int count = mChildrenCount;
5304 for (int i = 0; i < count; i++) {
5305 children[i].jumpDrawablesToCurrentState();
5306 }
5307 }
5308
5309 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005310 protected int[] onCreateDrawableState(int extraSpace) {
5311 if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) == 0) {
5312 return super.onCreateDrawableState(extraSpace);
5313 }
5314
5315 int need = 0;
5316 int n = getChildCount();
5317 for (int i = 0; i < n; i++) {
5318 int[] childState = getChildAt(i).getDrawableState();
5319
5320 if (childState != null) {
5321 need += childState.length;
5322 }
5323 }
5324
5325 int[] state = super.onCreateDrawableState(extraSpace + need);
5326
5327 for (int i = 0; i < n; i++) {
5328 int[] childState = getChildAt(i).getDrawableState();
5329
5330 if (childState != null) {
5331 state = mergeDrawableStates(state, childState);
5332 }
5333 }
5334
5335 return state;
5336 }
5337
5338 /**
5339 * Sets whether this ViewGroup's drawable states also include
5340 * its children's drawable states. This is used, for example, to
5341 * make a group appear to be focused when its child EditText or button
5342 * is focused.
5343 */
5344 public void setAddStatesFromChildren(boolean addsStates) {
5345 if (addsStates) {
5346 mGroupFlags |= FLAG_ADD_STATES_FROM_CHILDREN;
5347 } else {
5348 mGroupFlags &= ~FLAG_ADD_STATES_FROM_CHILDREN;
5349 }
5350
5351 refreshDrawableState();
5352 }
5353
5354 /**
5355 * Returns whether this ViewGroup's drawable states also include
5356 * its children's drawable states. This is used, for example, to
5357 * make a group appear to be focused when its child EditText or button
5358 * is focused.
5359 */
5360 public boolean addStatesFromChildren() {
5361 return (mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0;
5362 }
5363
5364 /**
Jeff Smitha45746e2012-07-19 14:19:24 -05005365 * If {@link #addStatesFromChildren} is true, refreshes this group's
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005366 * drawable state (to include the states from its children).
5367 */
5368 public void childDrawableStateChanged(View child) {
5369 if ((mGroupFlags & FLAG_ADD_STATES_FROM_CHILDREN) != 0) {
5370 refreshDrawableState();
5371 }
5372 }
5373
5374 /**
5375 * Specifies the animation listener to which layout animation events must
5376 * be sent. Only
5377 * {@link android.view.animation.Animation.AnimationListener#onAnimationStart(Animation)}
5378 * and
5379 * {@link android.view.animation.Animation.AnimationListener#onAnimationEnd(Animation)}
5380 * are invoked.
5381 *
5382 * @param animationListener the layout animation listener
5383 */
5384 public void setLayoutAnimationListener(Animation.AnimationListener animationListener) {
5385 mAnimationListener = animationListener;
5386 }
5387
5388 /**
Chet Haasecca2c982011-05-20 14:34:18 -07005389 * This method is called by LayoutTransition when there are 'changing' animations that need
5390 * to start after the layout/setup phase. The request is forwarded to the ViewAncestor, who
5391 * starts all pending transitions prior to the drawing phase in the current traversal.
5392 *
5393 * @param transition The LayoutTransition to be started on the next traversal.
5394 *
5395 * @hide
5396 */
5397 public void requestTransitionStart(LayoutTransition transition) {
Dianne Hackborn6dd005b2011-07-18 13:22:50 -07005398 ViewRootImpl viewAncestor = getViewRootImpl();
Chet Haase1abf7fa2011-08-17 18:31:56 -07005399 if (viewAncestor != null) {
5400 viewAncestor.requestTransitionStart(transition);
5401 }
Chet Haasecca2c982011-05-20 14:34:18 -07005402 }
5403
Fabrice Di Meglio4457e852012-09-18 19:23:12 -07005404 /**
5405 * @hide
5406 */
Fabrice Di Meglio80dc53d2011-06-21 18:36:33 -07005407 @Override
Fabrice Di Meglio84ebb352012-10-11 16:27:37 -07005408 public void resolveRtlPropertiesIfNeeded() {
5409 super.resolveRtlPropertiesIfNeeded();
5410 int count = getChildCount();
5411 for (int i = 0; i < count; i++) {
5412 final View child = getChildAt(i);
5413 if (child.isLayoutDirectionInherited()) {
5414 child.resolveRtlPropertiesIfNeeded();
5415 }
5416 }
5417 }
5418
5419 /**
5420 * @hide
5421 */
5422 @Override
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07005423 public boolean resolveLayoutDirection() {
5424 final boolean result = super.resolveLayoutDirection();
5425 if (result) {
5426 int count = getChildCount();
5427 for (int i = 0; i < count; i++) {
5428 final View child = getChildAt(i);
5429 if (child.isLayoutDirectionInherited()) {
5430 child.resolveLayoutDirection();
5431 }
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07005432 }
5433 }
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07005434 return result;
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07005435 }
5436
5437 /**
5438 * @hide
5439 */
5440 @Override
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07005441 public boolean resolveTextDirection() {
5442 final boolean result = super.resolveTextDirection();
5443 if (result) {
5444 int count = getChildCount();
5445 for (int i = 0; i < count; i++) {
5446 final View child = getChildAt(i);
5447 if (child.isTextDirectionInherited()) {
5448 child.resolveTextDirection();
5449 }
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07005450 }
5451 }
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07005452 return result;
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07005453 }
5454
5455 /**
5456 * @hide
5457 */
5458 @Override
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07005459 public boolean resolveTextAlignment() {
5460 final boolean result = super.resolveTextAlignment();
5461 if (result) {
5462 int count = getChildCount();
5463 for (int i = 0; i < count; i++) {
5464 final View child = getChildAt(i);
5465 if (child.isTextAlignmentInherited()) {
5466 child.resolveTextAlignment();
5467 }
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07005468 }
5469 }
Fabrice Di Meglio9a048562012-09-26 14:55:56 -07005470 return result;
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07005471 }
5472
5473 /**
5474 * @hide
5475 */
5476 @Override
Fabrice Di Meglio84ebb352012-10-11 16:27:37 -07005477 public void resolvePadding() {
5478 super.resolvePadding();
5479 int count = getChildCount();
5480 for (int i = 0; i < count; i++) {
5481 final View child = getChildAt(i);
5482 if (child.isLayoutDirectionInherited()) {
5483 child.resolvePadding();
5484 }
5485 }
5486 }
5487
5488 /**
5489 * @hide
5490 */
5491 @Override
5492 protected void resolveDrawables() {
5493 super.resolveDrawables();
5494 int count = getChildCount();
5495 for (int i = 0; i < count; i++) {
5496 final View child = getChildAt(i);
5497 if (child.isLayoutDirectionInherited()) {
5498 child.resolveDrawables();
5499 }
5500 }
5501 }
5502
Fabrice Di Meglio1e0ed6b2012-10-18 16:06:52 -07005503 /**
5504 * @hide
5505 */
Fabrice Di Megliofcc33482012-10-18 11:11:51 -07005506 @Override
5507 public void resolveLayoutParams() {
5508 super.resolveLayoutParams();
5509 int count = getChildCount();
5510 for (int i = 0; i < count; i++) {
5511 final View child = getChildAt(i);
5512 child.resolveLayoutParams();
5513 }
5514 }
5515
Fabrice Di Meglio84ebb352012-10-11 16:27:37 -07005516 /**
5517 * @hide
5518 */
5519 @Override
Fabrice Di Meglio4457e852012-09-18 19:23:12 -07005520 public void resetResolvedLayoutDirection() {
5521 super.resetResolvedLayoutDirection();
5522
Fabrice Di Meglio4457e852012-09-18 19:23:12 -07005523 int count = getChildCount();
Fabrice Di Meglio80dc53d2011-06-21 18:36:33 -07005524 for (int i = 0; i < count; i++) {
5525 final View child = getChildAt(i);
Fabrice Di Meglioe56ffdc2012-09-23 14:51:16 -07005526 if (child.isLayoutDirectionInherited()) {
Fabrice Di Meglio7f86c802011-07-01 15:09:24 -07005527 child.resetResolvedLayoutDirection();
Fabrice Di Meglio80dc53d2011-06-21 18:36:33 -07005528 }
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07005529 }
5530 }
5531
5532 /**
5533 * @hide
5534 */
5535 @Override
5536 public void resetResolvedTextDirection() {
5537 super.resetResolvedTextDirection();
5538
5539 int count = getChildCount();
5540 for (int i = 0; i < count; i++) {
5541 final View child = getChildAt(i);
Fabrice Di Meglio97e146c2012-09-23 15:45:16 -07005542 if (child.isTextDirectionInherited()) {
Fabrice Di Meglio22268862011-06-27 18:13:18 -07005543 child.resetResolvedTextDirection();
5544 }
Fabrice Di Meglio1f88ba82012-09-24 14:56:49 -07005545 }
5546 }
5547
5548 /**
5549 * @hide
5550 */
5551 @Override
5552 public void resetResolvedTextAlignment() {
5553 super.resetResolvedTextAlignment();
5554
5555 int count = getChildCount();
5556 for (int i = 0; i < count; i++) {
5557 final View child = getChildAt(i);
Fabrice Di Meglio1a7d4872012-09-23 16:19:58 -07005558 if (child.isTextAlignmentInherited()) {
Fabrice Di Meglio9da0f8a2012-03-13 19:37:57 -07005559 child.resetResolvedTextAlignment();
5560 }
5561 }
5562 }
5563
Fabrice Di Meglio22268862011-06-27 18:13:18 -07005564 /**
Fabrice Di Meglio84ebb352012-10-11 16:27:37 -07005565 * @hide
5566 */
5567 @Override
5568 public void resetResolvedPadding() {
5569 super.resetResolvedPadding();
5570
5571 int count = getChildCount();
5572 for (int i = 0; i < count; i++) {
5573 final View child = getChildAt(i);
5574 if (child.isLayoutDirectionInherited()) {
5575 child.resetResolvedPadding();
5576 }
5577 }
5578 }
5579
5580 /**
5581 * @hide
5582 */
5583 @Override
5584 protected void resetResolvedDrawables() {
5585 super.resetResolvedDrawables();
5586
5587 int count = getChildCount();
5588 for (int i = 0; i < count; i++) {
5589 final View child = getChildAt(i);
5590 if (child.isLayoutDirectionInherited()) {
5591 child.resetResolvedDrawables();
5592 }
5593 }
5594 }
5595
5596 /**
Patrick Dubroye0a799a2011-05-04 16:19:22 -07005597 * Return true if the pressed state should be delayed for children or descendants of this
5598 * ViewGroup. Generally, this should be done for containers that can scroll, such as a List.
5599 * This prevents the pressed state from appearing when the user is actually trying to scroll
5600 * the content.
5601 *
5602 * The default implementation returns true for compatibility reasons. Subclasses that do
5603 * not scroll should generally override this method and return false.
5604 */
5605 public boolean shouldDelayChildPressedState() {
5606 return true;
5607 }
5608
Philip Milned7dd8902012-01-26 16:55:30 -08005609 /** @hide */
5610 protected void onSetLayoutParams(View child, LayoutParams layoutParams) {
5611 }
5612
Patrick Dubroye0a799a2011-05-04 16:19:22 -07005613 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005614 * LayoutParams are used by views to tell their parents how they want to be
5615 * laid out. See
5616 * {@link android.R.styleable#ViewGroup_Layout ViewGroup Layout Attributes}
5617 * for a list of all child view attributes that this class supports.
Romain Guy8506ab42009-06-11 17:35:47 -07005618 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005619 * <p>
5620 * The base LayoutParams class just describes how big the view wants to be
5621 * for both width and height. For each dimension, it can specify one of:
5622 * <ul>
Dirk Dougherty75c66da2010-03-25 16:33:33 -07005623 * <li>FILL_PARENT (renamed MATCH_PARENT in API Level 8 and higher), which
5624 * means that the view wants to be as big as its parent (minus padding)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005625 * <li> WRAP_CONTENT, which means that the view wants to be just big enough
5626 * to enclose its content (plus padding)
Dirk Dougherty75c66da2010-03-25 16:33:33 -07005627 * <li> an exact number
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005628 * </ul>
5629 * There are subclasses of LayoutParams for different subclasses of
5630 * ViewGroup. For example, AbsoluteLayout has its own subclass of
Joe Fernandez558459f2011-10-13 16:47:36 -07005631 * LayoutParams which adds an X and Y value.</p>
5632 *
5633 * <div class="special reference">
5634 * <h3>Developer Guides</h3>
5635 * <p>For more information about creating user interface layouts, read the
5636 * <a href="{@docRoot}guide/topics/ui/declaring-layout.html">XML Layouts</a> developer
5637 * guide.</p></div>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005638 *
5639 * @attr ref android.R.styleable#ViewGroup_Layout_layout_height
5640 * @attr ref android.R.styleable#ViewGroup_Layout_layout_width
5641 */
5642 public static class LayoutParams {
5643 /**
Dirk Dougherty75c66da2010-03-25 16:33:33 -07005644 * Special value for the height or width requested by a View.
5645 * FILL_PARENT means that the view wants to be as big as its parent,
5646 * minus the parent's padding, if any. This value is deprecated
5647 * starting in API Level 8 and replaced by {@link #MATCH_PARENT}.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005648 */
Romain Guy980a9382010-01-08 15:06:28 -08005649 @SuppressWarnings({"UnusedDeclaration"})
5650 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005651 public static final int FILL_PARENT = -1;
5652
5653 /**
5654 * Special value for the height or width requested by a View.
Gilles Debunnef5c6eff2010-02-09 19:08:36 -08005655 * MATCH_PARENT means that the view wants to be as big as its parent,
Dirk Dougherty75c66da2010-03-25 16:33:33 -07005656 * minus the parent's padding, if any. Introduced in API Level 8.
Romain Guy980a9382010-01-08 15:06:28 -08005657 */
5658 public static final int MATCH_PARENT = -1;
5659
5660 /**
5661 * Special value for the height or width requested by a View.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005662 * WRAP_CONTENT means that the view wants to be just large enough to fit
5663 * its own internal content, taking its own padding into account.
5664 */
5665 public static final int WRAP_CONTENT = -2;
5666
5667 /**
Dirk Dougherty75c66da2010-03-25 16:33:33 -07005668 * Information about how wide the view wants to be. Can be one of the
5669 * constants FILL_PARENT (replaced by MATCH_PARENT ,
5670 * in API Level 8) or WRAP_CONTENT. or an exact size.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005671 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07005672 @ViewDebug.ExportedProperty(category = "layout", mapping = {
Romain Guy980a9382010-01-08 15:06:28 -08005673 @ViewDebug.IntToString(from = MATCH_PARENT, to = "MATCH_PARENT"),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005674 @ViewDebug.IntToString(from = WRAP_CONTENT, to = "WRAP_CONTENT")
5675 })
5676 public int width;
5677
5678 /**
Dirk Dougherty75c66da2010-03-25 16:33:33 -07005679 * Information about how tall the view wants to be. Can be one of the
5680 * constants FILL_PARENT (replaced by MATCH_PARENT ,
5681 * in API Level 8) or WRAP_CONTENT. or an exact size.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005682 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07005683 @ViewDebug.ExportedProperty(category = "layout", mapping = {
Romain Guy980a9382010-01-08 15:06:28 -08005684 @ViewDebug.IntToString(from = MATCH_PARENT, to = "MATCH_PARENT"),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005685 @ViewDebug.IntToString(from = WRAP_CONTENT, to = "WRAP_CONTENT")
5686 })
5687 public int height;
5688
5689 /**
5690 * Used to animate layouts.
5691 */
5692 public LayoutAnimationController.AnimationParameters layoutAnimationParameters;
5693
5694 /**
5695 * Creates a new set of layout parameters. The values are extracted from
5696 * the supplied attributes set and context. The XML attributes mapped
5697 * to this set of layout parameters are:
5698 *
5699 * <ul>
5700 * <li><code>layout_width</code>: the width, either an exact value,
Dirk Dougherty75c66da2010-03-25 16:33:33 -07005701 * {@link #WRAP_CONTENT}, or {@link #FILL_PARENT} (replaced by
5702 * {@link #MATCH_PARENT} in API Level 8)</li>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005703 * <li><code>layout_height</code>: the height, either an exact value,
Dirk Dougherty75c66da2010-03-25 16:33:33 -07005704 * {@link #WRAP_CONTENT}, or {@link #FILL_PARENT} (replaced by
5705 * {@link #MATCH_PARENT} in API Level 8)</li>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005706 * </ul>
5707 *
5708 * @param c the application environment
5709 * @param attrs the set of attributes from which to extract the layout
5710 * parameters' values
5711 */
5712 public LayoutParams(Context c, AttributeSet attrs) {
5713 TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.ViewGroup_Layout);
5714 setBaseAttributes(a,
5715 R.styleable.ViewGroup_Layout_layout_width,
5716 R.styleable.ViewGroup_Layout_layout_height);
5717 a.recycle();
5718 }
5719
5720 /**
5721 * Creates a new set of layout parameters with the specified width
5722 * and height.
5723 *
Dirk Dougherty75c66da2010-03-25 16:33:33 -07005724 * @param width the width, either {@link #WRAP_CONTENT},
5725 * {@link #FILL_PARENT} (replaced by {@link #MATCH_PARENT} in
5726 * API Level 8), or a fixed size in pixels
5727 * @param height the height, either {@link #WRAP_CONTENT},
5728 * {@link #FILL_PARENT} (replaced by {@link #MATCH_PARENT} in
5729 * API Level 8), or a fixed size in pixels
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005730 */
5731 public LayoutParams(int width, int height) {
5732 this.width = width;
5733 this.height = height;
5734 }
5735
5736 /**
5737 * Copy constructor. Clones the width and height values of the source.
5738 *
5739 * @param source The layout params to copy from.
5740 */
5741 public LayoutParams(LayoutParams source) {
5742 this.width = source.width;
5743 this.height = source.height;
5744 }
5745
5746 /**
5747 * Used internally by MarginLayoutParams.
5748 * @hide
5749 */
5750 LayoutParams() {
5751 }
5752
5753 /**
Dave Burke579e1402012-10-18 20:41:55 -07005754 * Extracts the layout parameters from the supplied attributes.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005755 *
5756 * @param a the style attributes to extract the parameters from
5757 * @param widthAttr the identifier of the width attribute
5758 * @param heightAttr the identifier of the height attribute
5759 */
5760 protected void setBaseAttributes(TypedArray a, int widthAttr, int heightAttr) {
Dave Burke579e1402012-10-18 20:41:55 -07005761 width = a.getLayoutDimension(widthAttr, "layout_width");
5762 height = a.getLayoutDimension(heightAttr, "layout_height");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005763 }
5764
5765 /**
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07005766 * Resolve layout parameters depending on the layout direction. Subclasses that care about
5767 * layoutDirection changes should override this method. The default implementation does
5768 * nothing.
5769 *
5770 * @param layoutDirection the direction of the layout
5771 *
5772 * {@link View#LAYOUT_DIRECTION_LTR}
5773 * {@link View#LAYOUT_DIRECTION_RTL}
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07005774 */
Fabrice Di Meglio2918ab62012-10-10 16:39:25 -07005775 public void resolveLayoutDirection(int layoutDirection) {
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07005776 }
5777
5778 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005779 * Returns a String representation of this set of layout parameters.
5780 *
5781 * @param output the String to prepend to the internal representation
5782 * @return a String with the following format: output +
5783 * "ViewGroup.LayoutParams={ width=WIDTH, height=HEIGHT }"
Romain Guy8506ab42009-06-11 17:35:47 -07005784 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005785 * @hide
5786 */
5787 public String debug(String output) {
5788 return output + "ViewGroup.LayoutParams={ width="
5789 + sizeToString(width) + ", height=" + sizeToString(height) + " }";
5790 }
5791
5792 /**
Philip Milne10ca24a2012-04-23 15:38:27 -07005793 * Use {@code canvas} to draw suitable debugging annotations for these LayoutParameters.
5794 *
5795 * @param view the view that contains these layout parameters
5796 * @param canvas the canvas on which to draw
5797 *
5798 * @hide
5799 */
Philip Milne7b757812012-09-19 18:13:44 -07005800 public void onDebugDraw(View view, Canvas canvas, Paint paint) {
Philip Milne10ca24a2012-04-23 15:38:27 -07005801 }
5802
5803 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005804 * Converts the specified size to a readable String.
5805 *
5806 * @param size the size to convert
5807 * @return a String instance representing the supplied size
Romain Guy8506ab42009-06-11 17:35:47 -07005808 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005809 * @hide
5810 */
5811 protected static String sizeToString(int size) {
5812 if (size == WRAP_CONTENT) {
5813 return "wrap-content";
5814 }
Romain Guy980a9382010-01-08 15:06:28 -08005815 if (size == MATCH_PARENT) {
5816 return "match-parent";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005817 }
5818 return String.valueOf(size);
5819 }
5820 }
5821
5822 /**
5823 * Per-child layout information for layouts that support margins.
5824 * See
5825 * {@link android.R.styleable#ViewGroup_MarginLayout ViewGroup Margin Layout Attributes}
5826 * for a list of all child view attributes that this class supports.
5827 */
5828 public static class MarginLayoutParams extends ViewGroup.LayoutParams {
5829 /**
Philip Milned7dd8902012-01-26 16:55:30 -08005830 * The left margin in pixels of the child.
5831 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
5832 * to this field.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005833 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07005834 @ViewDebug.ExportedProperty(category = "layout")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005835 public int leftMargin;
5836
5837 /**
Philip Milned7dd8902012-01-26 16:55:30 -08005838 * The top margin in pixels of the child.
5839 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
5840 * to this field.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005841 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07005842 @ViewDebug.ExportedProperty(category = "layout")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005843 public int topMargin;
5844
5845 /**
Philip Milned7dd8902012-01-26 16:55:30 -08005846 * The right margin in pixels of the child.
5847 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
5848 * to this field.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005849 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07005850 @ViewDebug.ExportedProperty(category = "layout")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005851 public int rightMargin;
5852
5853 /**
Philip Milned7dd8902012-01-26 16:55:30 -08005854 * The bottom margin in pixels of the child.
5855 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
5856 * to this field.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005857 */
Konstantin Lopyrevbea95162010-08-10 17:02:18 -07005858 @ViewDebug.ExportedProperty(category = "layout")
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005859 public int bottomMargin;
5860
5861 /**
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07005862 * The start margin in pixels of the child.
Fabrice Di Meglio54546f22012-02-14 16:26:16 -08005863 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
5864 * to this field.
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07005865 */
5866 @ViewDebug.ExportedProperty(category = "layout")
Fabrice Di Meglioa40627d2012-09-11 16:47:21 -07005867 private int startMargin = DEFAULT_RELATIVE;
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07005868
5869 /**
5870 * The end margin in pixels of the child.
Fabrice Di Meglio54546f22012-02-14 16:26:16 -08005871 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value
5872 * to this field.
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07005873 */
5874 @ViewDebug.ExportedProperty(category = "layout")
Fabrice Di Meglioa40627d2012-09-11 16:47:21 -07005875 private int endMargin = DEFAULT_RELATIVE;
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07005876
5877 /**
5878 * The default start and end margin.
Fabrice Di Megliof443f982012-07-13 20:24:03 -07005879 * @hide
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07005880 */
Fabrice Di Megliof443f982012-07-13 20:24:03 -07005881 public static final int DEFAULT_RELATIVE = Integer.MIN_VALUE;
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07005882
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07005883 private int initialLeftMargin;
5884 private int initialRightMargin;
5885
Fabrice Di Megliof443f982012-07-13 20:24:03 -07005886 private static int LAYOUT_DIRECTION_UNDEFINED = -1;
5887
5888 // Layout direction undefined by default
5889 private int layoutDirection = LAYOUT_DIRECTION_UNDEFINED;
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07005890
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07005891 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005892 * Creates a new set of layout parameters. The values are extracted from
5893 * the supplied attributes set and context.
5894 *
5895 * @param c the application environment
5896 * @param attrs the set of attributes from which to extract the layout
5897 * parameters' values
5898 */
5899 public MarginLayoutParams(Context c, AttributeSet attrs) {
5900 super();
5901
5902 TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.ViewGroup_MarginLayout);
5903 setBaseAttributes(a,
5904 R.styleable.ViewGroup_MarginLayout_layout_width,
5905 R.styleable.ViewGroup_MarginLayout_layout_height);
5906
5907 int margin = a.getDimensionPixelSize(
5908 com.android.internal.R.styleable.ViewGroup_MarginLayout_layout_margin, -1);
5909 if (margin >= 0) {
5910 leftMargin = margin;
5911 topMargin = margin;
5912 rightMargin= margin;
5913 bottomMargin = margin;
5914 } else {
5915 leftMargin = a.getDimensionPixelSize(
5916 R.styleable.ViewGroup_MarginLayout_layout_marginLeft, 0);
5917 topMargin = a.getDimensionPixelSize(
5918 R.styleable.ViewGroup_MarginLayout_layout_marginTop, 0);
5919 rightMargin = a.getDimensionPixelSize(
5920 R.styleable.ViewGroup_MarginLayout_layout_marginRight, 0);
5921 bottomMargin = a.getDimensionPixelSize(
5922 R.styleable.ViewGroup_MarginLayout_layout_marginBottom, 0);
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07005923 startMargin = a.getDimensionPixelSize(
5924 R.styleable.ViewGroup_MarginLayout_layout_marginStart, DEFAULT_RELATIVE);
5925 endMargin = a.getDimensionPixelSize(
5926 R.styleable.ViewGroup_MarginLayout_layout_marginEnd, DEFAULT_RELATIVE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005927 }
5928
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07005929 initialLeftMargin = leftMargin;
5930 initialRightMargin = rightMargin;
5931
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005932 a.recycle();
5933 }
5934
5935 /**
5936 * {@inheritDoc}
5937 */
5938 public MarginLayoutParams(int width, int height) {
5939 super(width, height);
5940 }
5941
5942 /**
5943 * Copy constructor. Clones the width, height and margin values of the source.
5944 *
5945 * @param source The layout params to copy from.
5946 */
5947 public MarginLayoutParams(MarginLayoutParams source) {
5948 this.width = source.width;
5949 this.height = source.height;
5950
5951 this.leftMargin = source.leftMargin;
5952 this.topMargin = source.topMargin;
5953 this.rightMargin = source.rightMargin;
5954 this.bottomMargin = source.bottomMargin;
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07005955 this.startMargin = source.startMargin;
5956 this.endMargin = source.endMargin;
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07005957
5958 this.initialLeftMargin = source.leftMargin;
5959 this.initialRightMargin = source.rightMargin;
5960
Fabrice Di Megliof443f982012-07-13 20:24:03 -07005961 setLayoutDirection(source.layoutDirection);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005962 }
5963
5964 /**
5965 * {@inheritDoc}
5966 */
5967 public MarginLayoutParams(LayoutParams source) {
5968 super(source);
5969 }
5970
5971 /**
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07005972 * Sets the margins, in pixels. A call to {@link android.view.View#requestLayout()} needs
5973 * to be done so that the new margins are taken into account. Left and right margins may be
5974 * overriden by {@link android.view.View#requestLayout()} depending on layout direction.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005975 *
5976 * @param left the left margin size
5977 * @param top the top margin size
5978 * @param right the right margin size
5979 * @param bottom the bottom margin size
5980 *
5981 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginLeft
5982 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginTop
5983 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginRight
5984 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginBottom
5985 */
5986 public void setMargins(int left, int top, int right, int bottom) {
5987 leftMargin = left;
5988 topMargin = top;
5989 rightMargin = right;
5990 bottomMargin = bottom;
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07005991 initialLeftMargin = left;
5992 initialRightMargin = right;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005993 }
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07005994
5995 /**
5996 * Sets the relative margins, in pixels. A call to {@link android.view.View#requestLayout()}
5997 * needs to be done so that the new relative margins are taken into account. Left and right
5998 * margins may be overriden by {@link android.view.View#requestLayout()} depending on layout
5999 * direction.
6000 *
6001 * @param start the start margin size
6002 * @param top the top margin size
6003 * @param end the right margin size
6004 * @param bottom the bottom margin size
6005 *
6006 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart
6007 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginTop
6008 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd
6009 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginBottom
6010 *
6011 * @hide
6012 */
6013 public void setMarginsRelative(int start, int top, int end, int bottom) {
6014 startMargin = start;
6015 topMargin = top;
6016 endMargin = end;
6017 bottomMargin = bottom;
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07006018 initialLeftMargin = 0;
6019 initialRightMargin = 0;
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006020 }
6021
6022 /**
Fabrice Di Meglioa40627d2012-09-11 16:47:21 -07006023 * Sets the relative start margin.
6024 *
Fabrice Di Meglio61a21772012-09-12 16:33:13 -07006025 * @param start the start margin size
Fabrice Di Meglioa40627d2012-09-11 16:47:21 -07006026 *
6027 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart
6028 */
6029 public void setMarginStart(int start) {
6030 startMargin = start;
6031 }
6032
6033 /**
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006034 * Returns the start margin in pixels.
6035 *
6036 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart
6037 *
6038 * @return the start margin in pixels.
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006039 */
6040 public int getMarginStart() {
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07006041 if (startMargin != DEFAULT_RELATIVE) return startMargin;
6042 switch(layoutDirection) {
6043 case View.LAYOUT_DIRECTION_RTL:
6044 return rightMargin;
6045 case View.LAYOUT_DIRECTION_LTR:
6046 default:
6047 return leftMargin;
6048 }
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006049 }
6050
6051 /**
Fabrice Di Meglioa40627d2012-09-11 16:47:21 -07006052 * Sets the relative end margin.
6053 *
Fabrice Di Meglio61a21772012-09-12 16:33:13 -07006054 * @param end the end margin size
Fabrice Di Meglioa40627d2012-09-11 16:47:21 -07006055 *
6056 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd
6057 */
6058 public void setMarginEnd(int end) {
6059 endMargin = end;
6060 }
6061
6062 /**
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006063 * Returns the end margin in pixels.
6064 *
6065 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd
6066 *
6067 * @return the end margin in pixels.
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006068 */
6069 public int getMarginEnd() {
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07006070 if (endMargin != DEFAULT_RELATIVE) return endMargin;
6071 switch(layoutDirection) {
6072 case View.LAYOUT_DIRECTION_RTL:
6073 return leftMargin;
6074 case View.LAYOUT_DIRECTION_LTR:
6075 default:
6076 return rightMargin;
6077 }
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006078 }
6079
6080 /**
6081 * Check if margins are relative.
6082 *
6083 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginStart
6084 * @attr ref android.R.styleable#ViewGroup_MarginLayout_layout_marginEnd
6085 *
Fabrice Di Megliof443f982012-07-13 20:24:03 -07006086 * @return true if either marginStart or marginEnd has been set.
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006087 */
6088 public boolean isMarginRelative() {
6089 return (startMargin != DEFAULT_RELATIVE) || (endMargin != DEFAULT_RELATIVE);
6090 }
6091
6092 /**
Fabrice Di Megliof443f982012-07-13 20:24:03 -07006093 * Set the layout direction
6094 * @param layoutDirection the layout direction.
6095 * Should be either {@link View#LAYOUT_DIRECTION_LTR}
6096 * or {@link View#LAYOUT_DIRECTION_RTL}.
6097 */
6098 public void setLayoutDirection(int layoutDirection) {
6099 if (layoutDirection != View.LAYOUT_DIRECTION_LTR &&
6100 layoutDirection != View.LAYOUT_DIRECTION_RTL) return;
6101 this.layoutDirection = layoutDirection;
6102 }
6103
6104 /**
6105 * Retuns the layout direction. Can be either {@link View#LAYOUT_DIRECTION_LTR} or
6106 * {@link View#LAYOUT_DIRECTION_RTL}.
6107 *
6108 * @return the layout direction.
6109 */
6110 public int getLayoutDirection() {
6111 return layoutDirection;
6112 }
6113
6114 /**
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006115 * This will be called by {@link android.view.View#requestLayout()}. Left and Right margins
Fabrice Di Meglio98aec1c2012-02-13 16:54:05 -08006116 * may be overridden depending on layout direction.
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006117 */
6118 @Override
Fabrice Di Meglio2918ab62012-10-10 16:39:25 -07006119 public void resolveLayoutDirection(int layoutDirection) {
Fabrice Di Megliof443f982012-07-13 20:24:03 -07006120 setLayoutDirection(layoutDirection);
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07006121
6122 if (!isMarginRelative()) return;
6123
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006124 switch(layoutDirection) {
6125 case View.LAYOUT_DIRECTION_RTL:
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07006126 leftMargin = (endMargin > DEFAULT_RELATIVE) ? endMargin : initialLeftMargin;
6127 rightMargin = (startMargin > DEFAULT_RELATIVE) ? startMargin : initialRightMargin;
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006128 break;
6129 case View.LAYOUT_DIRECTION_LTR:
6130 default:
Fabrice Di Meglio69bd5582012-07-02 13:17:24 -07006131 leftMargin = (startMargin > DEFAULT_RELATIVE) ? startMargin : initialLeftMargin;
6132 rightMargin = (endMargin > DEFAULT_RELATIVE) ? endMargin : initialRightMargin;
Fabrice Di Megliob76023a2011-06-20 17:41:21 -07006133 break;
6134 }
6135 }
Philip Milne10ca24a2012-04-23 15:38:27 -07006136
Fabrice Di Meglio03b8d3a2012-09-27 17:05:27 -07006137 /**
6138 * @hide
6139 */
6140 public boolean isLayoutRtl() {
Fabrice Di Megliof443f982012-07-13 20:24:03 -07006141 return (layoutDirection == View.LAYOUT_DIRECTION_RTL);
6142 }
6143
Philip Milne10ca24a2012-04-23 15:38:27 -07006144 /**
6145 * @hide
6146 */
6147 @Override
Philip Milne7b757812012-09-19 18:13:44 -07006148 public void onDebugDraw(View view, Canvas canvas, Paint paint) {
6149 Insets oi = isLayoutModeOptical(view.mParent) ? view.getOpticalInsets() : Insets.NONE;
6150
6151 fillDifference(canvas,
6152 view.getLeft() + oi.left,
6153 view.getTop() + oi.top,
6154 view.getRight() - oi.right,
6155 view.getBottom() - oi.bottom,
6156 leftMargin,
6157 topMargin,
6158 rightMargin,
6159 bottomMargin,
6160 paint);
Philip Milne10ca24a2012-04-23 15:38:27 -07006161 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006162 }
Adam Powell2b342f02010-08-18 18:14:13 -07006163
Jeff Brown20e987b2010-08-23 12:01:02 -07006164 /* Describes a touched view and the ids of the pointers that it has captured.
6165 *
6166 * This code assumes that pointer ids are always in the range 0..31 such that
6167 * it can use a bitfield to track which pointer ids are present.
6168 * As it happens, the lower layers of the input dispatch pipeline also use the
6169 * same trick so the assumption should be safe here...
6170 */
6171 private static final class TouchTarget {
6172 private static final int MAX_RECYCLED = 32;
6173 private static final Object sRecycleLock = new Object();
6174 private static TouchTarget sRecycleBin;
6175 private static int sRecycledCount;
Adam Powell2b342f02010-08-18 18:14:13 -07006176
Jeff Brown20e987b2010-08-23 12:01:02 -07006177 public static final int ALL_POINTER_IDS = -1; // all ones
Adam Powell2b342f02010-08-18 18:14:13 -07006178
Jeff Brown20e987b2010-08-23 12:01:02 -07006179 // The touched child view.
6180 public View child;
6181
6182 // The combined bit mask of pointer ids for all pointers captured by the target.
6183 public int pointerIdBits;
6184
6185 // The next target in the target list.
6186 public TouchTarget next;
6187
6188 private TouchTarget() {
Adam Powell2b342f02010-08-18 18:14:13 -07006189 }
6190
Jeff Brown20e987b2010-08-23 12:01:02 -07006191 public static TouchTarget obtain(View child, int pointerIdBits) {
6192 final TouchTarget target;
6193 synchronized (sRecycleLock) {
Adam Powell816c3be2010-08-23 18:00:05 -07006194 if (sRecycleBin == null) {
Jeff Brown20e987b2010-08-23 12:01:02 -07006195 target = new TouchTarget();
Adam Powell816c3be2010-08-23 18:00:05 -07006196 } else {
Jeff Brown20e987b2010-08-23 12:01:02 -07006197 target = sRecycleBin;
6198 sRecycleBin = target.next;
6199 sRecycledCount--;
6200 target.next = null;
Adam Powell816c3be2010-08-23 18:00:05 -07006201 }
Adam Powell816c3be2010-08-23 18:00:05 -07006202 }
Jeff Brown20e987b2010-08-23 12:01:02 -07006203 target.child = child;
6204 target.pointerIdBits = pointerIdBits;
6205 return target;
6206 }
Adam Powell816c3be2010-08-23 18:00:05 -07006207
Jeff Brown20e987b2010-08-23 12:01:02 -07006208 public void recycle() {
6209 synchronized (sRecycleLock) {
6210 if (sRecycledCount < MAX_RECYCLED) {
6211 next = sRecycleBin;
6212 sRecycleBin = this;
6213 sRecycledCount += 1;
Patrick Dubroyfb0547d2010-10-19 17:36:18 -07006214 } else {
6215 next = null;
Adam Powell816c3be2010-08-23 18:00:05 -07006216 }
Patrick Dubroyfb0547d2010-10-19 17:36:18 -07006217 child = null;
Adam Powell816c3be2010-08-23 18:00:05 -07006218 }
6219 }
Adam Powell2b342f02010-08-18 18:14:13 -07006220 }
Jeff Brown87b7f802011-06-21 18:35:45 -07006221
6222 /* Describes a hovered view. */
6223 private static final class HoverTarget {
6224 private static final int MAX_RECYCLED = 32;
6225 private static final Object sRecycleLock = new Object();
6226 private static HoverTarget sRecycleBin;
6227 private static int sRecycledCount;
6228
6229 // The hovered child view.
6230 public View child;
6231
6232 // The next target in the target list.
6233 public HoverTarget next;
6234
6235 private HoverTarget() {
6236 }
6237
6238 public static HoverTarget obtain(View child) {
6239 final HoverTarget target;
6240 synchronized (sRecycleLock) {
6241 if (sRecycleBin == null) {
6242 target = new HoverTarget();
6243 } else {
6244 target = sRecycleBin;
6245 sRecycleBin = target.next;
6246 sRecycledCount--;
6247 target.next = null;
6248 }
6249 }
6250 target.child = child;
6251 return target;
6252 }
6253
6254 public void recycle() {
6255 synchronized (sRecycleLock) {
6256 if (sRecycledCount < MAX_RECYCLED) {
6257 next = sRecycleBin;
6258 sRecycleBin = this;
6259 sRecycledCount += 1;
6260 } else {
6261 next = null;
6262 }
6263 child = null;
6264 }
6265 }
6266 }
Svetoslav Ganov42138042012-03-20 11:51:39 -07006267
6268 /**
6269 * Pooled class that orderes the children of a ViewGroup from start
6270 * to end based on how they are laid out and the layout direction.
6271 */
6272 static class ChildListForAccessibility {
6273
6274 private static final int MAX_POOL_SIZE = 32;
6275
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08006276 private static final SynchronizedPool<ChildListForAccessibility> sPool =
6277 new SynchronizedPool<ChildListForAccessibility>(MAX_POOL_SIZE);
Svetoslav Ganov42138042012-03-20 11:51:39 -07006278
6279 private final ArrayList<View> mChildren = new ArrayList<View>();
6280
6281 private final ArrayList<ViewLocationHolder> mHolders = new ArrayList<ViewLocationHolder>();
6282
6283 public static ChildListForAccessibility obtain(ViewGroup parent, boolean sort) {
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08006284 ChildListForAccessibility list = sPool.acquire();
6285 if (list == null) {
6286 list = new ChildListForAccessibility();
Svetoslav Ganov42138042012-03-20 11:51:39 -07006287 }
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08006288 list.init(parent, sort);
6289 return list;
Svetoslav Ganov42138042012-03-20 11:51:39 -07006290 }
6291
6292 public void recycle() {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006293 clear();
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08006294 sPool.release(this);
Svetoslav Ganov42138042012-03-20 11:51:39 -07006295 }
6296
6297 public int getChildCount() {
6298 return mChildren.size();
6299 }
6300
6301 public View getChildAt(int index) {
6302 return mChildren.get(index);
6303 }
6304
6305 public int getChildIndex(View child) {
6306 return mChildren.indexOf(child);
6307 }
6308
6309 private void init(ViewGroup parent, boolean sort) {
6310 ArrayList<View> children = mChildren;
6311 final int childCount = parent.getChildCount();
6312 for (int i = 0; i < childCount; i++) {
6313 View child = parent.getChildAt(i);
6314 children.add(child);
6315 }
6316 if (sort) {
6317 ArrayList<ViewLocationHolder> holders = mHolders;
6318 for (int i = 0; i < childCount; i++) {
6319 View child = children.get(i);
6320 ViewLocationHolder holder = ViewLocationHolder.obtain(parent, child);
6321 holders.add(holder);
6322 }
6323 Collections.sort(holders);
6324 for (int i = 0; i < childCount; i++) {
6325 ViewLocationHolder holder = holders.get(i);
6326 children.set(i, holder.mView);
6327 holder.recycle();
6328 }
6329 holders.clear();
6330 }
6331 }
6332
6333 private void clear() {
6334 mChildren.clear();
6335 }
6336 }
6337
6338 /**
6339 * Pooled class that holds a View and its location with respect to
6340 * a specified root. This enables sorting of views based on their
6341 * coordinates without recomputing the position relative to the root
6342 * on every comparison.
6343 */
6344 static class ViewLocationHolder implements Comparable<ViewLocationHolder> {
6345
6346 private static final int MAX_POOL_SIZE = 32;
6347
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08006348 private static final SynchronizedPool<ViewLocationHolder> sPool =
6349 new SynchronizedPool<ViewLocationHolder>(MAX_POOL_SIZE);
Svetoslav Ganov42138042012-03-20 11:51:39 -07006350
6351 private final Rect mLocation = new Rect();
6352
6353 public View mView;
6354
6355 private int mLayoutDirection;
6356
6357 public static ViewLocationHolder obtain(ViewGroup root, View view) {
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08006358 ViewLocationHolder holder = sPool.acquire();
6359 if (holder == null) {
6360 holder = new ViewLocationHolder();
Svetoslav Ganov42138042012-03-20 11:51:39 -07006361 }
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08006362 holder.init(root, view);
6363 return holder;
Svetoslav Ganov42138042012-03-20 11:51:39 -07006364 }
6365
6366 public void recycle() {
Svetoslav Ganov42138042012-03-20 11:51:39 -07006367 clear();
Svetoslav Ganovbe922dc2012-11-30 16:46:26 -08006368 sPool.release(this);
Svetoslav Ganov42138042012-03-20 11:51:39 -07006369 }
6370
6371 @Override
6372 public int compareTo(ViewLocationHolder another) {
6373 // This instance is greater than an invalid argument.
6374 if (another == null) {
6375 return 1;
6376 }
6377 if (getClass() != another.getClass()) {
6378 return 1;
6379 }
6380 // First is above second.
6381 if (mLocation.bottom - another.mLocation.top <= 0) {
6382 return -1;
6383 }
6384 // First is below second.
6385 if (mLocation.top - another.mLocation.bottom >= 0) {
6386 return 1;
6387 }
6388 // LTR
6389 if (mLayoutDirection == LAYOUT_DIRECTION_LTR) {
6390 final int leftDifference = mLocation.left - another.mLocation.left;
6391 // First more to the left than second.
6392 if (leftDifference != 0) {
6393 return leftDifference;
6394 }
6395 } else { // RTL
6396 final int rightDifference = mLocation.right - another.mLocation.right;
6397 // First more to the right than second.
6398 if (rightDifference != 0) {
6399 return -rightDifference;
6400 }
6401 }
6402 // Break tie by top.
6403 final int topDiference = mLocation.top - another.mLocation.top;
6404 if (topDiference != 0) {
6405 return topDiference;
6406 }
6407 // Break tie by height.
6408 final int heightDiference = mLocation.height() - another.mLocation.height();
6409 if (heightDiference != 0) {
6410 return -heightDiference;
6411 }
6412 // Break tie by width.
6413 final int widthDiference = mLocation.width() - another.mLocation.width();
6414 if (widthDiference != 0) {
6415 return -widthDiference;
6416 }
Svetoslav Ganov005b83b2012-04-16 18:17:17 -07006417 // Just break the tie somehow. The accessibliity ids are unique
6418 // and stable, hence this is deterministic tie breaking.
6419 return mView.getAccessibilityViewId() - another.mView.getAccessibilityViewId();
Svetoslav Ganov42138042012-03-20 11:51:39 -07006420 }
6421
6422 private void init(ViewGroup root, View view) {
6423 Rect viewLocation = mLocation;
6424 view.getDrawingRect(viewLocation);
6425 root.offsetDescendantRectToMyCoords(view, viewLocation);
6426 mView = view;
Fabrice Di Meglioe56ffdc2012-09-23 14:51:16 -07006427 mLayoutDirection = root.getLayoutDirection();
Svetoslav Ganov42138042012-03-20 11:51:39 -07006428 }
6429
6430 private void clear() {
6431 mView = null;
6432 mLocation.set(0, 0, 0, 0);
6433 }
6434 }
Romain Guycbc67742012-04-27 16:12:57 -07006435
6436 private static Paint getDebugPaint() {
6437 if (sDebugPaint == null) {
6438 sDebugPaint = new Paint();
6439 sDebugPaint.setAntiAlias(false);
6440 }
6441 return sDebugPaint;
6442 }
6443
Philip Milne7b757812012-09-19 18:13:44 -07006444 private void drawRect(Canvas canvas, Paint paint, int x1, int y1, int x2, int y2) {
Romain Guycbc67742012-04-27 16:12:57 -07006445 if (sDebugLines== null) {
6446 sDebugLines = new float[16];
6447 }
6448
Romain Guycbc67742012-04-27 16:12:57 -07006449 sDebugLines[0] = x1;
6450 sDebugLines[1] = y1;
6451 sDebugLines[2] = x2;
6452 sDebugLines[3] = y1;
6453
6454 sDebugLines[4] = x2;
6455 sDebugLines[5] = y1;
6456 sDebugLines[6] = x2;
Philip Milne7b757812012-09-19 18:13:44 -07006457 sDebugLines[7] = y2;
Romain Guycbc67742012-04-27 16:12:57 -07006458
Philip Milne7b757812012-09-19 18:13:44 -07006459 sDebugLines[8] = x2;
Romain Guycbc67742012-04-27 16:12:57 -07006460 sDebugLines[9] = y2;
6461 sDebugLines[10] = x1;
6462 sDebugLines[11] = y2;
6463
Philip Milne7b757812012-09-19 18:13:44 -07006464 sDebugLines[12] = x1;
6465 sDebugLines[13] = y2;
Romain Guycbc67742012-04-27 16:12:57 -07006466 sDebugLines[14] = x1;
6467 sDebugLines[15] = y1;
6468
Philip Milne7b757812012-09-19 18:13:44 -07006469 canvas.drawLines(sDebugLines, paint);
Romain Guycbc67742012-04-27 16:12:57 -07006470 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006471}